#ifndef Array_hxx #define Array_hxx // File: Array.hxx // Description: Template Class definitions for dynamic array class. // Notes: Array class has the following features: // 1. The array can grow dynamically // 2. The class T must have = operator. When the = operator // of class T is invoked, it is guaranteed that the memory // pointed to by the lvalue of the assignment statement is // cleared to 0. Further, << operator is required for printing // the list and == operator is required locating or removing // the objects of class T. // History: Gopal (08/26/95) -- Creation. #include #include #define AFLAG_OUTOFMEMORY 1 #define AFLAG_ISDIRTY 2 #define ALLOCATED 0 #define RESERVED -1 #define NOFREEITEM -2 typedef int BOOL; #define TRUE 1 #define FALSE 0 template class CArray { public: // Static constructor static CArray* CreateArray(const unsigned long ulStep=5, const unsigned long ulSlots=0) { return(new CArray(ulStep, ulSlots)); } // Copy constructor CArray(const CArray& a); // Reference counting functions unsigned long AddRef() { return(++m_refs); } unsigned long Release(); // New and Delete operators void* operator new(size_t size) { return PrivMemAlloc(size); }; void operator delete(void *pv){ PrivMemFree(pv); return; }; // Functionality functions unsigned long Length() { return(m_ulLength); } void SetStepSize(unsigned long ulStep) { m_ulStepSize = ulStep; return; } unsigned long Reserve(const unsigned long ulSlots) { if(m_ulCurSize) return(0); m_ulResSlots = ulSlots; return(ulSlots); } unsigned long Locate(const T& givenitem); BOOL AddReservedItem(const T& item, const unsigned long ulSlot); unsigned long AddItem(const T& item); T* GetItem(const unsigned long index); BOOL DeleteItem(const unsigned long index); void DeleteAllItems(void); BOOL ShiftToEnd(unsigned long ulNode); void Reset(unsigned long& index, BOOL fEnumResSlots=TRUE) { if(fEnumResSlots) index = 0; else index = m_ulResSlots; return; } T* GetNext(unsigned long& ulIndex); T* GetPrev(unsigned long& ulIndex); BOOL IsOutOfMemory() { return(m_ulFlags | AFLAG_OUTOFMEMORY); } BOOL IsDirty() { return(m_ulFlags | AFLAG_ISDIRTY); } CArray& operator=(const CArray& a); friend ostream& operator<<(ostream& os, CArray& l); void Dump(); private: // Private data type struct ArrayNode { // Member variables T item; unsigned long next; unsigned long prev; }; // Private constructor CArray(const unsigned long ulStep, const unsigned long ulSlots); // Private destructor ~CArray(); // Private member variables unsigned long m_refs; unsigned long m_ulFlags; unsigned long m_ulStepSize; unsigned long m_ulCurSize; unsigned long m_ulLength; unsigned long m_ulResSlots; unsigned long m_ulHeadNode; unsigned long m_ulTailNode; int m_iFree; int* m_piAllocList; ArrayNode* m_pBuffer; void MakeCopy(const CArray& a); }; template CArray::CArray(const unsigned long ulStep, const unsigned long ulSlots) { m_refs = 1; m_ulFlags = 0; m_ulStepSize = ulStep; if(m_ulStepSize<1) m_ulStepSize = 1; m_ulCurSize = 0; m_ulLength = 0; m_ulResSlots = ulSlots; m_ulHeadNode = 0; m_ulTailNode = 0; m_iFree = NOFREEITEM; m_piAllocList = 0; m_pBuffer = 0; } template void CArray::MakeCopy(const CArray& a) { // Copy the StepSize m_ulStepSize = a.m_ulStepSize; m_ulResSlots = a.m_ulResSlots; // Allocate the memory for buffer and Allocation list if(a.m_ulLength>0) { m_pBuffer = (struct ArrayNode *) PrivMemAlloc(sizeof(ArrayNode)*a.m_ulCurSize); if(m_pBuffer) { m_piAllocList = (int *) PrivMemAlloc(sizeof(int)*a.m_ulCurSize); if(m_piAllocList) { // Memory allocation succeded. m_ulFlags = a.m_ulFlags; m_ulFlags &= ~AFLAG_OUTOFMEMORY; m_ulCurSize = a.m_ulCurSize; m_ulLength = 0; m_ulHeadNode = a.m_ulHeadNode; m_ulTailNode = a.m_ulTailNode; m_iFree = a.m_iFree; memset(m_pBuffer, 0, sizeof(ArrayNode)*m_ulCurSize); // Now copy the allocation list and the buffer for(int i=0; i CArray::CArray(const CArray& a) { // Make a copy MakeCopy(a); return; } template CArray::~CArray() { // Call the destructor for valid objects in the buffer if(m_pBuffer) { for(unsigned long i=0;i unsigned long CArray::Release() { if(--m_refs==0) { delete this; return(0); } return(m_refs); } template unsigned long CArray::Locate(const T& GivenItem) { unsigned long i; if (m_pBuffer == NULL) return 0; // Search all the reserved and allocated items in the buffer for(i=0;i BOOL CArray::AddReservedItem(const T& item, const unsigned long ulSlot) { // Sanity check if(ulSlot<1 || ulSlot>m_ulResSlots) return(FALSE); // Check if buffer has been allocated if(!m_pBuffer && !(m_ulFlags & AFLAG_OUTOFMEMORY)) { unsigned long i, ulNewSize; ArrayNode* pNewBuffer; int* piNewAllocList; // Compute the new size ulNewSize = m_ulResSlots + m_ulStepSize; // Expand the buffer pNewBuffer = (ArrayNode *) PrivMemAlloc(sizeof(ArrayNode)*(ulNewSize)); if(pNewBuffer) { piNewAllocList = (int *) PrivMemAlloc(sizeof(int)*(ulNewSize)); if(piNewAllocList) { // Make the m_pBuffer and m_piAllocList point to the new // buffer and allocation list m_pBuffer = pNewBuffer; m_piAllocList = piNewAllocList; // Clear the memory in the buffer that is allocated now memset(&m_pBuffer[0], 0, sizeof(ArrayNode)*ulNewSize); // Reserve the desiresd number of slots for(i=0;i unsigned long CArray::AddItem(const T& item) { unsigned long i; // Check if we have free item in the buffer if(m_iFree==NOFREEITEM && !(m_ulFlags & AFLAG_OUTOFMEMORY)) { // No free item in the buffer unsigned long ulNewSize; ArrayNode* pNewBuffer; int* piNewAllocList; // Compute the new size if(m_pBuffer) ulNewSize = m_ulCurSize + m_ulStepSize; else ulNewSize = m_ulResSlots + m_ulStepSize; // Expand the buffer pNewBuffer = (ArrayNode *) PrivMemAlloc(sizeof(ArrayNode)*(ulNewSize)); if(pNewBuffer) { piNewAllocList = (int *) PrivMemAlloc(sizeof(int)*(ulNewSize)); if(piNewAllocList) { if(m_pBuffer) { // Copy the existing buffer and allocation list memcpy(pNewBuffer, m_pBuffer, sizeof(ArrayNode)*m_ulCurSize); memcpy(piNewAllocList, m_piAllocList, sizeof(int)*m_ulCurSize); PrivMemFree(m_pBuffer); PrivMemFree(m_piAllocList); } else { // Reserve the desiresd number of slots for(i=0;i T* CArray::GetItem(const unsigned long index) { // Sanity checks if(index>m_ulCurSize || index<1) return(0); if(m_piAllocList[index-1]!=ALLOCATED) return(0); return(&m_pBuffer[index-1].item); } template BOOL CArray::DeleteItem(const unsigned long index) { // Sanity checks if(index>m_ulCurSize || index<1) return(FALSE); if(m_piAllocList[index-1]!=ALLOCATED) return(FALSE); // Delete the object in the buffer m_pBuffer[index-1].item.~T(); // Relink if index points to a normal item if(index>m_ulResSlots) { if(m_pBuffer[index-1].prev) m_pBuffer[m_pBuffer[index-1].prev-1].next = m_pBuffer[index-1].next; else { Win4Assert(m_ulHeadNode==index); m_ulHeadNode = m_pBuffer[index-1].next; } if(m_pBuffer[index-1].next) m_pBuffer[m_pBuffer[index-1].next-1].prev = m_pBuffer[index-1].prev; else { Win4Assert(m_ulTailNode==index); m_ulTailNode = m_pBuffer[index-1].prev; } } // Clear memory memset(&m_pBuffer[index-1], 0, sizeof(ArrayNode)); --m_ulLength; if(index>m_ulResSlots) { // Update the free list m_piAllocList[index-1] = m_iFree; m_iFree = index; } else { // Revert slot to reserved m_piAllocList[index-1] = RESERVED; } return(TRUE); } template void CArray::DeleteAllItems(void) { unsigned long i; // If we haven't even allocated a buffer yet, // just return. if (NULL == m_pBuffer) return; // Delete all objects in the buffer for(i=0;i BOOL CArray::ShiftToEnd(unsigned long ulNode) { // Sanity check if(ulNode<=m_ulResSlots || m_piAllocList[ulNode-1]!=ALLOCATED) return(FALSE); // Degenerate case if(!m_pBuffer[ulNode-1].next) { Win4Assert(ulNode==m_ulTailNode); return(TRUE); } // Fix link info m_pBuffer[m_ulTailNode-1].next = m_ulHeadNode; m_pBuffer[m_ulHeadNode-1].prev = m_ulTailNode; m_ulHeadNode = m_pBuffer[ulNode-1].next; m_pBuffer[m_ulHeadNode-1].prev = 0; m_ulTailNode = ulNode; m_pBuffer[m_ulTailNode-1].next = 0; return(TRUE); } template T* CArray::GetNext(unsigned long& index) { // Sanity check if(index>m_ulCurSize) return(0); // Search for the next valid item in the buffer unsigned long i=index; // Search the reserved slots while(i T* CArray::GetPrev(unsigned long& index) { // Sanity check if(index<1) return 0; // Search for the previous valid item in the buffer unsigned long i=index; // Skip to the previous normal node if(i>m_ulResSlots) { Win4Assert(m_piAllocList[i-1]==ALLOCATED); i = m_pBuffer[i-1].prev; if(i) { Win4Assert(m_piAllocList[i-1]==ALLOCATED); index = i; return(&m_pBuffer[i-1].item); } else i = m_ulResSlots+1; } // Search the reserved slots while(i>1) { --i; if(m_piAllocList[i-1]==ALLOCATED) { index = i; return(&m_pBuffer[i-1].item); } } return 0; } template CArray& CArray::operator=(const CArray& a) { // Check to see, if this a=a case if(this==&a) return(*this); // Self destroy CArray::~CArray(); // Now, make a copy MakeCopy(a); return(*this); } template ostream& operator<<(ostream& os, CArray& a) { unsigned long i, index; a.Reset(index); os << "Length = " << a.m_ulLength << " Current Size = " << a.m_ulCurSize << endl; if(a.m_ulLength) { os << '['; for(i=0;i void CArray::Dump() { unsigned long i; cerr << "Current Size = " << m_ulCurSize << endl; cerr << "HeadNode = " << m_ulHeadNode << endl; cerr << "TailNode = " << m_ulTailNode << endl; cerr << "FreeNode = " << m_iFree << endl; if(m_ulCurSize) { cerr << '['; for(i=0;i class CInterfacePtr { public: // Default Constructor CInterfacePtr(T* a=NULL) { m_ptr = a; } // Copy constructor CInterfacePtr(const CInterfacePtr& a) { m_ptr = a.m_ptr; if(m_ptr) m_ptr->AddRef(); } // Destructor ~CInterfacePtr() { if(m_ptr) m_ptr->Release(); } // New and Delete operators void* operator new(size_t size) { return PrivMemAlloc(size); }; void operator delete(void *pv){ PrivMemFree(pv); return; }; // Operators operator T*() { return(m_ptr); } T* operator->() { return(m_ptr); } T& operator*() { return(*m_ptr); } T& operator[](int i) { return(m_ptr[i]); } T** operator&() { return(&m_ptr); } const CInterfacePtr& operator=(T* a) { // Check for a=a case if(this->m_ptr==a) return(*this); // Self destroy CInterfacePtr::~CInterfacePtr(); m_ptr = a; if(m_ptr) m_ptr->AddRef(); return(*this); } private: T* m_ptr; }; #endif // Array_hxx