// ------------------------------------------------------------------------
/*
	author: Jaap Suter

	Copyright (C) Electronic Arts Canada Inc. 2002.  All rights reserved.	
*/
// ------------------------------------------------------------------------

/*! \file */

#ifndef REVEAL_SCOPED_PTR_H
#define REVEAL_SCOPED_PTR_H

#include <assert.h>

namespace Reveal {
    namespace SmartPtr {

// ------------------------------------------------------------------------
/*!
    \brief  Single-ownership, non-copyable, non-transferable smart pointer.

    \param T    Type of the object pointed to

    Holds a pointer to a dynamic resource (allocated with operator new), and
    garantuees destruction of the resource either upon destruction of the ScopedPtr
    itself, or through an explicit reset.

    It is one of the simplest smart pointer one can write. It is very
    limited, and hence very safe. Performane-wise it acts as a built-in pointer.

    \warning    Do NOT use this ScopedPtr for arrays, as this will result in
                undefined behaviour. This is because the destructor uses
                operator delete and not operator delete[]. Use the seperate
				ScopedArray class for that.

    \warning    Also, make sure that no other smart pointer is holding a pointer to
                this resource. Consider the following:
                \code
                    int *i = new int( 0 );
                    ScopedPtr< int > a( i );
                    Scopedptr< int > b( i );
                \endcode
                Here the scope is left, and both a and b will be
                destructed, and hence i will be deleted twice resulting
                in undefined behaviour (most probably a crash, which is ofcourse
                still better than the memory leaks occuring from not using ScopedPtr's).
                As a guideline, try to use direct initialization like this:
                \code
                   ScopedPtr< int > a( new int( 0 ) );
                \endcode

    \remark     This smart pointer is modeled after boost::scoped_array. See
                http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for more information, a
                rationale, and more discussions.
*/
// ------------------------------------------------------------------------
template < class T >
class ScopedPtr
{
public:

    /*!
        \param  ptr Pointer to an object instantiated with operator new.
        \post   a\ mPtr = \a ptr and \a this owns \a mPtr

        This constructor acts as default constructor too because the
        parameter has a default 0 value;
    */
    ScopedPtr( T* ptr = 0 ) : mPtr( ptr ) {}

    /*!
        \post  \a mPtr is destructed en deleted
    */
    ~ScopedPtr()
    {
        // Compile-time check to make sure we're deleting a complete complete type;
        // Will fail if the type is incomplete because zero-sized arrays are not allowed;
        typedef char typeMustBeComplete[ sizeof( T ) ];

        delete mPtr;
    }

    /*!
        \brief  Dereference operator.
        \return \a mPtr
        \pre    \a mPtr != 0 (asserted)

        \remark Some people use operator -> () to get the actual pointer, for example to
                check if it is 0, as follows:
                \code
                    ScopedPtr< int > i( new int( 0 ) );
                    if ( i->() ) { ... }
                \endcode
                Which is valid C++ even if \a mPtr is 0, because no dereferencing occurs. However,
                since 99% of the time people use operator -> () as a dereferencing mechanism, the
                pre-condition that \a mPtr != 0 provides a lot of benefits. See the \a Get() method
                for a way to get the raw pointer.
    */
    T* operator -> () const { assert( mPtr ); return  mPtr; }

    /*!
        \brief  Dereference operator.
        \return \a *mPtr
        \pre    \a mPtr != 0 (asserted)
    */
    T& operator *  () const { assert( mPtr ); return *mPtr; }


    /*!
        \brief Swaps two pointers;
        \pre   this points to A and scopedPtr points to B
        \post  this points to B and scopedPtr points to A
    */
    void Swap( ScopedPtr& scopedPtr )
    {
        T* tmp = scopedPtr.mPtr;
        scopedPtr.mPtr = mPtr;
        mPtr = tmp;
    }

    /*!
        \brief Gives the scoped pointer a new value, deleting the old one.
        \param ptr new value for the poiner
        \post  What \a mPtr used to point to is deleted and \a mPtr == \a ptr
    */
    void Reset( T* ptr = 0 )
    {
        delete mPtr;
        mPtr = ptr;
    }

    /*!
        \brief Gets the actual raw pointer;
        \return \a mPtr

        This is usefull for interfacing with code that expects raw ptrs (without ownership), for
        example for weak/observe purposes.

        \warning Don't delete the pointer that is returned, because this ScopedPtr is still
                 the owner of the resource. Thus, the results of the following code are
                 undefined:
                 \code
                    ScopedPtr< int > i( new int( 0 ) );
                    int* p = i;
                    delete p;
                 \endcode
    */
	T* Get() const { return mPtr; }

private:

    //! Copy ctor disabled, not implemented;
    ScopedPtr( const ScopedPtr& );

    //! Assigment operator disabled, not implemented;
    ScopedPtr& operator = ( const ScopedPtr& );

    //! Actual raw pointer;
    T* mPtr;
};

    } // Namespace SmartPtr
} // Namespace Reveal

#endif
