//************************************************************************************** // Filename: AMacHandle.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 AMacHandle { public: AMacHandle() : mObject(NULL), mIsOwner(kMemObj_NotOwned) {} //memory allocation constructor //CAUTION: the size is interpreted as a count of T objects AMacHandle(SInt32 inSize, EMemObjClearOption inClearOption = kMemObj_DontClearMemory) : mObject(NULL), mIsOwner(kMemObj_NotOwned) { AllocateAndCopy(NULL,inSize,inClearOption); } //plain assignment with optional ownership taking, no copy. //inMacH must be allocated with NewHandle or NewHandleClear AMacHandle( T** inMacH, EMemObjOwnershipType inIsOwner = kMemObj_Owned) : mObject(inMacH), mIsOwner(inIsOwner) {} //pointer and size constructor //CAUTION: the size is interpreted as a count of T objects AMacHandle( 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 AMacHandle(const AMacHandle& inOrig, EMemObjCopyType inCopyParam = kMemObj_ShallowCopy) : mObject(NULL), mIsOwner(kMemObj_NotOwned) { if(inCopyParam == kMemObj_DeepCopy) { Handle newH = (Handle)inOrig; if(newH != NULL) CThrownOSErr err = ::HandToHand( &newH ); Reset(reinterpret_cast(newH), kMemObj_Owned); } else if(inCopyParam == kMemObj_ShallowCopy) { EMemObjOwnershipType isOwner = inOrig.mIsOwner; Reset(inOrig.Detach(), isOwner ); } } virtual ~AMacHandle() { Dispose(); } //object assignment as a shallow copy with ownership change AMacHandle& operator=( const AMacHandle& inMacHandle) { EMemObjOwnershipType isOwner = inMacHandle.mIsOwner; Reset(inMacHandle.Detach(), isOwner ); return *this; } //plain pointer assignment with ownership taking, no copy //inMacH must be allocated with NewHandle or NewHandleClear AMacHandle& operator=( const Handle inMacH) { Reset(reinterpret_cast(const_cast(inMacH)), kMemObj_Owned); return *this; } //you cannot have both operator Handle and operator T** //pick the one you like more #if 1 operator Handle() const { return reinterpret_cast(mObject); } #else operator T**() const { return mObject; } #endif //CAUTION: dereferencing Handle, make sure you lock it first T* operator*() const { return *mObject; } SInt32 GetSize() const { if(mObject != NULL) return ::GetHandleSize(reinterpret_cast(mObject))/sizeof(T); return 0; } bool IsValid() { if(mObject == NULL) return false; return ::IsHandleValid(reinterpret_cast(mObject)); } void Lock() { if(mObject != NULL) ::HLock(reinterpret_cast(mObject)); } void Unlock() { if(mObject != NULL) ::HUnlock(reinterpret_cast(mObject)); } bool IsLocked() { return ::HGetState(reinterpret_cast(mObject)) & kHandleLockedMask; } //CAUTION: you are responsible for making sure the Handle is unlocked //CAUTION: the size is interpreted as a count of T objects void Resize(SInt32 inNewSize) { if(mObject != NULL) { ::SetHandleSize(reinterpret_cast(mObject), inNewSize*sizeof(T)); CThrownOSErr err = ::MemError(); } else { mObject = reinterpret_cast(::NewHandle(inNewSize*sizeof(T))); CThrownOSErr err = ::MemError(); mIsOwner = kMemObj_Owned; } } static void CopyData(const T *inSource, T *inDest, SInt32 inSize) { ::BlockMoveData(inSource, inDest, inSize *sizeof(T)); } //AssignData is very different from assigning a handle or pointer //our Handle takes exact size of the new data (smaller or bigger) void AssignData(const T *inSource, SInt32 inSize) { if(mObject != NULL) CThrownOSErr err = ::PtrToXHand(inSource, reinterpret_cast(mObject), inSize *sizeof(T)); else AllocateAndCopy(inSource,inSize); } //AssignData is very different from assigning a handle or pointer //our Handle takes exact size of the new data (smaller or bigger) void AssignData(const T **inSource) { if(inSource == NULL) Reset(NULL, kMemObj_NotOwned); else if(mObject != NULL) { SInt32 newSize = ::GetHandleSize(reinterpret_cast(const_cast(inSource)))/sizeof(T); Resize(newSize); CopyData(*inSource, *mObject, newSize); } else { Handle newH = reinterpret_cast(const_cast(inSource)); CThrownOSErr err = ::HandToHand( &newH ); Reset(reinterpret_cast(newH), kMemObj_Owned); } } //copies the source pointer data, resizing only when our Handle is too small void PutData(const T *inSource, SInt32 inSize) { if(inSize > GetSize()) Resize(inSize); if(inSource != NULL) CopyData(inSource, *mObject, inSize); } //copies the source handle data, resizing only when our Handle is too small void PutData(const T **inSource) { SInt32 copySize = 0; if(inSource != NULL) { copySize = ::GetHandleSize(reinterpret_cast(const_cast(inSource)))/sizeof(T); } if(copySize > GetSize()) Resize(copySize); if(inSource != NULL) CopyData(*inSource, *mObject, copySize); } void InsertData(SInt32 inOffset, const T *inSource, SInt32 inSize) { if((inSource == NULL) || (inSize == 0)) return; SInt32 oldSize = GetSize(); if( inOffset >= oldSize ) { AppendData(inSource, inSize); } else { Resize(inSize + oldSize);//make room CopyData(*mObject + inOffset, *mObject + inOffset + inSize, oldSize-inOffset);//shift old data CopyData(inSource, *mObject + inOffset, inSize); } } void ClearData() { if(mObject != NULL) ::BlockZero(static_cast(*mObject), GetSize() *sizeof(T)); } void AppendData(const T *inPtr, SInt32 inSize) { if((inPtr == NULL) || (inSize == 0)) return; if(mObject != NULL) CThrownOSErr err = ::PtrAndHand(static_cast(inPtr), reinterpret_cast(mObject), inSize *sizeof(T)); else AllocateAndCopy(inPtr,inSize); } void AppendData(const T **inH) { if(inH != NULL) return; if(mObject != NULL) { CThrownOSErr err = ::HandAndHand(reinterpret_cast(const_cast(inH)), reinterpret_cast(mObject)); } else AssignData(inH); } 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) { Handle *objPtr = reinterpret_cast(inObj); if(*objPtr != NULL) ::DisposeHandle(*objPtr); *objPtr = NULL; } } protected: void AllocateAndCopy( const T *inSrcPtr, SInt32 inSize, EMemObjClearOption inClearOption = kMemObj_DontClearMemory) { if(inSize != 0) { CThrownOSErr err; if(inSrcPtr != NULL) err = ::PtrToHand(inSrcPtr, reinterpret_cast(&mObject), inSize*sizeof(T)); else if(inClearOption == kMemObj_ClearMemory) mObject = reinterpret_cast(::NewHandleClear(inSize*sizeof(T))); else mObject = reinterpret_cast(::NewHandle(inSize*sizeof(T))); err = ::MemError(); mIsOwner = kMemObj_Owned; } } void DisposeSelf() { ::DisposeHandle(reinterpret_cast(mObject)); } private: operator T*() const;//we do not want this operator because it is confusing T& operator [] (UInt32 index) const;//neither we want this one T* operator -> () const;//or this one protected: T** mObject; mutable EMemObjOwnershipType mIsOwner; }; typedef AMacHandle AHandle; template inline bool operator==( const AMacHandle& obj1, const AMacHandle& obj2) { return (obj1.mObject == obj2.mObject); } template inline bool operator==( const AMacHandle& obj, Handle handle) { return ((Handle)obj == handle); } template inline bool operator==( Handle handle, const AMacHandle& obj) { return (handle == (Handle)obj); } template inline bool operator!=( const AMacHandle& obj1, const AMacHandle& obj2) { return (obj1.mObject != obj2.mObject); } template inline bool operator!=( const AMacHandle& obj, Handle handle) { return ((Handle)obj != handle); } template inline bool operator!=( Handle handle, const AMacHandle& obj) { return (handle != (Handle)obj); }