// Copyright (c) 1996-1997 Vladimir Batov
//
// Permission to use, copy, modify, distribute and sell this
// software and its documentation for any purpose is hereby
// granted without fee, provided that the above copyright notice
// appear in all copies and that both that copyright notice and
// this permission notice appear in supporting documentation.
// I make no representations about the suitability of this software
// for any purpose. It is provided "as is" without express or
// implied warranty.
// Handle<T> requires T class to have T::T() and
// T::T(const T&) constructors.
#ifndef BATOV_HANDLE_H
#define BATOV_HANDLE_H
typedef unsigned int uint;
class HandleError
{
public:
~HandleError () {}
HandleError () : _error(_allocate()) {}
HandleError (uint err) : _error(err) {}
operator uint () const { return _error; }
bool operator== (const HandleError& e) const
{ return _error == e._error; }
static HandleError no_error;
static HandleError unknown;
private:
uint _error;
uint _allocate();
};
template<class T/*, class Allocator = MemoryAllocator
When supported*/>
class Handle
{
public:
typedef HandleError Error;
private:
class Counted
{
public:
~Counted () {}
Counted ();
Counted (const T&);
void dismiss () { if (!--_num_references) delete this; }
void use () { ++_num_references; }
operator T& () { return _instance; }
operator const T& () const { return _instance; }
operator T* () { return &_instance; }
operator const T* () const { return &_instance; }
T* operator-> () { return &_instance; }
const T* operator-> () const { return &_instance; }
// Possible memory optimization. See [6].
// void* operator new (size_t)
// { return _allocator.allocate(); }
// void operator delete (void* storage)
// { _allocator.deallocate(storage); }
bool is_shared () const
{ return 1 < _num_references ? true : false; }
bool is_error () const { return _error ? true : false; }
Error get_error () const { return _error; }
void set_error (Error);
private:
T _instance;
uint _num_references : 16; // Reference counter.
// (<=65535 looks enough)
uint _error : 16; // Error conditions flag.
// (<=65535)
// Possible memory optimization. See [6].
// static MemoryAllocator _allocator;
};
public:
~Handle ();
Handle ();
Handle (const T&);
Handle (const T*);
Handle (const Handle<T>&);
operator T& () { return _counted->operator T&(); }
operator T* () { return _counted->operator T*(); }
operator const T& () const { return _counted->operator T&(); }
operator const T* () const { return _counted->operator T*(); }
const T* operator-> () const
{ return _counted->operator ->(); }
T* operator-> () { return _counted->operator ->(); }
Handle<T>& operator = (const T&);
Handle<T>& operator = (const T*);
Handle<T>& operator = (const Handle<T>&);
static Handle<T> error (Error =Error::unknown);
void set_error (Error =Error::unknown);
Error get_error () const { return _counted->get_error(); }
bool is_error () const { return _counted-> is_error(); }
bool is_shared () const { return _counted->is_shared(); }
Handle<T> duplicate () const; // Convenience method to create
// a copy of a "T-Handle<T>" pair.
private:
Counted* _counted;
// User has NO ACCESS TO THE ADDRESS OF A HANDLE instance
// as such access bypasses reference counter mechanism.
// User is forced to pass it by value (Handle) that is
// supervised by the mechanism.
Handle<T>* operator& (); // Not defined to prevent usage.
};
template<class T>
inline
Handle<T>::Counted::Counted() : _num_references(0),
_error(Error::no_error),
_instance()
{
// Preferred form of T instance creation.
}
template<class T>
inline
Handle<T>::Counted::Counted(const T& from)
: _num_references(0),
_error(Error::no_error),
_instance(from)
{
// Should be avoided as an internal copy of 'from'
// is created.
}
template<class T>
inline
void
Handle<T>::Counted::set_error(Error err)
{
_error = err < Error::unknown
? err
: Error::unknown;
}
template<class T>
inline
Handle<T>
Handle<T>::error(Error num)
{
Handle<T> h;
h.set_error(num);
return h;
}
template<class T>
inline
void
Handle<T>::set_error(Error err)
{
_counted->set_error(err);
}
template<class T>
inline
Handle<T>::~Handle()
{
_counted->dismiss();
}
template<class T>
inline
Handle<T>::Handle() : _counted(new Counted())
{
_counted->use();
}
template<class T>
inline
Handle<T>::Handle(const T& copy) : _counted(new Counted(copy))
{
_counted->use();
}
template<class T>
inline
Handle<T>::Handle(const T* copy)
: _counted(copy ? new Counted(*copy) : new Counted())
{
_counted->use();
}
template<class T>
inline
Handle<T>::Handle(const Handle<T>& ref) : _counted(ref._counted)
{
_counted->use();
}
template<class T>
inline
Handle<T>&
Handle<T>::operator=(const T& src) //8.
{
if (*this != &src)
{
_counted->dismiss();
_counted = new Counted(src);
_counted->use();
}
return *this;
}
template<class T>
inline
Handle<T>&
Handle<T>::operator=(const T* src) //8.
{
if (*this != src)
{
_counted->dismiss();
_counted = src ? new Counted(*src) : new Counted();
_counted->use();
}
return *this;
}
template<class T>
inline
Handle<T>&
Handle<T>::operator=(const Handle<T>& src)
{
if (this->_counted != src._counted)
{
_counted->dismiss();
_counted = src._counted;
_counted->use();
}
return *this;
}
template<class T>
inline
Handle<T>
Handle<T>::duplicate() const
{
return Handle<T>(operator->());
}
#endif // BATOV_HANDLE_H
// End of File