CXXR (C++ R) API
GCStackRoot.h
Go to the documentation of this file.
1 /*CXXR $Id: GCStackRoot.h 799 2010-02-19 14:12:57Z 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-10 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 
47 #ifndef GCSTACKROOT_H
48 #define GCSTACKROOT_H 1
49 
50 #include "CXXR/RObject.h"
51 
52 #ifdef __cplusplus
53 
54 #include <vector>
55 #include "CXXR/GCNode.hpp"
56 
57 namespace CXXR {
58  class Context;
59  class RObject;
60 
76  public:
90  static void ppsRestoreSize(size_t new_size);
91 
100 #ifdef DEBUG_PPS
101  static size_t ppsSize();
102 #else
103  static size_t ppsSize()
104  {
105  return s_pps->size();
106  }
107 #endif
108 
119 #ifndef NDEBUG
120  static unsigned int protect(RObject* node);
121 #else
122  static unsigned int protect(RObject* node)
123  {
125  unsigned int index = s_pps->size();
126  if (node)
127  node->incRefCount();
128  s_pps->push_back(node);
129  return index;
130  }
131 #endif
132 
151  static void reprotect(RObject* node, unsigned int index);
152 
164  static void unprotect(unsigned int count = 1);
165 
176  static void unprotectPtr(RObject* node);
177 
185  static void visitRoots(GCNode::const_visitor* v);
186  protected:
187  GCStackRootBase(const GCNode* node)
188  : m_next(s_roots), m_target(node)
189  {
190  s_roots = this;
192  if (m_target)
193  m_target->incRefCount();
194  }
195 
196  GCStackRootBase(const GCStackRootBase& source)
197  : m_next(s_roots), m_target(source.m_target)
198  {
199  s_roots = this;
200  if (m_target)
201  m_target->incRefCount();
202  }
203 
204  ~GCStackRootBase()
205  {
206 #ifndef NDEBUG
207  if (this != s_roots)
208  seq_error();
209 #endif
210  if (m_target && m_target->decRefCount() == 0)
211  m_target->makeMoribund();
212  s_roots = m_next;
213  }
214 
215  GCStackRootBase& operator=(const GCStackRootBase& source)
216  {
217  if (source.m_target)
218  source.m_target->incRefCount();
219  if (m_target && m_target->decRefCount() == 0)
220  m_target->makeMoribund();
221  m_target = source.m_target;
222  return *this;
223  }
224 
230  void redirect(const GCNode* node)
231  {
233  if (node)
234  node->incRefCount();
235  if (m_target && m_target->decRefCount() == 0)
236  m_target->makeMoribund();
237  m_target = node;
238  }
239 
244  const GCNode* ptr() const
245  {
246  return m_target;
247  }
248  private:
249  friend class GCNode;
250 
251  // Ye olde pointer protection stack:
252 #ifdef NDEBUG
253  static std::vector<RObject*>* s_pps;
254 #else
255  static std::vector<std::pair<RObject*, Context*> >* s_pps;
256 #endif
257 
258  static GCStackRootBase* s_roots;
259 
260  GCStackRootBase* m_next;
261  const GCNode* m_target;
262 
263  // Clean up static data at end of run (called by
264  // GCNode::SchwarzCtr destructor:
265  static void cleanup()
266  {
267  delete s_pps;
268  }
269 
270  // Initialize static data (called by GCNode::SchwarzCtr
271  // constructor):
272  static void initialize();
273 
274  // Report out-of-sequence destructor call and abort program.
275  // (We can't use an exception here because it's called from a
276  // destructor.)
277  static void seq_error();
278  };
279 
315  template <class T = RObject>
316  class GCStackRoot : public GCStackRootBase {
317  public:
323  explicit GCStackRoot(T* node = 0)
324  : GCStackRootBase(node) {}
325 
332  GCStackRoot(const GCStackRoot& source) : GCStackRootBase(source) {}
333 
340  {
342  return *this;
343  }
344 
354  {
356  return *this;
357  }
358 
363  T* operator->() const
364  {
365  return get();
366  }
367 
374  T& operator*() const
375  {
376  return *get();
377  }
378 
386  operator T*() const
387  {
388  return get();
389  }
390 
395  T* get() const
396  {
397  return static_cast<T*>(const_cast<GCNode*>(ptr()));
398  }
399  };
400 }
401 
402 extern "C" {
403 #endif /* __cplusplus */
404 
405  /* ***** C interface ***** */
406 
407  typedef unsigned int PROTECT_INDEX;
408 
421 #ifndef __cplusplus
422  void R_ProtectWithIndex(SEXP node, PROTECT_INDEX *iptr);
423 #else
424  inline void R_ProtectWithIndex(SEXP node, PROTECT_INDEX *iptr)
425  {
426  *iptr = CXXR::GCStackRootBase::protect(node);
427  }
428 #endif
429 
447 #ifndef __cplusplus
448  void R_Reprotect(SEXP node, PROTECT_INDEX index);
449 #else
450  inline void R_Reprotect(SEXP node, PROTECT_INDEX index)
451  {
453  }
454 #endif
455 
469  void Rf_ppsRestoreSize(size_t new_size);
470 
479  size_t Rf_ppsSize();
480 
487 #ifndef __cplusplus
488  SEXP Rf_protect(SEXP node);
489 #else
490  inline SEXP Rf_protect(SEXP node)
491  {
493  return node;
494  }
495 #endif
496 
507 #ifndef __cplusplus
508  void Rf_unprotect(int count);
509 #else
510  inline void Rf_unprotect(int count)
511  {
513  }
514 #endif
515 
527 #ifndef __cplusplus
528  void Rf_unprotect_ptr(SEXP node);
529 #else
530  inline void Rf_unprotect_ptr(SEXP node)
531  {
533  }
534 #endif
535 
536 #ifdef __cplusplus
537 } /* extern "C" */
538 #endif
539 
540 #endif // GCSTACKROOT_H