home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-12-27 | 6.4 KB | 201 lines | [TEXT/CWIE] |
- //
- // ObjectHandle.h
- //
- // Template Classes for creating dynamic objects inside of a Macintosh handle.
- // There are no virtual methods so that the "envelope" classes are no bigger
- // than an ordinary handle.
- //
- // The contained classes must have a default constructor.
- //
- // class ObjectHandle<Type> Holds a single object.
- // class ObjectArrayHandle<Type> Holds an array of objects.
- //
- // Note: I'm using a non-standard method of construction and destruction.
- // See "Advanced C++ Programming Styles and Idioms" by James Coplien, pg 80.
- //
- // James Jennings
- // Started October 13, 1995
- //
- // Written for SC++ v8 and CodeWarrior v7.
- // Note: The SC++ v7.0.4 compiler generates an error on:
- // ((Type*)*theObject)->~Type();
- // You need the v8.0 compiler update. (Available on AOL.)
- //
-
- #pragma once
-
- #include <new.h> // to get the overloaded version of operator new()
-
- class AbstractObjectHandle {
- // Has the methods that don't require a template.
- // Declared here to limit the method explosion that templates give
- enum { kIsLocked = 0x80 };
- protected:
- // a protected constructor keeps it an abstract class
- AbstractObjectHandle(void) : theObject(0) {}
- ~AbstractObjectHandle(void) { DisposeHandle(theObject); theObject = 0; }
- Handle theObject; // where the data is stored
- public:
- // Handle maintenence
- Boolean IsValid(void) { return theObject!=0 && *theObject!=0 ; }
- void Lock(void) { HLock(theObject); }
- void Unlock(void) { HUnlock(theObject); }
- Boolean IsLocked(void) { return (HGetState(theObject) & kIsLocked) != 0; }
- Boolean Lock(Boolean lock)
- { Boolean old = IsLocked(); lock ? Lock() : Unlock(); return old; }
- void MoveHi(void) { MoveHHi(theObject); }
- private:
- // Since nothing is virtual, we don't want people to
- // subclass this and then make a pointer to it.
- // Declaring a private operator new will stop them.
- void * operator new(size_t);
- #if _HAS_ARRAY_NEW // I'd like to forbid new arrays too, but this doesn't compile.
- void * operator new[](size_t);
- #endif
- };
-
- //////////////////////////////////////////////////////////////////////
-
- template <class Type>
- class ObjectHandle : public AbstractObjectHandle {
- // An object that looks like a pointer. It points to another object
- // which is stored in a Macintosh Handle.
- public:
- ObjectHandle(Boolean longLived = false); // constructor
- ~ObjectHandle(void);// destructor
- // make it look like a pointer to a Type
- Type * operator->(void) { return *(Type**)(theObject); }
- };
-
- template<class Type>
- ObjectHandle<Type>::ObjectHandle(Boolean longLived) {
- if (longLived) // make room at the bottom of the heap
- ReserveMem(sizeof(Type));
- // allocate the memory as a handle
- theObject = NewHandle(sizeof(Type));
- if (theObject) { // if the handle is good...
- Boolean oldLock = Lock(true); // lock it...
- Type *t = new (*theObject) Type; // trigger the constructor...
- Lock(oldLock); // restore the lock
- }
- }
-
- template<class Type>
- ObjectHandle<Type>::~ObjectHandle(void) {
- if (theObject) { // if the handle is good...
- Boolean oldLock = Lock(true); // lock it...
- // We can't use "delete" because the memory wasn't malloc'ed
- (*(Type**)theObject)->Type::~Type(); // trigger the destructor...
- Lock(oldLock); // restore the lock
- }
- }
-
- //////////////////////////////////////////////////////////////////////
- /* // We may want to create an intermediate array kind
- // for holding built-in types. Eg:
- template<class Type>
- class ArrayHandle : public AbstractObjectHandle {
- public:
- ArrayHandle(long cnt=1) { theObject = NewHandle(sizeof(Type)*cnt); }
- // no destructor
- Type & operator[](int i) { return *( ((Type*)*theObject) + i ); }
- long GetSize(void);
- Boolean SetSize(long size);
- };
- // that would allow operator->() in the ObjectArrayHandle
- */
- //////////////////////////////////////////////////////////////////////
-
- template<class Type>
- class ObjectArrayHandle : public AbstractObjectHandle {
- // An object that looks like an array. The actual array is
- // stored in a Macintosh handle.
- public:
- ObjectArrayHandle(long cnt=1); // constructor
- ~ObjectArrayHandle(void); // destructor
- // make it look like a pointer to the 1st elt of the array
- // NOTE: operator-> won't work for arrays of built-in types
- // Type * operator->(void) { return *(Type**)(theObject); }
- // make it look like an array
- Type & operator[](int i) { return *( (*(Type**)theObject) + i ); }
- long GetSize(void);
- Boolean SetSize(long size);
- protected:
- // allocation utilities
- void ConstructRange(long start, long end);
- void DestructRange(long start, long end);
- };
-
- template<class Type>
- void ObjectArrayHandle<Type>::ConstructRange(long start, long end)
- { // apply the constuctor to a range of objects
- if (IsValid()) {
- Boolean oldLock = Lock(true); // lock it...
- for (long i=start; i<=end; i++)
- Type *t = new ( (*(Type**)theObject) + i ) Type; // trigger each constructor
- Lock(oldLock); // restore the lock
- }
- }
-
- template<class Type>
- void ObjectArrayHandle<Type>::DestructRange(long start, long end)
- { // apply the destructor to a range of objects
- if (IsValid()) {
- Boolean oldLock = Lock(true); // lock it...
- for (long i=end; i>=start; i--) {
- // destruct each object (in reverse order)
- Type *t = (*(Type**)theObject) + i;
- t->Type::~Type(); // trigger each destructor
- }
- Lock(oldLock); // restore the lock
- }
- }
-
- template<class Type>
- ObjectArrayHandle<Type>::ObjectArrayHandle(long cnt) {
- // allocate the memory as a handle
- theObject = NewHandle( sizeof(Type) * cnt );
- ConstructRange(0, cnt-1);
- }
-
- template<class Type>
- ObjectArrayHandle<Type>::~ObjectArrayHandle(void) {
- DestructRange(0, GetSize()-1);
- }
-
- template<class Type>
- //inline
- long ObjectArrayHandle<Type>::GetSize(void)
- {
- return (IsValid() ? (GetHandleSize(theObject)/sizeof(Type)) : 0);
- }
-
- template<class Type>
- Boolean ObjectArrayHandle<Type>::SetSize(long size)
- { // Change the number of objects in the array.
- // Return true if successful.
- // User note: more likely to work if Unlock()ed first.
- if (!IsValid()) return false;
- long oldSize = GetSize();
- OSErr err = noErr;
- if (oldSize<size) {
- // array is getting bigger
- SetHandleSize(theObject, sizeof(Type)*size);
- err = MemError();
- if (err==noErr)
- ConstructRange(oldSize,size-1);
- } else if (oldSize>size) {
- // array is getting smaller
- DestructRange(size,oldSize-1);
- SetHandleSize(theObject, sizeof(Type)*size);
- err = MemError();
- } // else oldSize==size -- no change
- return err==noErr;
- }
-
- //////////////////////////////////////////////////////////////////////
-
- // handy macros
- #define OH ObjectHandle
- #define OAH ObjectArrayHandle
-