#ifndef HANDLE_H
#define HANDLE_H
#include <cassert>
#include <algorithm>
#include <typeinfo>
class Shared {
private:
int refcount;
public:
Shared(): refcount(1) { }
Shared(const Shared&): refcount(1) { }
virtual ~Shared() { };
Shared& operator=(const Shared&) { return *this; }
void reference() { ++refcount; }
void unreference() { if (--refcount <= 0) delete this; }
int get_refcount() const { return refcount; }
};
class NoHandle { };
const NoHandle nohandle;
template<typename T>
class HandleT
{
public:
typedef T Type;
protected:
Type *pointer;
public:
HandleT(): pointer() { }
HandleT(const NoHandle &): HandleT() { }
explicit HandleT(Type *pointer): HandleT() { set(pointer); }
HandleT(const HandleT &x): HandleT(x.get()) { }
HandleT(HandleT &&x): pointer(x.pointer) { x.pointer = 0; }
~HandleT() { reset(); }
Type* get() const { return pointer; }
Type& getref() const { assert(pointer); return *pointer; }
Type& operator*() const { return getref(); }
Type* operator->() const { return &getref(); }
operator bool() const { return pointer; }
bool empty() const { return !pointer; }
int get_refcount() const { return pointer ? pointer->get_refcount() : 0; }
bool unique() const { return get_refcount() == 1; }
bool operator<(const HandleT &x) const { return pointer < x.get(); }
bool operator==(const HandleT &x) const { return pointer == x.get(); }
bool operator!=(const HandleT &x) const { return pointer != x.get(); }
void set(Type *x) {
if (x != pointer) {
if (x) x->reference();
if (pointer) pointer->unreference();
pointer = x;
}
}
void swap(HandleT &x)
{ swap(pointer, x.pointer); }
void grab(HandleT &x) {
if (&x != this) {
if (pointer) pointer->unreference();
pointer = x.pointer;
x.pointer = 0;
}
}
void reset() { set(0); }
HandleT& operator=(const HandleT &x) { set(x.get()); return *this; }
HandleT& operator=(HandleT &&x) { grab(x); return *this; }
template<typename TT> static HandleT cast(TT *x)
{ return HandleT<T>(dynamic_cast<T*>(x)); }
template<typename TT> static HandleT cast(const HandleT<TT> &x)
{ return cast(x.get()); }
template<class TT> operator HandleT<TT>() const
{ return HandleT<TT>(pointer); }
template<typename TT> bool type_is() const
{ return cast<const TT*>(pointer); }
template<typename TT> TT* type_pointer() const
{ return dynamic_cast<TT*>(pointer); }
template<typename TT> bool type_equal() const
{ return typeid(*pointer) == typeid(TT); }
};
#endif