aboutsummaryrefslogtreecommitdiff
path: root/include/lldb/Utility/SharingPtr.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/lldb/Utility/SharingPtr.h')
-rw-r--r--include/lldb/Utility/SharingPtr.h816
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_