#ifndef RELATIVE_PTR_
#define RELATIVE_PTR_

// TODO - instead of incuding this, just declare a specialization of
// iterator_traits<relative_ptr<T> >.
#include <bits/stl_iterator_base_types.h>

using namespace std;

namespace shm {

// Note:  The const qualifier works with this pointer type as follows:
//
//  T*              ==  relative_ptr<T>        (pointer to mutable T)
//  const T*        ==  relative_ptr<const T>  (pointer to immutable T)
//  T * const       ==  const relative_ptr<T>  (immutable pointer to mutable T)
//  const T * const ==  const relative_ptr<const T>


// By virtue of the fact that this template is partially specialized for 'const T' below,
// this particular template only applies to non-const T.
template <typename T>
class relative_ptr {

public:
	// These are needed for iterator_traits (see <iterator>)
    typedef random_access_iterator_tag iterator_category;
    typedef T                          value_type;
    typedef ptrdiff_t                  difference_type;
    typedef relative_ptr<T>              pointer;
    typedef T&                         reference;

	// As you look at the stuff below, remember that 'const' methods mean that
	// the method is valid when the pointer is immutable, and it has nothing to
	// do with whether the type T is const.

	// explicit conversion to T*
	T* get() const {
		if ( _diff == 1 )
			return NULL;
		else
			return reinterpret_cast<T*>( const_cast<char*>(reinterpret_cast<const char*>(this)) + _diff );
	}

	// explicit set from T*
	void set( T* arg ) {
		if (arg == NULL)
			_diff = 1;
		else
			_diff = reinterpret_cast<char*>(const_cast<T *>(arg)) - reinterpret_cast<char*>(this);
	}

	// Default Constructor (Convert from T*)
	relative_ptr( T * arg = NULL ) {
		set( arg );
	}

	// Copy constructors
	relative_ptr( const relative_ptr& arg ) {
		set( arg.get() );
	}

	// Convert from T2* if T2 is in the same class hierarchy as T
	template <typename T2>
	relative_ptr( T2 *arg )
		{ set( static_cast<T*>(arg) ); }

	// Conversion from another relative_ptr if T2 is in the same class hierarchy as T.
	template <typename T2>
	relative_ptr( const relative_ptr<T2>& arg ) {
		set( static_cast<T*>(arg.get()) );
	}

	// Destructor
	~relative_ptr() { }
	
	// Assignment operators
	relative_ptr<T>& operator=(T* arg) {
		set( arg );
		return *this;
	}

	relative_ptr<T>& operator=( const relative_ptr<T>& arg ) {
		set( arg.get() );
		return *this;
	}

	// Implicit conversion to T*
	operator T*() const {
		return this->get();
	}
	
	// Operator*, returns T&
	T& operator*() const {
		return *get();
	}

	// Operator->, returns T*
	T* operator->() const {
		return get();
	}

	// Operator[], returns a T& to the item at that loc.
	T& operator[](int index) const {
		return get()[index];
	}

	// ! operator (for if (!ptr)...)
	bool operator!() const {
		return _diff == 1;
	}

	// Equality comparisons
	inline friend bool operator==(const relative_ptr<T>& lhs, const T* rhs) {
		return lhs.get() == rhs;
	}
	
	inline friend bool operator==(const T* lhs, const relative_ptr<T>& rhs) {
		return lhs == rhs.get();
	}
	
	template <class T2>
	inline friend bool operator==(const relative_ptr<T>& lhs, const T2* rhs) {
		return lhs.get() == static_cast<const T*>(rhs);
	}

	template <class T2>
	inline friend bool operator==(const T2* lhs, const relative_ptr<T>& rhs) {
		return static_cast<const T*>(lhs) == rhs.get();
	}
	
	// ambiguity buster
	template <class T2>
	bool operator==(const relative_ptr<T2>& rhs) const {
		return this->get() == static_cast<const T*>(rhs.get());
	}

	
	// Inequality comparisons
	inline friend bool operator!=(const relative_ptr<T>& lhs, const T* rhs) {
		return lhs.get() != rhs;
	}
	
	inline friend bool operator!=(const T* lhs, const relative_ptr<T>& rhs) {
		return lhs != rhs.get();
	}

	template <class T2>
	inline friend bool operator!=(const relative_ptr<T>& lhs, const T2* rhs) {
		return lhs.get() != static_cast<const T*>(rhs);
	}

	template <class T2>
	inline friend bool operator!=(const T2* lhs, const relative_ptr<T>& rhs) {
		return static_cast<const T*>(lhs) != rhs.get();
	}
	
