// Revision: 88 1.9.2.2 source/core/utils/icntptr.inl, utilities, ioc.v400, 001006 
// icntptr.inl
//
// Contains:
//      Inline methods for ICountedPointerTo
//
// Author:
//      Laura Werner
//
// COPYRIGHT:
//      IBM Open Class Library
//      (C) Copyright International Business Machines Corporation 1992, 1997
//      Licensed Material - Program-Property of IBM - All Rights Reserved.
//
#ifndef _ICNTPTR_INL_
#define _ICNTPTR_INL_

#include <imstrmbl.hpp>
#include <idatstrm.hpp>
#include <iexcept.hpp>

#ifndef IC_BUILD
#define __IOC_INLINE inline
#else
#define __IOC_INLINE
#endif

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

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

//-----------------------------------------------------------------------------
// IVoidMasterPointer
//      This is an internal utility class used by ICountedPointerTo.
//      It should NOT be used directly by clients.  It is declared here in
//      a header file only because the ICountedPointerTo inlines depend on it.
//
class IVoidMasterPointer : public IMRefCounted, public IMSTREAMABLE {
        StreamableDeclarationsMacro(IVoidMasterPointer);
public:
        typedef void (*Deleter) (void* theObject);

                                IVoidMasterPointer(void* adoptObject, Deleter function);
        virtual         ~IVoidMasterPointer     ();

        void*           getObject () const;
        void            adoptObject(void *obj, Deleter function);

        static void throwInvalid();

        // For IMStreamable only...
                                IVoidMasterPointer();
                                IVoidMasterPointer(const IVoidMasterPointer&);  // TODO: kill me
        void            writeToStream(IDataStream&) const;
        void            readFromStream(IDataStream&);

private:
        // Copying and assignment aren't allowed
        void            operator=(const IVoidMasterPointer&);

        void*           fObject;
        Deleter         fDeleter;
};

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

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

inline void *
IVoidMasterPointer::getObject () const
{
        return fObject;
}

inline void
IVoidMasterPointer::adoptObject (void *obj, Deleter function)
{
        fObject = obj;
        fDeleter = function;
}


//-----------------------------------------------------------------------------
// ICountedPointerTo pointer-wrapping methods
//      These must come first because many of the other inlines depend on them.
//
template <class AType> inline
void ICountedPointerTo<AType>::wrapIt(IMRefCounted*)
{
        // Since it is IMRefCounted, do nothing.
}

template <class AType> inline
void ICountedPointerTo<AType>::wrapIt(void* it)
{
        fIndirect = it ? new IVoidMasterPointer (it, &doDelete) : 0;
}

template <class AType>
__IOC_INLINE 
void ICountedPointerTo<AType>::doDelete(void* it)
{
        // This function is called (via a function pointer) by IVoidMasterPointer
        // and is only used for non-IMRefCounted ATypes...
        delete (AType*) it;
}

template <class AType> inline
bool ICountedPointerTo<AType>::isWrapped(IMRefCounted*)
{
        return false;
}

template <class AType> inline
bool ICountedPointerTo<AType>::isWrapped(void*)
{
        return true;
}

template <class AType> inline
bool ICountedPointerTo<AType>::isWrapped()
{
        return isWrapped((AType*)0);
}

template <class AType> inline
IMRefCounted*
ICountedPointerTo<AType>::getCounted() const
{
        return isWrapped() ? fIndirect : (IMRefCounted*)fDirect;
}

//-----------------------------------------------------------------------------
// ICountedPointerTo reference-counting methods
//
template <class AType> inline
void
ICountedPointerTo<AType>::addRef()
{
        if (valid())
                getCounted()->addRef();
}

template <class AType> inline
void
ICountedPointerTo<AType>::removeRef()
{
        if (valid())
                getCounted()->removeRef();
        fDirect = 0;
}

//-----------------------------------------------------------------------------
// ICountedPointerTo constructors, destructors, etc
//
template <class AType> inline
ICountedPointerTo<AType>::ICountedPointerTo(AType* adopt)
        : fDirect(adopt)
{
        // TODO: if wrapIt throws an exception, what happens to "adopt"?
        // Will it leak?
        wrapIt(adopt);
        addRef();
}

// We could have had the above constructor take a default argument (adopt=0)
// which would remove the need for the following constructor. But this way
// we can avoid doing the valid() check inside addRef.
//
template <class AType> inline
ICountedPointerTo<AType>::ICountedPointerTo()
: fDirect(0)
{
}

