00001 /* 00002 00003 A* Algorithm Implementation using STL is 00004 Copyright (C)2001-2005 Justin Heyes-Jones 00005 00006 Permission is given by the author to freely redistribute and 00007 include this code in any program as long as this credit is 00008 given where due. 00009 00010 COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, 00011 WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, 00012 INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE 00013 IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE 00014 OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND 00015 PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED 00016 CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL 00017 DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY 00018 NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF 00019 WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE 00020 OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER 00021 THIS DISCLAIMER. 00022 00023 Use at your own risk! 00024 00025 00026 00027 FixedSizeAllocator class 00028 Copyright 2001 Justin Heyes-Jones 00029 00030 This class is a constant time O(1) memory manager for objects of 00031 a specified type. The type is specified using a template class. 00032 00033 Memory is allocated from a fixed size buffer which you can specify in the 00034 class constructor or use the default. 00035 00036 Using GetFirst and GetNext it is possible to iterate through the elements 00037 one by one, and this would be the most common use for the class. 00038 00039 I would suggest using this class when you want O(1) add and delete 00040 and you don't do much searching, which would be O(n). Structures such as binary 00041 trees can be used instead to get O(logn) access time. 00042 00043 */ 00044 00045 #ifndef FSA_H 00046 #define FSA_H 00047 00048 #include <string.h> 00049 #include <stdio.h> 00050 00051 template <class USER_TYPE> class FixedSizeAllocator 00052 { 00053 00054 public: 00055 // Constants 00056 enum 00057 { 00058 FSA_DEFAULT_SIZE = 100 00059 }; 00060 00061 // This class enables us to transparently manage the extra data 00062 // needed to enable the user class to form part of the double-linked 00063 // list class 00064 struct FSA_ELEMENT 00065 { 00066 USER_TYPE UserType; 00067 00068 FSA_ELEMENT *pPrev; 00069 FSA_ELEMENT *pNext; 00070 }; 00071 00072 public: // methods 00073 FixedSizeAllocator( unsigned int MaxElements = FSA_DEFAULT_SIZE ) : 00074 m_MaxElements( MaxElements ), 00075 m_pFirstUsed( NULL ) 00076 { 00077 // Allocate enough memory for the maximum number of elements 00078 00079 m_pMemory = (FSA_ELEMENT *) (new char[ m_MaxElements * sizeof(FSA_ELEMENT) ]); 00080 00081 // Set the free list first pointer 00082 m_pFirstFree = m_pMemory; 00083 00084 // Clear the memory 00085 memset( m_pMemory, 0, sizeof( FSA_ELEMENT ) * m_MaxElements ); 00086 00087 // Point at first element 00088 FSA_ELEMENT *pElement = m_pFirstFree; 00089 00090 // Set the double linked free list 00091 for( unsigned int i=0; i<m_MaxElements; i++ ) 00092 { 00093 pElement->pPrev = pElement-1; 00094 pElement->pNext = pElement+1; 00095 00096 pElement++; 00097 } 00098 00099 // first element should have a null prev 00100 m_pFirstFree->pPrev = NULL; 00101 // last element should have a null next 00102 (pElement-1)->pNext = NULL; 00103 00104 } 00105 00106 00107 ~FixedSizeAllocator() 00108 { 00109 // Free up the memory 00110 delete [] (char *) m_pMemory; 00111 } 00112 00113 // Allocate a new USER_TYPE and return a pointer to it 00114 USER_TYPE *alloc() 00115 { 00116 00117 FSA_ELEMENT *pNewNode = NULL; 00118 00119 if( !m_pFirstFree ) 00120 { 00121 return NULL; 00122 } 00123 else 00124 { 00125 pNewNode = m_pFirstFree; 00126 m_pFirstFree = pNewNode->pNext; 00127 00128 // if the new node points to another free node then 00129 // change that nodes prev free pointer... 00130 if( pNewNode->pNext ) 00131 { 00132 pNewNode->pNext->pPrev = NULL; 00133 } 00134 00135 // node is now on the used list 00136 00137 pNewNode->pPrev = NULL; // the allocated node is always first in the list 00138 00139 if( m_pFirstUsed == NULL ) 00140 { 00141 pNewNode->pNext = NULL; // no other nodes 00142 } 00143 else 00144 { 00145 m_pFirstUsed->pPrev = pNewNode; // insert this at the head of the used list 00146 pNewNode->pNext = m_pFirstUsed; 00147 } 00148 00149 m_pFirstUsed = pNewNode; 00150 } 00151 00152 return reinterpret_cast<USER_TYPE*>(pNewNode); 00153 } 00154 00155 // Free the given user type 00156 // For efficiency I don't check whether the user_data is a valid 00157 // pointer that was allocated. I may add some debug only checking 00158 // (To add the debug check you'd need to make sure the pointer is in 00159 // the m_pMemory area and is pointing at the start of a node) 00160 void free( USER_TYPE *user_data ) 00161 { 00162 FSA_ELEMENT *pNode = reinterpret_cast<FSA_ELEMENT*>(user_data); 00163 00164 // manage used list, remove this node from it 00165 if( pNode->pPrev ) 00166 { 00167 pNode->pPrev->pNext = pNode->pNext; 00168 } 00169 else 00170 { 00171 // this handles the case that we delete the first node in the used list 00172 m_pFirstUsed = pNode->pNext; 00173 } 00174 00175 if( pNode->pNext ) 00176 { 00177 pNode->pNext->pPrev = pNode->pPrev; 00178 } 00179 00180 // add to free list 00181 if( m_pFirstFree == NULL ) 00182 { 00183 // free list was empty 00184 m_pFirstFree = pNode; 00185 pNode->pPrev = NULL; 00186 pNode->pNext = NULL; 00187 } 00188 else 00189 { 00190 // Add this node at the start of the free list 00191 m_pFirstFree->pPrev = pNode; 00192 pNode->pNext = m_pFirstFree; 00193 m_pFirstFree = pNode; 00194 } 00195 00196 } 00197 00198 // For debugging this displays both lists (using the prev/next list pointers) 00199 void Debug() 00200 { 00201 printf( "free list " ); 00202 00203 FSA_ELEMENT *p = m_pFirstFree; 00204 while( p ) 00205 { 00206 printf( "%x!%x ", p->pPrev, p->pNext ); 00207 p = p->pNext; 00208 } 00209 printf( "\n" ); 00210 00211 printf( "used list " ); 00212 00213 p = m_pFirstUsed; 00214 while( p ) 00215 { 00216 printf( "%x!%x ", p->pPrev, p->pNext ); 00217 p = p->pNext; 00218 } 00219 printf( "\n" ); 00220 } 00221 00222 // Iterators 00223 00224 USER_TYPE *GetFirst() 00225 { 00226 return reinterpret_cast<USER_TYPE *>(m_pFirstUsed); 00227 } 00228 00229 USER_TYPE *GetNext( USER_TYPE *node ) 00230 { 00231 return reinterpret_cast<USER_TYPE *> 00232 ( 00233 (reinterpret_cast<FSA_ELEMENT *>(node))->pNext 00234 ); 00235 } 00236 00237 public: // data 00238 00239 private: // methods 00240 00241 private: // data 00242 00243 FSA_ELEMENT *m_pFirstFree; 00244 FSA_ELEMENT *m_pFirstUsed; 00245 unsigned int m_MaxElements; 00246 FSA_ELEMENT *m_pMemory; 00247 00248 }; 00249 00250 #endif // defined FSA_H