//************************************************************************************** // Filename: AMacPtr.h // Part of Contextual Menu Workshop by Abracode Inc. // http://free.abracode.com/cmworkshop/ // Copyright © 2003 Abracode, Inc. All rights reserved. // // Description: Extension to David Catmull's ACCELA Mac toolbox C++ wrapper library //************************************************************************************** #pragma once #include "AMemoryCommon.h" #include "CThrownResult.h" template class AMacPtr { public: AMacPtr() : mObject(NULL), mIsOwner(kMemObj_NotOwned) {} //memory allocation constructor //CAUTION: the size is interpreted as a count of T objects AMacPtr(SInt32 inSize, EMemObjClearOption inClearOption = kMemObj_DontClearMemory) : mObject(NULL), mIsOwner(kMemObj_NotOwned) { AllocateAndCopy(NULL, inSize, inClearOption); } //plain assignment with optional ownership taking, no copy. //inMacPtr must be allocated with NewPtr or NewPtrClear AMacPtr( Ptr inMacPtr, EMemObjOwnershipType inIsOwner = kMemObj_Owned) : mObject(reinterpret_cast(inMacPtr)), mIsOwner(inIsOwner) {} //pointer and size constructor //the input pointer may not be allocated by NewPtr, so we allocate private copy //CAUTION: the size is interpreted as a count of T objects AMacPtr( const T *inPtr, SInt32 inSize) : mObject(NULL), mIsOwner(kMemObj_NotOwned) { AllocateAndCopy(inPtr,inSize); } //copy constructor - deep or shallow - with shallow copy as default //the object is detached from the original AMacPtr(const AMacPtr& inOrig, EMemObjCopyType inCopyParam = kMemObj_ShallowCopy) : mObject(NULL), mIsOwner(kMemObj_NotOwned) { if(inCopyParam == kMemObj_DeepCopy) { AllocateAndCopy(inOrig.Get(),inOrig.GetSize()); } else if(inCopyParam == kMemObj_ShallowCopy) { EMemObjOwnershipType isOwner = inOrig.mIsOwner; Reset(inOrig.Detach(), isOwner ); } } virtual ~AMacPtr() { Dispose(); } //object assignment as a shallow copy with ownership change AMacPtr& operator=( const AMacPtr& inMacPtr) { EMemObjOwnershipType isOwner = inMacPtr.mIsOwner; Reset(inMacPtr.Detach(), isOwner ); return *this; } //plain pointer assignment with ownership taking, no copy //inMacPtr must be allocated with NewPtr or NewPtrClear AMacPtr& operator=( const Ptr inMacPtr) { Reset(reinterpret_cast(const_cast(inMacPtr)), kMemObj_Owned); return *this; } operator T*() const { return mObject; } T& operator * () const { return *mObject; } T* operator -> () const { return mObject; } T& operator [] (UInt32 index) const { return mObject[index]; } SInt32 GetSize() const { if(mObject != NULL) return ::GetPtrSize(reinterpret_cast(mObject))/sizeof(T); return 0; } //CAUTION: potentially costly //CAUTION: you cannot reallocate not owned pointer // so resize may fail if reallocation is required //CAUTION: the size is interpreted as a count of T objects void Resize(SInt32 inNewSize) { if(mObject != NULL) { ::SetPtrSize(reinterpret_cast(mObject), inNewSize*sizeof(T)); OSErr err = ::MemError(); if(err != noErr) {//could not resize easily, fall back to reallocation if(mIsOwner == kMemObj_Owned) {//reallocate ONLY if we own the pointer T* newPtr = reinterpret_cast(::NewPtr(inNewSize*sizeof(T))); CThrownOSErr throwErr = ::MemError(); CopyData(mObject, newPtr, inNewSize); Reset(newPtr, kMemObj_Owned); } else CThrownOSErr throwErr = err; } } else AllocateAndCopy(NULL, inNewSize); } static void CopyData(const T *inSource, T *inDest, SInt32 inSize) { ::BlockMoveData(inSource, inDest, inSize *sizeof(T)); } void ClearData() { if(mObject != NULL) ::BlockZero(mObject, GetSize() *sizeof(T)); } void Append(const T *inPtr, SInt32 inSize) { if((inPtr != NULL) && (inSize != 0)) { SInt32 oldSize = GetSize(); Resize(oldSize + inSize); if(mObject != NULL) CopyData(inPtr, mObject + oldSize, inSize); } } T * Get() const { return mObject; } T * Detach() const { mIsOwner = kMemObj_NotOwned; return mObject; } void Reset( T *inObject, EMemObjOwnershipType inIsOwner = kMemObj_Owned) { if ((mIsOwner == kMemObj_Owned) && (mObject != NULL) && (inObject != mObject)) DisposeSelf(); mObject = inObject; mIsOwner = inIsOwner; } void Dispose() { if (mObject != NULL) { if(mIsOwner == kMemObj_Owned) DisposeSelf(); mObject = NULL; } mIsOwner = kMemObj_NotOwned; } //DisposeProc receives a pointer to stored object, not the actual object //DisposeProc is responsible for checking if the object stored is valid static void DisposeProc(void *inObj) { if(inObj != NULL) { Ptr *objPtr = (reinterpret_cast(inObj)); if(*objPtr != NULL) ::DisposePtr(*objPtr); *objPtr = NULL; } } protected: void AllocateAndCopy( const T *inSrcPtr, SInt32 inSize, EMemObjClearOption inClearOption = kMemObj_DontClearMemory) { if(inSize != 0) { if( (inClearOption == kMemObj_ClearMemory) && (inSrcPtr == NULL) ) mObject = reinterpret_cast(::NewPtrClear(inSize*sizeof(T))); else mObject = reinterpret_cast(::NewPtr(inSize*sizeof(T))); CThrownOSErr err = ::MemError(); mIsOwner = kMemObj_Owned; if( (inSrcPtr != NULL) && (mObject != NULL) ) CopyData(inSrcPtr, mObject, inSize); } } void DisposeSelf() { ::DisposePtr(reinterpret_cast(mObject)); } protected: T *mObject; mutable EMemObjOwnershipType mIsOwner; }; typedef AMacPtr APtr;