template <class AType> inline
ICountedPointerTo<AType>::ICountedPointerTo(const ICountedPointerTo<AType>& share)
: fDirect(share.fDirect)
{
        addRef();
}

template <class AType> inline
ICountedPointerTo<AType>::~ICountedPointerTo()
{
        removeRef();
}

template <class AType> inline
ICountedPointerTo<AType>& ICountedPointerTo<AType>::operator=(AType* adopt)
{
    if(getAlias() != adopt) {
                removeRef();
                fDirect = adopt;
                wrapIt(adopt);
                addRef();
        }
    return *this;
}

template <class AType> inline
ICountedPointerTo<AType>& ICountedPointerTo<AType>::operator=(const ICountedPointerTo<AType>& share)
{
    if(fDirect != share.fDirect) {
                removeRef();
                fDirect = share.fDirect;
                addRef();
        }
    return *this;
}


//-----------------------------------------------------------------------------
// ICountedPointerTo miscellaney
//
template <class AType> inline
AType*  ICountedPointerTo<AType>::getAlias() const
{
        return isWrapped()      ? (fIndirect ? (AType*)fIndirect->getObject() : 0)
                                                : fDirect;
}

template <class AType> inline
bool ICountedPointerTo<AType>::valid() const
{
    return (fDirect != 0);
}

template <class AType> inline
void ICountedPointerTo<AType>::validate() const
{
    if (!valid())
                IVoidMasterPointer::throwInvalid();
}

template <class AType> inline
AType* ICountedPointerTo<AType>::operator->() const
{
    validate();
    return getAlias();
}

template <class AType> inline
AType& ICountedPointerTo<AType>::operator*() const
{
    validate();
    return *(getAlias());
}

template <class AType> inline
unsigned long ICountedPointerTo<AType>::count () const
{
        return valid() ? getCounted()->count() : 0;
}

//-----------------------------------------------------------------------------
// ICountedPointerTo comparison operators
//
template<class AType> inline
bool ICountedPointerTo<AType>::operator == (const AType *r) const
{
        return getAlias() == r;
}

template<class AType> inline
bool ICountedPointerTo<AType>::operator != (const AType *r) const
{
        return getAlias() != r;
}

template<class AType> inline
bool ICountedPointerTo<AType>::operator == (const ICountedPointerTo<AType>& r) const
{
        return getAlias() == r.getAlias();
}

template<class AType> inline
bool ICountedPointerTo<AType>::operator != (const ICountedPointerTo<AType>& r) const
{
        return getAlias() != r.getAlias();
}

template<class AType> inline
bool operator == (const AType* l, const ICountedPointerTo<AType>&r)
{
        return l == r.getAlias();
}

template<class AType> inline
bool operator != (const AType* l, const ICountedPointerTo<AType>&r)
{
        return l != r.getAlias();
}

//-----------------------------------------------------------------------------
// Streaming support functions.
//
template <class AType>
__IOC_INLINE 
void ICountedPointerTo<AType>::in(AType* raw, IVoidMasterPointer* indirect, void*)
{
        removeRef();

        // AType is not IMRefCounted.
        fIndirect = indirect;
        if (raw)
                fIndirect->adoptObject(raw, doDelete);
}

template <class AType>
__IOC_INLINE 
void ICountedPointerTo<AType>::in(AType* raw, IVoidMasterPointer*, IMRefCounted*)
{

        // AType is IMRefCounted, so there's no need for additional wrapping.
        operator=( raw );

        getCounted()->removeRef();
}

//-----------------------------------------------------------------------------
// Global functions that operate on ICountedPointerTo
// All three of these functions will only work on ATypes that inherit
// from IMStreamable.  You will get a compile error otherwise.
//
template <class AType> inline AType*
copyPointer(const ICountedPointerTo<AType>& object)
{
        return ::copy( *(object.getAlias()) ) ;
}

template <class AType> inline void
operator>>=(const ICountedPointerTo<AType>& object, IDataStream& toStream)
{
        ::writeCountedObject( object.getAlias(), object.getCounted(), object.isWrapped(), toStream );
}

template <class AType> inline void
operator<<=(ICountedPointerTo<AType>& result, IDataStream& fromStream)
{
        AType* raw;
        IVoidMasterPointer* indirect;
        ::readCountedObject( raw, indirect, result.isWrapped(), fromStream );
        result.in( raw, indirect, (AType*)0 );
}

#endif // _ICNTPTR_INL_
