//===---------------------SharingPtr.h --------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef utility_SharingPtr_h_ #define utility_SharingPtr_h_ #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 #include //#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 &) = delete; shared_count &operator=(const shared_count &) = delete; public: explicit shared_count(long refs = 0) : shared_owners_(refs) {} void add_shared(); void release_shared(); long use_count() const { return shared_owners_ + 1; } protected: #ifdef _MSC_VER long shared_owners_; #else std::atomic shared_owners_; #endif virtual ~shared_count(); private: virtual void on_zero_shared() = 0; }; template class shared_ptr_pointer : public shared_count { T data_; public: shared_ptr_pointer(T p) : data_(p) {} private: void on_zero_shared() override; shared_ptr_pointer(const shared_ptr_pointer &) = delete; shared_ptr_pointer &operator=(const shared_ptr_pointer &) = delete; }; 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: void on_zero_shared() override; public: T *get() { return &data_; } }; template void shared_ptr_emplace::on_zero_shared() {} } // namespace imp 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_ == nullptr; } 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_(nullptr), cntrl_(nullptr) {} template inline SharingPtr::SharingPtr(std::nullptr_t) : ptr_(nullptr), cntrl_(nullptr) {} template template SharingPtr::SharingPtr(Y *p) : ptr_(p), cntrl_(nullptr) { 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 LoggingSharingPtr() : cb_(0), baton_(nullptr) {} LoggingSharingPtr(Callback cb, void *baton) : cb_(cb), baton_(baton) { if (cb_) cb_(baton_, *this, false); } template LoggingSharingPtr(Y *p) : base(p), cb_(0), baton_(nullptr) {} 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; } private: Callback cb_; void *baton_; }; 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 &) = delete; ReferenceCountedBase &operator=(const ReferenceCountedBase &) = delete; }; 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) {} ~ReferenceCountedBaseVirtual() override = default; void on_zero_shared() override; }; 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(); ptr_ = nullptr; } 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 = nullptr) { 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, nullptr, 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_