![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 00002 00003 00004 00005 00006 00007 00008 00009 00010 #ifndef __QUEUE_H 00011 #define __QUEUE_H 00012 00013 // Template classes have to have all the code in the header file 00014 #include "RakAssert.h" 00015 #include "Export.h" 00016 #include "RakMemoryOverride.h" 00017 00020 namespace DataStructures 00021 { 00023 template <class queue_type> 00024 class RAK_DLL_EXPORT Queue 00025 { 00026 public: 00027 Queue(); 00028 ~Queue(); 00029 Queue( Queue& original_copy ); 00030 bool operator= ( const Queue& original_copy ); 00031 void Push( const queue_type& input, const char *file, unsigned int line ); 00032 void PushAtHead( const queue_type& input, unsigned index, const char *file, unsigned int line ); 00033 queue_type& operator[] ( unsigned int position ) const; // Not a normal thing you do with a queue but can be used for efficiency 00034 void RemoveAtIndex( unsigned int position ); // Not a normal thing you do with a queue but can be used for efficiency 00035 inline queue_type Peek( void ) const; 00036 inline queue_type PeekTail( void ) const; 00037 inline queue_type Pop( void ); 00038 // Debug: Set pointer to 0, for memory leak detection 00039 inline queue_type PopDeref( void ); 00040 inline unsigned int Size( void ) const; 00041 inline bool IsEmpty(void) const; 00042 inline unsigned int AllocationSize( void ) const; 00043 inline void Clear( const char *file, unsigned int line ); 00044 void Compress( const char *file, unsigned int line ); 00045 bool Find ( queue_type q ); 00046 void ClearAndForceAllocation( int size, const char *file, unsigned int line ); // Force a memory allocation to a certain larger size 00047 00048 private: 00049 queue_type* array; 00050 unsigned int head; // Array index for the head of the queue 00051 unsigned int tail; // Array index for the tail of the queue 00052 unsigned int allocation_size; 00053 }; 00054 00055 00056 template <class queue_type> 00057 inline unsigned int Queue<queue_type>::Size( void ) const 00058 { 00059 if ( head <= tail ) 00060 return tail -head; 00061 else 00062 return allocation_size -head + tail; 00063 } 00064 00065 template <class queue_type> 00066 inline bool Queue<queue_type>::IsEmpty(void) const 00067 { 00068 return head==tail; 00069 } 00070 00071 template <class queue_type> 00072 inline unsigned int Queue<queue_type>::AllocationSize( void ) const 00073 { 00074 return allocation_size; 00075 } 00076 00077 template <class queue_type> 00078 Queue<queue_type>::Queue() 00079 { 00080 //allocation_size = 16; 00081 //array = RakNet::OP_NEW_ARRAY<queue_type>(allocation_size, _FILE_AND_LINE_ ); 00082 allocation_size = 0; 00083 array=0; 00084 head = 0; 00085 tail = 0; 00086 } 00087 00088 template <class queue_type> 00089 Queue<queue_type>::~Queue() 00090 { 00091 if (allocation_size>0) 00092 RakNet::OP_DELETE_ARRAY(array, _FILE_AND_LINE_); 00093 } 00094 00095 template <class queue_type> 00096 inline queue_type Queue<queue_type>::Pop( void ) 00097 { 00098 #ifdef _DEBUG 00099 RakAssert( head != tail); 00100 #endif 00101 //head=(head+1) % allocation_size; 00102 00103 if ( ++head == allocation_size ) 00104 head = 0; 00105 00106 if ( head == 0 ) 00107 return ( queue_type ) array[ allocation_size -1 ]; 00108 00109 return ( queue_type ) array[ head -1 ]; 00110 } 00111 00112 template <class queue_type> 00113 inline queue_type Queue<queue_type>::PopDeref( void ) 00114 { 00115 if ( ++head == allocation_size ) 00116 head = 0; 00117 00118 queue_type q; 00119 if ( head == 0 ) 00120 { 00121 q=array[ allocation_size -1 ]; 00122 array[ allocation_size -1 ]=0; 00123 return q; 00124 } 00125 00126 q=array[ head -1 ]; 00127 array[ head -1 ]=0; 00128 return q; 00129 } 00130 00131 template <class queue_type> 00132 void Queue<queue_type>::PushAtHead( const queue_type& input, unsigned index, const char *file, unsigned int line ) 00133 { 00134 RakAssert(index <= Size()); 00135 00136 // Just force a reallocation, will be overwritten 00137 Push(input, file, line ); 00138 00139 if (Size()==1) 00140 return; 00141 00142 unsigned writeIndex, readIndex, trueWriteIndex, trueReadIndex; 00143 writeIndex=Size()-1; 00144 readIndex=writeIndex-1; 00145 while (readIndex >= index) 00146 { 00147 if ( head + writeIndex >= allocation_size ) 00148 trueWriteIndex = head + writeIndex - allocation_size; 00149 else 00150 trueWriteIndex = head + writeIndex; 00151 00152 if ( head + readIndex >= allocation_size ) 00153 trueReadIndex = head + readIndex - allocation_size; 00154 else 00155 trueReadIndex = head + readIndex; 00156 00157 array[trueWriteIndex]=array[trueReadIndex]; 00158 00159 if (readIndex==0) 00160 break; 00161 writeIndex--; 00162 readIndex--; 00163 } 00164 00165 if ( head + index >= allocation_size ) 00166 trueWriteIndex = head + index - allocation_size; 00167 else 00168 trueWriteIndex = head + index; 00169 00170 array[trueWriteIndex]=input; 00171 } 00172 00173 00174 template <class queue_type> 00175 inline queue_type Queue<queue_type>::Peek( void ) const 00176 { 00177 #ifdef _DEBUG 00178 RakAssert( head != tail ); 00179 #endif 00180 00181 return ( queue_type ) array[ head ]; 00182 } 00183 00184 template <class queue_type> 00185 inline queue_type Queue<queue_type>::PeekTail( void ) const 00186 { 00187 #ifdef _DEBUG 00188 RakAssert( head != tail ); 00189 #endif 00190 if (tail!=0) 00191 return ( queue_type ) array[ tail-1 ]; 00192 else 00193 return ( queue_type ) array[ allocation_size-1 ]; 00194 } 00195 00196 template <class queue_type> 00197 void Queue<queue_type>::Push( const queue_type& input, const char *file, unsigned int line ) 00198 { 00199 if ( allocation_size == 0 ) 00200 { 00201 array = RakNet::OP_NEW_ARRAY<queue_type>(16, file, line ); 00202 head = 0; 00203 tail = 1; 00204 array[ 0 ] = input; 00205 allocation_size = 16; 00206 return ; 00207 } 00208 00209 array[ tail++ ] = input; 00210 00211 if ( tail == allocation_size ) 00212 tail = 0; 00213 00214 if ( tail == head ) 00215 { 00216 // unsigned int index=tail; 00217 00218 // Need to allocate more memory. 00219 queue_type * new_array; 00220 new_array = RakNet::OP_NEW_ARRAY<queue_type>(allocation_size * 2, file, line ); 00221 #ifdef _DEBUG 00222 RakAssert( new_array ); 00223 #endif 00224 if (new_array==0) 00225 return; 00226 00227 for ( unsigned int counter = 0; counter < allocation_size; ++counter ) 00228 new_array[ counter ] = array[ ( head + counter ) % ( allocation_size ) ]; 00229 00230 head = 0; 00231 00232 tail = allocation_size; 00233 00234 allocation_size *= 2; 00235 00236 // Delete the old array and move the pointer to the new array 00237 RakNet::OP_DELETE_ARRAY(array, file, line); 00238 00239 array = new_array; 00240 } 00241 00242 } 00243 00244 template <class queue_type> 00245 Queue<queue_type>::Queue( Queue& original_copy ) 00246 { 00247 // Allocate memory for copy 00248 00249 if ( original_copy.Size() == 0 ) 00250 { 00251 allocation_size = 0; 00252 } 00253 00254 else 00255 { 00256 array = RakNet::OP_NEW_ARRAY<queue_type >( original_copy.Size() + 1 , _FILE_AND_LINE_ ); 00257 00258 for ( unsigned int counter = 0; counter < original_copy.Size(); ++counter ) 00259 array[ counter ] = original_copy.array[ ( original_copy.head + counter ) % ( original_copy.allocation_size ) ]; 00260 00261 head = 0; 00262 00263 tail = original_copy.Size(); 00264 00265 allocation_size = original_copy.Size() + 1; 00266 } 00267 } 00268 00269 template <class queue_type> 00270 bool Queue<queue_type>::operator= ( const Queue& original_copy ) 00271 { 00272 if ( ( &original_copy ) == this ) 00273 return false; 00274 00275 Clear(_FILE_AND_LINE_); 00276 00277 // Allocate memory for copy 00278 if ( original_copy.Size() == 0 ) 00279 { 00280 allocation_size = 0; 00281 } 00282 00283 else 00284 { 00285 array = RakNet::OP_NEW_ARRAY<queue_type >( original_copy.Size() + 1 , _FILE_AND_LINE_ ); 00286 00287 for ( unsigned int counter = 0; counter < original_copy.Size(); ++counter ) 00288 array[ counter ] = original_copy.array[ ( original_copy.head + counter ) % ( original_copy.allocation_size ) ]; 00289 00290 head = 0; 00291 00292 tail = original_copy.Size(); 00293 00294 allocation_size = original_copy.Size() + 1; 00295 } 00296 00297 return true; 00298 } 00299 00300 template <class queue_type> 00301 inline void Queue<queue_type>::Clear ( const char *file, unsigned int line ) 00302 { 00303 if ( allocation_size == 0 ) 00304 return ; 00305 00306 if (allocation_size > 32) 00307 { 00308 RakNet::OP_DELETE_ARRAY(array, file, line); 00309 allocation_size = 0; 00310 } 00311 00312 head = 0; 00313 tail = 0; 00314 } 00315 00316 template <class queue_type> 00317 void Queue<queue_type>::Compress ( const char *file, unsigned int line ) 00318 { 00319 queue_type* new_array; 00320 unsigned int newAllocationSize; 00321 if (allocation_size==0) 00322 return; 00323 00324 newAllocationSize=1; 00325 while (newAllocationSize <= Size()) 00326 newAllocationSize<<=1; // Must be a better way to do this but I'm too dumb to figure it out quickly :) 00327 00328 new_array = RakNet::OP_NEW_ARRAY<queue_type >(newAllocationSize, file, line ); 00329 00330 for (unsigned int counter=0; counter < Size(); ++counter) 00331 new_array[counter] = array[(head + counter)%(allocation_size)]; 00332 00333 tail=Size(); 00334 allocation_size=newAllocationSize; 00335 head=0; 00336 00337 // Delete the old array and move the pointer to the new array 00338 RakNet::OP_DELETE_ARRAY(array, file, line); 00339 array=new_array; 00340 } 00341 00342 template <class queue_type> 00343 bool Queue<queue_type>::Find ( queue_type q ) 00344 { 00345 if ( allocation_size == 0 ) 00346 return false; 00347 00348 unsigned int counter = head; 00349 00350 while ( counter != tail ) 00351 { 00352 if ( array[ counter ] == q ) 00353 return true; 00354 00355 counter = ( counter + 1 ) % allocation_size; 00356 } 00357 00358 return false; 00359 } 00360 00361 template <class queue_type> 00362 void Queue<queue_type>::ClearAndForceAllocation( int size, const char *file, unsigned int line ) 00363 { 00364 RakNet::OP_DELETE_ARRAY(array, file, line); 00365 if (size>0) 00366 array = RakNet::OP_NEW_ARRAY<queue_type>(size, file, line ); 00367 else 00368 array=0; 00369 allocation_size = size; 00370 head = 0; 00371 tail = 0; 00372 } 00373 00374 template <class queue_type> 00375 inline queue_type& Queue<queue_type>::operator[] ( unsigned int position ) const 00376 { 00377 #ifdef _DEBUG 00378 RakAssert( position < Size() ); 00379 #endif 00380 //return array[(head + position) % allocation_size]; 00381 00382 if ( head + position >= allocation_size ) 00383 return array[ head + position - allocation_size ]; 00384 else 00385 return array[ head + position ]; 00386 } 00387 00388 template <class queue_type> 00389 void Queue<queue_type>::RemoveAtIndex( unsigned int position ) 00390 { 00391 #ifdef _DEBUG 00392 RakAssert( position < Size() ); 00393 RakAssert( head != tail ); 00394 #endif 00395 00396 if ( head == tail || position >= Size() ) 00397 return ; 00398 00399 unsigned int index; 00400 00401 unsigned int next; 00402 00403 //index = (head + position) % allocation_size; 00404 if ( head + position >= allocation_size ) 00405 index = head + position - allocation_size; 00406 else 00407 index = head + position; 00408 00409 //next = (index + 1) % allocation_size; 00410 next = index + 1; 00411 00412 if ( next == allocation_size ) 00413 next = 0; 00414 00415 while ( next != tail ) 00416 { 00417 // Overwrite the previous element 00418 array[ index ] = array[ next ]; 00419 index = next; 00420 //next = (next + 1) % allocation_size; 00421 00422 if ( ++next == allocation_size ) 00423 next = 0; 00424 } 00425 00426 // Move the tail back 00427 if ( tail == 0 ) 00428 tail = allocation_size - 1; 00429 else 00430 --tail; 00431 } 00432 } // End namespace 00433 00434 #endif 00435
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.