SharingPtr.h   [plain text]


//===---------------------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>

namespace lldb_private {

namespace imp {

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;
    }
};

} // namespace lldb

#endif  // utility_SharingPtr_h_