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