Shadowrun: Awakened 29 September 2011 - Build 871
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_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.

GNU Lesser General Public License 3 Sourceforge.net