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