• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

DS_Queue.h

Go to the documentation of this file.
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__, __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__, __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__, __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__, __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__, __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                 array = RakNet::OP_NEW_ARRAY<queue_type>(size, file, line );
00366                 allocation_size = size;
00367                 head = 0;
00368                 tail = 0;
00369         }
00370 
00371         template <class queue_type>
00372                 inline queue_type& Queue<queue_type>::operator[] ( unsigned int position ) const
00373         {
00374 #ifdef _DEBUG
00375                 RakAssert( position < Size() );
00376 #endif
00377                 //return array[(head + position) % allocation_size];
00378 
00379                 if ( head + position >= allocation_size )
00380                         return array[ head + position - allocation_size ];
00381                 else
00382                         return array[ head + position ];
00383         }
00384 
00385         template <class queue_type>
00386         void Queue<queue_type>::RemoveAtIndex( unsigned int position )
00387         {
00388 #ifdef _DEBUG
00389                 RakAssert( position < Size() );
00390                 RakAssert( head != tail );
00391 #endif
00392 
00393                 if ( head == tail || position >= Size() )
00394                         return ;
00395 
00396                 unsigned int index;
00397 
00398                 unsigned int next;
00399 
00400                 //index  = (head + position) % allocation_size;
00401                 if ( head + position >= allocation_size )
00402                         index = head + position - allocation_size;
00403                 else
00404                         index = head + position;
00405 
00406                 //next = (index + 1) % allocation_size;
00407                 next = index + 1;
00408 
00409                 if ( next == allocation_size )
00410                         next = 0;
00411 
00412                 while ( next != tail )
00413                 {
00414                         // Overwrite the previous element
00415                         array[ index ] = array[ next ];
00416                         index = next;
00417                         //next = (next + 1) % allocation_size;
00418 
00419                         if ( ++next == allocation_size )
00420                                 next = 0;
00421                 }
00422 
00423                 // Move the tail back
00424                 if ( tail == 0 )
00425                         tail = allocation_size - 1;
00426                 else
00427                         --tail;
00428         }
00429 } // End namespace
00430 
00431 #endif
00432 

Generated on Thu Sep 30 2010 01:27:22 for RakNet by  doxygen 1.7.1