//===---------------------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 #include // Microsoft Visual C++ currently does not enable std::atomic to work // in CLR mode - as such we need to "hack around it" for MSVC++ builds only // using Windows specific intrinsics instead of the C++11 atomic support #ifdef _MSC_VER #include #else #include #endif //#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 { class shared_count { shared_count(const shared_count&); shared_count& operator=(const shared_count&); protected: #ifdef _MSC_VER long shared_owners_; #else std::atomic shared_owners_; #endif 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 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 effective C++ // warnings down to a minimum shared_ptr_pointer (const shared_ptr_pointer &); shared_ptr_pointer & operator=(const shared_ptr_pointer &); }; template void shared_ptr_pointer::on_zero_shared() { delete data_; } template class shared_ptr_emplace : public shared_count { T data_; public: shared_ptr_emplace() : data_() {} template shared_ptr_emplace(A0& a0) : data_(a0) {} template shared_ptr_emplace(A0& a0, A1& a1) : data_(a0, a1) {} template shared_ptr_emplace(A0& a0, A1& a1, A2& a2) : data_(a0, a1, a2) {} template shared_ptr_emplace(A0& a0, A1& a1, A2& a2, A3& a3) : data_(a0, a1, a2, a3) {} template 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 void shared_ptr_emplace::on_zero_shared() { } } // namespace template class SharingPtr { public: typedef T element_type; private: element_type* ptr_; imp::shared_count* cntrl_; struct nat {int for_bool_;}; public: SharingPtr(); SharingPtr(std::nullptr_t); template explicit SharingPtr(Y* p); template explicit SharingPtr(Y* p, imp::shared_count *ctrl_block); template SharingPtr(const SharingPtr& r, element_type *p); SharingPtr(const SharingPtr& r); template SharingPtr(const SharingPtr& r); ~SharingPtr(); SharingPtr& operator=(const SharingPtr& r); template SharingPtr& operator=(const SharingPtr& r); void swap(SharingPtr& r); void reset(); template void reset(Y* p); void reset(std::nullptr_t); 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 make_shared(); template static SharingPtr make_shared(A0&); template static SharingPtr make_shared(A0&, A1&); template static SharingPtr make_shared(A0&, A1&, A2&); template static SharingPtr make_shared(A0&, A1&, A2&, A3&); template static SharingPtr make_shared(A0&, A1&, A2&, A3&, A4&); private: template friend class SharingPtr; }; template inline SharingPtr::SharingPtr() : ptr_(0), cntrl_(0) { } template inline SharingPtr::SharingPtr(std::nullptr_t) : ptr_(0), cntrl_(0) { } template template SharingPtr::SharingPtr(Y* p) : ptr_(p), cntrl_(0) { std::unique_ptr hold(p); typedef imp::shared_ptr_pointer _CntrlBlk; cntrl_ = new _CntrlBlk(p); hold.release(); } template template SharingPtr::SharingPtr(Y* p, imp::shared_count *cntrl_block) : ptr_(p), cntrl_(cntrl_block) { } template template inline SharingPtr::SharingPtr(const SharingPtr& r, element_type *p) : ptr_(p), cntrl_(r.cntrl_) { if (cntrl_) cntrl_->add_shared(); } template inline SharingPtr::SharingPtr(const SharingPtr& r) : ptr_(r.ptr_), cntrl_(r.cntrl_) { if (cntrl_) cntrl_->add_shared(); } template template inline SharingPtr::SharingPtr(const SharingPtr& r) : ptr_(r.ptr_), cntrl_(r.cntrl_) { if (cntrl_) cntrl_->add_shared(); } template SharingPtr::~SharingPtr() { if (cntrl_) cntrl_->release_shared(); } template inline SharingPtr& SharingPtr::operator=(const SharingPtr& r) { SharingPtr(r).swap(*this); return *this; } template template inline SharingPtr& SharingPtr::operator=(const SharingPtr& r) { SharingPtr(r).swap(*this); return *this; } template inline void SharingPtr::swap(SharingPtr& r) { std::swap(ptr_, r.ptr_); std::swap(cntrl_, r.cntrl_); } template inline void SharingPtr::reset() { SharingPtr().swap(*this); } template inline void SharingPtr::reset (std::nullptr_t p) { reset(); } template template inline void SharingPtr::reset(Y* p) { SharingPtr(p).swap(*this); } template SharingPtr SharingPtr::make_shared() { typedef imp::shared_ptr_emplace CntrlBlk; SharingPtr r; r.cntrl_ = new CntrlBlk(); r.ptr_ = static_cast(r.cntrl_)->get(); return r; } template template SharingPtr SharingPtr::make_shared(A0& a0) { typedef imp::shared_ptr_emplace CntrlBlk; SharingPtr r; r.cntrl_ = new CntrlBlk(a0); r.ptr_ = static_cast(r.cntrl_)->get(); return r; } template template SharingPtr SharingPtr::make_shared(A0& a0, A1& a1) { typedef imp::shared_ptr_emplace CntrlBlk; SharingPtr r; r.cntrl_ = new CntrlBlk(a0, a1); r.ptr_ = static_cast(r.cntrl_)->get(); return r; } template template SharingPtr SharingPtr::make_shared(A0& a0, A1& a1, A2& a2) { typedef imp::shared_ptr_emplace CntrlBlk; SharingPtr r; r.cntrl_ = new CntrlBlk(a0, a1, a2); r.ptr_ = static_cast(r.cntrl_)->get(); return r; } template template SharingPtr SharingPtr::make_shared(A0& a0, A1& a1, A2& a2, A3& a3) { typedef imp::shared_ptr_emplace CntrlBlk; SharingPtr r; r.cntrl_ = new CntrlBlk(a0, a1, a2, a3); r.ptr_ = static_cast(r.cntrl_)->get(); return r; } template template SharingPtr SharingPtr::make_shared(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4) { typedef imp::shared_ptr_emplace CntrlBlk; SharingPtr r; r.cntrl_ = new CntrlBlk(a0, a1, a2, a3, a4); r.ptr_ = static_cast(r.cntrl_)->get(); return r; } template inline SharingPtr make_shared() { return SharingPtr::make_shared(); } template inline SharingPtr make_shared(A0& a0) { return SharingPtr::make_shared(a0); } template inline SharingPtr make_shared(A0& a0, A1& a1) { return SharingPtr::make_shared(a0, a1); } template inline SharingPtr make_shared(A0& a0, A1& a1, A2& a2) { return SharingPtr::make_shared(a0, a1, a2); } template inline SharingPtr make_shared(A0& a0, A1& a1, A2& a2, A3& a3) { return SharingPtr::make_shared(a0, a1, a2, a3); } template inline SharingPtr make_shared(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4) { return SharingPtr::make_shared(a0, a1, a2, a3, a4); } template inline bool operator==(const SharingPtr& __x, const SharingPtr& __y) { return __x.get() == __y.get(); } template inline bool operator!=(const SharingPtr& __x, const SharingPtr& __y) { return !(__x == __y); } template inline bool operator<(const SharingPtr& __x, const SharingPtr& __y) { return __x.get() < __y.get(); } template inline void swap(SharingPtr& __x, SharingPtr& __y) { __x.swap(__y); } template inline SharingPtr static_pointer_cast(const SharingPtr& r) { return SharingPtr(r, static_cast(r.get())); } template SharingPtr const_pointer_cast(const SharingPtr& r) { return SharingPtr(r, const_cast(r.get())); } template class LoggingSharingPtr : public SharingPtr { typedef SharingPtr 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 LoggingSharingPtr(Y* p) : base(p), cb_(0), baton_(0) {} template 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 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 IntrusiveSharingPtr; template 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; private: ReferenceCountedBase(const ReferenceCountedBase&); ReferenceCountedBase& operator=(const ReferenceCountedBase&); }; template void lldb_private::ReferenceCountedBase::add_shared() { #ifdef _MSC_VER _InterlockedIncrement(&shared_owners_); #else ++shared_owners_; #endif } template void lldb_private::ReferenceCountedBase::release_shared() { #ifdef _MSC_VER if (_InterlockedDecrement(&shared_owners_) == -1) #else if (--shared_owners_ == -1) #endif delete static_cast(this); } template class ReferenceCountedBaseVirtual : public imp::shared_count { public: explicit ReferenceCountedBaseVirtual () : imp::shared_count(-1) { } virtual ~ReferenceCountedBaseVirtual () { } virtual void on_zero_shared (); }; template void ReferenceCountedBaseVirtual::on_zero_shared() { } template 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 IntrusiveSharingPtr (const IntrusiveSharingPtr& rhs) : ptr_(rhs.get()) { add_shared(); } IntrusiveSharingPtr& operator= (const IntrusiveSharingPtr& rhs) { reset(rhs.get()); return *this; } template IntrusiveSharingPtr& operator= (const IntrusiveSharingPtr& 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_; } explicit 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 inline bool operator== (const IntrusiveSharingPtr& lhs, const IntrusiveSharingPtr& rhs) { return lhs.get() == rhs.get(); } template inline bool operator!= (const IntrusiveSharingPtr& lhs, const IntrusiveSharingPtr& rhs) { return lhs.get() != rhs.get(); } template inline bool operator== (const IntrusiveSharingPtr& lhs, U* rhs) { return lhs.get() == rhs; } template inline bool operator!= (const IntrusiveSharingPtr& lhs, U* rhs) { return lhs.get() != rhs; } template inline bool operator== (T* lhs, const IntrusiveSharingPtr& rhs) { return lhs == rhs.get(); } template inline bool operator!= (T* lhs, const IntrusiveSharingPtr& rhs) { return lhs != rhs.get(); } } // namespace lldb_private #endif // utility_SharingPtr_h_