Home | History | Annotate | Download | only in Utility
      1 //===---------------------SharingPtr.h --------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #ifndef utility_SharingPtr_h_
     11 #define utility_SharingPtr_h_
     12 
     13 #include <algorithm>
     14 #include <memory>
     15 
     16 //#define ENABLE_SP_LOGGING 1 // DON'T CHECK THIS LINE IN UNLESS COMMENTED OUT
     17 #if defined (ENABLE_SP_LOGGING)
     18 
     19 extern "C" void track_sp (void *sp_this, void *ptr, long count);
     20 
     21 #endif
     22 
     23 namespace lldb_private {
     24 
     25 namespace imp {
     26 
     27 template <class T>
     28 inline T
     29 increment(T& t)
     30 {
     31     return __sync_add_and_fetch(&t, 1);
     32 }
     33 
     34 template <class T>
     35 inline T
     36 decrement(T& t)
     37 {
     38     return __sync_add_and_fetch(&t, -1);
     39 }
     40 
     41 class shared_count
     42 {
     43     shared_count(const shared_count&);
     44     shared_count& operator=(const shared_count&);
     45 
     46 protected:
     47     long shared_owners_;
     48     virtual ~shared_count();
     49 private:
     50     virtual void on_zero_shared() = 0;
     51 
     52 public:
     53     explicit shared_count(long refs = 0)
     54         : shared_owners_(refs) {}
     55 
     56     void add_shared();
     57     void release_shared();
     58     long use_count() const {return shared_owners_ + 1;}
     59 };
     60 
     61 template <class T>
     62 class shared_ptr_pointer
     63     : public shared_count
     64 {
     65     T data_;
     66 public:
     67     shared_ptr_pointer(T p)
     68         :  data_(p) {}
     69 
     70 private:
     71     virtual void on_zero_shared();
     72 
     73     // Outlaw copy constructor and assignment operator to keep effictive C++
     74     // warnings down to a minumum
     75     shared_ptr_pointer (const shared_ptr_pointer &);
     76     shared_ptr_pointer & operator=(const shared_ptr_pointer &);
     77 };
     78 
     79 template <class T>
     80 void
     81 shared_ptr_pointer<T>::on_zero_shared()
     82 {
     83     delete data_;
     84 }
     85 
     86 template <class T>
     87 class shared_ptr_emplace
     88     : public shared_count
     89 {
     90     T data_;
     91 public:
     92 
     93     shared_ptr_emplace()
     94         :  data_() {}
     95 
     96     template <class A0>
     97         shared_ptr_emplace(A0& a0)
     98             :  data_(a0) {}
     99 
    100     template <class A0, class A1>
    101         shared_ptr_emplace(A0& a0, A1& a1)
    102             :  data_(a0, a1) {}
    103 
    104     template <class A0, class A1, class A2>
    105         shared_ptr_emplace(A0& a0, A1& a1, A2& a2)
    106             :  data_(a0, a1, a2) {}
    107 
    108     template <class A0, class A1, class A2, class A3>
    109         shared_ptr_emplace(A0& a0, A1& a1, A2& a2, A3& a3)
    110             :  data_(a0, a1, a2, a3) {}
    111 
    112     template <class A0, class A1, class A2, class A3, class A4>
    113         shared_ptr_emplace(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4)
    114             :  data_(a0, a1, a2, a3, a4) {}
    115 
    116 private:
    117     virtual void on_zero_shared();
    118 public:
    119     T* get() {return &data_;}
    120 };
    121 
    122 template <class T>
    123 void
    124 shared_ptr_emplace<T>::on_zero_shared()
    125 {
    126 }
    127 
    128 }  // namespace
    129 
    130 template<class T>
    131 class SharingPtr
    132 {
    133 public:
    134     typedef T element_type;
    135 private:
    136     element_type*      ptr_;
    137     imp::shared_count* cntrl_;
    138 
    139     struct nat {int for_bool_;};
    140 public:
    141     SharingPtr();
    142     template<class Y> explicit SharingPtr(Y* p);
    143     template<class Y> explicit SharingPtr(Y* p, imp::shared_count *ctrl_block);
    144     template<class Y> SharingPtr(const SharingPtr<Y>& r, element_type *p);
    145     SharingPtr(const SharingPtr& r);
    146     template<class Y>
    147         SharingPtr(const SharingPtr<Y>& r);
    148 
    149     ~SharingPtr();
    150 
    151     SharingPtr& operator=(const SharingPtr& r);
    152     template<class Y> SharingPtr& operator=(const SharingPtr<Y>& r);
    153 
    154     void swap(SharingPtr& r);
    155     void reset();
    156     template<class Y> void reset(Y* p);
    157 
    158     element_type* get() const {return ptr_;}
    159     element_type& operator*() const {return *ptr_;}
    160     element_type* operator->() const {return ptr_;}
    161     long use_count() const {return cntrl_ ? cntrl_->use_count() : 0;}
    162     bool unique() const {return use_count() == 1;}
    163     bool empty() const {return cntrl_ == 0;}
    164     operator nat*() const {return (nat*)get();}
    165 
    166     static SharingPtr<T> make_shared();
    167 
    168     template<class A0>
    169         static SharingPtr<T> make_shared(A0&);
    170 
    171     template<class A0, class A1>
    172         static SharingPtr<T> make_shared(A0&, A1&);
    173 
    174     template<class A0, class A1, class A2>
    175         static SharingPtr<T> make_shared(A0&, A1&, A2&);
    176 
    177     template<class A0, class A1, class A2, class A3>
    178         static SharingPtr<T> make_shared(A0&, A1&, A2&, A3&);
    179 
    180     template<class A0, class A1, class A2, class A3, class A4>
    181         static SharingPtr<T> make_shared(A0&, A1&, A2&, A3&, A4&);
    182 
    183 private:
    184 
    185     template <class U> friend class SharingPtr;
    186 };
    187 
    188 template<class T>
    189 inline
    190 SharingPtr<T>::SharingPtr()
    191     : ptr_(0),
    192       cntrl_(0)
    193 {
    194 }
    195 
    196 template<class T>
    197 template<class Y>
    198 SharingPtr<T>::SharingPtr(Y* p)
    199     : ptr_(p), cntrl_(0)
    200 {
    201     std::unique_ptr<Y> hold(p);
    202     typedef imp::shared_ptr_pointer<Y*> _CntrlBlk;
    203     cntrl_ = new _CntrlBlk(p);
    204     hold.release();
    205 }
    206 
    207 template<class T>
    208 template<class Y>
    209 SharingPtr<T>::SharingPtr(Y* p, imp::shared_count *cntrl_block)
    210     : ptr_(p), cntrl_(cntrl_block)
    211 {
    212 }
    213 
    214 template<class T>
    215 template<class Y>
    216 inline
    217 SharingPtr<T>::SharingPtr(const SharingPtr<Y>& r, element_type *p)
    218     : ptr_(p),
    219       cntrl_(r.cntrl_)
    220 {
    221     if (cntrl_)
    222         cntrl_->add_shared();
    223 }
    224 
    225 template<class T>
    226 inline
    227 SharingPtr<T>::SharingPtr(const SharingPtr& r)
    228     : ptr_(r.ptr_),
    229       cntrl_(r.cntrl_)
    230 {
    231     if (cntrl_)
    232         cntrl_->add_shared();
    233 }
    234 
    235 template<class T>
    236 template<class Y>
    237 inline
    238 SharingPtr<T>::SharingPtr(const SharingPtr<Y>& r)
    239     : ptr_(r.ptr_),
    240       cntrl_(r.cntrl_)
    241 {
    242     if (cntrl_)
    243         cntrl_->add_shared();
    244 }
    245 
    246 template<class T>
    247 SharingPtr<T>::~SharingPtr()
    248 {
    249     if (cntrl_)
    250         cntrl_->release_shared();
    251 }
    252 
    253 template<class T>
    254 inline
    255 SharingPtr<T>&
    256 SharingPtr<T>::operator=(const SharingPtr& r)
    257 {
    258     SharingPtr(r).swap(*this);
    259     return *this;
    260 }
    261 
    262 template<class T>
    263 template<class Y>
    264 inline
    265 SharingPtr<T>&
    266 SharingPtr<T>::operator=(const SharingPtr<Y>& r)
    267 {
    268     SharingPtr(r).swap(*this);
    269     return *this;
    270 }
    271 
    272 template<class T>
    273 inline
    274 void
    275 SharingPtr<T>::swap(SharingPtr& r)
    276 {
    277     std::swap(ptr_, r.ptr_);
    278     std::swap(cntrl_, r.cntrl_);
    279 }
    280 
    281 template<class T>
    282 inline
    283 void
    284 SharingPtr<T>::reset()
    285 {
    286     SharingPtr().swap(*this);
    287 }
    288 
    289 template<class T>
    290 template<class Y>
    291 inline
    292 void
    293 SharingPtr<T>::reset(Y* p)
    294 {
    295     SharingPtr(p).swap(*this);
    296 }
    297 
    298 template<class T>
    299 SharingPtr<T>
    300 SharingPtr<T>::make_shared()
    301 {
    302     typedef imp::shared_ptr_emplace<T> CntrlBlk;
    303     SharingPtr<T> r;
    304     r.cntrl_ = new CntrlBlk();
    305     r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get();
    306     return r;
    307 }
    308 
    309 template<class T>
    310 template<class A0>
    311 SharingPtr<T>
    312 SharingPtr<T>::make_shared(A0& a0)
    313 {
    314     typedef imp::shared_ptr_emplace<T> CntrlBlk;
    315     SharingPtr<T> r;
    316     r.cntrl_ = new CntrlBlk(a0);
    317     r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get();
    318     return r;
    319 }
    320 
    321 template<class T>
    322 template<class A0, class A1>
    323 SharingPtr<T>
    324 SharingPtr<T>::make_shared(A0& a0, A1& a1)
    325 {
    326     typedef imp::shared_ptr_emplace<T> CntrlBlk;
    327     SharingPtr<T> r;
    328     r.cntrl_ = new CntrlBlk(a0, a1);
    329     r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get();
    330     return r;
    331 }
    332 
    333 template<class T>
    334 template<class A0, class A1, class A2>
    335 SharingPtr<T>
    336 SharingPtr<T>::make_shared(A0& a0, A1& a1, A2& a2)
    337 {
    338     typedef imp::shared_ptr_emplace<T> CntrlBlk;
    339     SharingPtr<T> r;
    340     r.cntrl_ = new CntrlBlk(a0, a1, a2);
    341     r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get();
    342     return r;
    343 }
    344 
    345 template<class T>
    346 template<class A0, class A1, class A2, class A3>
    347 SharingPtr<T>
    348 SharingPtr<T>::make_shared(A0& a0, A1& a1, A2& a2, A3& a3)
    349 {
    350     typedef imp::shared_ptr_emplace<T> CntrlBlk;
    351     SharingPtr<T> r;
    352     r.cntrl_ = new CntrlBlk(a0, a1, a2, a3);
    353     r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get();
    354     return r;
    355 }
    356 
    357 template<class T>
    358 template<class A0, class A1, class A2, class A3, class A4>
    359 SharingPtr<T>
    360 SharingPtr<T>::make_shared(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4)
    361 {
    362     typedef imp::shared_ptr_emplace<T> CntrlBlk;
    363     SharingPtr<T> r;
    364     r.cntrl_ = new CntrlBlk(a0, a1, a2, a3, a4);
    365     r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get();
    366     return r;
    367 }
    368 
    369 template<class T>
    370 inline
    371 SharingPtr<T>
    372 make_shared()
    373 {
    374     return SharingPtr<T>::make_shared();
    375 }
    376 
    377 template<class T, class A0>
    378 inline
    379 SharingPtr<T>
    380 make_shared(A0& a0)
    381 {
    382     return SharingPtr<T>::make_shared(a0);
    383 }
    384 
    385 template<class T, class A0, class A1>
    386 inline
    387 SharingPtr<T>
    388 make_shared(A0& a0, A1& a1)
    389 {
    390     return SharingPtr<T>::make_shared(a0, a1);
    391 }
    392 
    393 template<class T, class A0, class A1, class A2>
    394 inline
    395 SharingPtr<T>
    396 make_shared(A0& a0, A1& a1, A2& a2)
    397 {
    398     return SharingPtr<T>::make_shared(a0, a1, a2);
    399 }
    400 
    401 template<class T, class A0, class A1, class A2, class A3>
    402 inline
    403 SharingPtr<T>
    404 make_shared(A0& a0, A1& a1, A2& a2, A3& a3)
    405 {
    406     return SharingPtr<T>::make_shared(a0, a1, a2, a3);
    407 }
    408 
    409 template<class T, class A0, class A1, class A2, class A3, class A4>
    410 inline
    411 SharingPtr<T>
    412 make_shared(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4)
    413 {
    414     return SharingPtr<T>::make_shared(a0, a1, a2, a3, a4);
    415 }
    416 
    417 
    418 template<class T, class U>
    419 inline
    420 bool
    421 operator==(const SharingPtr<T>& __x, const SharingPtr<U>& __y)
    422 {
    423     return __x.get() == __y.get();
    424 }
    425 
    426 template<class T, class U>
    427 inline
    428 bool
    429 operator!=(const SharingPtr<T>& __x, const SharingPtr<U>& __y)
    430 {
    431     return !(__x == __y);
    432 }
    433 
    434 template<class T, class U>
    435 inline
    436 bool
    437 operator<(const SharingPtr<T>& __x, const SharingPtr<U>& __y)
    438 {
    439     return __x.get() < __y.get();
    440 }
    441 
    442 template<class T>
    443 inline
    444 void
    445 swap(SharingPtr<T>& __x, SharingPtr<T>& __y)
    446 {
    447     __x.swap(__y);
    448 }
    449 
    450 template<class T, class U>
    451 inline
    452 SharingPtr<T>
    453 static_pointer_cast(const SharingPtr<U>& r)
    454 {
    455     return SharingPtr<T>(r, static_cast<T*>(r.get()));
    456 }
    457 
    458 template<class T, class U>
    459 SharingPtr<T>
    460 const_pointer_cast(const SharingPtr<U>& r)
    461 {
    462     return SharingPtr<T>(r, const_cast<T*>(r.get()));
    463 }
    464 
    465 template <class T>
    466 class LoggingSharingPtr
    467     : public SharingPtr<T>
    468 {
    469     typedef SharingPtr<T> base;
    470 
    471 public:
    472     typedef void (*Callback)(void*, const LoggingSharingPtr&, bool action);
    473     // action:  false means increment just happened
    474     //          true  means decrement is about to happen
    475 
    476 private:
    477     Callback cb_;
    478     void* baton_;
    479 
    480 public:
    481     LoggingSharingPtr() : cb_(0), baton_(0) {}
    482     LoggingSharingPtr(Callback cb, void* baton)
    483         : cb_(cb), baton_(baton)
    484     {
    485         if (cb_)
    486             cb_(baton_, *this, false);
    487     }
    488 
    489     template <class Y>
    490     LoggingSharingPtr(Y* p)
    491         : base(p), cb_(0), baton_(0) {}
    492 
    493     template <class Y>
    494     LoggingSharingPtr(Y* p, Callback cb, void* baton)
    495         : base(p), cb_(cb), baton_(baton)
    496     {
    497         if (cb_)
    498             cb_(baton_, *this, false);
    499     }
    500 
    501     ~LoggingSharingPtr()
    502     {
    503         if (cb_)
    504             cb_(baton_, *this, true);
    505     }
    506 
    507     LoggingSharingPtr(const LoggingSharingPtr& p)
    508         : base(p), cb_(p.cb_), baton_(p.baton_)
    509     {
    510         if (cb_)
    511             cb_(baton_, *this, false);
    512     }
    513 
    514     LoggingSharingPtr& operator=(const LoggingSharingPtr& p)
    515     {
    516         if (cb_)
    517             cb_(baton_, *this, true);
    518         base::operator=(p);
    519         cb_ = p.cb_;
    520         baton_ = p.baton_;
    521         if (cb_)
    522             cb_(baton_, *this, false);
    523         return *this;
    524     }
    525 
    526     void reset()
    527     {
    528         if (cb_)
    529             cb_(baton_, *this, true);
    530         base::reset();
    531     }
    532 
    533     template <class Y>
    534     void reset(Y* p)
    535     {
    536         if (cb_)
    537             cb_(baton_, *this, true);
    538         base::reset(p);
    539         if (cb_)
    540             cb_(baton_, *this, false);
    541     }
    542 
    543     void SetCallback(Callback cb, void* baton)
    544     {
    545         cb_ = cb;
    546         baton_ = baton;
    547     }
    548 
    549     void ClearCallback()
    550     {
    551         cb_ = 0;
    552         baton_ = 0;
    553     }
    554 };
    555 
    556 
    557 template <class T>
    558 class IntrusiveSharingPtr;
    559 
    560 template <class T>
    561 class ReferenceCountedBase
    562 {
    563 public:
    564     explicit ReferenceCountedBase()
    565         : shared_owners_(-1)
    566     {
    567     }
    568 
    569     void
    570     add_shared();
    571 
    572     void
    573     release_shared();
    574 
    575     long
    576     use_count() const
    577     {
    578         return shared_owners_ + 1;
    579     }
    580 
    581 protected:
    582     long shared_owners_;
    583 
    584     friend class IntrusiveSharingPtr<T>;
    585 
    586 private:
    587     ReferenceCountedBase(const ReferenceCountedBase&);
    588     ReferenceCountedBase& operator=(const ReferenceCountedBase&);
    589 };
    590 
    591     template <class T>
    592     void
    593     lldb_private::ReferenceCountedBase<T>::add_shared()
    594     {
    595         imp::increment(shared_owners_);
    596     }
    597 
    598     template <class T>
    599     void
    600     lldb_private::ReferenceCountedBase<T>::release_shared()
    601     {
    602         if (imp::decrement(shared_owners_) == -1)
    603             delete static_cast<T*>(this);
    604     }
    605 
    606 
    607 template <class T>
    608 class ReferenceCountedBaseVirtual : public imp::shared_count
    609 {
    610 public:
    611     explicit ReferenceCountedBaseVirtual () :
    612         imp::shared_count(-1)
    613     {
    614     }
    615 
    616     virtual
    617     ~ReferenceCountedBaseVirtual ()
    618     {
    619     }
    620 
    621     virtual void on_zero_shared ();
    622 
    623 };
    624 
    625 template <class T>
    626 void
    627 ReferenceCountedBaseVirtual<T>::on_zero_shared()
    628 {
    629 }
    630 
    631 template <typename T>
    632 class IntrusiveSharingPtr
    633 {
    634 public:
    635     typedef T element_type;
    636 
    637     explicit
    638     IntrusiveSharingPtr () :
    639         ptr_(0)
    640     {
    641     }
    642 
    643     explicit
    644     IntrusiveSharingPtr (T* ptr) :
    645         ptr_(ptr)
    646     {
    647         add_shared();
    648     }
    649 
    650     IntrusiveSharingPtr (const IntrusiveSharingPtr& rhs) :
    651         ptr_(rhs.ptr_)
    652     {
    653         add_shared();
    654     }
    655 
    656     template <class X>
    657     IntrusiveSharingPtr (const IntrusiveSharingPtr<X>& rhs)
    658         : ptr_(rhs.get())
    659     {
    660         add_shared();
    661     }
    662 
    663     IntrusiveSharingPtr&
    664     operator= (const IntrusiveSharingPtr& rhs)
    665     {
    666         reset(rhs.get());
    667         return *this;
    668     }
    669 
    670     template <class X> IntrusiveSharingPtr&
    671     operator= (const IntrusiveSharingPtr<X>& rhs)
    672     {
    673         reset(rhs.get());
    674         return *this;
    675     }
    676 
    677     IntrusiveSharingPtr&
    678     operator= (T *ptr)
    679     {
    680         reset(ptr);
    681         return *this;
    682     }
    683 
    684     ~IntrusiveSharingPtr()
    685     {
    686         release_shared();
    687 #if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE)
    688         // NULL out the pointer in objects which can help with leaks detection.
    689         // We don't enable this for LLDB_CONFIGURATION_BUILD_AND_INTEGRATION or
    690         // when none of the LLDB_CONFIGURATION_XXX macros are defined since
    691         // those would be builds for release. But for debug and release builds
    692         // that are for development, we NULL out the pointers to catch potential
    693         // issues.
    694         ptr_ = NULL;
    695 #endif  // #if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE)
    696     }
    697 
    698     T&
    699     operator*() const
    700     {
    701         return *ptr_;
    702     }
    703 
    704     T*
    705     operator->() const
    706     {
    707         return ptr_;
    708     }
    709 
    710     T*
    711     get() const
    712     {
    713         return ptr_;
    714     }
    715 
    716     operator bool() const
    717     {
    718         return ptr_ != 0;
    719     }
    720 
    721     void
    722     swap (IntrusiveSharingPtr& rhs)
    723     {
    724         std::swap(ptr_, rhs.ptr_);
    725 #if defined (ENABLE_SP_LOGGING)
    726         track_sp (this, ptr_, use_count());
    727         track_sp (&rhs, rhs.ptr_, rhs.use_count());
    728 #endif
    729     }
    730 
    731     void
    732     reset(T* ptr = NULL)
    733     {
    734         IntrusiveSharingPtr(ptr).swap(*this);
    735     }
    736 
    737     long
    738     use_count () const
    739     {
    740         if (ptr_)
    741             return ptr_->use_count();
    742         return 0;
    743     }
    744 
    745     bool
    746     unique () const
    747     {
    748         return use_count () == 1;
    749     }
    750 
    751 private:
    752     element_type *ptr_;
    753 
    754     void
    755     add_shared()
    756     {
    757         if (ptr_)
    758         {
    759             ptr_->add_shared();
    760 #if defined (ENABLE_SP_LOGGING)
    761             track_sp (this, ptr_, ptr_->use_count());
    762 #endif
    763         }
    764     }
    765     void
    766     release_shared()
    767     {
    768         if (ptr_)
    769         {
    770 #if defined (ENABLE_SP_LOGGING)
    771             track_sp (this, NULL, ptr_->use_count() - 1);
    772 #endif
    773             ptr_->release_shared();
    774         }
    775     }
    776 };
    777 
    778 template<class T, class U>
    779 inline bool operator== (const IntrusiveSharingPtr<T>& lhs, const IntrusiveSharingPtr<U>& rhs)
    780 {
    781     return lhs.get() == rhs.get();
    782 }
    783 
    784 template<class T, class U>
    785 inline bool operator!= (const IntrusiveSharingPtr<T>& lhs, const IntrusiveSharingPtr<U>& rhs)
    786 {
    787     return lhs.get() != rhs.get();
    788 }
    789 
    790 template<class T, class U>
    791 inline bool operator== (const IntrusiveSharingPtr<T>& lhs, U* rhs)
    792 {
    793     return lhs.get() == rhs;
    794 }
    795 
    796 template<class T, class U>
    797 inline bool operator!= (const IntrusiveSharingPtr<T>& lhs, U* rhs)
    798 {
    799     return lhs.get() != rhs;
    800 }
    801 
    802 template<class T, class U>
    803 inline bool operator== (T* lhs, const IntrusiveSharingPtr<U>& rhs)
    804 {
    805     return lhs == rhs.get();
    806 }
    807 
    808 template<class T, class U>
    809 inline bool operator!= (T* lhs, const IntrusiveSharingPtr<U>& rhs)
    810 {
    811     return lhs != rhs.get();
    812 }
    813 
    814 } // namespace lldb_private
    815 
    816 #endif  // utility_SharingPtr_h_
    817