NVBIO
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
shared_pointer.h
Go to the documentation of this file.
1 /*
2  * nvbio
3  * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the NVIDIA CORPORATION nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #pragma once
29 
30 #include <typeinfo>
31 #include <iosfwd> // for basic_ostream<>
32 #include <algorithm> // for std::swap
33 
34 namespace nvbio {
35 
36 #ifdef WIN32
37 #else
38 //#define SharedPointer std::tr1::shared_ptr
39 #pragma GCC poison shared_ptr
40 #endif
41 
42  // A shared pointer, with an interface same as the boost/tr1 one
43  // but templatized on the counter's type as well. This is so you
44  // can have it thread safe or non-thread-safe.
45 
46  typedef long CounterT_default;
47 
48  namespace internals {
49  template <typename T>
50  struct Deleter {
51  typedef void result_type;
52  typedef T* argument_type;
53 
54  void operator() (argument_type p) const { delete p; }
55  };
56 
57  template<typename CounterT>
58  class CountedBase {
59  public:
60  typedef CounterT Counter_Type;
62  m_shcount(1),
63  m_wkcount(1)
64  {}
65 
66  virtual ~CountedBase() {}
67 
69  virtual void dispose() = 0;
70 
72  virtual void destroy() { delete this; }
73 
74  virtual void* get_deleter(const std::type_info&) = 0;
75 
76  void add_ref_copy() { ++m_shcount; }
77 
78  void add_ref_lock() { ++m_shcount; }
79 
80  void release() {
81  if (!--m_shcount) {
82  dispose();
83  weak_release();
84  }
85  }
86 
87  void weak_add_ref() { ++m_wkcount; }
88  void weak_release() {
89  if (!--m_wkcount) {
90  destroy();
91  }
92  }
93 
94  Counter_Type use_count() const { return m_shcount; }
95 
96  private:
97  // No copies nor assignments
98  CountedBase(const CountedBase&);
99  CountedBase& operator=(const CountedBase&);
100 
101  Counter_Type m_shcount; //< shared pointers count
102  Counter_Type m_wkcount; //< weak pointers count + (m_shcount + 1)
103  };
104 
105  template<typename PtrT, typename DeleterT, typename CounterT>
106  class CountedBase_impl : public CountedBase<CounterT>
107  {
108  public:
109  CountedBase_impl(PtrT p, DeleterT d) :
110  CountedBase<CounterT>(),
111  m_ptr(p),
112  m_del(d)
113  {}
114 
115  virtual void dispose() { m_del(m_ptr); }
116 
117  virtual void* get_deleter(const std::type_info& ti) {
118  return (ti == typeid(DeleterT)) ? &m_del : NULL;
119  }
120 
121  private:
122  // No copies nor assignments
124  CountedBase_impl& operator=(const CountedBase<CounterT>&);
125 
126  PtrT m_ptr;
127  DeleterT m_del;
128  };
129 
130  template<typename CounterT> class WeakCount;
131 
132  template<typename CounterT>
133  class SharedCount {
134  public:
136 
138  m_pi(NULL)
139  {}
140 
141  template<typename PtrT, typename DeleterT>
142  SharedCount(PtrT p, DeleterT d) :
143  m_pi(NULL)
144  {
145  try {
147  } catch (...) {
148  d(p);
149  throw;
150  }
151  }
152 
153  // swallowed support for auto_ptr<T>, should go here
154 
155  explicit SharedCount(const WeakCount<CounterT>& wc);
156 
158  if (m_pi)
159  m_pi->release();
160  }
161 
163  m_pi(sc.m_pi)
164  {
165  if (m_pi)
166  m_pi->add_ref_copy();
167  }
168 
170  {
171  CountedBase<CounterT>* _tmp = sc.m_pi;
172 
173  if (_tmp != m_pi) {
174  if (_tmp)
175  _tmp->add_ref_copy();
176  if (m_pi)
177  m_pi->release();
178  m_pi = _tmp;
179  }
180  return *this;
181  }
182 
183  void swap(SharedCount& sc)
184  {
185  CountedBase<CounterT>* _tmp = sc.m_pi;
186  sc.m_pi = m_pi;
187  m_pi = _tmp;
188  }
189 
191  {
192  return m_pi ? m_pi->use_count() : CountedBase<CounterT>::Counter_Type(0);
193  }
194 
195  bool unique() const { return use_count() == 1;}
196 
197  friend inline bool operator== (const SharedCount& a, const SharedCount& b)
198  {
199  return a.m_pi == b.m_pi;
200  }
201 
202  friend inline bool operator< (const SharedCount& a, const SharedCount& b)
203  {
204  return a.m_pi < b.m_pi;
205  }
206 
207  void* get_deleter(const std::type_info& ti) const {
208  return m_pi ? m_pi->get_deleter(ti) : NULL;
209  }
210  private:
211  friend class WeakCount<CounterT>;
212  CountedBase<CounterT>* m_pi;
213  };
214 
215  template<typename CounterT>
216  class WeakCount {
217  public:
219 
221  m_pi(NULL)
222  {}
223 
225  m_pi(sc.m_pi)
226  {
227  if (m_pi)
228  m_pi->weak_add_ref();
229  }
230 
231  WeakCount(const WeakCount& wc) :
232  m_pi(wc.m_pi)
233  {
234  if (m_pi)
235  m_pi->weak_add_ref();
236  }
237 
239  if (m_pi)
240  m_pi->weak_release();
241  }
242 
244  {
245  CountedBase<CounterT>* _tmp = sc.m_pi;
246 
247  if (_tmp)
248  _tmp->weak_add_ref();
249  if (m_pi)
250  m_pi->weak_release();
251  m_pi = _tmp;
252 
253  return *this;
254  }
255 
257  {
258  CountedBase<CounterT>* _tmp = wc.m_pi;
259 
260  if (_tmp)
261  _tmp->weak_add_ref();
262  if (m_pi)
263  m_pi->weak_release();
264  m_pi = _tmp;
265 
266  return *this;
267  }
268 
269  void swap(WeakCount& wc)
270  {
271  CountedBase<CounterT>* _tmp = wc.m_pi;
272  wc.m_pi = m_pi;
273  m_pi = _tmp;
274  }
275 
277  {
278  return m_pi ? m_pi->use_count() : Counter_Type(0);
279  }
280 
281  friend inline bool operator== (const WeakCount& a, const WeakCount& b)
282  {
283  return a.m_pi == b.m_pi;
284  }
285 
286  friend inline bool operator< (const WeakCount& a, const WeakCount& b)
287  {
288  return a.m_pi < b.m_pi;
289  }
290 
291  void* get_deleter(const std::type_info& ti) const {
292  return m_pi ? m_pi->get_deleter(ti) : NULL;
293  }
294  private:
295  friend class SharedCount<CounterT>;
296  CountedBase<CounterT>* m_pi;
297  };
298 
299  template<typename CounterT>
300  inline
302  m_pi(wc.m_pi)
303  {
304  if (m_pi)
305  m_pi->add_ref_lock();
306  else {
307  // FIXME: throw bad weak pointer
308  }
309  }
310 
311  template<class T> struct SharedPointerTraits
312  {
313  typedef T& reference;
314  };
315 
316  template<> struct SharedPointerTraits<void>
317  {
318  typedef void reference;
319  };
320 
321  template<> struct SharedPointerTraits<void const>
322  {
323  typedef void reference;
324  };
325 
326  template<> struct SharedPointerTraits<void volatile>
327  {
328  typedef void reference;
329  };
330 
331  template<> struct SharedPointerTraits<void const volatile>
332  {
333  typedef void reference;
334  };
335 
337  struct const_cast_marker {};
340  }
341 
342  template<typename T, typename CounterT> class WeakPointer;
343 
344  template<typename T, typename CounterT = CounterT_default>
346  {
347  typedef typename internals::SharedPointerTraits<T>::reference _Reference;
348  public:
349  typedef T element_type;
351 
353  m_ptr(NULL),
354  m_count()
355  {}
356 
357  template<typename U>
358  explicit SharedPointer(U* p) :
359  m_ptr(p),
360  m_count(p, internals::Deleter<T>())
361  {}
362 
363  template<typename U, typename DeleterT>
364  explicit SharedPointer(U* p, DeleterT d) :
365  m_ptr(p),
366  m_count(p, d)
367  {}
368 
369  // generated copy constructor, assignment, destructor are fine
370 
371  template<typename U>
373  m_ptr(other.m_ptr),
374  m_count(other.m_count)
375  {
376 
377  }
378 
379  template<typename U>
381  m_count(other.m_count)
382  {
383  // the constructor of m_count may throw if the reference counter
384  // in the weak pointer is 0, which means the pointer is gone.
385  // In that case we never get here.
386  m_ptr = other.m_ptr;
387  }
388 
389  // swallowed support for auto_ptr<T>, should go here
390 
391  template<typename U>
393  m_ptr(static_cast<element_type*>(other.m_ptr)),
394  m_count(other.m_count)
395  {}
396 
397  template<typename U>
399  m_ptr(const_cast<element_type*>(other.m_ptr)),
400  m_count(other.m_count)
401  {}
402 
403  template<typename U>
405  m_ptr(dynamic_cast<element_type*>(other.m_ptr)),
406  m_count(other.m_count)
407  {
408  // the cast may fail at runtime
409  if (m_ptr == NULL)
411  }
412 
413  template<typename U>
415  {
416  m_ptr = other.m_ptr;
417  m_count = other.m_count;
418  return *this;
419  }
420 
421  template<typename U>
423  {
424  reset( p );
425  return *this;
426  }
427 
428  // swallowed support for auto_ptr<T>, should go here
429 
430  void reset()
431  {
432  SharedPointer().swap(*this);
433  }
434 
435  template<typename U>
436  void reset(U* p)
437  {
438  if (p != m_ptr)
439  SharedPointer(p).swap(*this);
440  }
441 
442  template<typename U, typename UDeleterT>
443  void reset(U* p, UDeleterT d)
444  {
445  if (p != m_ptr)
446  SharedPointer(p, d).swap(*this);
447  }
448 
449  _Reference operator*() const { return *m_ptr; }
450  element_type* operator->() const { return m_ptr; }
451  element_type* get() const { return m_ptr; }
452 
453  private:
454  // conversion to "bool"
455  typedef element_type* SharedPointer::*BooleanType;
456  public:
457  operator BooleanType() const
458  {
459  return m_ptr ? &SharedPointer::m_ptr : NULL;
460  }
461 
462  bool unique() const { return m_count.unique(); }
463 
464  Counter_Type use_count() const { return m_count.use_count(); }
465 
467  {
468  std::swap(m_ptr, other.m_ptr);
469  m_count.swap(other.m_count);
470  }
471 
472  // for private usage. Use free standing get_deleter() instead
473  void* _M_get_deleter(const std::type_info& ti) const
474  {
475  return m_count.get_deleter(ti);
476  }
477 
478  private:
479  template<typename U>
480  bool _M_less(const SharedPointer<U>& rhs) const
481  {
482  return m_count < rhs.m_count;
483  }
484 
485  // All SharedPointer's are friends
486  template<typename U, typename UCounterT> friend class SharedPointer;
487  // with all WeakPointer's too
488  template<typename U, typename UCounterT> friend class WeakPointer;
489 
490  template<typename U>
491  friend inline bool operator==(const SharedPointer& a, const SharedPointer<U>& b)
492  {
493  return a.get() == b.get();
494  }
495 
496  template<typename U>
497  friend inline bool operator!=(const SharedPointer& a, const SharedPointer<U>& b)
498  {
499  return a.get() != b.get();
500  }
501 
502  template<typename U>
503  friend inline bool operator<(const SharedPointer& a, const SharedPointer<U>& b)
504  {
505  return a._M_less(b);
506  }
507 
508  element_type* m_ptr;
510  };
511 
512 
513  template<typename T, typename CounterT>
515  {
516  a.swap(b);
517  }
518 
519  template<typename T, typename U, typename CounterT>
521  {
523  }
524 
525  template<typename T, typename U, typename CounterT>
527  {
529  }
530 
531  template<typename T, typename U, typename CounterT>
533  {
535  }
536 
537  template<typename CharT, typename TraitsT, typename T, typename CounterT>
538  std::basic_ostream<CharT, TraitsT>&
539  operator<<(std::basic_ostream<CharT, TraitsT>& os, const SharedPointer<T, CounterT>& p)
540  {
541  return os << p.get();
542  }
543 
544  template<typename DeleterT, typename T, typename CounterT>
545  inline DeleterT* get_deleter(const SharedPointer<T, CounterT>& p)
546  {
547  return static_cast<DeleterT*>(p._M_get_deleter(typeid(DeleterT)));
548  }
549 
550  template<typename T, typename CounterT = long>
551  class WeakPointer
552  {
553  public:
554  typedef T element_type;
556 
558  m_ptr(NULL),
559  m_count()
560  {}
561 
562  // generated copy constructor, assignment, destructor are fine
563 
564  // this implementation is required because the pointer could be
565  // invalidated during construction, so we lock, copy, unlock
566  template<typename U>
567  WeakPointer(const WeakPointer<U>& other) :
568  m_count(other.m_count)
569  {
570  m_ptr = other.lock().get();
571  }
572 
573  template<typename U>
575  m_ptr(other.m_ptr),
576  m_count(other.m_count)
577  {
578  }
579 
580  template<typename U>
582  {
583  m_ptr = other.lock().get();
584  m_count = other.m_count;
585  return *this;
586  }
587 
588  template<typename U>
590  {
591  m_ptr = other.m_ptr;
592  m_count = other.m_count;
593  return *this;
594  }
595 
597  // there is a possible race-condition here. See notes in the
598  // BOOST implementation for a solution
600  }
601 
602  Counter_Type use_count() const { return m_count.use_count(); }
603 
604  bool expired() const { return m_count.use_count() == 0; }
605 
606  void reset() { WeakPointer().swap(*this); }
607 
608  void swap(WeakPointer& other)
609  {
610  std::swap(m_ptr, other.m_ptr);
611  m_count.swap(other.m_count);
612  }
613 
614  private:
615  template<typename U>
616  bool _M_less(const SharedPointer<U>& rhs) const
617  {
618  return m_count < rhs.m_count;
619  }
620 
621  // All SharedPointer's are friends
622  template<typename U, typename UCounterT> friend class SharedPointer;
623  // with all WeakPointer's too
624  template<typename U, typename UCounterT> friend class WeakPointer;
625 
626  template<typename U>
627  friend inline bool operator<(const WeakPointer& a, const WeakPointer<U>& b)
628  {
629  return a._M_less(b);
630  }
631 
632  element_type* m_ptr;
634  };
635 
636  template<typename T, typename CounterT>
638  {
639  a.swap(b);
640  }
641 
642  // swallowed enable_shared_from_this
643 
644 } // namespace nvbio
645 
646 namespace std {
647  template<typename T, typename CounterT>
649  {
650  a.swap(b);
651  }
652 
653  template<typename T, typename CounterT>
655  {
656  a.swap(b);
657  }
658 }