/**
 * Reference-counted smart pointers
 *
 * @author      Bryan Atsatt, Laura Werner, Glenn Marcy
 *
 * @package Utilities
 *
 * @copyright
 *      IBM Open Class Library
 *      (C) Copyright International Business Machines Corporation 1997, 1997
 *      Licensed Material - Program-Property of IBM - All Rights Reserved.
 *
 * Revision:   87   1.12.1.4   source/core/utils/icntptr.hpp, utilities, ioc.v400, 980918   
 */
#ifndef _ICNTPTR_
#define _ICNTPTR_

#include <iprimtyp.hpp>
#include <imrefcnt.hpp>

#if __IBMCPP__ >= 400
#pragma namemangling(compat)
#endif

class IDataStream;
class IVoidMasterPointer;

#pragma pack(push,4)
#pragma enum(4)

/** ------------------------------------------------------------------------
 * Templatized smart pointer class with automatic reference counting.
 *
 * This class mimics a C++ pointer, but it automatically calls addRef
 * and removeRef on the object to which it points.  When you create a new
 * ICountedPointerTo, it calls IMRefCounted::addRef on the object to which
 * it points.  When the ICountedPointerTo is destroyed, it calls
 * IMRefCounted::removeRef.  When the object's reference count reaches zero,
 * it will be destroyed.
 * <p>
 * ICountedPointerTo also allows you to perform reference counting on
 * objects that do <em>not</em> descend from IMRefCounted.  In this case,
 * it "wraps" the object in a reference-counted wrapper.
 *
 * @see IMRefCounted
 */
template<class AType> class ICountedPointerTo {
  public:
/** @group Constructors and destructor */

    /**
     * Constructs an object which points to nothing.
     *
     * This is slightly more efficient than calling ICountedPointerTo(0).
     */
                                        ICountedPointerTo       ();     // More efficient than ICountedPointerTo(0)

    /**
     * Constructs an ICountedPointerTo that points to the given object.
     *
     * @param adopt The object to be pointed to. This constructor will
     *              "adopt" the object passed in and will increment its
     *              reference count. All further references to the object
     *              should be made through the ICountedPointerTo object;
     *              the raw pointer that was passed in to this constructor
     *              should be discarded.
     */
                                        ICountedPointerTo       (AType* adopt);

    /**
     * Copies a counted pointer
     *
     * The reference count of the object to which it points
     * will be incremented.
     */
                                        ICountedPointerTo       (const ICountedPointerTo<AType>& share);

    /**
     * Destroys a counted pointer.
     *
     * The reference count of the object to which it points will be
     * decremented.  If this causes the reference count to reach zero, the
     * object will be deleted.
     */
                                        ~ICountedPointerTo      ();

/** @group Assignment */
    /**
     * Causes this counted pointer to point to a new object.
     *
     * If this pointer already refers to a valid object, that object's
     * reference count will be decremented.  If this causes the reference
     * count to reach zero, the object will be deleted.
     *
     * @param adopt The object to be pointed to. This operator will
     *              "adopt" the object passed in and will increment its
     *              reference count. All further references to the object
     *              should be made through the ICountedPointerTo object;
     *              the raw pointer that was passed in should be discarded.
     */
    ICountedPointerTo<AType>& operator = (AType* adopt);

    /**
     * Causes this counted pointer to point to the same object as another
     * counted pointer.
     *
     * If this pointer already refers to a valid object, that object's
     * reference count will be decremented.  If this causes the reference
     * count to reach zero, the object will be deleted.
     *
     * @param share A counted pointer to the new object to which this pointer
     *              will point.
     */
    ICountedPointerTo<AType>& operator = (const ICountedPointerTo<AType>& share);

/** @group Pointer Operators */
    /**
     * Returns the object to which this points.
     *
     * This operator is called when you use a counted pointer with the C++
     * class member access operator "->".
     *
     * @exception IInvalidRequest
     *              Attempted to dereference a null pointer.
     */
    AType*                      operator ->             ()      const;

    /**
     * Returns a reference to the object to which this points.
     *
     * @exception IInvalidRequest
     *              Attempted to dereference a null pointer.
     */
    AType&                      operator *              ()      const;

/** @group Access */

    /**
     * Returns a raw C++ pointer to the object to which this points.
     *
     * If this pointer does not refer to an object, this method
     * will return zero.
     * <p>
     * This method is intended for situations where you need to pass a
     * raw C++ pointer to an existing function that is expecting one.
     * You should not continue to use the pointer after this ICountedPointerTo
     * object has been destroyed.
     */
    AType*                      getAlias                ()      const;

    /**
     * Queries whether this pointer refers to a valid object
     *
     * Returns true if this refers to a valid, non-null object,
     * and false otherwise
     */
    bool                        valid                   ()      const;

    /**
     * Asserts that this pointer refers to a valid object and throws
     * an exception if it does not.
     *
     * @exception IInvalidRequest
     *              This pointer does not refer to a valid object.
     */
    void                        validate                ()      const;

    /**
     * Returns the current reference count.
     *
     * This method returns the reference count of the object to which
     * this pointer refers.  If this pointer does not refer to a valid object,
     * zero will be returned.
     * <p>
     * Note that when pointing to an object that does not inherit from
     * IMRefCounted, this method will return the reference count of the
     * internal wrapper around that object
     */
        unsigned long   count () const;

/** @group Comparison */

    /** Determines whether this pointer refers to the given object. */
    bool                        operator ==             (const AType *r) const;

    /** Determines whether this pointer refers to the same object as
     *  another counted pointer.
     */
    bool                        operator ==             (const ICountedPointerTo<AType>& r) const;

    /** Determines whether this pointer refers to the given object. */
    bool                        operator !=             (const AType *r) const;

    /** Determines whether this pointer refers to the same object as
     *  another counted pointer.
     */
    bool                        operator !=             (const ICountedPointerTo<AType>& r) const;

/** @group Internal Methods
 * These methods are NOT intended for use by clients.
 * They should only be called by the global streaming operator
 * template functions defined below.
 */
        void                                    in(AType* r, IVoidMasterPointer *indirect, IMRefCounted *);
        void                                    in(AType* r, IVoidMasterPointer *indirect, void *);
        IMRefCounted*                   getCounted() const;
        static bool                             isWrapped ();


private:
// Internal utility functions....
        void                                    addRef();
        void                                    removeRef();

        void                                    wrapIt (IMRefCounted* it);
        void                                    wrapIt (void* it);
        static bool                             isWrapped (IMRefCounted*);
        static bool                             isWrapped (void*);
        static void                     doDelete(void* it);

// Private data
        union {
                AType *                         fDirect;
                IVoidMasterPointer*     fIndirect;
        };
};

#pragma enum(pop)
#pragma pack(pop)

template <class AType> AType*   copyPointer(const ICountedPointerTo<AType>&);

template <class AType> void             operator>>=(const ICountedPointerTo<AType>&,
                                                                                        IDataStream& toStream);
template <class AType> void             operator<<=(ICountedPointerTo<AType>&,
                                                                                        IDataStream& fromStream);

#if __IBMCPP__ >= 400
#pragma namemangling()
#endif

#include <icntptr.inl>

#endif // _ICNTPTR_
