Blob Blame Raw
#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