Chombo + EB  3.2
RefCountedPtr.H
Go to the documentation of this file.
1 #ifdef CH_LANG_CC
2 /*
3  * _______ __
4  * / ___/ / ___ __ _ / / ___
5  * / /__/ _ \/ _ \/ V \/ _ \/ _ \
6  * \___/_//_/\___/_/_/_/_.__/\___/
7  * Please refer to Copyright.txt, in Chombo's root directory.
8  */
9 #endif
10 
11 #ifndef _REFCOUNTEDPTR_H_
12 #define _REFCOUNTEDPTR_H_
13 
14 #include <cstdlib>
15 #include <string>
16 #include <typeinfo>
17 #include "MayDay.H"
18 #include "Arena.H"
19 #include "CH_assert.H"
20 #ifdef DEBUGRCP
21  #include "parstream.H"
22 #endif
23 #include "BaseNamespaceHeader.H"
24 
25 #ifdef CH_USE_MEMORY_TRACKING
26 extern unsigned long long int ch_memcount;
27 #endif
28 
29 #ifdef DEBUGRCP
30  #define RCPDBG(x) x
31 #else
32  #define RCPDBG(x) (void)0;
33 #endif
34 
35 //--Traits
36 
37 /*--------------------------------------------------------------------*
38  * Provides a type with inverse constantness from T
39  *--------------------------------------------------------------------*/
40 
41 /// General case T is non-const and inverse is const
42 template <typename T>
43 struct RCPTypeTr
44 {
45  typedef const T InvertConstType;
46 };
47 
48 /// Specialization where T is const and inverse is non-const
49 template <typename T>
50 struct RCPTypeTr<const T>
51 {
52  typedef T InvertConstType;
53 };
54 
55 /*--------------------------------------------------------------------*
56  * Checks if two types are the same
57  *--------------------------------------------------------------------*/
58 
59 /// General case T and S are not the same
60 template <typename T, typename S>
61 struct RCPPairTr
62 {
63  enum
64  {
65  IsSame = 0
66  };
67 };
68 
69 /// Specialization for same type
70 template <typename T>
71 struct RCPPairTr<T, T>
72 {
73  enum
74  {
75  IsSame = 1
76  };
77  typedef T SamePolicyType;
78 };
79 
80 //--Policies
81 
82 /*--------------------------------------------------------------------*
83  * For destroying pointer types
84  *--------------------------------------------------------------------*/
85 
86 /// Policies for when T is a scalar object
88 {
89  template <typename T>
90  static void destroy(T* a_pointer)
91  {
92  delete a_pointer;
93  }
94 };
95 
96 /// Policies for when T is an array
98 {
99  template <typename T>
100  static void destroy(T* a_array)
101  {
102  delete[] a_array;
103  }
104 };
105 
106 /// Policies for when T is created via malloc (or otherwise requires free)
108 {
109  template <typename T>
110  static void destroy(T* a_mem)
111  {
112  free((void*)a_mem);
113  }
114 };
115 
116 /*--------------------------------------------------------------------*/
117 /// A reference-counting handle class.
118 /**
119 
120 \tparam T Type of object pointed to
121 \tparam OP Object Policy for T. If T* is an object pointer, use the
122  RCPPointerPolicy. If T* is an array, use the
123  RCPArrayPolicy to get proper destruction. If T* requires
124  deletion with 'free', use the RCPFreePolicy. By default
125  RCPPointerPolicy is used.
126 
127 This is to be used as a pointer to class T. This will feel and smell
128 just like a built-in pointer except:
129 
130  -# There is no need to call delete on the pointer.
131  -# The default copy constructor and assignment implement ref-counting.
132  -# The user may call isNonUnique to determine if this pointer is
133  the only pointer to the data. This can be used to hide the
134  ref-counting behavior of a class.
135  -# Checks for dereference of a null pointer.
136 
137 This class is completely inlined.
138 
139 typical usage:
140 
141 \code
142 
143 {
144  Box b;
145  IntVect a;
146  //refCount() == 1
147  RefCountedPtr<IntVectSet> set(new IntVectSet());
148 
149  // still just one IntVectSet, but refCount()==2
150  RefCountedPtr<IntVectSet> otherSet(set);
151 
152  // Like a pointer, modifying one modifies the other
153  otherSet->define(b);
154  (*set)|=a;
155  {
156  RefCountedPtr<IntVectSet> anotherSet; // null
157  anotherSet = otherSet ; //now all three have refCount()==3
158  }//anotherSet out of scope, so deleted. IntVectSet NOT deleted.
159 
160  // set.refCount() == 2
161  // otherSet.refCount() == 2;
162  // otherset == set;
163 
164 }
165 // when all RefCountedPtr's for a given object are deleted, the last
166 // one calls 'delete' on the member pointer.
167 \endcode
168 
169 *//*------------------------------------------------------------------*/
170 
171 template <typename T,
172  typename OP = RCPPointerPolicy> // OP means ObjectPolicy
174 {
175 public:
176  // types
177  typedef T value_type;
178  typedef T* pointer;
179  typedef T& reference;
181 
182  /// construct with POD pointer
183  explicit RefCountedPtr(pointer const ptr = 0);
184 
185  /// copy
186  RefCountedPtr(const Self& other);
187 
188  /// const converting copy adds const qualifier.
189  /** the related converting copy could be used but this avoids the
190  dynamic_cast when just adding qualifiers
191  */
193  const RefCountedPtr<typename RCPTypeTr<T>::InvertConstType, OP>& other);
194 
195  /// related converting copy
196  /** allows conversion between related POD pointers. E.g. base to derived
197  (requires dynamic_cast) or derived to base.
198  */
199  template <typename S>
200  RefCountedPtr(const RefCountedPtr<S, OP>& other);
201 
202  // COMPILE TIME ERROR HANDLING
203  // If we copy construct a RCP with a different object policy, the compiler
204  // may try implicit conversion to POD pointer and then use the pointer
205  // constructor. This is bad since the pointer will then be delete twice.
206  // These copy constructors are designed to capture that case (the compiler
207  // prefers them over conversion) and force an error.
208  template <typename OP2>
210  {
211  // A compiler error here means 'other' is not using the same object
212  // policy as 'this'
213  //typedef typename RCPPairTr<OP, OP2>::SamePolicyType Check;
214  MayDay::Error("Invalid runtime code");
215  }
216  template <typename OP2>
218  const RefCountedPtr<typename RCPTypeTr<T>::InvertConstType, OP2>& other)
219  {
220  // A compiler error here means 'other' is not using the same object
221  // policy as 'this'
222  //typedef typename RCPPairTr<OP, OP2>::SamePolicyType Check;
223  MayDay::Error("Invalid runtime code");
224  }
225 
226  /// Destructor
227  ~RefCountedPtr();
228 
229  /// assignment operator copies pointer member
230  /** copies pointer member and integer pointer, decreases 'this' refcount
231  before assignment, then increases refcount of this=rhs.
232  */
233  Self& operator=(const Self& rhs);
234 
235  /// const converting assignment operator adds const qualifier.
236  Self& operator=(
237  const RefCountedPtr<typename RCPTypeTr<T>::InvertConstType, OP>& rhs);
238 
239  /// related assignment operator
240  /** allows conversion between related POD pointers. E.g. base to derived
241  (requires dynamic_cast) or derived to base.
242  */
243  template <typename S>
244  Self& operator=(const RefCountedPtr<S, OP>& rhs);
245 
246  // COMPILE TIME ERROR HANDLING
247  // Similar to copy except an error of ambiguous operator overloading is
248  // seen instead of implicit conversion. These routines make the error
249  // more clear
250  template <typename OP2>
252  {
253  // A compiler error here means 'rhs' is not using the same object
254  // policy as 'this'
255  //typedef typename RCPPairTr<OP, OP2>::SamePolicyType Check;
256  MayDay::Error("Invalid runtime code");
257  }
258  template <typename OP2>
260  const RefCountedPtr<typename RCPTypeTr<T>::InvertConstType, OP2>& rhs)
261  {
262  // A compiler error here means 'rhs' is not using the same object
263  // policy as 'this'
264  //typedef typename RCPPairTr<OP, OP2>::SamePolicyType Check;
265  MayDay::Error("Invalid runtime code");
266  }
267 
268  /// dereference access operator used like a pointer derefence access function.
269  pointer operator ->() const;
270 
271  /// Return a const reference to the pointer and don't ask questions
272  /** Same as operator -> but obtains the reference even if the pointer has
273  * not yet been assigned. Used in some early setup where we want to track
274  * the RCP but it hasn't been defined yet. If you want the pointer
275  * and know it has been allocated, -> should be preferred.
276  */
277  pointer const& getRefToThePointer() const;
278 
279  /// pointer dereference.
280  reference operator *() const;
281 
282  /// [] access
283  reference operator [](const int a_idx) const;
284 
285  /// auto conversion to regular pointer where required.
286  /** kind of dangerous. Deleting the returned pointer will cause havoc.
287  */
288  operator T* () const;
289 
290  bool isNull() const;
291 
292  /// true when refcount is one.
293  bool isNonUnique() const;
294 
295  int refCount() const;
296 
297  void swap(Self& b);
298 
299  /// Will never delete ptr_
300  /**
301  useful in functions that need to return a pointer which, under some
302  circumstances, we want to own, and under others we don't.
303  */
304  void neverDelete();
305 
306  template<typename T2, typename OP2>
307  friend class RefCountedPtr;
308 
309  static const std::string& name()
310  {
311  return name_;
312  }
313 
314  // these functions mostly control the memory tracking features.
315  // However, deletion of the pointer is in freeMem
316 
317  void incrementMem();
318  void freeMem();
319 
320  /// move constructor
321  inline RefCountedPtr(RefCountedPtr<T,OP>&& a_in) noexcept
322  :ptr_(a_in.ptr_), refCount_(a_in.refCount_)
323  {a_in.ptr_=0; a_in.refCount_=0; }
324 
326  { std::swap(ptr_, a_in.ptr_); std::swap(refCount_,a_in.refCount_);
327  return *this;}
328 
329 protected:
330  void refUp(); // atomic refcount increment
331  void refDown();// atomic refcount decrement and freeMem on refCount_==0
333  int* refCount_;
334  static std::string name_;
335  static BArena s_Arena;
336  static int size_;
337 private:
338 
339 };
340 
341 template<typename T, typename OP>
342 std::string RefCountedPtr<T, OP>::name_(
343  std::string("RefCountedPtr ")+std::string(typeid(T).name()));
344 
345 //template<typename T, typename OP>
346 //BArena RefCountedPtr<T>::s_Arena(name_.c_str());
347 template<typename T, typename OP>
349 
350 template<typename T, typename OP>
351 int RefCountedPtr<T, OP>::size_ = sizeof(T)+2*sizeof(int);
352 
353 template <typename T, typename OP>
354 inline void
356 {
357 #ifdef CH_USE_MEMORY_TRACKING
358 #pragma omp critical(s_Arena)
359  {
360  ch_memcount+=size_;
361  s_Arena.bytes += size_;
362  }
363  refCount_[1] = size_;
364  if (s_Arena.bytes > s_Arena.peak)
365  {
366  s_Arena.peak = s_Arena.bytes;
367  }
368 #endif
369 }
370 
371 template <typename T, typename OP>
372 inline
374 {
375 #ifdef CH_USE_MEMORY_TRACKING
376 #pragma omp critical(s_Arena)
377  {
378  ch_memcount-=refCount_[1];
379  s_Arena.bytes -= refCount_[1];
380  }
381 #endif
382  RCPDBG(pout() << "====> Destroying " << ptr_ << std::endl;)
383  OP::destroy(ptr_);
384  ptr_ = 0;
385  delete [] refCount_;
386  refCount_ = 0;
387 }
388 
389 template <typename T, typename OP>
390 inline
392  : ptr_(ptr),
393  refCount_(0)
394 {
395  RCPDBG(pout() << "POD pointer constructor\n";)
396  if (ptr_)
397  {
398  refCount_ = new int[2];
399  if (refCount_ == 0)
400  MayDay::Error("RefCountedPtr::RefCountedPtr(T* ptr) out of memory");
401  *refCount_ = 1;
402  incrementMem();
403  RCPDBG(pout() << "====> Creating " << ptr << std::endl;)
404  }
405 }
406 
407 template<typename T, typename OP>
408 inline
410 {
411  RCPDBG(pout() << "refUp " << ptr_ << std::endl;);
412  if(refCount_ != 0)
413  {
414 #pragma omp atomic
415  ++(*refCount_); // this looks dumb, but the atomic MUST be on the very next line
416  }
417 }
418 
419 template<typename T, typename OP>
420 inline
422 {
423  RCPDBG(pout() << "refDown " << ptr_ << std::endl;);
424  if(refCount_ != 0)
425  {
426  int c;
427 #pragma omp atomic capture
428  c = --(*refCount_); // many threads can be decrementing refCount_
429  // we should never "bounce" off zero with RefCountedPtr. If we do then there is
430  // a use case I have not comprehended.
431  if(c==0) freeMem();
432  }
433 }
434 template <typename T, typename OP>
435 inline
437  : ptr_(other.ptr_),
438  refCount_(other.refCount_)
439 {
440  RCPDBG(pout() << "standard copy " << ptr_ << std::endl;);
441  refUp();
442 }
443 
444 template <typename T, typename OP>
445 inline
447  const RefCountedPtr<typename RCPTypeTr<T>::InvertConstType, OP>& other)
448  : ptr_(other.ptr_),
449  refCount_(other.refCount_)
450 {
451  RCPDBG(pout() << "const conversion copy " << ptr_ << std::endl;);
452  refUp();
453 }
454 
455 template <typename T, typename OP>
456 template <typename S>
457 inline
459  : ptr_(dynamic_cast<T*>(other.ptr_)),
460  refCount_(other.refCount_)
461 {
462  RCPDBG(pout() << "related conversion copy " << ptr_ << std::endl;)
463  // Note: a failure here means you cannot convert S* into T* as they are
464  // not properly related.
465  if (other.ptr_ != NULL)
466  {
467  CH_assert(ptr_ != NULL);
468  }
469  refUp();
470 }
471 
472 template <typename T, typename OP>
473 inline
475 {
476  refDown();
477 }
478 
479 template <typename T, typename OP>
480 inline typename RefCountedPtr<T, OP>::Self&
482 {
483  RCPDBG(pout() << "standard assign " << rhs.ptr_ << std::endl;)
484 
485  // this is THE tricky code for RefCountedPtr
486  // rhs is const for the life of this function, BUT rhs might be *this
487  // for another thread on the next line of code.
488 #pragma omp critical(RCPAssign)
489  {
490  if (ptr_ != rhs.ptr_)
491  {
492  refDown();
493 
494  ptr_ = rhs.ptr_;
495  refCount_ = rhs.refCount_;
496  refUp();
497 
498  }
499  }
500  return *this;
501 }
502 
503 template <typename T, typename OP>
504 inline typename RefCountedPtr<T, OP>::Self&
506  const RefCountedPtr<typename RCPTypeTr<T>::InvertConstType, OP>& rhs)
507 {
508  RCPDBG(pout() << "const conversion assign " << rhs.ptr_ << std::endl;)
509 #pragma omp critical(RCPAssign)
510  {
511  if (ptr_ != rhs.ptr_)
512  {
513  //refDown();
514  if (refCount_ != 0 && --(*refCount_) == 0)
515  {
516  freeMem();
517  }
518  ptr_ = rhs.ptr_;
519  refCount_ = rhs.refCount_;
520  //refUp();
521  if (refCount_ != 0)
522  ++(*refCount_);
523  }
524  }
525  return *this;
526 }
527 
528 template <typename T, typename OP>
529 template <typename S>
530 inline typename RefCountedPtr<T, OP>::Self&
532 {
533  RCPDBG(pout() << "related conversion assign " << rhs.ptr_ << std::endl;)
534 #pragma omp critical(RCPAssign)
535  {
536  if (ptr_ != rhs.ptr_)
537  {
538  //refDown();
539  if (refCount_ != 0 && --(*refCount_) == 0)
540  {
541  freeMem();
542  }
543  ptr_ = dynamic_cast<T*>(rhs.ptr_);
544  // Note: a failure here means you cannot convert S* into T* as they are
545  // not properly related.
546  if (rhs.ptr_ != NULL){ CH_assert(ptr_ != NULL); }
547  refCount_ = rhs.refCount_;
548  //refUp();
549  if (refCount_ != 0)
550  ++(*refCount_);
551  }
552  }
553  return *this;
554 }
555 
556 template <typename T, typename OP>
557 inline typename RefCountedPtr<T, OP>::pointer
559 {
560  if (ptr_ == 0)
561  MayDay::Error("RefCountedPtr<T>::operator ->() on null pointer");
562  return ptr_;
563 }
564 
565 template <typename T, typename OP>
566 inline typename RefCountedPtr<T, OP>::pointer const&
568 {
569  return ptr_;
570 }
571 
572 template <typename T, typename OP>
573 inline typename RefCountedPtr<T, OP>::reference
575 {
576  if (ptr_ == 0)
577  MayDay::Error("RefCountedPtr<T>::operator *() on null pointer");
578  return *ptr_;
579 }
580 
581 template <typename T, typename OP>
582 inline typename RefCountedPtr<T, OP>::reference
583 RefCountedPtr<T, OP>::operator [](const int a_idx) const
584 {
585  CH_assert(ptr_);
586  return ptr_[a_idx];
587 }
588 
589 template <class T, typename OP>
590 inline
592 {
593  RCPDBG(pout() << "auto conversion " << ptr_ << std::endl;)
594  return ptr_;
595 }
596 
597 template <typename T, typename OP>
598 inline bool
600 {
601  return (ptr_ == 0);
602 }
603 
604 template <typename T, typename OP>
605 inline bool
607 {
608  return refCount_ == 0 ? false : *refCount_ != 1;
609 }
610 
611 template <typename T, typename OP>
612 inline int
614 {
615  return refCount_ == 0 ? 0 : *refCount_;
616 }
617 
618 template <typename T, typename OP>
619 inline void
621 {
622 #ifdef _OPENMP
623 #pragma omp critical
624 #endif
625  {
626  // not precisely a robust swap. Lots of bad things could happen
627  pointer s = ptr_;
628  ptr_ = b.ptr_;
629  b.ptr_ = s;
630 
631  int* r = refCount_;
632  refCount_ = b.refCount_;
633  b.refCount_ = r;
634  }
635 }
636 
637 template <typename T, typename OP>
638 inline void
640 {
641  ++ *refCount_;
642 }
643 
644 #include "BaseNamespaceFooter.H"
645 #endif
std::ostream & pout()
Use this in place of std::cout for program output.
static int size_
Definition: RefCountedPtr.H:336
int * refCount_
Definition: RefCountedPtr.H:333
void swap(Self &b)
Definition: RefCountedPtr.H:620
A reference-counting handle class.
Definition: RefCountedPtr.H:173
#define CH_assert(cond)
Definition: CHArray.H:37
static void destroy(T *a_array)
Definition: RefCountedPtr.H:100
T value_type
Definition: RefCountedPtr.H:177
General case T is non-const and inverse is const.
Definition: RefCountedPtr.H:43
void neverDelete()
Will never delete ptr_.
Definition: RefCountedPtr.H:639
static std::string name_
Definition: RefCountedPtr.H:334
#define RCPDBG(x)
Definition: RefCountedPtr.H:32
void refUp()
Definition: RefCountedPtr.H:409
T InvertConstType
Definition: RefCountedPtr.H:52
Self & operator=(const RefCountedPtr< typename RCPTypeTr< T >::InvertConstType, OP2 > &rhs)
Definition: RefCountedPtr.H:259
T * pointer
Definition: RefCountedPtr.H:178
void refDown()
Definition: RefCountedPtr.H:421
A Concrete Class for Dynamic Memory Management.
Definition: Arena.H:124
Policies for when T is an array.
Definition: RefCountedPtr.H:97
pointer ptr_
Definition: RefCountedPtr.H:332
T & reference
Definition: RefCountedPtr.H:179
RefCountedPtr(const RefCountedPtr< T, OP2 > &other)
Definition: RefCountedPtr.H:209
int refCount() const
Definition: RefCountedPtr.H:613
pointer operator->() const
dereference access operator used like a pointer derefence access function.
Definition: RefCountedPtr.H:558
reference operator[](const int a_idx) const
[] access
Definition: RefCountedPtr.H:583
reference operator*() const
pointer dereference.
Definition: RefCountedPtr.H:574
bool isNull() const
Definition: RefCountedPtr.H:599
RefCountedPtr< T, OP > Self
Definition: RefCountedPtr.H:180
static void destroy(T *a_mem)
Definition: RefCountedPtr.H:110
const char * name(const FArrayBox &a_dummySpecializationArg)
Definition: CH_HDF5.H:864
T SamePolicyType
Definition: RefCountedPtr.H:77
~RefCountedPtr()
Destructor.
Definition: RefCountedPtr.H:474
static BArena s_Arena
Definition: RefCountedPtr.H:335
friend class RefCountedPtr
Definition: RefCountedPtr.H:307
RefCountedPtr< T, OP > & operator=(RefCountedPtr< T, OP > &&a_in) noexcept
Definition: RefCountedPtr.H:325
static const std::string & name()
Definition: RefCountedPtr.H:309
static void Error(const char *const a_msg=m_nullString, int m_exitCode=CH_DEFAULT_ERROR_CODE)
Print out message to cerr and exit with the specified exit code.
void freeMem()
Definition: RefCountedPtr.H:373
const T InvertConstType
Definition: RefCountedPtr.H:45
Self & operator=(const RefCountedPtr< T, OP2 > &rhs)
Definition: RefCountedPtr.H:251
pointer const & getRefToThePointer() const
Return a const reference to the pointer and don't ask questions.
Definition: RefCountedPtr.H:567
static void destroy(T *a_pointer)
Definition: RefCountedPtr.H:90
General case T and S are not the same.
Definition: RefCountedPtr.H:61
Policies for when T is created via malloc (or otherwise requires free)
Definition: RefCountedPtr.H:107
Definition: RefCountedPtr.H:65
void incrementMem()
Definition: RefCountedPtr.H:355
RefCountedPtr(RefCountedPtr< T, OP > &&a_in) noexcept
move constructor
Definition: RefCountedPtr.H:321
RefCountedPtr(const RefCountedPtr< typename RCPTypeTr< T >::InvertConstType, OP2 > &other)
Definition: RefCountedPtr.H:217
Policies for when T is a scalar object.
Definition: RefCountedPtr.H:87
Self & operator=(const Self &rhs)
assignment operator copies pointer member
Definition: RefCountedPtr.H:481
bool isNonUnique() const
true when refcount is one.
Definition: RefCountedPtr.H:606