/*****************************************************************************
 * $Id: gfx_ptr.hh,v 1.1 2006/08/10 03:18:58 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Template class to shield a pointer from deletion.
 *//*
 * LEGAL:	COPYRIGHT (C) JIM E. BROOKS 2006
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef GFX_PTR_HH
#define GFX_PTR_HH

namespace gfx {

////////////////////////////////////////////////////////////////////////////////
/// @brief Template class to shield a pointer from deletion,
/// and helps the object's creator to retain ownership.
/// It prevents the pitfall of passing pointers around
/// and some subroutine deletes it by mistake.
///
/// @verbatim
///
/// Remember:
/// ---------
/// - Return "const Ptr<>" instead of just "Ptr<>" (covers pitfall).
/// - Passing "const Ptr<>" is recommended.
/// - Pass Ptr<> by value (by reference is actually slower)
/// - Be careful using Ptr<> in existing code that casts pointers.
///
/// These typedefs can optimize non-debug builds.
/// "Ptrc" means a "const Ptr<>".
/// #if DEBUG
///     typedef       Ptr<Object> ObjectPtr;
///     typedef const Ptr<Object> ObjectPtrc;
/// #else
///     typedef Object* ObjectPtr;
///     typedef Object* ObjectPtrc;
/// #endif
///
/// WARNING:
/// --------
/// Ptr<> suffers from the assignment-to-temporary pitfall.
/// The cure is const: functions should return "const Ptr<>", not just "Ptr<>".
/// For example, changing mData to private and interfacing it with
/// a getter method opens the pitfall:
///     Ptr<Object> GetObject(void);
///     mObject = obj;      // old code
///     GetObject() = obj;  // new code: oops! A temporary Ptr<> object was assigned!
///
/// Design notes:
/// -------------
/// Omitted is a conversion operator from Ptr<T> to T* as that
/// would defeat the purpose by making "delete ptr" compile.
/// operator bool() is implicitly defined for actual pointers but omitted for Ptr<>,
/// so writing explicitly writing NULL is required: "if (ptr != NULL)"
/// and the requirement helps finding/eliminating NULL states.
///
/// @endverbatim
///
template<typename T>
class Ptr
{
public:
            Ptr( void ) : mObj(NULL) { } 
            Ptr( T* obj ) : mObj(obj) { }
            ~Ptr() { }  // Ptr<> doesn't own actual object

            // Copy ctors for related types.
            // Ptr<Base> = new Derived (v.v. is illegal and won't compile).
template<typename T2> Ptr( T2* obj ) : mObj(obj) { }
template<typename T2> Ptr( const Ptr<T2> ptr ) : mObj(ptr.mObj) { }

    T*      operator->( void ) const { return mObj; }
    T&      operator*( void ) const { return *mObj; }  // dereference, not multiply

// Methods for identical types:

    // Assign this Ptr with an actual pointer.
    Ptr<T>& operator=( T* obj ) { mObj = obj; return *this; }

    // Compare addresses of actual objects of same type.
    bool    operator==( const Ptr& other ) const { return mObj == other.mObj; }
    bool    operator!=( const Ptr& other ) const { return mObj != other.mObj; }

// Methods for related types (base and derived):

    // Assign Ptr<> with an actual pointer to a related type.
	// Ptr<Base> ptrBase = new Derived;  // ok
	// Ptr<Derived> ptrDerived = new Base;  // wrong (missing slice), should not compile
    template<typename T2> Ptr<T>& operator=( T2* obj )
	{
        mObj = obj;    // Base* obj = pDerived (T=Base T2=Derived)
		return *this;  // return Ptr<Base>
	}

    // Assign Ptr<Base> = Ptr<Derived> (v.v. is illegal).
	// Equivalent to: Base* pBase = pDerived;
    template<typename T2> Ptr<T>& operator=( Ptr<T2> ptr )
    {
        T* obj = ptr.mObj;  // Base* base = Ptr<Derived>.mObj (T=Base T2=Derived)
        mObj = obj;         // Base* mObj = base
        return *this;       // return Ptr<Base>
    }

#if ! GCC29
private:
#endif
    T*		mObj;

template<typename OBJ> friend OBJ* GET_PTR( const Ptr<OBJ> ptr );  // not "T"
template<typename OBJ> friend const OBJ* GET_PTRC( const Ptr<OBJ> ptr );

#if ! GCC29  // friend declaration causes ICE on gcc 2.95.3
template<typename> friend class Ptr;  // variations of Ptr<> are distinct types so friend is necessary
#endif
};

// Restricted usage.
template<typename T> T* GET_PTR( const Ptr<T> ptr ) { return ptr.mObj; }
template<typename T> const T* GET_PTRC( const Ptr<T> ptr ) { return ptr.mObj; }
// For compatibility with compiling Ptr<> or actual pointers in debug or release builds, resp.
// gcc will optimize these as efficiently as macros.
template<typename T> T* GET_PTR( T* obj ) { return obj; }
template<typename T> const T* GET_PTRC( T* obj ) { return obj; }

// Comparing addresses of actual objects.
template<typename T>              bool operator==( const Ptr<T>& ptr, const T* obj )          { return GET_PTRC(ptr) == obj; }
template<typename T>              bool operator!=( const Ptr<T>& ptr, const T* obj )          { return GET_PTRC(ptr) != obj; }
template<typename T>              bool operator==( const T* obj, const Ptr<T>& ptr )          { return GET_PTRC(ptr) == obj; }
template<typename T>              bool operator!=( const T* obj, const Ptr<T>& ptr )          { return GET_PTRC(ptr) != obj; }
template<typename T1,typename T2> bool operator==( const T1* obj, const Ptr<T2>& ptr )        { return GET_PTRC(ptr) == obj; }
template<typename T1,typename T2> bool operator!=( const T1* obj, const Ptr<T2>& ptr )        { return GET_PTRC(ptr) != obj; }
template<typename T1,typename T2> bool operator==( const Ptr<T1>& ptr1, const Ptr<T2>& ptr2 ) { return GET_PTRC(ptr1) == GET_PTRC(ptr2); }
template<typename T1,typename T2> bool operator!=( const Ptr<T1>& ptr1, const Ptr<T2>& ptr2 ) { return GET_PTRC(ptr1) != GET_PTRC(ptr2); }

} // namespace gfx

#endif // GFX_PTR_HH