	// ambiguity buster
	template <class T2>
	bool operator!=(const relative_ptr<T2>& rhs) const {
		return this->get() != static_cast<const T*>(rhs.get());
	}


private:
	ptrdiff_t _diff;

}; // class relative_ptr



// And now the partial specialization for const T
template <typename T>
class relative_ptr<const T> {

public:
	// These are needed for iterator_traits (see <iterator>)
    typedef random_access_iterator_tag iterator_category;
    typedef const T                    value_type;
    typedef ptrdiff_t                  difference_type;
    typedef relative_ptr<const T>        pointer;
    typedef const T&                   reference;

	// explicit conversion to T*
	const T* get() const {
		if (_diff == 1)
			return NULL;
		else
			return reinterpret_cast<const T*>( reinterpret_cast<const char*>(this) + _diff );
	}

	// explicit set from T*
	void set( const T* arg ) {
		if (arg == NULL)
			_diff = 1;
		else
			_diff = reinterpret_cast<char*>(const_cast<T *>(arg)) - reinterpret_cast<char*>(this);
	}

	// Default Constructor (Convert from const T*)
	relative_ptr( const T* arg = NULL ) {
		set( arg );
	}

	// Copy constructors
	relative_ptr( const relative_ptr& arg ) {
		set( arg.get() );
	}

	// Conversion constructor from relative_ptr<T> (pointer to non-const T)
	relative_ptr(const relative_ptr<T>& arg ) {
		set( arg.get() );
	}

	// Convert from T2* if T2 is in the same class hierarchy as T
	template <typename T2>
	relative_ptr( const T2 *arg )
		{ set( static_cast<const T*>(arg) ); }

	// Conversion from another relative_ptr if T2 is in the same class hierarchy as T.
// This had to be commented out to avoid ambiguities.
//	template <typename T2>
//	relative_ptr( const relative_ptr<T2>& arg ) {
//		set( static_cast<T*>(arg.get()) );
//	}

	// Conversion from another relative_ptr if T2 is in the same class hierarchy as T.
	template <typename T2>
	relative_ptr( const relative_ptr<const T2>& arg ) {
		set( static_cast<const T*>(arg.get()) );
	}

	// Destructor
	~relative_ptr() { }

	// Assignment operators
	relative_ptr<const T>& operator=(const T* arg ) {
		set( arg );
		return *this;
	}
	
	relative_ptr<const T>& operator=(const relative_ptr<const T>& arg ) {
		set( arg.get() );
		return *this;
	}

	relative_ptr<const T>& operator=(const relative_ptr<T>& arg ) {
		set( arg.get() );
		return *this;
	}

	// Implicit conversion to T*
	operator const T*() const {
		return this->get();
	}

	// Operator*, returns T&
	const T& operator*() const {
		return *get();
	}

	// Operator->, returns T*
	const T* operator->() const {
		return get();
	}

	// Operator[], returns a T& to the item at that loc.
	const T& operator[](int index) const {
		return get()[index];
	}

	// ! operator (for if (!ptr)...)
	bool operator!() const {
		return _diff == 1;
	}

	// Equality comparisons
	inline friend bool operator==(const relative_ptr& lhs, const T* rhs) {
		return lhs.get() == rhs;
	}

	inline friend bool operator==(const T* lhs, const relative_ptr& rhs) {
		return lhs == rhs.get();
	}

	template <class T2>
	inline friend bool operator==(const relative_ptr& lhs, const T2* rhs) {
		return lhs.get() == static_cast<const T*>(rhs);
	}

	template <class T2>
	inline friend bool operator==(const T2* lhs, const relative_ptr& rhs) {
		return static_cast<const T*>(lhs) == rhs.get();
	}

	// ambiguity buster
	template <class T2>
	bool operator==(const relative_ptr<T2>& rhs) const {
		return this->get() == static_cast<const T*>(rhs.get());
	}

	// Inequality comparisons
	inline friend bool operator!=(const relative_ptr& lhs, const T* rhs) {
		return lhs.get() != rhs;
	}
	
	inline friend bool operator!=(const T* lhs, const relative_ptr& rhs) {
		return lhs != rhs.get();
	}

	template <class T2>
	inline friend bool operator!=(const relative_ptr& lhs, const T2* rhs) {
		return lhs.get() != static_cast<const T*>(rhs);
	}

	template <class T2>
	inline friend bool operator!=(const T2* lhs, const relative_ptr& rhs) {
		return static_cast<const T*>(lhs) != rhs.get();
	}
	
