DS_List.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  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_List.h
  11. /// \internal
  12. /// \brief Array based list.
  13. /// \details Usually the Queue class is used instead, since it has all the same functionality and is only worse at random access.
  14. ///
  15. #ifndef __LIST_H
  16. #define __LIST_H
  17. #include "RakAssert.h"
  18. #include <string.h> // memmove
  19. #include "Export.h"
  20. #include "RakMemoryOverride.h"
  21. /// Maximum unsigned long
  22. static const unsigned int MAX_UNSIGNED_LONG = 4294967295U;
  23. /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
  24. /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
  25. namespace DataStructures
  26. {
  27. /// \brief Array based implementation of a list.
  28. /// \note ONLY USE THIS FOR SHALLOW COPIES. I don't bother with operator= to improve performance.
  29. template <class list_type>
  30. class RAK_DLL_EXPORT List
  31. {
  32. public:
  33. /// Default constructor
  34. List();
  35. // Destructor
  36. ~List();
  37. /// \brief Copy constructor.
  38. /// \param[in] original_copy The list to duplicate
  39. List( const List& original_copy );
  40. /// \brief Assign one list to another.
  41. List& operator= ( const List& original_copy );
  42. /// \brief Access an element by its index in the array.
  43. /// \param[in] position The index into the array.
  44. /// \return The element at position \a position.
  45. list_type& operator[] ( const unsigned int position ) const;
  46. /// \brief Access an element by its index in the array.
  47. /// \param[in] position The index into the array.
  48. /// \return The element at position \a position.
  49. list_type& Get ( const unsigned int position ) const;
  50. /// \brief Push an element at the end of the stack.
  51. /// \param[in] input The new element.
  52. void Push(const list_type &input, const char *file, unsigned int line );
  53. /// \brief Pop an element from the end of the stack.
  54. /// \pre Size()>0
  55. /// \return The element at the end.
  56. list_type& Pop(void);
  57. /// \brief Insert an element at position \a position in the list.
  58. /// \param[in] input The new element.
  59. /// \param[in] position The position of the new element.
  60. void Insert( const list_type &input, const unsigned int position, const char *file, unsigned int line );
  61. /// \brief Insert at the end of the list.
  62. /// \param[in] input The new element.
  63. void Insert( const list_type &input, const char *file, unsigned int line );
  64. /// \brief Replace the value at \a position by \a input.
  65. /// \details If the size of the list is less than @em position, it increase the capacity of
  66. /// the list and fill slot with @em filler.
  67. /// \param[in] input The element to replace at position @em position.
  68. /// \param[in] filler The element use to fill new allocated capacity.
  69. /// \param[in] position The position of input in the list.
  70. void Replace( const list_type &input, const list_type filler, const unsigned int position, const char *file, unsigned int line );
  71. /// \brief Replace the last element of the list by \a input.
  72. /// \param[in] input The element used to replace the last element.
  73. void Replace( const list_type &input );
  74. /// \brief Delete the element at position \a position.
  75. /// \param[in] position The index of the element to delete
  76. void RemoveAtIndex( const unsigned int position );
  77. /// \brief Delete the element at position \a position.
  78. /// \note - swaps middle with end of list, only use if list order does not matter
  79. /// \param[in] position The index of the element to delete
  80. void RemoveAtIndexFast( const unsigned int position );
  81. /// \brief Delete the element at the end of the list.
  82. void RemoveFromEnd(const unsigned num=1);
  83. /// \brief Returns the index of the specified item or MAX_UNSIGNED_LONG if not found.
  84. /// \param[in] input The element to check for
  85. /// \return The index or position of @em input in the list.
  86. /// \retval MAX_UNSIGNED_LONG The object is not in the list
  87. /// \retval [Integer] The index of the element in the list
  88. unsigned int GetIndexOf( const list_type &input ) const;
  89. /// \return The number of elements in the list
  90. unsigned int Size( void ) const;
  91. /// \brief Clear the list
  92. void Clear( bool doNotDeallocateSmallBlocks, const char *file, unsigned int line );
  93. /// \brief Preallocate the list, so it needs fewer reallocations at runtime.
  94. void Preallocate( unsigned countNeeded, const char *file, unsigned int line );
  95. /// \brief Frees overallocated members, to use the minimum memory necessary.
  96. /// \attention
  97. /// This is a slow operation
  98. void Compress( const char *file, unsigned int line );
  99. private:
  100. /// An array of user values
  101. list_type* listArray;
  102. /// Number of elements in the list
  103. unsigned int list_size;
  104. /// Size of \a array
  105. unsigned int allocation_size;
  106. };
  107. template <class list_type>
  108. List<list_type>::List()
  109. {
  110. allocation_size = 0;
  111. listArray = 0;
  112. list_size = 0;
  113. }
  114. template <class list_type>
  115. List<list_type>::~List()
  116. {
  117. if (allocation_size>0)
  118. RakNet::OP_DELETE_ARRAY(listArray, _FILE_AND_LINE_);
  119. }
  120. template <class list_type>
  121. List<list_type>::List( const List& original_copy )
  122. {
  123. // Allocate memory for copy
  124. if ( original_copy.list_size == 0 )
  125. {
  126. list_size = 0;
  127. allocation_size = 0;
  128. }
  129. else
  130. {
  131. listArray = RakNet::OP_NEW_ARRAY<list_type >( original_copy.list_size , _FILE_AND_LINE_ );
  132. for ( unsigned int counter = 0; counter < original_copy.list_size; ++counter )
  133. listArray[ counter ] = original_copy.listArray[ counter ];
  134. // Don't call constructors, assignment operators, etc.
  135. //memcpy(listArray, original_copy.listArray, original_copy.list_size*sizeof(list_type));
  136. list_size = allocation_size = original_copy.list_size;
  137. }
  138. }
  139. template <class list_type>
  140. List<list_type>& List<list_type>::operator= ( const List& original_copy )
  141. {
  142. if ( ( &original_copy ) != this )
  143. {
  144. Clear( false, _FILE_AND_LINE_ );
  145. // Allocate memory for copy
  146. if ( original_copy.list_size == 0 )
  147. {
  148. list_size = 0;
  149. allocation_size = 0;
  150. }
  151. else
  152. {
  153. listArray = RakNet::OP_NEW_ARRAY<list_type >( original_copy.list_size , _FILE_AND_LINE_ );
  154. for ( unsigned int counter = 0; counter < original_copy.list_size; ++counter )
  155. listArray[ counter ] = original_copy.listArray[ counter ];
  156. // Don't call constructors, assignment operators, etc.
  157. //memcpy(listArray, original_copy.listArray, original_copy.list_size*sizeof(list_type));
  158. list_size = allocation_size = original_copy.list_size;
  159. }
  160. }
  161. return *this;
  162. }
  163. template <class list_type>
  164. inline list_type& List<list_type>::operator[] ( const unsigned int position ) const
  165. {
  166. #ifdef _DEBUG
  167. if (position>=list_size)
  168. {
  169. RakAssert ( position < list_size );
  170. }
  171. #endif
  172. return listArray[ position ];
  173. }
  174. // Just here for debugging
  175. template <class list_type>
  176. inline list_type& List<list_type>::Get ( const unsigned int position ) const
  177. {
  178. return listArray[ position ];
  179. }
  180. template <class list_type>
  181. void List<list_type>::Push(const list_type &input, const char *file, unsigned int line)
  182. {
  183. Insert(input, file, line);
  184. }
  185. template <class list_type>
  186. inline list_type& List<list_type>::Pop(void)
  187. {
  188. #ifdef _DEBUG
  189. RakAssert(list_size>0);
  190. #endif
  191. --list_size;
  192. return listArray[list_size];
  193. }
  194. template <class list_type>
  195. void List<list_type>::Insert( const list_type &input, const unsigned int position, const char *file, unsigned int line )
  196. {
  197. #ifdef _DEBUG
  198. if (position>list_size)
  199. {
  200. RakAssert( position <= list_size );
  201. }
  202. #endif
  203. // Reallocate list if necessary
  204. if ( list_size == allocation_size )
  205. {
  206. // allocate twice the currently allocated memory
  207. list_type * new_array;
  208. if ( allocation_size == 0 )
  209. allocation_size = 16;
  210. else
  211. allocation_size *= 2;
  212. new_array = RakNet::OP_NEW_ARRAY<list_type >( allocation_size , file, line );
  213. // copy old array over
  214. for ( unsigned int counter = 0; counter < list_size; ++counter )
  215. new_array[ counter ] = listArray[ counter ];
  216. // Don't call constructors, assignment operators, etc.
  217. //memcpy(new_array, listArray, list_size*sizeof(list_type));
  218. // set old array to point to the newly allocated and twice as large array
  219. RakNet::OP_DELETE_ARRAY(listArray, file, line);
  220. listArray = new_array;
  221. }
  222. // Move the elements in the list to make room
  223. for ( unsigned int counter = list_size; counter != position; counter-- )
  224. listArray[ counter ] = listArray[ counter - 1 ];
  225. // Don't call constructors, assignment operators, etc.
  226. //memmove(listArray+position+1, listArray+position, (list_size-position)*sizeof(list_type));
  227. // Insert the new item at the correct spot
  228. listArray[ position ] = input;
  229. ++list_size;
  230. }
  231. template <class list_type>
  232. void List<list_type>::Insert( const list_type &input, const char *file, unsigned int line )
  233. {
  234. // Reallocate list if necessary
  235. if ( list_size == allocation_size )
  236. {
  237. // allocate twice the currently allocated memory
  238. list_type * new_array;
  239. if ( allocation_size == 0 )
  240. allocation_size = 16;
  241. else
  242. allocation_size *= 2;
  243. new_array = RakNet::OP_NEW_ARRAY<list_type >( allocation_size , file, line );
  244. if (listArray)
  245. {
  246. // copy old array over
  247. for ( unsigned int counter = 0; counter < list_size; ++counter )
  248. new_array[ counter ] = listArray[ counter ];
  249. // Don't call constructors, assignment operators, etc.
  250. //memcpy(new_array, listArray, list_size*sizeof(list_type));
  251. // set old array to point to the newly allocated and twice as large array
  252. RakNet::OP_DELETE_ARRAY(listArray, file, line);
  253. }
  254. listArray = new_array;
  255. }
  256. // Insert the new item at the correct spot
  257. listArray[ list_size ] = input;
  258. ++list_size;
  259. }
  260. template <class list_type>
  261. inline void List<list_type>::Replace( const list_type &input, const list_type filler, const unsigned int position, const char *file, unsigned int line )
  262. {
  263. if ( ( list_size > 0 ) && ( position < list_size ) )
  264. {
  265. // Direct replacement
  266. listArray[ position ] = input;
  267. }
  268. else
  269. {
  270. if ( position >= allocation_size )
  271. {
  272. // Reallocate the list to size position and fill in blanks with filler
  273. list_type * new_array;
  274. allocation_size = position + 1;
  275. new_array = RakNet::OP_NEW_ARRAY<list_type >( allocation_size , file, line );
  276. // copy old array over
  277. for ( unsigned int counter = 0; counter < list_size; ++counter )
  278. new_array[ counter ] = listArray[ counter ];
  279. // Don't call constructors, assignment operators, etc.
  280. //memcpy(new_array, listArray, list_size*sizeof(list_type));
  281. // set old array to point to the newly allocated array
  282. RakNet::OP_DELETE_ARRAY(listArray, file, line);
  283. listArray = new_array;
  284. }
  285. // Fill in holes with filler
  286. while ( list_size < position )
  287. listArray[ list_size++ ] = filler;
  288. // Fill in the last element with the new item
  289. listArray[ list_size++ ] = input;
  290. #ifdef _DEBUG
  291. RakAssert( list_size == position + 1 );
  292. #endif
  293. }
  294. }
  295. template <class list_type>
  296. inline void List<list_type>::Replace( const list_type &input )
  297. {
  298. if ( list_size > 0 )
  299. listArray[ list_size - 1 ] = input;
  300. }
  301. template <class list_type>
  302. void List<list_type>::RemoveAtIndex( const unsigned int position )
  303. {
  304. #ifdef _DEBUG
  305. if (position >= list_size)
  306. {
  307. RakAssert( position < list_size );
  308. return;
  309. }
  310. #endif
  311. if ( position < list_size )
  312. {
  313. // Compress the array
  314. for ( unsigned int counter = position; counter < list_size - 1 ; ++counter )
  315. listArray[ counter ] = listArray[ counter + 1 ];
  316. // Don't call constructors, assignment operators, etc.
  317. // memmove(listArray+position, listArray+position+1, (list_size-1-position) * sizeof(list_type));
  318. RemoveFromEnd();
  319. }
  320. }
  321. template <class list_type>
  322. void List<list_type>::RemoveAtIndexFast( const unsigned int position )
  323. {
  324. #ifdef _DEBUG
  325. if (position >= list_size)
  326. {
  327. RakAssert( position < list_size );
  328. return;
  329. }
  330. #endif
  331. --list_size;
  332. listArray[position]=listArray[list_size];
  333. }
  334. template <class list_type>
  335. inline void List<list_type>::RemoveFromEnd( const unsigned num )
  336. {
  337. // Delete the last elements on the list. No compression needed
  338. #ifdef _DEBUG
  339. RakAssert(list_size>=num);
  340. #endif
  341. list_size-=num;
  342. }
  343. template <class list_type>
  344. unsigned int List<list_type>::GetIndexOf( const list_type &input ) const
  345. {
  346. for ( unsigned int i = 0; i < list_size; ++i )
  347. if ( listArray[ i ] == input )
  348. return i;
  349. return MAX_UNSIGNED_LONG;
  350. }
  351. template <class list_type>
  352. inline unsigned int List<list_type>::Size( void ) const
  353. {
  354. return list_size;
  355. }
  356. template <class list_type>
  357. void List<list_type>::Clear( bool doNotDeallocateSmallBlocks, const char *file, unsigned int line )
  358. {
  359. if ( allocation_size == 0 )
  360. return;
  361. if (allocation_size>512 || doNotDeallocateSmallBlocks==false)
  362. {
  363. RakNet::OP_DELETE_ARRAY(listArray, file, line);
  364. allocation_size = 0;
  365. listArray = 0;
  366. }
  367. list_size = 0;
  368. }
  369. template <class list_type>
  370. void List<list_type>::Compress( const char *file, unsigned int line )
  371. {
  372. list_type * new_array;
  373. if ( allocation_size == 0 )
  374. return ;
  375. new_array = RakNet::OP_NEW_ARRAY<list_type >( allocation_size , file, line );
  376. // copy old array over
  377. for ( unsigned int counter = 0; counter < list_size; ++counter )
  378. new_array[ counter ] = listArray[ counter ];
  379. // Don't call constructors, assignment operators, etc.
  380. //memcpy(new_array, listArray, list_size*sizeof(list_type));
  381. // set old array to point to the newly allocated array
  382. RakNet::OP_DELETE_ARRAY(listArray, file, line);
  383. listArray = new_array;
  384. }
  385. template <class list_type>
  386. void List<list_type>::Preallocate( unsigned countNeeded, const char *file, unsigned int line )
  387. {
  388. unsigned amountToAllocate = allocation_size;
  389. if (allocation_size==0)
  390. amountToAllocate=16;
  391. while (amountToAllocate < countNeeded)
  392. amountToAllocate<<=1;
  393. if ( allocation_size < amountToAllocate)
  394. {
  395. // allocate twice the currently allocated memory
  396. list_type * new_array;
  397. allocation_size=amountToAllocate;
  398. new_array = RakNet::OP_NEW_ARRAY< list_type >( allocation_size , file, line );
  399. if (listArray)
  400. {
  401. // copy old array over
  402. for ( unsigned int counter = 0; counter < list_size; ++counter )
  403. new_array[ counter ] = listArray[ counter ];
  404. // Don't call constructors, assignment operators, etc.
  405. //memcpy(new_array, listArray, list_size*sizeof(list_type));
  406. // set old array to point to the newly allocated and twice as large array
  407. RakNet::OP_DELETE_ARRAY(listArray, file, line);
  408. }
  409. listArray = new_array;
  410. }
  411. }
  412. } // End namespace
  413. #endif
粤ICP备19079148号