/* A* Algorithm Implementation using STL is Copyright (C)2001-2005 Justin Heyes-Jones Permission is given by the author to freely redistribute and include this code in any program as long as this credit is given where due. COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. Use at your own risk! FixedSizeAllocator class Copyright 2001 Justin Heyes-Jones This class is a constant time O(1) memory manager for objects of a specified type. The type is specified using a template class. Memory is allocated from a fixed size buffer which you can specify in the class constructor or use the default. Using GetFirst and GetNext it is possible to iterate through the elements one by one, and this would be the most common use for the class. I would suggest using this class when you want O(1) add and delete and you don't do much searching, which would be O(n). Structures such as binary trees can be used instead to get O(logn) access time. */ #ifndef FSA_H #define FSA_H #include #include template class FixedSizeAllocator { public: // Constants enum { FSA_DEFAULT_SIZE = 100 }; // This class enables us to transparently manage the extra data // needed to enable the user class to form part of the double-linked // list class struct FSA_ELEMENT { USER_TYPE UserType; FSA_ELEMENT *pPrev; FSA_ELEMENT *pNext; }; public: // methods FixedSizeAllocator( unsigned int MaxElements = FSA_DEFAULT_SIZE ) : m_pFirstUsed( NULL ), m_MaxElements( MaxElements ) { // Allocate enough memory for the maximum number of elements char *pMem = new char[ m_MaxElements * sizeof(FSA_ELEMENT) ]; m_pMemory = (FSA_ELEMENT *) pMem; // Set the free list first pointer m_pFirstFree = m_pMemory; // Clear the memory memset( m_pMemory, 0, sizeof( FSA_ELEMENT ) * m_MaxElements ); // Point at first element FSA_ELEMENT *pElement = m_pFirstFree; // Set the double linked free list for( unsigned int i=0; ipPrev = pElement-1; pElement->pNext = pElement+1; pElement++; } // first element should have a null prev m_pFirstFree->pPrev = NULL; // last element should have a null next (pElement-1)->pNext = NULL; } ~FixedSizeAllocator() { // Free up the memory delete [] (char *) m_pMemory; } // Allocate a new USER_TYPE and return a pointer to it USER_TYPE *alloc() { FSA_ELEMENT *pNewNode = NULL; if( !m_pFirstFree ) { return NULL; } else { pNewNode = m_pFirstFree; m_pFirstFree = pNewNode->pNext; // if the new node points to another free node then // change that nodes prev free pointer... if( pNewNode->pNext ) { pNewNode->pNext->pPrev = NULL; } // node is now on the used list pNewNode->pPrev = NULL; // the allocated node is always first in the list if( m_pFirstUsed == NULL ) { pNewNode->pNext = NULL; // no other nodes } else { m_pFirstUsed->pPrev = pNewNode; // insert this at the head of the used list pNewNode->pNext = m_pFirstUsed; } m_pFirstUsed = pNewNode; } return reinterpret_cast(pNewNode); } // Free the given user type // For efficiency I don't check whether the user_data is a valid // pointer that was allocated. I may add some debug only checking // (To add the debug check you'd need to make sure the pointer is in // the m_pMemory area and is pointing at the start of a node) void free( USER_TYPE *user_data ) { FSA_ELEMENT *pNode = reinterpret_cast(user_data); // manage used list, remove this node from it if( pNode->pPrev ) { pNode->pPrev->pNext = pNode->pNext; } else { // this handles the case that we delete the first node in the used list m_pFirstUsed = pNode->pNext; } if( pNode->pNext ) { pNode->pNext->pPrev = pNode->pPrev; } // add to free list if( m_pFirstFree == NULL ) { // free list was empty m_pFirstFree = pNode; pNode->pPrev = NULL; pNode->pNext = NULL; } else { // Add this node at the start of the free list m_pFirstFree->pPrev = pNode; pNode->pNext = m_pFirstFree; m_pFirstFree = pNode; } } // For debugging this displays both lists (using the prev/next list pointers) void Debug() { printf( "free list " ); FSA_ELEMENT *p = m_pFirstFree; while( p ) { printf( "%x!%x ", p->pPrev, p->pNext ); p = p->pNext; } printf( "\n" ); printf( "used list " ); p = m_pFirstUsed; while( p ) { printf( "%x!%x ", p->pPrev, p->pNext ); p = p->pNext; } printf( "\n" ); } // Iterators USER_TYPE *GetFirst() { return reinterpret_cast(m_pFirstUsed); } USER_TYPE *GetNext( USER_TYPE *node ) { return reinterpret_cast ( (reinterpret_cast(node))->pNext ); } public: // data private: // methods private: // data FSA_ELEMENT *m_pFirstFree; FSA_ELEMENT *m_pFirstUsed; unsigned int m_MaxElements; FSA_ELEMENT *m_pMemory; }; #endif // defined FSA_H