	// ambiguity buster
	template <class T2>
	bool operator!=(const relative_ptr<T2>& rhs) const {
		return this->get() != static_cast<const T*>(rhs.get());
	}

private:
	ptrdiff_t _diff;

}; // class relative_ptr



/**
 * unfortunately, we do need a specialization of relative_ptr for cases where the
 * pointed to type is void (i.e. relative_ptr<void> is semantically the same as a void*)
 */
template <>
class relative_ptr<void> {

	// cheating...
	typedef void T;

public:
	// These are needed for iterator_traits (see <iterator>)
    typedef random_access_iterator_tag iterator_category;
    typedef void                       value_type;
    typedef ptrdiff_t                  difference_type;
    typedef relative_ptr<void>           pointer;

	// explicit conversion to T*
	T* get() const {
		if ( _diff == 1 )
			return NULL;
		else
			return reinterpret_cast<T*>( const_cast<char*>(reinterpret_cast<const char*>(this)) + _diff );
	}

	// explicit set from T*
	void set( const T* arg ) {
		if (arg == NULL)
			_diff = 1;
		else
			_diff = reinterpret_cast<char*>(const_cast<T *>(arg)) - reinterpret_cast<char*>(this);
	}

	// Conversion Constructors
	relative_ptr( const T* arg = NULL ) {
		set( arg );
	}

	// Any pointer type can be converted into a void*
	template <typename T2>
	relative_ptr( const T2 *arg ) 
		{ set( static_cast<const T*>(arg) ); }

	// Copy constructors
	relative_ptr( const relative_ptr<void>& arg ) {
		set( arg.get() );
	}
	
	template <typename T2>
	relative_ptr( const relative_ptr<T2>& arg ) {
		set( static_cast<const T*>(arg.get()) ); 
	}

	// Destructor
	~relative_ptr() { }

	// Assignment operators
	template <typename T2>
	relative_ptr<T>& operator=(const T2* arg ) {
		set( static_cast<const T*>(arg) );
		return *this;
	}

	template <typename T2>
	relative_ptr<T>& operator=(const relative_ptr<T2>& arg ) {
		set( static_cast<const T*>(arg.addr()) );
		return *this;
	}

	// Implicit conversion to T*
	operator T*() {
		return this->get();
	}

	/*
	// Operator*, returns T&
	T& operator*() {
		return *get();
	}

	const T& operator*() const {
		return *get();
	}

	// Operator->, returns T*
	T* operator->() {
		return get();
	}

	const T* operator->() const {
		return get();
	}

	// Operator[], returns a T& to the item at that loc.
	T& operator[](int index) {
		return get()[index];
	}

	const T& operator[](int index) const {
		return get()[index];
	}
	*/
	
	// ! operator (for if (!ptr)...)
	bool operator!() const {
		return _diff == 1;
	}

	// Equality comparisons
	inline friend bool operator==(const relative_ptr& lhs, const T* rhs) {
		return lhs.get() == rhs;
	}
	
	inline friend bool operator==(const T* lhs, const relative_ptr& rhs) {
		return lhs == rhs.get();
	}
	
	template <class T2>
	inline friend bool operator==(const relative_ptr& lhs, const T2* rhs) {
		return lhs.get() == static_cast<const T*>(rhs);
	}

	template <class T2>
	inline friend bool operator==(const T2* lhs, const relative_ptr& rhs) {
		return static_cast<const T*>(lhs) == rhs.get();
	}
	
	// ambiguity buster
	template <class T2>
	bool operator==(const relative_ptr<T2>& rhs) const {
		return this->get() == static_cast<const T*>(rhs.get());
	}

	// Inequality comparisons
	inline friend bool operator!=(const relative_ptr& lhs, const T* rhs) {
		return lhs.get() != rhs;
	}
	
	inline friend bool operator!=(const T* lhs, const relative_ptr& rhs) {
		return lhs != rhs.get();
	}

	template <class T2>
	inline friend bool operator!=(const relative_ptr& lhs, const T2* rhs) {
		return lhs.get() != static_cast<const T*>(rhs);
	}

	template <class T2>
	inline friend bool operator!=(const T2* lhs, const relative_ptr& rhs) {
		return static_cast<const T*>(lhs) != rhs.get();
	}
	
	// ambiguity buster
	template <class T2>
	bool operator!=(const relative_ptr<T2>& rhs) const {
		return this->get() != static_cast<T*>(rhs.get());
	}

private:
	ptrdiff_t _diff;

}; // class relative_ptr


// And now the partial specialization for const T
template <>
class relative_ptr<const void> {

	// cheating
	typedef void T;

public:
	// These are needed for iterator_traits (see <iterator>)
    typedef random_access_iterator_tag iterator_category;
    typedef const void                 value_type;
    typedef ptrdiff_t                  difference_type;
    typedef relative_ptr<const void>     pointer;

