/// \file /// \brief \b [Internal] A queue used by RakNet. /// /// This file is part of RakNet Copyright 2003 Kevin Jenkins. /// /// Usage of RakNet is subject to the appropriate license agreement. /// Creative Commons Licensees are subject to the /// license found at /// http://creativecommons.org/licenses/by-nc/2.5/ /// Single application licensees are subject to the license found at /// http://www.jenkinssoftware.com/SingleApplicationLicense.html /// Custom license users are subject to the terms therein. /// GPL license users are subject to the GNU General Public /// License as published by the Free /// Software Foundation; either version 2 of the License, or (at your /// option) any later version. #ifndef __QUEUE_H #define __QUEUE_H // Template classes have to have all the code in the header file #include #include "Export.h" /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish. namespace DataStructures { /// \brief A queue implemented as an array with a read and write index. template class RAK_DLL_EXPORT Queue { public: Queue(); ~Queue(); Queue( Queue& original_copy ); bool operator= ( const Queue& original_copy ); void Push( const queue_type& input ); void PushAtHead( const queue_type& input, unsigned index=0 ); queue_type& operator[] ( unsigned int position ) const; // Not a normal thing you do with a queue but can be used for efficiency void RemoveAtIndex( unsigned int position ); // Not a normal thing you do with a queue but can be used for efficiency inline queue_type Peek( void ) const; inline queue_type PeekTail( void ) const; inline queue_type Pop( void ); inline unsigned int Size( void ) const; inline bool IsEmpty(void) const; inline unsigned int AllocationSize( void ) const; inline void Clear( void ); void Compress( void ); bool Find ( queue_type q ); void ClearAndForceAllocation( int size ); // Force a memory allocation to a certain larger size private: queue_type* array; unsigned int head; // Array index for the head of the queue unsigned int tail; // Array index for the tail of the queue unsigned int allocation_size; }; template inline unsigned int Queue::Size( void ) const { if ( head <= tail ) return tail -head; else return allocation_size -head + tail; } template inline bool Queue::IsEmpty(void) const { return head==tail; } template inline unsigned int Queue::AllocationSize( void ) const { return allocation_size; } template Queue::Queue() { allocation_size = 16; array = new queue_type[ allocation_size ]; head = 0; tail = 0; } template Queue::~Queue() { if (allocation_size>0) delete [] array; } template inline queue_type Queue::Pop( void ) { #ifdef _DEBUG assert( allocation_size > 0 && Size() >= 0 && head != tail); #endif //head=(head+1) % allocation_size; if ( ++head == allocation_size ) head = 0; if ( head == 0 ) return ( queue_type ) array[ allocation_size -1 ]; return ( queue_type ) array[ head -1 ]; } template void Queue::PushAtHead( const queue_type& input, unsigned index ) { assert(index <= Size()); // Just force a reallocation, will be overwritten Push(input); if (Size()==1) return; unsigned writeIndex, readIndex, trueWriteIndex, trueReadIndex; writeIndex=Size()-1; readIndex=writeIndex-1; while (readIndex >= index) { if ( head + writeIndex >= allocation_size ) trueWriteIndex = head + writeIndex - allocation_size; else trueWriteIndex = head + writeIndex; if ( head + readIndex >= allocation_size ) trueReadIndex = head + readIndex - allocation_size; else trueReadIndex = head + readIndex; array[trueWriteIndex]=array[trueReadIndex]; if (readIndex==0) break; writeIndex--; readIndex--; } if ( head + index >= allocation_size ) trueWriteIndex = head + index - allocation_size; else trueWriteIndex = head + index; array[trueWriteIndex]=input; } template inline queue_type Queue::Peek( void ) const { #ifdef _DEBUG assert( head != tail ); assert( allocation_size > 0 && Size() >= 0 ); #endif return ( queue_type ) array[ head ]; } template inline queue_type Queue::PeekTail( void ) const { #ifdef _DEBUG assert( head != tail ); assert( allocation_size > 0 && Size() >= 0 ); #endif if (tail!=0) return ( queue_type ) array[ tail-1 ]; else return ( queue_type ) array[ allocation_size-1 ]; } template void Queue::Push( const queue_type& input ) { if ( allocation_size == 0 ) { array = new queue_type[ 16 ]; head = 0; tail = 1; array[ 0 ] = input; allocation_size = 16; return ; } array[ tail++ ] = input; if ( tail == allocation_size ) tail = 0; if ( tail == head ) { // unsigned int index=tail; // Need to allocate more memory. queue_type * new_array; new_array = new queue_type[ allocation_size * 2 ]; #ifdef _DEBUG assert( new_array ); #endif if (new_array==0) return; for ( unsigned int counter = 0; counter < allocation_size; ++counter ) new_array[ counter ] = array[ ( head + counter ) % ( allocation_size ) ]; head = 0; tail = allocation_size; allocation_size *= 2; // Delete the old array and move the pointer to the new array delete [] array; array = new_array; } } template Queue::Queue( Queue& original_copy ) { // Allocate memory for copy if ( original_copy.Size() == 0 ) { allocation_size = 0; } else { array = new queue_type [ original_copy.Size() + 1 ]; for ( unsigned int counter = 0; counter < original_copy.Size(); ++counter ) array[ counter ] = original_copy.array[ ( original_copy.head + counter ) % ( original_copy.allocation_size ) ]; head = 0; tail = original_copy.Size(); allocation_size = original_copy.Size() + 1; } } template bool Queue::operator= ( const Queue& original_copy ) { if ( ( &original_copy ) == this ) return false; Clear(); // Allocate memory for copy if ( original_copy.Size() == 0 ) { allocation_size = 0; } else { array = new queue_type [ original_copy.Size() + 1 ]; for ( unsigned int counter = 0; counter < original_copy.Size(); ++counter ) array[ counter ] = original_copy.array[ ( original_copy.head + counter ) % ( original_copy.allocation_size ) ]; head = 0; tail = original_copy.Size(); allocation_size = original_copy.Size() + 1; } return true; } template inline void Queue::Clear ( void ) { if ( allocation_size == 0 ) return ; if (allocation_size > 32) { delete[] array; allocation_size = 0; } head = 0; tail = 0; } template void Queue::Compress ( void ) { queue_type* new_array; unsigned int newAllocationSize; if (allocation_size==0) return; newAllocationSize=1; while (newAllocationSize <= Size()) newAllocationSize<<=1; // Must be a better way to do this but I'm too dumb to figure it out quickly :) new_array = new queue_type [newAllocationSize]; for (unsigned int counter=0; counter < Size(); ++counter) new_array[counter] = array[(head + counter)%(allocation_size)]; tail=Size(); allocation_size=newAllocationSize; head=0; // Delete the old array and move the pointer to the new array delete [] array; array=new_array; } template bool Queue::Find ( queue_type q ) { if ( allocation_size == 0 ) return false; unsigned int counter = head; while ( counter != tail ) { if ( array[ counter ] == q ) return true; counter = ( counter + 1 ) % allocation_size; } return false; } template void Queue::ClearAndForceAllocation( int size ) { delete [] array; array = new queue_type[ size ]; allocation_size = size; head = 0; tail = 0; } template inline queue_type& Queue::operator[] ( unsigned int position ) const { #ifdef _DEBUG assert( position < Size() ); #endif //return array[(head + position) % allocation_size]; if ( head + position >= allocation_size ) return array[ head + position - allocation_size ]; else return array[ head + position ]; } template void Queue::RemoveAtIndex( unsigned int position ) { #ifdef _DEBUG assert( position < Size() ); assert( head != tail ); #endif if ( head == tail || position >= Size() ) return ; unsigned int index; unsigned int next; //index = (head + position) % allocation_size; if ( head + position >= allocation_size ) index = head + position - allocation_size; else index = head + position; //next = (index + 1) % allocation_size; next = index + 1; if ( next == allocation_size ) next = 0; while ( next != tail ) { // Overwrite the previous element array[ index ] = array[ next ]; index = next; //next = (next + 1) % allocation_size; if ( ++next == allocation_size ) next = 0; } // Move the tail back if ( tail == 0 ) tail = allocation_size - 1; else --tail; } } // End namespace #endif