STXXL  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
counting_ptr.h
Go to the documentation of this file.
1 /***************************************************************************
2  * include/stxxl/bits/common/counting_ptr.h
3  *
4  * Part of the STXXL. See http://stxxl.sourceforge.net
5  *
6  * Copyright (C) 2010-2011 Raoul Steffen <[email protected]>
7  * Copyright (C) 2013 Timo Bingmann <[email protected]>
8  *
9  * Distributed under the Boost Software License, Version 1.0.
10  * (See accompanying file LICENSE_1_0.txt or copy at
11  * http://www.boost.org/LICENSE_1_0.txt)
12  **************************************************************************/
13 
14 #ifndef STXXL_COMMON_COUNTING_PTR_HEADER
15 #define STXXL_COMMON_COUNTING_PTR_HEADER
16 
17 #include <cassert>
18 #include <cstdlib>
19 #include <algorithm>
20 #include <stxxl/types>
21 #include <stxxl/bits/config.h>
23 
24 
26 
27 /*!
28  * High-performance smart pointer used as a wrapping reference counting
29  * pointer.
30  *
31  * This smart pointer class requires two functions in the templated type: void
32  * inc_reference() and void dec_reference(). These must increment and decrement
33  * a reference counter inside the templated object. When initialized, the type
34  * must have reference count zero. It is _not_ immediately called with
35  * add_reference(). Each new object referencing the data calls add_reference()
36  * and each destroying holder calls del_reference(). When the data object
37  * determines that it's internal counter is zero, then it must destroy itself.
38  *
39  * Accompanying the counting_ptr is a const_counting_ptr and a class
40  * counted_object, from which reference counted classes must be derive
41  * from. The class counted_object implement all methods required for reference
42  * counting.
43  *
44  * The whole method is more similar to boost' instrusive_ptr, but also yields
45  * something resembling shared_ptr.
46  */
47 template <class Type>
49 {
50 public:
51  //! contained type.
52  typedef Type element_type;
53 
54 private:
55  //! the pointer to the currently referenced object.
56  Type* m_ptr;
57 
58 protected:
59  //! increment reference counter for current object.
61  { inc_reference(m_ptr); }
62 
63  //! increment reference counter of other object.
64  void inc_reference(Type* o)
65  { if (o) o->inc_reference(); }
66 
67  //! decrement reference counter of current object and maybe delete it.
69  { if (m_ptr && m_ptr->dec_reference()) delete m_ptr; }
70 
71 public:
72  //! default constructor: contains a NULL pointer.
73  counting_ptr() : m_ptr(NULL)
74  { }
75 
76  //! constructor with pointer: initializes new reference to ptr.
77  counting_ptr(Type* ptr) : m_ptr(ptr)
78  { inc_reference(); }
79 
80  //! copy-constructor: also initializes new reference to ptr.
81  counting_ptr(const counting_ptr& other_ptr) : m_ptr(other_ptr)
82  { inc_reference(); }
83 
84  //! assignment operator: dereference current object and acquire reference on new one.
85  counting_ptr& operator = (const counting_ptr& other_ptr)
86  { return operator = (other_ptr.m_ptr); }
87 
88  //! assignment to pointer: dereference current and acquire reference to new ptr.
89  counting_ptr& operator = (Type* ptr)
90  {
91  inc_reference(ptr);
92  dec_reference();
93  m_ptr = ptr;
94  return *this;
95  }
96 
97  //! destructor: decrements reference counter in ptr.
99  { dec_reference(); }
100 
101  //! return the enclosed object as reference.
102  Type& operator * () const
103  {
104  assert(m_ptr);
105  return *m_ptr;
106  }
107 
108  //! return the enclosed pointer.
109  Type* operator -> () const
110  {
111  assert(m_ptr);
112  return m_ptr;
113  }
114 
115  //! implicit cast to the enclosed pointer.
116  operator Type* () const
117  { return m_ptr; }
118 
119  //! return the enclosed pointer.
120  Type * get() const
121  { return m_ptr; }
122 
123  //! test equality of only the pointer values.
124  bool operator == (const counting_ptr& other_ptr) const
125  { return m_ptr == other_ptr.m_ptr; }
126 
127  //! test inequality of only the pointer values.
128  bool operator != (const counting_ptr& other_ptr) const
129  { return m_ptr != other_ptr.m_ptr; }
130 
131  //! cast to bool check for a NULL pointer
132  operator bool () const
133  { return valid(); }
134 
135  //! test for a non-NULL pointer
136  bool valid() const
137  { return (m_ptr != NULL); }
138 
139  //! test for a NULL pointer
140  bool empty() const
141  { return (m_ptr == NULL); }
142 
143  //! if the object is referred by this counting_ptr only
144  bool unique() const
145  { return m_ptr && m_ptr->unique(); }
146 
147  //! make and refer a copy if the original object was shared.
148  void unify()
149  {
150  if (m_ptr && ! m_ptr->unique())
151  operator = (new Type(*m_ptr));
152  }
153 
154  //! swap enclosed object with another counting pointer (no reference counts need change)
156  {
157  std::swap(m_ptr, b.m_ptr);
158  }
159 };
160 
161 //! swap enclosed object with another counting pointer (no reference counts need change)
162 template <class A>
163 void swap(counting_ptr<A>& a1, counting_ptr<A>& a2)
164 {
165  a1.swap(a2);
166 }
167 
168 /*!
169  * High-performance smart pointer used as a wrapping reference counting
170  * pointer.
171  *
172  * This smart pointer class requires two functions in the templated type: void
173  * inc_reference() and void dec_reference(). These must increment and decrement
174  * a reference counter inside the templated object. When initialized, the type
175  * must have reference count zero. It is _not_ immediately called with
176  * add_reference(). Each new object referencing the data calls add_reference()
177  * and each destroying holder calls del_reference(). When the data object
178  * determines that it's internal counter is zero, then it must destroy itself.
179  *
180  * Accompanying the counting_ptr is a const_counting_ptr and a class
181  * counted_object, from which reference counted classes must be derive
182  * from. The class counted_object implement all methods required for reference
183  * counting.
184  *
185  * The whole method is more similar to boost' instrusive_ptr, but also yields
186  * something resembling shared_ptr.
187  */
188 template <class Type>
190 {
191 public:
192  //! contained type.
193  typedef Type element_type;
194 
195 private:
196  //! the pointer to the currently referenced object.
197  const Type* m_ptr;
198 
199 protected:
200  //! increment reference counter for current object.
202  { inc_reference(m_ptr); }
203 
204  //! increment reference counter of other object.
205  void inc_reference(const Type* o)
206  { if (o) o->inc_reference(); }
207 
208  //! decrement reference counter of current object and maybe delete it.
210  { if (m_ptr && m_ptr->dec_reference()) delete m_ptr; }
211 
212 public:
213  //! default constructor: contains a NULL pointer.
214  const_counting_ptr() : m_ptr(NULL)
215  { }
216 
217  //! constructor with pointer: initializes new reference to ptr.
218  const_counting_ptr(const Type* ptr) : m_ptr(ptr)
219  { inc_reference(); }
220 
221  //! copy-constructor: also initializes new reference to ptr.
222  const_counting_ptr(const const_counting_ptr& other_ptr) : m_ptr(other_ptr)
223  { inc_reference(); }
224 
225  //! constructor from non-const: also initializes new reference to ptr.
226  const_counting_ptr(const counting_ptr<Type>& other_ptr) : m_ptr(other_ptr.get())
227  { inc_reference(); }
228 
229  //! assignment operator: dereference current object and acquire reference on new one.
230  const_counting_ptr& operator = (const const_counting_ptr& other_ptr)
231  { return operator = (other_ptr.m_ptr); }
232 
233  //! assignment operator: dereference current object and acquire reference on new one.
234  const_counting_ptr& operator = (const counting_ptr<Type>& other_ptr)
235  { return operator = (other_ptr.get()); }
236 
237  //! assignment to pointer: dereference current and acquire reference to new ptr.
238  const_counting_ptr& operator = (const Type* ptr)
239  {
240  inc_reference(ptr);
241  dec_reference();
242  m_ptr = ptr;
243  return *this;
244  }
245 
246  //! destructor: decrements reference counter in ptr.
248  { dec_reference(); }
249 
250  //! return the enclosed object as reference.
251  const Type& operator * () const
252  {
253  assert(m_ptr);
254  return *m_ptr;
255  }
256 
257  //! return the enclosed pointer.
258  const Type* operator -> () const
259  {
260  assert(m_ptr);
261  return m_ptr;
262  }
263 
264  //! implicit cast to the enclosed pointer.
265  operator const Type* () const
266  { return m_ptr; }
267 
268  //! return the enclosed pointer.
269  const Type * get() const
270  { return m_ptr; }
271 
272  //! test equality of only the pointer values.
273  bool operator == (const const_counting_ptr& other_ptr) const
274  { return m_ptr == other_ptr.m_ptr; }
275 
276  //! test inequality of only the pointer values.
277  bool operator != (const const_counting_ptr& other_ptr) const
278  { return m_ptr != other_ptr.m_ptr; }
279 
280  //! test equality of only the pointer values.
281  bool operator == (const counting_ptr<Type>& other_ptr) const
282  { return m_ptr == other_ptr.get(); }
283 
284  //! test inequality of only the pointer values.
285  bool operator != (const counting_ptr<Type>& other_ptr) const
286  { return m_ptr != other_ptr.get(); }
287 
288  //! cast to bool check for a NULL pointer
289  operator bool () const
290  { return m_ptr; }
291 
292  //! test for a non-NULL pointer
293  bool valid() const
294  { return m_ptr; }
295 
296  //! test for a NULL pointer
297  bool empty() const
298  { return !m_ptr; }
299 
300  //! if the object is referred by this const_counting_ptr only
301  bool unique() const
302  { return m_ptr && m_ptr->unique(); }
303 
304  //! swap enclosed object with another const_counting pointer (no reference counts need change)
306  {
307  std::swap(m_ptr, b.m_ptr);
308  }
309 };
310 
311 //! swap enclosed object with another const_counting pointer (no reference counts need change)
312 template <class A>
314 {
315  a1.swap(a2);
316 }
317 
318 /*!
319  * Provides reference counting abilities for use with counting_ptr.
320  *
321  * Use as superclass of the actual object, this adds a reference_count
322  * value. Then either use counting_ptr as pointer to manage references and
323  * deletion, or just do normal new and delete.
324  *
325  * For thread-safe functions, use atomic_counted_object instead of this class!
326  */
328 {
329 private:
330  //! the reference count is kept mutable to all const_counting_ptr() to
331  //! change the reference count.
333 
334 public:
335  //! new objects have zero reference count
337  : m_reference_count(0) { }
338 
339  //! coping still creates a new object with zero reference count
341  : m_reference_count(0) { }
342 
343  //! assignment operator, leaves pointers unchanged
344  counted_object& operator = (const counted_object&)
345  { return *this; } // changing the contents leaves pointers unchanged
346 
348  { assert(m_reference_count == 0); }
349 
350 public:
351  //! Call whenever setting a pointer to the object
352  void inc_reference() const
353  { ++m_reference_count; }
354 
355  //! Call whenever resetting (i.e. overwriting) a pointer to the object.
356  //! IMPORTANT: In case of self-assignment, call AFTER inc_reference().
357  //! \return if the object has to be deleted (i.e. if it's reference count dropped to zero)
358  bool dec_reference() const
359  { return (! --m_reference_count); }
360 
361  //! Test if the counted_object is referenced by only one counting_ptr.
362  bool unique() const
363  { return (m_reference_count == 1); }
364 
365  //! Return the number of references to this object (for debugging)
367  { return m_reference_count; }
368 };
369 
370 #if STXXL_HAVE_SYNC_ADD_AND_FETCH || STXXL_MSVC
371 
372 /*!
373  * Provides reference counting abilities for use with counting_ptr with atomics
374  * operations.
375  *
376  * Use as superclass of the actual object, this adds a reference_count
377  * value. Then either use counting_ptr as pointer to manage references and
378  * deletion, or just do normal new and delete.
379  *
380  * This class does thread-safe increment and decrement using atomic operations
381  * on an integral type.
382  */
383 class atomic_counted_object
384 {
385 private:
386  //! the reference count is kept mutable to all const_counting_ptr() to
387  //! change the reference count.
388 #if STXXL_MSVC
389  mutable long m_reference_count;
390 #else
391  mutable unsigned_type m_reference_count;
392 #endif
393 
394 public:
395  //! new objects have zero reference count
396  atomic_counted_object()
397  : m_reference_count(0) { }
398 
399  //! coping still creates a new object with zero reference count
400  atomic_counted_object(const atomic_counted_object&)
401  : m_reference_count(0) { }
402 
403  //! assignment operator, leaves pointers unchanged
404  atomic_counted_object& operator = (const atomic_counted_object&)
405  { return *this; } // changing the contents leaves pointers unchanged
406 
407  ~atomic_counted_object()
408  { assert(m_reference_count == 0); }
409 
410 public:
411  //! Call whenever setting a pointer to the object
412  void inc_reference() const
413  {
414 #if STXXL_MSVC
415  _InterlockedIncrement(&m_reference_count);
416 #else
417  __sync_add_and_fetch(&m_reference_count, +1);
418 #endif
419  }
420 
421  //! Call whenever resetting (i.e. overwriting) a pointer to the object.
422  //! IMPORTANT: In case of self-assignment, call AFTER inc_reference().
423  //! \return if the object has to be deleted (i.e. if it's reference count dropped to zero)
424  bool dec_reference() const
425  {
426 #if STXXL_MSVC
427  return (_InterlockedDecrement(&m_reference_count) == 0);
428 #else
429  return (__sync_add_and_fetch(&m_reference_count, -1) == 0);
430 #endif
431  }
432 
433  //! Test if the counted_object is referenced by only one counting_ptr.
434  bool unique() const
435  {
436  return (m_reference_count == 1);
437  }
438 
439  //! Return the number of references to this object (for debugging)
440  unsigned_type get_reference_count() const
441  {
442  return m_reference_count;
443  }
444 };
445 
446 #else // no atomic intrinsics found, use mutexes (slow)
447 
448 /*!
449  * Provides reference counting abilities for use with counting_ptr with mutex
450  * locking.
451  *
452  * Use as superclass of the actual object, this adds a reference_count
453  * value. Then either use counting_ptr as pointer to manage references and
454  * deletion, or just do normal new and delete.
455  *
456  * This class does thread-safe increment and decrement using scoped locks. A
457  * faster version of this class is available using atomic operations.
458  */
460 {
461 private:
462  //! the reference count is kept mutable to all const_counting_ptr() to
463  //! change the reference count.
465 
466  //! the mutex used to synchronize access to the reference counter.
468 
469 public:
470  //! new objects have zero reference count
472  : m_reference_count(0) { }
473 
474  //! coping still creates a new object with zero reference count
476  : m_reference_count(0) { }
477 
478  //! assignment operator, leaves pointers unchanged
480  { return *this; } // changing the contents leaves pointers unchanged
481 
483  { assert(m_reference_count == 0); }
484 
485 public:
486  //! Call whenever setting a pointer to the object
487  void inc_reference() const
488  {
489  scoped_mutex_lock lock(m_reference_count_mutex);
490  ++m_reference_count;
491  }
492 
493  //! Call whenever resetting (i.e. overwriting) a pointer to the object.
494  //! IMPORTANT: In case of self-assignment, call AFTER inc_reference().
495  //! \return if the object has to be deleted (i.e. if it's reference count dropped to zero)
496  bool dec_reference() const
497  {
498  scoped_mutex_lock lock(m_reference_count_mutex);
499  return (--m_reference_count == 0);
500  }
501 
502  //! Test if the counted_object is referenced by only one counting_ptr.
503  bool unique() const
504  {
505  scoped_mutex_lock lock(m_reference_count_mutex);
506  return (m_reference_count == 1);
507  }
508 
509  //! Return the number of references to this object (for debugging)
511  {
512  scoped_mutex_lock lock(m_reference_count_mutex);
513  return m_reference_count;
514  }
515 };
516 
517 #endif
518 
520 
521 #endif // !STXXL_COMMON_COUNTING_PTR_HEADER
unsigned_type m_reference_count
the reference count is kept mutable to all const_counting_ptr() to change the reference count...
Definition: counting_ptr.h:464
Type * m_ptr
the pointer to the currently referenced object.
Definition: counting_ptr.h:56
void swap(const_counting_ptr &b)
swap enclosed object with another const_counting pointer (no reference counts need change) ...
Definition: counting_ptr.h:305
bool valid() const
test for a non-NULL pointer
Definition: counting_ptr.h:293
void inc_reference() const
Call whenever setting a pointer to the object.
Definition: counting_ptr.h:487
Type element_type
contained type.
Definition: counting_ptr.h:52
bool dec_reference() const
Call whenever resetting (i.e. overwriting) a pointer to the object. IMPORTANT: In case of self-assign...
Definition: counting_ptr.h:496
~counting_ptr()
destructor: decrements reference counter in ptr.
Definition: counting_ptr.h:98
High-performance smart pointer used as a wrapping reference counting pointer.
Definition: counting_ptr.h:189
void inc_reference() const
Call whenever setting a pointer to the object.
Definition: counting_ptr.h:352
Provides reference counting abilities for use with counting_ptr with mutex locking.
Definition: counting_ptr.h:459
High-performance smart pointer used as a wrapping reference counting pointer.
Definition: counting_ptr.h:48
Type * get() const
return the enclosed pointer.
Definition: counting_ptr.h:120
bool empty() const
test for a NULL pointer
Definition: counting_ptr.h:297
counted_object()
new objects have zero reference count
Definition: counting_ptr.h:336
bool empty() const
test for a NULL pointer
Definition: counting_ptr.h:140
const Type * m_ptr
the pointer to the currently referenced object.
Definition: counting_ptr.h:197
const_counting_ptr()
default constructor: contains a NULL pointer.
Definition: counting_ptr.h:214
bool valid() const
test for a non-NULL pointer
Definition: counting_ptr.h:136
~const_counting_ptr()
destructor: decrements reference counter in ptr.
Definition: counting_ptr.h:247
counting_ptr(const counting_ptr &other_ptr)
copy-constructor: also initializes new reference to ptr.
Definition: counting_ptr.h:81
counting_ptr(Type *ptr)
constructor with pointer: initializes new reference to ptr.
Definition: counting_ptr.h:77
bool unique() const
Test if the counted_object is referenced by only one counting_ptr.
Definition: counting_ptr.h:503
void inc_reference()
increment reference counter for current object.
Definition: counting_ptr.h:60
mutex m_reference_count_mutex
the mutex used to synchronize access to the reference counter.
Definition: counting_ptr.h:467
void swap(counting_ptr &b)
swap enclosed object with another counting pointer (no reference counts need change) ...
Definition: counting_ptr.h:155
bool operator!=(const uint_pair &b) const
inequality checking operator
Definition: uint_types.h:201
void dec_reference()
decrement reference counter of current object and maybe delete it.
Definition: counting_ptr.h:68
counting_ptr()
default constructor: contains a NULL pointer.
Definition: counting_ptr.h:73
Provides reference counting abilities for use with counting_ptr.
Definition: counting_ptr.h:327
atomic_counted_object()
new objects have zero reference count
Definition: counting_ptr.h:471
void inc_reference(const Type *o)
increment reference counter of other object.
Definition: counting_ptr.h:205
const_counting_ptr(const Type *ptr)
constructor with pointer: initializes new reference to ptr.
Definition: counting_ptr.h:218
counted_object(const counted_object &)
coping still creates a new object with zero reference count
Definition: counting_ptr.h:340
Aquire a lock that&#39;s valid until the end of scope.
Definition: mutex.h:106
#define STXXL_BEGIN_NAMESPACE
Definition: namespace.h:16
unsigned_type m_reference_count
the reference count is kept mutable to all const_counting_ptr() to change the reference count...
Definition: counting_ptr.h:332
bool unique() const
if the object is referred by this counting_ptr only
Definition: counting_ptr.h:144
void inc_reference(Type *o)
increment reference counter of other object.
Definition: counting_ptr.h:64
bool unique() const
if the object is referred by this const_counting_ptr only
Definition: counting_ptr.h:301
Type element_type
contained type.
Definition: counting_ptr.h:193
void dec_reference()
decrement reference counter of current object and maybe delete it.
Definition: counting_ptr.h:209
bool unique() const
Test if the counted_object is referenced by only one counting_ptr.
Definition: counting_ptr.h:362
void inc_reference()
increment reference counter for current object.
Definition: counting_ptr.h:201
atomic_counted_object(const atomic_counted_object &)
coping still creates a new object with zero reference count
Definition: counting_ptr.h:475
choose_int_types< my_pointer_size >::unsigned_type unsigned_type
Definition: types.h:67
bool dec_reference() const
Call whenever resetting (i.e. overwriting) a pointer to the object. IMPORTANT: In case of self-assign...
Definition: counting_ptr.h:358
const_counting_ptr(const counting_ptr< Type > &other_ptr)
constructor from non-const: also initializes new reference to ptr.
Definition: counting_ptr.h:226
unsigned_type get_reference_count() const
Return the number of references to this object (for debugging)
Definition: counting_ptr.h:510
void unify()
make and refer a copy if the original object was shared.
Definition: counting_ptr.h:148
bool operator==(const uint_pair &b) const
equality checking operator
Definition: uint_types.h:195
const_counting_ptr(const const_counting_ptr &other_ptr)
copy-constructor: also initializes new reference to ptr.
Definition: counting_ptr.h:222
#define STXXL_END_NAMESPACE
Definition: namespace.h:17
unsigned_type get_reference_count() const
Return the number of references to this object (for debugging)
Definition: counting_ptr.h:366