	// explicit conversion to T*
	const T* get() const {
		if (_diff == 1)
			return NULL;
		else
			return reinterpret_cast<const T*>( reinterpret_cast<const char*>(this) + _diff );
	}

	// explicit set from T*
	void set( const T* arg ) {
		if (arg == NULL)
			_diff = 1;
		else
			_diff = reinterpret_cast<char*>(const_cast<T *>(arg)) - reinterpret_cast<char*>(this);
	}

	// Conversion Constructors
	relative_ptr( const T* arg = NULL ) {
		set( arg );
	}

	// Constructor from non-const (commented out because it was ambiguous when combined with others)
	//relative_ptr( T* arg ) {
	//	set( arg );
	//}

	//template <typename T2>
	//relative_ptr( const T2 *arg ) 
	//	{ set( static_cast<const T*>(arg) ); }

	// Copy constructors
	relative_ptr( const relative_ptr<const T>& arg ) {
		set( arg.get() );
	}

	relative_ptr(const relative_ptr<T>& arg ) {
		set( arg.get() );
	}

	// ambiguity buster  Well, almost.  Caused other ambiguities.
	//template <typename T2>
	//relative_ptr( const relative_ptr<T2>& arg ) {
	//	set( static_cast<T*>(arg.get()) );
	//}

	template <typename T2>
	relative_ptr( const relative_ptr<const T2>& arg ) {
		set( static_cast<const T*>(arg.get()) ); 
	}


	// Destructor
	~relative_ptr() { }

	// Assignment operators
	relative_ptr<const T>& operator=(const T* arg ) {
		set( arg );
		return *this;
	}
	
	relative_ptr<const T>& operator=(const relative_ptr<const T>& arg ) {
		set( arg.get() );
		return *this;
	}

	relative_ptr<const T>& operator=(const relative_ptr<T>& arg ) {
		set( arg.get() );
		return *this;
	}

	//template <typename T2>
	//relative_ptr<T>& operator=(const T2* arg ) {
	//	set( static_cast<const T*>(arg) );
	//	return *this;
	//}

	template <typename T2>
	relative_ptr<T>& operator=(const relative_ptr<T2>& arg ) {
		set( static_cast<const T*>(arg.addr()) );
		return *this;
	}

	// Implicit conversion to T*
	operator const T*() const {
		return this->get();
	}

	/*
	// Operator*, returns T&
	const T& operator*() const {
		return *get();
	}

	// Operator->, returns T*
	const T* operator->() const {
		return get();
	}

	// Operator[], returns a T& to the item at that loc.
	const T& operator[](int index) const {
		return get()[index];
	}
	*/
	
	// ! operator (for if (!ptr)...)
	bool operator!() const {
		return _diff == 1;
	}

	// Equality comparisons
	inline friend bool operator==(const relative_ptr& lhs, const T* rhs) {
		return lhs.get() == rhs;
	}

	inline friend bool operator==(const T* lhs, const relative_ptr& rhs) {
		return lhs == rhs.get();
	}

	template <class T2>
	inline friend bool operator==(const relative_ptr& lhs, const T2* rhs) {
		return lhs.get() == static_cast<const T*>(rhs);
	}

	template <class T2>
	inline friend bool operator==(const T2* lhs, const relative_ptr& rhs) {
		return static_cast<const T*>(lhs) == rhs.get();
	}

	// ambiguity buster
	template <class T2>
	bool operator==(const relative_ptr<T2>& rhs) const {
		return this->get() == static_cast<const T*>(rhs.get());
	}

	// Inequality comparisons
	inline friend bool operator!=(const relative_ptr& lhs, const T* rhs) {
		return lhs.get() != rhs;
	}
	
	inline friend bool operator!=(const T* lhs, const relative_ptr& rhs) {
		return lhs != rhs.get();
	}

	template <class T2>
	inline friend bool operator!=(const relative_ptr& lhs, const T2* rhs) {
		return lhs.get() != static_cast<const T*>(rhs);
	}

	template <class T2>
	inline friend bool operator!=(const T2* lhs, const relative_ptr& rhs) {
		return static_cast<const T*>(lhs) != rhs.get();
	}
	
	// ambiguity buster
	template <class T2>
	bool operator!=(const relative_ptr<T2>& rhs) const {
		return this->get() != static_cast<const T*>(rhs.get());
	}

private:
	ptrdiff_t _diff;

}; // class relative_ptr


} // namespace shm


#endif /*OFFSET_PTR_*/
