CXXR (C++ R) API
NodeStack.hpp
Go to the documentation of this file.
1 /*CXXR $Id: NodeStack.hpp 1348 2013-02-25 17:49:03Z arr $
2  *CXXR
3  *CXXR This file is part of CXXR, a project to refactor the R interpreter
4  *CXXR into C++. It may consist in whole or in part of program code and
5  *CXXR documentation taken from the R project itself, incorporated into
6  *CXXR CXXR (and possibly MODIFIED) under the terms of the GNU General Public
7  *CXXR Licence.
8  *CXXR
9  *CXXR CXXR is Copyright (C) 2008-13 Andrew R. Runnalls, subject to such other
10  *CXXR copyrights and copyright restrictions as may be stated below.
11  *CXXR
12  *CXXR CXXR is not part of the R project, and bugs and other issues should
13  *CXXR not be reported via r-bugs or other R project channels; instead refer
14  *CXXR to the CXXR website.
15  *CXXR */
16 
17 /*
18  * R : A Computer Language for Statistical Data Analysis
19  *
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License as published by
22  * the Free Software Foundation; either version 2.1 of the License, or
23  * (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28  * GNU Lesser General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program; if not, a copy is available at
32  * http://www.r-project.org/Licenses/
33  */
34 
40 #ifndef NODESTACK_H
41 #define NODESTACK_H 1
42 
43 #include <vector>
44 #include "CXXR/RObject.h"
45 
46 namespace CXXR {
56  class NodeStack {
57  public:
72  class ElementProxy {
73  public:
82  {
83  m_stack->retarget((*rhs.m_stack)[rhs.m_index], m_index);
84  return *this;
85  }
86 
94  {
95  m_stack->retarget(node, m_index);
96  return *this;
97  }
98 
103  operator RObject* const() const
104  {
105  return m_stack->m_vector[m_index];
106  }
107  private:
108  friend class NodeStack;
109 
110  NodeStack* m_stack;
111  unsigned int m_index;
112 
113  ElementProxy(NodeStack* stack, unsigned int index)
114  : m_stack(stack), m_index(index)
115  {}
116  };
117 
128  class Scope {
129  public:
135  Scope(NodeStack* stack)
136  : m_nodestack(stack),
137 #ifndef NDEBUG
138  m_next_scope(stack->m_innermost_scope),
139 #endif
140  m_saved_size(m_nodestack->size())
141  {
142 #ifndef NDEBUG
143  stack->m_innermost_scope = this;
144 #endif
145  }
146 
147  ~Scope()
148  {
149 #ifndef NDEBUG
150  if (this != m_nodestack->m_innermost_scope)
151  nestingError();
152 #endif
153  m_nodestack->resize(m_saved_size);
154 #ifndef NDEBUG
155  m_nodestack->m_innermost_scope = m_next_scope;
156 #endif
157  }
158  private:
159  friend class NodeStack;
160 
161  NodeStack* m_nodestack;
162 #ifndef NDEBUG
163  Scope* m_next_scope;
164 #endif
165  size_t m_saved_size;
166 
173  size_t startSize() const
174  {
175  return m_saved_size;
176  }
177 
178  static void nestingError();
179  };
180 
188  NodeStack(size_t initial_capacity);
189 
190  ~NodeStack()
191  {
192  resize(0);
193  }
194 
204  ElementProxy operator[](unsigned int index)
205  {
206  return ElementProxy(this, index);
207  }
208 
217  RObject* const operator[](unsigned int index) const
218  {
219  return m_vector[index];
220  }
221 
244  void eraseTopmost(RObject* node);
245 
256  ElementProxy fromEnd(unsigned int count)
257  {
258  return operator[](size() - count);
259  }
260 
274 #ifndef NDEBUG
275  void pop(unsigned int count = 1);
276 #else
277  void pop(unsigned int count = 1)
278  {
279  resize(size() - count);
280  }
281 #endif
282 
288  void protectAll();
289 
298  unsigned int push(RObject* node)
299  {
301  unsigned int index = m_vector.size();
302  m_vector.push_back(node);
303  return index;
304  }
305 
323 #ifndef NDEBUG
324  void retarget(RObject* node, unsigned int index);
325 #else
326  void retarget(RObject* node, unsigned int index)
327  {
329  if (index < m_protected_count)
330  retarget_aux(m_vector[index], node);
331  m_vector[index] = node;
332  }
333 #endif
334 
343  void resize(size_t new_size)
344  {
345  if (new_size >= m_protected_count)
346  m_vector.resize(new_size, 0);
347  else resize_aux(new_size);
348  }
349 
354  size_t size() const
355  {
356  return m_vector.size();
357  }
358 
367  RObject* ans = operator[](size() - 1);
368  pop();
369  return ans;
370  }
371 
380  private:
381  std::vector<RObject*> m_vector;
382  size_t m_protected_count; // The nodes (if any) pointed to
383  // (*m_vector)[0] through (*m_vector)[m_protected_count - 1]
384  // will have had their reference counts increased by this
385  // class. Stack entries beyond this (if any) will not yet
386  // have had this protection applied.
387 
388 #ifndef NDEBUG
389  Scope* m_innermost_scope;
390 #endif
391 
392  // Helper function for retarget(), handling the case where
393  // 'index' is within the protected range:
394 #ifdef __GNUC__
395  __attribute__((hot,fastcall))
396 #endif
397  static void retarget_aux(RObject* oldnode, RObject* newnode);
398 
399  // Helper function for trim(), handling the case where the trim
400  // cuts down into protected nodes:
401 #ifdef __GNUC__
402  __attribute__((hot,fastcall))
403 #endif
404  void resize_aux(size_t new_size);
405  };
406 } // namespace CXXR
407 
408 #endif // NODESTACK_H