SharingPtr.h revision 102b2c2681c9a830afe25bfea35557421905e42c
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
19extern "C" void track_sp (void *sp_this, void *ptr, long count);
20
21#endif
22
23namespace lldb_private {
24
25namespace imp {
26
27template <class T>
28inline T
29increment(T& t)
30{
31    return __sync_add_and_fetch(&t, 1);
32}
33
34template <class T>
35inline T
36decrement(T& t)
37{
38    return __sync_add_and_fetch(&t, -1);
39}
40
41class shared_count
42{
43    shared_count(const shared_count&);
44    shared_count& operator=(const shared_count&);
45
46protected:
47    long shared_owners_;
48    virtual ~shared_count();
49private:
50    virtual void on_zero_shared() = 0;
51
52public:
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
61template <class T>
62class shared_ptr_pointer
63    : public shared_count
64{
65    T data_;
66public:
67    shared_ptr_pointer(T p)
68        :  data_(p) {}
69
70private:
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
79template <class T>
80void
81shared_ptr_pointer<T>::on_zero_shared()
82{
83    delete data_;
84}
85
86template <class T>
87class shared_ptr_emplace
88    : public shared_count
89{
90    T data_;
91public:
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
116private:
117    virtual void on_zero_shared();
118public:
119    T* get() {return &data_;}
120};
121
122template <class T>
123void
124shared_ptr_emplace<T>::on_zero_shared()
125{
126}
127
128}  // namespace
129
130template<class T>
131class SharingPtr
132{
133public:
134    typedef T element_type;
135private:
136    element_type*      ptr_;
137    imp::shared_count* cntrl_;
138
139    struct nat {int for_bool_;};
140public:
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
183private:
184
185    template <class U> friend class SharingPtr;
186};
187
188template<class T>
189inline
190SharingPtr<T>::SharingPtr()
191    : ptr_(0),
192      cntrl_(0)
193{
194}
195
196template<class T>
197template<class Y>
198SharingPtr<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
207template<class T>
208template<class Y>
209SharingPtr<T>::SharingPtr(Y* p, imp::shared_count *cntrl_block)
210    : ptr_(p), cntrl_(cntrl_block)
211{
212}
213
214template<class T>
215template<class Y>
216inline
217SharingPtr<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
225template<class T>
226inline
227SharingPtr<T>::SharingPtr(const SharingPtr& r)
228    : ptr_(r.ptr_),
229      cntrl_(r.cntrl_)
230{
231    if (cntrl_)
232        cntrl_->add_shared();
233}
234
235template<class T>
236template<class Y>
237inline
238SharingPtr<T>::SharingPtr(const SharingPtr<Y>& r)
239    : ptr_(r.ptr_),
240      cntrl_(r.cntrl_)
241{
242    if (cntrl_)
243        cntrl_->add_shared();
244}
245
246template<class T>
247SharingPtr<T>::~SharingPtr()
248{
249    if (cntrl_)
250        cntrl_->release_shared();
251}
252
253template<class T>
254inline
255SharingPtr<T>&
256SharingPtr<T>::operator=(const SharingPtr& r)
257{
258    SharingPtr(r).swap(*this);
259    return *this;
260}
261
262template<class T>
263template<class Y>
264inline
265SharingPtr<T>&
266SharingPtr<T>::operator=(const SharingPtr<Y>& r)
267{
268    SharingPtr(r).swap(*this);
269    return *this;
270}
271
272template<class T>
273inline
274void
275SharingPtr<T>::swap(SharingPtr& r)
276{
277    std::swap(ptr_, r.ptr_);
278    std::swap(cntrl_, r.cntrl_);
279}
280
281template<class T>
282inline
283void
284SharingPtr<T>::reset()
285{
286    SharingPtr().swap(*this);
287}
288
289template<class T>
290template<class Y>
291inline
292void
293SharingPtr<T>::reset(Y* p)
294{
295    SharingPtr(p).swap(*this);
296}
297
298template<class T>
299SharingPtr<T>
300SharingPtr<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
309template<class T>
310template<class A0>
311SharingPtr<T>
312SharingPtr<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
321template<class T>
322template<class A0, class A1>
323SharingPtr<T>
324SharingPtr<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
333template<class T>
334template<class A0, class A1, class A2>
335SharingPtr<T>
336SharingPtr<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
345template<class T>
346template<class A0, class A1, class A2, class A3>
347SharingPtr<T>
348SharingPtr<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
357template<class T>
358template<class A0, class A1, class A2, class A3, class A4>
359SharingPtr<T>
360SharingPtr<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
369template<class T>
370inline
371SharingPtr<T>
372make_shared()
373{
374    return SharingPtr<T>::make_shared();
375}
376
377template<class T, class A0>
378inline
379SharingPtr<T>
380make_shared(A0& a0)
381{
382    return SharingPtr<T>::make_shared(a0);
383}
384
385template<class T, class A0, class A1>
386inline
387SharingPtr<T>
388make_shared(A0& a0, A1& a1)
389{
390    return SharingPtr<T>::make_shared(a0, a1);
391}
392
393template<class T, class A0, class A1, class A2>
394inline
395SharingPtr<T>
396make_shared(A0& a0, A1& a1, A2& a2)
397{
398    return SharingPtr<T>::make_shared(a0, a1, a2);
399}
400
401template<class T, class A0, class A1, class A2, class A3>
402inline
403SharingPtr<T>
404make_shared(A0& a0, A1& a1, A2& a2, A3& a3)
405{
406    return SharingPtr<T>::make_shared(a0, a1, a2, a3);
407}
408
409template<class T, class A0, class A1, class A2, class A3, class A4>
410inline
411SharingPtr<T>
412make_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
418template<class T, class U>
419inline
420bool
421operator==(const SharingPtr<T>& __x, const SharingPtr<U>& __y)
422{
423    return __x.get() == __y.get();
424}
425
426template<class T, class U>
427inline
428bool
429operator!=(const SharingPtr<T>& __x, const SharingPtr<U>& __y)
430{
431    return !(__x == __y);
432}
433
434template<class T, class U>
435inline
436bool
437operator<(const SharingPtr<T>& __x, const SharingPtr<U>& __y)
438{
439    return __x.get() < __y.get();
440}
441
442template<class T>
443inline
444void
445swap(SharingPtr<T>& __x, SharingPtr<T>& __y)
446{
447    __x.swap(__y);
448}
449
450template<class T, class U>
451inline
452SharingPtr<T>
453static_pointer_cast(const SharingPtr<U>& r)
454{
455    return SharingPtr<T>(r, static_cast<T*>(r.get()));
456}
457
458template<class T, class U>
459SharingPtr<T>
460const_pointer_cast(const SharingPtr<U>& r)
461{
462    return SharingPtr<T>(r, const_cast<T*>(r.get()));
463}
464
465template <class T>
466class LoggingSharingPtr
467    : public SharingPtr<T>
468{
469    typedef SharingPtr<T> base;
470
471public:
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
476private:
477    Callback cb_;
478    void* baton_;
479
480public:
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
557template <class T>
558class IntrusiveSharingPtr;
559
560template <class T>
561class ReferenceCountedBase
562{
563public:
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
581protected:
582    long shared_owners_;
583
584    friend class IntrusiveSharingPtr<T>;
585
586private:
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
607template <class T>
608class ReferenceCountedBaseVirtual : public imp::shared_count
609{
610public:
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
625template <class T>
626void
627ReferenceCountedBaseVirtual<T>::on_zero_shared()
628{
629}
630
631template <typename T>
632class IntrusiveSharingPtr
633{
634public:
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
751private:
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
778template<class T, class U>
779inline bool operator== (const IntrusiveSharingPtr<T>& lhs, const IntrusiveSharingPtr<U>& rhs)
780{
781    return lhs.get() == rhs.get();
782}
783
784template<class T, class U>
785inline bool operator!= (const IntrusiveSharingPtr<T>& lhs, const IntrusiveSharingPtr<U>& rhs)
786{
787    return lhs.get() != rhs.get();
788}
789
790template<class T, class U>
791inline bool operator== (const IntrusiveSharingPtr<T>& lhs, U* rhs)
792{
793    return lhs.get() == rhs;
794}
795
796template<class T, class U>
797inline bool operator!= (const IntrusiveSharingPtr<T>& lhs, U* rhs)
798{
799    return lhs.get() != rhs;
800}
801
802template<class T, class U>
803inline bool operator== (T* lhs, const IntrusiveSharingPtr<U>& rhs)
804{
805    return lhs == rhs.get();
806}
807
808template<class T, class U>
809inline 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