DS_Queue.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. /// \file DS_Queue.h
  11. /// \internal
  12. /// \brief A queue used by RakNet.
  13. ///
  14. #ifndef __QUEUE_H
  15. #define __QUEUE_H
  16. // Template classes have to have all the code in the header file
  17. #include "RakAssert.h"
  18. #include "Export.h"
  19. #include "RakMemoryOverride.h"
  20. /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
  21. /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
  22. namespace DataStructures
  23. {
  24. /// \brief A queue implemented as an array with a read and write index.
  25. template <class queue_type>
  26. class RAK_DLL_EXPORT Queue
  27. {
  28. public:
  29. Queue();
  30. ~Queue();
  31. Queue( Queue& original_copy );
  32. bool operator= ( const Queue& original_copy );
  33. void Push( const queue_type& input, const char *file, unsigned int line );
  34. void PushAtHead( const queue_type& input, unsigned index, const char *file, unsigned int line );
  35. queue_type& operator[] ( unsigned int position ) const; // Not a normal thing you do with a queue but can be used for efficiency
  36. void RemoveAtIndex( unsigned int position ); // Not a normal thing you do with a queue but can be used for efficiency
  37. inline queue_type Peek( void ) const;
  38. inline queue_type PeekTail( void ) const;
  39. inline queue_type Pop( void );
  40. inline queue_type PopTail( void );
  41. // Debug: Set pointer to 0, for memory leak detection
  42. inline queue_type PopDeref( void );
  43. inline unsigned int Size( void ) const;
  44. inline bool IsEmpty(void) const;
  45. inline unsigned int AllocationSize( void ) const;
  46. inline void Clear( const char *file, unsigned int line );
  47. void Compress( const char *file, unsigned int line );
  48. bool Find ( const queue_type& q );
  49. void ClearAndForceAllocation( int size, const char *file, unsigned int line ); // Force a memory allocation to a certain larger size
  50. private:
  51. queue_type* array;
  52. unsigned int head; // Array index for the head of the queue
  53. unsigned int tail; // Array index for the tail of the queue
  54. unsigned int allocation_size;
  55. };
  56. template <class queue_type>
  57. inline unsigned int Queue<queue_type>::Size( void ) const
  58. {
  59. if ( head <= tail )
  60. return tail -head;
  61. else
  62. return allocation_size -head + tail;
  63. }
  64. template <class queue_type>
  65. inline bool Queue<queue_type>::IsEmpty(void) const
  66. {
  67. return head==tail;
  68. }
  69. template <class queue_type>
  70. inline unsigned int Queue<queue_type>::AllocationSize( void ) const
  71. {
  72. return allocation_size;
  73. }
  74. template <class queue_type>
  75. Queue<queue_type>::Queue()
  76. {
  77. //allocation_size = 16;
  78. //array = RakNet::OP_NEW_ARRAY<queue_type>(allocation_size, _FILE_AND_LINE_ );
  79. allocation_size = 0;
  80. array=0;
  81. head = 0;
  82. tail = 0;
  83. }
  84. template <class queue_type>
  85. Queue<queue_type>::~Queue()
  86. {
  87. if (allocation_size>0)
  88. RakNet::OP_DELETE_ARRAY(array, _FILE_AND_LINE_);
  89. }
  90. template <class queue_type>
  91. inline queue_type Queue<queue_type>::Pop( void )
  92. {
  93. #ifdef _DEBUG
  94. RakAssert( head != tail);
  95. #endif
  96. //head=(head+1) % allocation_size;
  97. if ( ++head == allocation_size )
  98. head = 0;
  99. if ( head == 0 )
  100. return ( queue_type ) array[ allocation_size -1 ];
  101. return ( queue_type ) array[ head -1 ];
  102. }
  103. template <class queue_type>
  104. inline queue_type Queue<queue_type>::PopTail( void )
  105. {
  106. #ifdef _DEBUG
  107. RakAssert( head != tail );
  108. #endif
  109. if (tail!=0)
  110. {
  111. --tail;
  112. return ( queue_type ) array[ tail ];
  113. }
  114. else
  115. {
  116. tail=allocation_size-1;
  117. return ( queue_type ) array[ tail ];
  118. }
  119. }
  120. template <class queue_type>
  121. inline queue_type Queue<queue_type>::PopDeref( void )
  122. {
  123. if ( ++head == allocation_size )
  124. head = 0;
  125. queue_type q;
  126. if ( head == 0 )
  127. {
  128. q=array[ allocation_size -1 ];
  129. array[ allocation_size -1 ]=0;
  130. return q;
  131. }
  132. q=array[ head -1 ];
  133. array[ head -1 ]=0;
  134. return q;
  135. }
  136. template <class queue_type>
  137. void Queue<queue_type>::PushAtHead( const queue_type& input, unsigned index, const char *file, unsigned int line )
  138. {
  139. RakAssert(index <= Size());
  140. // Just force a reallocation, will be overwritten
  141. Push(input, file, line );
  142. if (Size()==1)
  143. return;
  144. unsigned writeIndex, readIndex, trueWriteIndex, trueReadIndex;
  145. writeIndex=Size()-1;
  146. readIndex=writeIndex-1;
  147. while (readIndex >= index)
  148. {
  149. if ( head + writeIndex >= allocation_size )
  150. trueWriteIndex = head + writeIndex - allocation_size;
  151. else
  152. trueWriteIndex = head + writeIndex;
  153. if ( head + readIndex >= allocation_size )
  154. trueReadIndex = head + readIndex - allocation_size;
  155. else
  156. trueReadIndex = head + readIndex;
  157. array[trueWriteIndex]=array[trueReadIndex];
  158. if (readIndex==0)
  159. break;
  160. writeIndex--;
  161. readIndex--;
  162. }
  163. if ( head + index >= allocation_size )
  164. trueWriteIndex = head + index - allocation_size;
  165. else
  166. trueWriteIndex = head + index;
  167. array[trueWriteIndex]=input;
  168. }
  169. template <class queue_type>
  170. inline queue_type Queue<queue_type>::Peek( void ) const
  171. {
  172. #ifdef _DEBUG
  173. RakAssert( head != tail );
  174. #endif
  175. return ( queue_type ) array[ head ];
  176. }
  177. template <class queue_type>
  178. inline queue_type Queue<queue_type>::PeekTail( void ) const
  179. {
  180. #ifdef _DEBUG
  181. RakAssert( head != tail );
  182. #endif
  183. if (tail!=0)
  184. return ( queue_type ) array[ tail-1 ];
  185. else
  186. return ( queue_type ) array[ allocation_size-1 ];
  187. }
  188. template <class queue_type>
  189. void Queue<queue_type>::Push( const queue_type& input, const char *file, unsigned int line )
  190. {
  191. if ( allocation_size == 0 )
  192. {
  193. array = RakNet::OP_NEW_ARRAY<queue_type>(16, file, line );
  194. head = 0;
  195. tail = 1;
  196. array[ 0 ] = input;
  197. allocation_size = 16;
  198. return ;
  199. }
  200. array[ tail++ ] = input;
  201. if ( tail == allocation_size )
  202. tail = 0;
  203. if ( tail == head )
  204. {
  205. // unsigned int index=tail;
  206. // Need to allocate more memory.
  207. queue_type * new_array;
  208. new_array = RakNet::OP_NEW_ARRAY<queue_type>((int)allocation_size * 2, file, line );
  209. #ifdef _DEBUG
  210. RakAssert( new_array );
  211. #endif
  212. if (new_array==0)
  213. return;
  214. for ( unsigned int counter = 0; counter < allocation_size; ++counter )
  215. new_array[ counter ] = array[ ( head + counter ) % ( allocation_size ) ];
  216. head = 0;
  217. tail = allocation_size;
  218. allocation_size *= 2;
  219. // Delete the old array and move the pointer to the new array
  220. RakNet::OP_DELETE_ARRAY(array, file, line);
  221. array = new_array;
  222. }
  223. }
  224. template <class queue_type>
  225. Queue<queue_type>::Queue( Queue& original_copy )
  226. {
  227. // Allocate memory for copy
  228. if ( original_copy.Size() == 0 )
  229. {
  230. allocation_size = 0;
  231. }
  232. else
  233. {
  234. array = RakNet::OP_NEW_ARRAY<queue_type >( original_copy.Size() + 1 , _FILE_AND_LINE_ );
  235. for ( unsigned int counter = 0; counter < original_copy.Size(); ++counter )
  236. array[ counter ] = original_copy.array[ ( original_copy.head + counter ) % ( original_copy.allocation_size ) ];
  237. head = 0;
  238. tail = original_copy.Size();
  239. allocation_size = original_copy.Size() + 1;
  240. }
  241. }
  242. template <class queue_type>
  243. bool Queue<queue_type>::operator= ( const Queue& original_copy )
  244. {
  245. if ( ( &original_copy ) == this )
  246. return false;
  247. Clear(_FILE_AND_LINE_);
  248. // Allocate memory for copy
  249. if ( original_copy.Size() == 0 )
  250. {
  251. allocation_size = 0;
  252. }
  253. else
  254. {
  255. array = RakNet::OP_NEW_ARRAY<queue_type >( original_copy.Size() + 1 , _FILE_AND_LINE_ );
  256. for ( unsigned int counter = 0; counter < original_copy.Size(); ++counter )
  257. array[ counter ] = original_copy.array[ ( original_copy.head + counter ) % ( original_copy.allocation_size ) ];
  258. head = 0;
  259. tail = original_copy.Size();
  260. allocation_size = original_copy.Size() + 1;
  261. }
  262. return true;
  263. }
  264. template <class queue_type>
  265. inline void Queue<queue_type>::Clear ( const char *file, unsigned int line )
  266. {
  267. if ( allocation_size == 0 )
  268. return ;
  269. if (allocation_size > 32)
  270. {
  271. RakNet::OP_DELETE_ARRAY(array, file, line);
  272. allocation_size = 0;
  273. }
  274. head = 0;
  275. tail = 0;
  276. }
  277. template <class queue_type>
  278. void Queue<queue_type>::Compress ( const char *file, unsigned int line )
  279. {
  280. queue_type* new_array;
  281. unsigned int newAllocationSize;
  282. if (allocation_size==0)
  283. return;
  284. newAllocationSize=1;
  285. while (newAllocationSize <= Size())
  286. newAllocationSize<<=1; // Must be a better way to do this but I'm too dumb to figure it out quickly :)
  287. new_array = RakNet::OP_NEW_ARRAY<queue_type >(newAllocationSize, file, line );
  288. for (unsigned int counter=0; counter < Size(); ++counter)
  289. new_array[counter] = array[(head + counter)%(allocation_size)];
  290. tail=Size();
  291. allocation_size=newAllocationSize;
  292. head=0;
  293. // Delete the old array and move the pointer to the new array
  294. RakNet::OP_DELETE_ARRAY(array, file, line);
  295. array=new_array;
  296. }
  297. template <class queue_type>
  298. bool Queue<queue_type>::Find ( const queue_type &q )
  299. {
  300. if ( allocation_size == 0 )
  301. return false;
  302. unsigned int counter = head;
  303. while ( counter != tail )
  304. {
  305. if ( array[ counter ] == q )
  306. return true;
  307. counter = ( counter + 1 ) % allocation_size;
  308. }
  309. return false;
  310. }
  311. template <class queue_type>
  312. void Queue<queue_type>::ClearAndForceAllocation( int size, const char *file, unsigned int line )
  313. {
  314. RakNet::OP_DELETE_ARRAY(array, file, line);
  315. if (size>0)
  316. array = RakNet::OP_NEW_ARRAY<queue_type>(size, file, line );
  317. else
  318. array=0;
  319. allocation_size = size;
  320. head = 0;
  321. tail = 0;
  322. }
  323. template <class queue_type>
  324. inline queue_type& Queue<queue_type>::operator[] ( unsigned int position ) const
  325. {
  326. #ifdef _DEBUG
  327. RakAssert( position < Size() );
  328. #endif
  329. //return array[(head + position) % allocation_size];
  330. if ( head + position >= allocation_size )
  331. return array[ head + position - allocation_size ];
  332. else
  333. return array[ head + position ];
  334. }
  335. template <class queue_type>
  336. void Queue<queue_type>::RemoveAtIndex( unsigned int position )
  337. {
  338. #ifdef _DEBUG
  339. RakAssert( position < Size() );
  340. RakAssert( head != tail );
  341. #endif
  342. if ( head == tail || position >= Size() )
  343. return ;
  344. unsigned int index;
  345. unsigned int next;
  346. //index = (head + position) % allocation_size;
  347. if ( head + position >= allocation_size )
  348. index = head + position - allocation_size;
  349. else
  350. index = head + position;
  351. //next = (index + 1) % allocation_size;
  352. next = index + 1;
  353. if ( next == allocation_size )
  354. next = 0;
  355. while ( next != tail )
  356. {
  357. // Overwrite the previous element
  358. array[ index ] = array[ next ];
  359. index = next;
  360. //next = (next + 1) % allocation_size;
  361. if ( ++next == allocation_size )
  362. next = 0;
  363. }
  364. // Move the tail back
  365. if ( tail == 0 )
  366. tail = allocation_size - 1;
  367. else
  368. --tail;
  369. }
  370. } // End namespace
  371. #endif
粤ICP备19079148号