#ifndef HANDLE_H
#define HANDLE_H
#include <cassert>
#include <atomic>
#include <utility>
class Shared;
class Counter {
private:
friend class Shared;
friend class HandleBase;
friend class WeakHandleBase;
typedef unsigned int Type;
std::atomic<Type> refCount;
std::atomic<Type> ptrRefCount;
Shared* pointer;
inline explicit Counter(Shared &shared): refCount(1), ptrRefCount(0), pointer(&shared) { }
inline ~Counter() { assert(!refCount && !ptrRefCount); }
Counter& operator=(const Counter&) = delete;
};
class Shared {
private:
friend class HandleBase;
friend class WeakHandleBase;
Counter * const counter;
Shared(const Shared&) = delete;
Shared& operator=(const Shared&) = delete;
public:
inline Shared(): counter(new Counter(*this)) { }
virtual ~Shared();
};
class WeakHandleBase {
private:
friend class HandleBase;
Counter* counter;
inline void set(Counter* counter) {
if (this->counter == counter) return;
if (counter) counter->refCount++;
if (this->counter && !--this->counter->refCount) delete this->counter;
this->counter = counter;
}
protected:
inline WeakHandleBase(): counter() { }
void set(Shared* pointer) { set(pointer ? pointer->counter : nullptr); }
void set(const WeakHandleBase &other) { set(other.counter); }
void swap(WeakHandleBase &other) { std::swap(counter, other.counter); }
public:
inline ~WeakHandleBase()
{ reset(); }
inline void reset()
{ return set((Counter*)nullptr); }
inline bool operator<(const WeakHandleBase &other) const
{ return counter < other.counter; }
};
class HandleBase {
private:
Shared *pointer;
protected:
inline HandleBase(): pointer() { }
inline void set(Shared *pointer) {
if (this->pointer == pointer) return;
if (pointer) pointer->counter->ptrRefCount++;
if (this->pointer && !--this->pointer->counter->ptrRefCount) delete this->pointer;
this->pointer = pointer;
}
inline void set(const WeakHandleBase &weak) {
Counter *counter = weak.counter;
if (!counter) { set((Shared*)nullptr); return; }
if (pointer && pointer->counter == counter) return;
Shared *pointer = nullptr;
Counter::Type cnt = counter->refCount;
while(cnt)
if (counter->ptrRefCount.compare_exchange_weak(cnt, cnt+1))
{ pointer = counter->pointer; break; }
if (this->pointer && !--this->pointer->counter->ptrRefCount) delete this->pointer;
this->pointer = pointer;
}
inline void swap(HandleBase &other) { std::swap(pointer, other.pointer); }
inline Shared* get() const
{ return pointer; }
public:
inline ~HandleBase()
{ reset(); }
inline void reset()
{ return set((Shared*)nullptr); }
inline operator bool() const
{ return pointer; }
inline bool operator<(const HandleBase &other) const
{ return pointer < other.pointer; }
inline bool operator==(const HandleBase &other) const
{ return pointer == other.pointer; }
inline bool operator==(const Shared *pointer) const
{ return this->pointer == pointer; }
inline friend bool operator==(const Shared *pointer, const HandleBase &handle)
{ return pointer == handle.pointer; }
inline bool operator!=(const HandleBase &other) const
{ return pointer != other.pointer; }
inline bool operator!=(const Shared *pointer) const
{ return this->pointer != pointer; }
inline friend bool operator!=(const Shared *pointer, const HandleBase &handle)
{ return pointer != handle.pointer; }
};
template<typename T> class Handle;
template<typename T>
class WeakHandle: public WeakHandleBase {
public:
typedef T Type;
typedef ::Handle<Type> Handle;
private:
inline void typeChecker(const Type*) { }
public:
inline WeakHandle() { }
inline WeakHandle(const std::nullptr_t) { }
inline WeakHandle(WeakHandle &&other) { WeakHandleBase::swap(other); }
inline WeakHandle(const WeakHandle &other) { WeakHandleBase::set(other.get()); }
inline explicit WeakHandle(const Handle &handle) { WeakHandleBase::set(handle.pointer()); }
inline explicit WeakHandle(Type *pointer) { WeakHandleBase::set(pointer); }
inline WeakHandle& operator=(WeakHandle &&other)
{ WeakHandleBase::swap(other); return *this; }
inline WeakHandle& operator=(const WeakHandle &other)
{ WeakHandleBase::set(other); return *this; }
inline WeakHandle& operator=(const Handle &handle)
{ WeakHandleBase::set(handle.pointer()); return *this; }
inline WeakHandle& operator=(Type *pointer)
{ WeakHandleBase::set(pointer); return *this; }
inline void swap(WeakHandle &other)
{ WeakHandleBase::swap(other); return *this; }
template<typename TT>
inline operator WeakHandle<TT>&()
{ typeChecker((TT*)nullptr); return *reinterpret_cast<WeakHandle<TT>*>(this); }
template<typename TT>
inline operator const WeakHandle<TT>&() const
{ typeChecker((TT*)nullptr); return *reinterpret_cast<const WeakHandle<TT>*>(this); }
};
template<typename T>
class Handle: public HandleBase {
public:
typedef T Type;
typedef WeakHandle<Type> Weak;
private:
inline void typeChecker(const Type*) { }
public:
inline Handle() { }
inline Handle(const std::nullptr_t) { }
inline Handle(Handle &&other) { HandleBase::swap(other); }
inline Handle(const Handle &other) { HandleBase::set(other.get()); }
inline explicit Handle(const Weak &weak) { HandleBase::set(weak); }
inline explicit Handle(Type *pointer) { HandleBase::set(pointer); }
inline Handle& operator=(Handle &&other)
{ HandleBase::swap(other); return *this; }
inline Handle& operator=(const Handle &other)
{ HandleBase::set(other.get()); return *this; }
inline Handle& operator=(const Weak &weak)
{ HandleBase::set(weak); return *this; }
inline Handle& operator=(Type *pointer)
{ HandleBase::set(pointer); return *this; }
inline void swap(Handle &other)
{ HandleBase::swap(other); return *this; }
inline Type* pointer() const { return (Type*)HandleBase::get(); }
inline Type* operator->() const { return pointer(); }
inline Type& operator*() const { return *pointer(); }
template<typename TT>
inline operator Handle<TT>&()
{ typeChecker((TT*)nullptr); return *reinterpret_cast<Handle<TT>*>(this); }
template<typename TT>
inline operator const Handle<TT>&() const
{ typeChecker((TT*)nullptr); return *reinterpret_cast<const Handle<TT>*>(this); }
};
#endif