diff options
Diffstat (limited to 'include/lldb/Utility/SharingPtr.h')
-rw-r--r-- | include/lldb/Utility/SharingPtr.h | 816 |
1 files changed, 816 insertions, 0 deletions
diff --git a/include/lldb/Utility/SharingPtr.h b/include/lldb/Utility/SharingPtr.h new file mode 100644 index 000000000000..814b54b5cfe6 --- /dev/null +++ b/include/lldb/Utility/SharingPtr.h @@ -0,0 +1,816 @@ +//===---------------------SharingPtr.h --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef utility_SharingPtr_h_ +#define utility_SharingPtr_h_ + +#include <algorithm> +#include <memory> + +//#define ENABLE_SP_LOGGING 1 // DON'T CHECK THIS LINE IN UNLESS COMMENTED OUT +#if defined (ENABLE_SP_LOGGING) + +extern "C" void track_sp (void *sp_this, void *ptr, long count); + +#endif + +namespace lldb_private { + +namespace imp { + +template <class T> +inline T +increment(T& t) +{ + return __sync_add_and_fetch(&t, 1); +} + +template <class T> +inline T +decrement(T& t) +{ + return __sync_add_and_fetch(&t, -1); +} + +class shared_count +{ + shared_count(const shared_count&); + shared_count& operator=(const shared_count&); + +protected: + long shared_owners_; + virtual ~shared_count(); +private: + virtual void on_zero_shared() = 0; + +public: + explicit shared_count(long refs = 0) + : shared_owners_(refs) {} + + void add_shared(); + void release_shared(); + long use_count() const {return shared_owners_ + 1;} +}; + +template <class T> +class shared_ptr_pointer + : public shared_count +{ + T data_; +public: + shared_ptr_pointer(T p) + : data_(p) {} + +private: + virtual void on_zero_shared(); + + // Outlaw copy constructor and assignment operator to keep effictive C++ + // warnings down to a minumum + shared_ptr_pointer (const shared_ptr_pointer &); + shared_ptr_pointer & operator=(const shared_ptr_pointer &); +}; + +template <class T> +void +shared_ptr_pointer<T>::on_zero_shared() +{ + delete data_; +} + +template <class T> +class shared_ptr_emplace + : public shared_count +{ + T data_; +public: + + shared_ptr_emplace() + : data_() {} + + template <class A0> + shared_ptr_emplace(A0& a0) + : data_(a0) {} + + template <class A0, class A1> + shared_ptr_emplace(A0& a0, A1& a1) + : data_(a0, a1) {} + + template <class A0, class A1, class A2> + shared_ptr_emplace(A0& a0, A1& a1, A2& a2) + : data_(a0, a1, a2) {} + + template <class A0, class A1, class A2, class A3> + shared_ptr_emplace(A0& a0, A1& a1, A2& a2, A3& a3) + : data_(a0, a1, a2, a3) {} + + template <class A0, class A1, class A2, class A3, class A4> + shared_ptr_emplace(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4) + : data_(a0, a1, a2, a3, a4) {} + +private: + virtual void on_zero_shared(); +public: + T* get() {return &data_;} +}; + +template <class T> +void +shared_ptr_emplace<T>::on_zero_shared() +{ +} + +} // namespace + +template<class T> +class SharingPtr +{ +public: + typedef T element_type; +private: + element_type* ptr_; + imp::shared_count* cntrl_; + + struct nat {int for_bool_;}; +public: + SharingPtr(); + template<class Y> explicit SharingPtr(Y* p); + template<class Y> explicit SharingPtr(Y* p, imp::shared_count *ctrl_block); + template<class Y> SharingPtr(const SharingPtr<Y>& r, element_type *p); + SharingPtr(const SharingPtr& r); + template<class Y> + SharingPtr(const SharingPtr<Y>& r); + + ~SharingPtr(); + + SharingPtr& operator=(const SharingPtr& r); + template<class Y> SharingPtr& operator=(const SharingPtr<Y>& r); + + void swap(SharingPtr& r); + void reset(); + template<class Y> void reset(Y* p); + + element_type* get() const {return ptr_;} + element_type& operator*() const {return *ptr_;} + element_type* operator->() const {return ptr_;} + long use_count() const {return cntrl_ ? cntrl_->use_count() : 0;} + bool unique() const {return use_count() == 1;} + bool empty() const {return cntrl_ == 0;} + operator nat*() const {return (nat*)get();} + + static SharingPtr<T> make_shared(); + + template<class A0> + static SharingPtr<T> make_shared(A0&); + + template<class A0, class A1> + static SharingPtr<T> make_shared(A0&, A1&); + + template<class A0, class A1, class A2> + static SharingPtr<T> make_shared(A0&, A1&, A2&); + + template<class A0, class A1, class A2, class A3> + static SharingPtr<T> make_shared(A0&, A1&, A2&, A3&); + + template<class A0, class A1, class A2, class A3, class A4> + static SharingPtr<T> make_shared(A0&, A1&, A2&, A3&, A4&); + +private: + + template <class U> friend class SharingPtr; +}; + +template<class T> +inline +SharingPtr<T>::SharingPtr() + : ptr_(0), + cntrl_(0) +{ +} + +template<class T> +template<class Y> +SharingPtr<T>::SharingPtr(Y* p) + : ptr_(p), cntrl_(0) +{ + std::unique_ptr<Y> hold(p); + typedef imp::shared_ptr_pointer<Y*> _CntrlBlk; + cntrl_ = new _CntrlBlk(p); + hold.release(); +} + +template<class T> +template<class Y> +SharingPtr<T>::SharingPtr(Y* p, imp::shared_count *cntrl_block) + : ptr_(p), cntrl_(cntrl_block) +{ +} + +template<class T> +template<class Y> +inline +SharingPtr<T>::SharingPtr(const SharingPtr<Y>& r, element_type *p) + : ptr_(p), + cntrl_(r.cntrl_) +{ + if (cntrl_) + cntrl_->add_shared(); +} + +template<class T> +inline +SharingPtr<T>::SharingPtr(const SharingPtr& r) + : ptr_(r.ptr_), + cntrl_(r.cntrl_) +{ + if (cntrl_) + cntrl_->add_shared(); +} + +template<class T> +template<class Y> +inline +SharingPtr<T>::SharingPtr(const SharingPtr<Y>& r) + : ptr_(r.ptr_), + cntrl_(r.cntrl_) +{ + if (cntrl_) + cntrl_->add_shared(); +} + +template<class T> +SharingPtr<T>::~SharingPtr() +{ + if (cntrl_) + cntrl_->release_shared(); +} + +template<class T> +inline +SharingPtr<T>& +SharingPtr<T>::operator=(const SharingPtr& r) +{ + SharingPtr(r).swap(*this); + return *this; +} + +template<class T> +template<class Y> +inline +SharingPtr<T>& +SharingPtr<T>::operator=(const SharingPtr<Y>& r) +{ + SharingPtr(r).swap(*this); + return *this; +} + +template<class T> +inline +void +SharingPtr<T>::swap(SharingPtr& r) +{ + std::swap(ptr_, r.ptr_); + std::swap(cntrl_, r.cntrl_); +} + +template<class T> +inline +void +SharingPtr<T>::reset() +{ + SharingPtr().swap(*this); +} + +template<class T> +template<class Y> +inline +void +SharingPtr<T>::reset(Y* p) +{ + SharingPtr(p).swap(*this); +} + +template<class T> +SharingPtr<T> +SharingPtr<T>::make_shared() +{ + typedef imp::shared_ptr_emplace<T> CntrlBlk; + SharingPtr<T> r; + r.cntrl_ = new CntrlBlk(); + r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get(); + return r; +} + +template<class T> +template<class A0> +SharingPtr<T> +SharingPtr<T>::make_shared(A0& a0) +{ + typedef imp::shared_ptr_emplace<T> CntrlBlk; + SharingPtr<T> r; + r.cntrl_ = new CntrlBlk(a0); + r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get(); + return r; +} + +template<class T> +template<class A0, class A1> +SharingPtr<T> +SharingPtr<T>::make_shared(A0& a0, A1& a1) +{ + typedef imp::shared_ptr_emplace<T> CntrlBlk; + SharingPtr<T> r; + r.cntrl_ = new CntrlBlk(a0, a1); + r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get(); + return r; +} + +template<class T> +template<class A0, class A1, class A2> +SharingPtr<T> +SharingPtr<T>::make_shared(A0& a0, A1& a1, A2& a2) +{ + typedef imp::shared_ptr_emplace<T> CntrlBlk; + SharingPtr<T> r; + r.cntrl_ = new CntrlBlk(a0, a1, a2); + r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get(); + return r; +} + +template<class T> +template<class A0, class A1, class A2, class A3> +SharingPtr<T> +SharingPtr<T>::make_shared(A0& a0, A1& a1, A2& a2, A3& a3) +{ + typedef imp::shared_ptr_emplace<T> CntrlBlk; + SharingPtr<T> r; + r.cntrl_ = new CntrlBlk(a0, a1, a2, a3); + r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get(); + return r; +} + +template<class T> +template<class A0, class A1, class A2, class A3, class A4> +SharingPtr<T> +SharingPtr<T>::make_shared(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4) +{ + typedef imp::shared_ptr_emplace<T> CntrlBlk; + SharingPtr<T> r; + r.cntrl_ = new CntrlBlk(a0, a1, a2, a3, a4); + r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get(); + return r; +} + +template<class T> +inline +SharingPtr<T> +make_shared() +{ + return SharingPtr<T>::make_shared(); +} + +template<class T, class A0> +inline +SharingPtr<T> +make_shared(A0& a0) +{ + return SharingPtr<T>::make_shared(a0); +} + +template<class T, class A0, class A1> +inline +SharingPtr<T> +make_shared(A0& a0, A1& a1) +{ + return SharingPtr<T>::make_shared(a0, a1); +} + +template<class T, class A0, class A1, class A2> +inline +SharingPtr<T> +make_shared(A0& a0, A1& a1, A2& a2) +{ + return SharingPtr<T>::make_shared(a0, a1, a2); +} + +template<class T, class A0, class A1, class A2, class A3> +inline +SharingPtr<T> +make_shared(A0& a0, A1& a1, A2& a2, A3& a3) +{ + return SharingPtr<T>::make_shared(a0, a1, a2, a3); +} + +template<class T, class A0, class A1, class A2, class A3, class A4> +inline +SharingPtr<T> +make_shared(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4) +{ + return SharingPtr<T>::make_shared(a0, a1, a2, a3, a4); +} + + +template<class T, class U> +inline +bool +operator==(const SharingPtr<T>& __x, const SharingPtr<U>& __y) +{ + return __x.get() == __y.get(); +} + +template<class T, class U> +inline +bool +operator!=(const SharingPtr<T>& __x, const SharingPtr<U>& __y) +{ + return !(__x == __y); +} + +template<class T, class U> +inline +bool +operator<(const SharingPtr<T>& __x, const SharingPtr<U>& __y) +{ + return __x.get() < __y.get(); +} + +template<class T> +inline +void +swap(SharingPtr<T>& __x, SharingPtr<T>& __y) +{ + __x.swap(__y); +} + +template<class T, class U> +inline +SharingPtr<T> +static_pointer_cast(const SharingPtr<U>& r) +{ + return SharingPtr<T>(r, static_cast<T*>(r.get())); +} + +template<class T, class U> +SharingPtr<T> +const_pointer_cast(const SharingPtr<U>& r) +{ + return SharingPtr<T>(r, const_cast<T*>(r.get())); +} + +template <class T> +class LoggingSharingPtr + : public SharingPtr<T> +{ + typedef SharingPtr<T> base; + +public: + typedef void (*Callback)(void*, const LoggingSharingPtr&, bool action); + // action: false means increment just happened + // true means decrement is about to happen + +private: + Callback cb_; + void* baton_; + +public: + LoggingSharingPtr() : cb_(0), baton_(0) {} + LoggingSharingPtr(Callback cb, void* baton) + : cb_(cb), baton_(baton) + { + if (cb_) + cb_(baton_, *this, false); + } + + template <class Y> + LoggingSharingPtr(Y* p) + : base(p), cb_(0), baton_(0) {} + + template <class Y> + LoggingSharingPtr(Y* p, Callback cb, void* baton) + : base(p), cb_(cb), baton_(baton) + { + if (cb_) + cb_(baton_, *this, false); + } + + ~LoggingSharingPtr() + { + if (cb_) + cb_(baton_, *this, true); + } + + LoggingSharingPtr(const LoggingSharingPtr& p) + : base(p), cb_(p.cb_), baton_(p.baton_) + { + if (cb_) + cb_(baton_, *this, false); + } + + LoggingSharingPtr& operator=(const LoggingSharingPtr& p) + { + if (cb_) + cb_(baton_, *this, true); + base::operator=(p); + cb_ = p.cb_; + baton_ = p.baton_; + if (cb_) + cb_(baton_, *this, false); + return *this; + } + + void reset() + { + if (cb_) + cb_(baton_, *this, true); + base::reset(); + } + + template <class Y> + void reset(Y* p) + { + if (cb_) + cb_(baton_, *this, true); + base::reset(p); + if (cb_) + cb_(baton_, *this, false); + } + + void SetCallback(Callback cb, void* baton) + { + cb_ = cb; + baton_ = baton; + } + + void ClearCallback() + { + cb_ = 0; + baton_ = 0; + } +}; + + +template <class T> +class IntrusiveSharingPtr; + +template <class T> +class ReferenceCountedBase +{ +public: + explicit ReferenceCountedBase() + : shared_owners_(-1) + { + } + + void + add_shared(); + + void + release_shared(); + + long + use_count() const + { + return shared_owners_ + 1; + } + +protected: + long shared_owners_; + + friend class IntrusiveSharingPtr<T>; + +private: + ReferenceCountedBase(const ReferenceCountedBase&); + ReferenceCountedBase& operator=(const ReferenceCountedBase&); +}; + + template <class T> + void + lldb_private::ReferenceCountedBase<T>::add_shared() + { + imp::increment(shared_owners_); + } + + template <class T> + void + lldb_private::ReferenceCountedBase<T>::release_shared() + { + if (imp::decrement(shared_owners_) == -1) + delete static_cast<T*>(this); + } + + +template <class T> +class ReferenceCountedBaseVirtual : public imp::shared_count +{ +public: + explicit ReferenceCountedBaseVirtual () : + imp::shared_count(-1) + { + } + + virtual + ~ReferenceCountedBaseVirtual () + { + } + + virtual void on_zero_shared (); + +}; + +template <class T> +void +ReferenceCountedBaseVirtual<T>::on_zero_shared() +{ +} + +template <typename T> +class IntrusiveSharingPtr +{ +public: + typedef T element_type; + + explicit + IntrusiveSharingPtr () : + ptr_(0) + { + } + + explicit + IntrusiveSharingPtr (T* ptr) : + ptr_(ptr) + { + add_shared(); + } + + IntrusiveSharingPtr (const IntrusiveSharingPtr& rhs) : + ptr_(rhs.ptr_) + { + add_shared(); + } + + template <class X> + IntrusiveSharingPtr (const IntrusiveSharingPtr<X>& rhs) + : ptr_(rhs.get()) + { + add_shared(); + } + + IntrusiveSharingPtr& + operator= (const IntrusiveSharingPtr& rhs) + { + reset(rhs.get()); + return *this; + } + + template <class X> IntrusiveSharingPtr& + operator= (const IntrusiveSharingPtr<X>& rhs) + { + reset(rhs.get()); + return *this; + } + + IntrusiveSharingPtr& + operator= (T *ptr) + { + reset(ptr); + return *this; + } + + ~IntrusiveSharingPtr() + { + release_shared(); +#if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE) + // NULL out the pointer in objects which can help with leaks detection. + // We don't enable this for LLDB_CONFIGURATION_BUILD_AND_INTEGRATION or + // when none of the LLDB_CONFIGURATION_XXX macros are defined since + // those would be builds for release. But for debug and release builds + // that are for development, we NULL out the pointers to catch potential + // issues. + ptr_ = NULL; +#endif // #if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE) + } + + T& + operator*() const + { + return *ptr_; + } + + T* + operator->() const + { + return ptr_; + } + + T* + get() const + { + return ptr_; + } + + operator bool() const + { + return ptr_ != 0; + } + + void + swap (IntrusiveSharingPtr& rhs) + { + std::swap(ptr_, rhs.ptr_); +#if defined (ENABLE_SP_LOGGING) + track_sp (this, ptr_, use_count()); + track_sp (&rhs, rhs.ptr_, rhs.use_count()); +#endif + } + + void + reset(T* ptr = NULL) + { + IntrusiveSharingPtr(ptr).swap(*this); + } + + long + use_count () const + { + if (ptr_) + return ptr_->use_count(); + return 0; + } + + bool + unique () const + { + return use_count () == 1; + } + +private: + element_type *ptr_; + + void + add_shared() + { + if (ptr_) + { + ptr_->add_shared(); +#if defined (ENABLE_SP_LOGGING) + track_sp (this, ptr_, ptr_->use_count()); +#endif + } + } + void + release_shared() + { + if (ptr_) + { +#if defined (ENABLE_SP_LOGGING) + track_sp (this, NULL, ptr_->use_count() - 1); +#endif + ptr_->release_shared(); + } + } +}; + +template<class T, class U> +inline bool operator== (const IntrusiveSharingPtr<T>& lhs, const IntrusiveSharingPtr<U>& rhs) +{ + return lhs.get() == rhs.get(); +} + +template<class T, class U> +inline bool operator!= (const IntrusiveSharingPtr<T>& lhs, const IntrusiveSharingPtr<U>& rhs) +{ + return lhs.get() != rhs.get(); +} + +template<class T, class U> +inline bool operator== (const IntrusiveSharingPtr<T>& lhs, U* rhs) +{ + return lhs.get() == rhs; +} + +template<class T, class U> +inline bool operator!= (const IntrusiveSharingPtr<T>& lhs, U* rhs) +{ + return lhs.get() != rhs; +} + +template<class T, class U> +inline bool operator== (T* lhs, const IntrusiveSharingPtr<U>& rhs) +{ + return lhs == rhs.get(); +} + +template<class T, class U> +inline bool operator!= (T* lhs, const IntrusiveSharingPtr<U>& rhs) +{ + return lhs != rhs.get(); +} + +} // namespace lldb_private + +#endif // utility_SharingPtr_h_ |