blob: e5b2bceebbd8449c4e1deba46a17be26840d58b0 [file] [log] [blame]
//===---------------------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::auto_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_