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