// -*- mode: cpp; mode: fold -*- // Description /*{{{*/ // $Id: pointer.cc,v 1.2 1997/05/13 06:07:00 jgg Exp $ /* ###################################################################### Smart Pointer Class - Reference counted pointer implementation This is the non template base class for the smart pointer, it provides a basic set of functions for working with a smart pointers, including the prepended PtrExtra structure. All allocations are done with sizeof(PtrExtra) bytes and a structure is placed at the start of the allocation that contains the reference count and other information about the pointer. This source is placed in the Public Domain, do with it what you will It was originally written by Brian C. White. ##################################################################### */ /*}}}*/ #include #include #include #include #include // Prepended structure struct PtrExtra { unsigned short Cookie; size_t ArraySize; unsigned short LinkCount; unsigned short Flags; }; // Usefull macros to extract PtrExtra #define ExtraBytes sizeof(PtrExtra) #define ptrInfo(p) (((PtrExtra *)p) - 1) // Random unique value #define PTRCOOKIE 0xA454 Pointer::Pointer(void) { Ptr = NULL; } Pointer::Pointer(void* mem) { if (mem == NULL) { Ptr = NULL; return; } // If this happens someone goofed the souce code. if (ptrInfo(mem)->Cookie != PTRCOOKIE) abort(); Ptr = mem; ptrInfo(Ptr)->LinkCount++; } Pointer::Pointer(const Pointer& rhs) { Ptr = rhs.Ptr; if (Ptr != NULL) ptrInfo(Ptr)->LinkCount++; } Pointer::~Pointer(void) { if (Ptr != NULL) free(); } bool Pointer::operator==(const Pointer& rhs) const { return(Ptr == rhs.Ptr); } bool Pointer::operator!=(const Pointer& rhs) const { return(Ptr != rhs.Ptr); } //***************************************************************************** // // operator= -- copy from one smart pointer into another // Pointer &Pointer::operator=(const Pointer& rhs) { // dont assign to itself if (this == &rhs) return(*this); // free old pointer memory if (Ptr != NULL) free(); // copy Ptr & inc link count if ((Ptr = rhs.Ptr) != NULL) ptrInfo(Ptr)->LinkCount++; return(*this); // allow '=' chaining } //***************************************************************************** // // AllocMem -- Allocate a given number of bytes (plus extras) to a pointer // void *Pointer::allocMem(size_t size, bool zeromem) { const size_t allocsize = ExtraBytes + size; void *ptr; ptr = (void*) new char[allocsize]; // clear all allocated memory if (zeromem) memset(ptr,0,allocsize); // Advance pointer past extra fields ptr = (void *)(((PtrExtra *)ptr) + 1); // Assign the usual values into the pointer info ptrInfo(ptr)->Cookie = PTRCOOKIE; ptrInfo(ptr)->ArraySize = 1; ptrInfo(ptr)->LinkCount = 1; ptrInfo(ptr)->Flags = FLAG(PTRF_CHANGED); return ptr; } //***************************************************************************** // // FreeMem -- decrement the link count and if it goes to zero then deallocate // the corresponding memory. // void Pointer::freeMem(void* ptr) { if (ptr != NULL) if (--ptrInfo(ptr)->LinkCount == 0) delete [] (char *)ptrInfo(ptr); } //***************************************************************************** // // Pointer utility functions: // // ArraySize -- get/set the stored array size // LinkCount -- return the number of links to this memory // ???PFlag -- set/clr/chk the status of a pointer flag // void Pointer::arraySize(unsigned int size) { if (Ptr) ptrInfo(Ptr)->ArraySize = size; } unsigned int Pointer::arraySize(void) const { return Ptr ? ptrInfo(Ptr)->ArraySize : 0; } int Pointer::linkCount(void) const { return Ptr ? ptrInfo(Ptr)->LinkCount : 0; } void Pointer::setFlag(int F) { if (Ptr) SETFLAG(ptrInfo(Ptr)->Flags,F); } void Pointer::clrFlag(int F) { if (Ptr) CLRFLAG(ptrInfo(Ptr)->Flags,F); } bool Pointer::chkFlag(int F) const { return Ptr ? CHKFLAG(ptrInfo(Ptr)->Flags,F) : false; } //***************************************************************************** // // Malloc -- allocate n bytes of memory, copy data if necessary // void Pointer::malloc(size_t size, const void* memory) { if (Ptr != NULL) free(); Ptr = allocMem(size, memory == NULL); if (memory != NULL) memcpy(Ptr,memory,size); } //***************************************************************************** // // Free -- deallocate memory // void Pointer::free(void) { freeMem(Ptr); Ptr = NULL; } //***************************************************************************** // // Resize -- change size of memory, keep data intact // void Pointer::resize(size_t oldsize, size_t newsize) { void *newptr; void *oldptr; // create pointers of a type easier to work with, calculate size oldptr = Ptr; newptr = allocMem(newsize); // copy over old flags & data if available if (Ptr != NULL) { ptrInfo(newptr)->Flags |= ptrInfo(oldptr)->Flags; memcpy(newptr,oldptr,MIN(oldsize,newsize)); } // change internal pointer and unlink old memory Ptr = (void*)newptr; freeMem(oldptr); } /*---------------------------------------------------------------------------*/ DPointer::DPointer(void) { dPtr.New(); } DPointer::DPointer(const DPointer& rhs) { dPtr = rhs.dPtr; } DPointer::~DPointer(void) { dPtr.Delete(); } DPointer& DPointer::operator=(const DPointer& rhs) { // dont assign to itself if (this == &rhs) return(*this); // copy (smart) pointer dPtr = rhs.dPtr; return *this; } DPointer& DPointer::operator=(const Pointer& rhs) { // copy into second pointer (*dPtr) = rhs; return *this; } bool DPointer::operator==(const DPointer& rhs) const { return dPtr == rhs.dPtr || *dPtr == *rhs.dPtr; } bool DPointer::operator!=(const DPointer& rhs) const { return dPtr != rhs.dPtr && *dPtr != *rhs.dPtr; } bool DPointer::operator==(const Pointer& rhs) const { return *dPtr == rhs; } bool DPointer::operator!=(const Pointer& rhs) const { return *dPtr != rhs; } bool DPointer::operator!(void) const { return !dPtr && !(*dPtr); } bool DPointer::isValid(void) const { return dPtr.isValid() && (*dPtr).isValid(); } bool DPointer::isNull(void) const { return dPtr.isNull() || (*dPtr).isNull(); }