ptrlist.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. #include "ptrlist.h"
  2. #include <bfc/bfc_assert.h>
  3. // if this symbol is enabled, do sanity checking in a bunch of methods
  4. //#define DO_VERIFY_PTRLIST
  5. #if defined(ASSERTS_ENABLED) && defined(DO_VERIFY_PTRLIST)
  6. #define VERIFY_PTRLIST verify()
  7. #else
  8. #define VERIFY_PTRLIST
  9. #endif
  10. #ifdef _DEBUG
  11. int ptrlist_totalnitems = 0;
  12. #endif
  13. PtrListRoot::PtrListRoot( int initial_size )
  14. {
  15. nitems = nslots = 0;
  16. items = NULL;
  17. //FG>why? we might as well save initial_size*4 bytes if nobody inserts anything in the list, no?
  18. //BU No. initial_size defaults to 0 and therefore no memory is actually
  19. //allocated in a typical construction. But, sometimes you want to start with
  20. //a specific size, generally when you know the exact size you want,
  21. //so that you can avoid REALLOCs when you initially populate the list.
  22. //FG>Ah, makes sense.
  23. setMinimumSize( initial_size );
  24. }
  25. PtrListRoot::PtrListRoot( const PtrListRoot *from )
  26. {
  27. nitems = nslots = 0;
  28. items = NULL;
  29. copyFrom( from );
  30. }
  31. PtrListRoot::~PtrListRoot()
  32. {
  33. removeAll();
  34. }
  35. void PtrListRoot::copyFrom( const PtrListRoot *from )
  36. {
  37. ASSERT( from != NULL );
  38. removeAll();
  39. appendFrom( from );
  40. VERIFY_PTRLIST;
  41. }
  42. void PtrListRoot::appendFrom( const PtrListRoot *from )
  43. {
  44. ASSERT( from != NULL );
  45. int n = from->getNumItems();
  46. if ( n <= 0 )
  47. return;
  48. void **mem = from->getItemList();
  49. ASSERT( mem != NULL ); // can't be NULL if getNumItems() >= 1
  50. setMinimumSize( getNumItems() + n );
  51. MEMCPY( items + getNumItems(), from->getItemList(), sizeof( void * ) * n );
  52. nitems += n;
  53. #ifdef _DEBUG
  54. ptrlist_totalnitems += n;
  55. #endif
  56. VERIFY_PTRLIST;
  57. }
  58. void PtrListRoot::setMinimumSize( int _nslots )
  59. {
  60. ASSERT( _nslots >= 0 );
  61. #ifdef DECREASE_PTRLISTS_SIZE
  62. if ( _nslots + 2 * DEF_PTRLIST_INCREMENT < nslots )
  63. {
  64. nslots = ( ( _nslots / DEF_PTRLIST_INCREMENT ) + 2 ) * DEF_PTRLIST_INCREMENT;
  65. items = (void **) REALLOC( items, sizeof( void * ) * nslots );
  66. }
  67. #endif
  68. if ( _nslots == 0 || _nslots <= nslots )
  69. return;
  70. nslots = _nslots;
  71. if ( items )
  72. items = (void **) REALLOC( items, sizeof( void * ) * nslots );
  73. else
  74. items = (void **) MALLOC( sizeof( void * ) * nslots );
  75. VERIFY_PTRLIST;
  76. }
  77. int PtrListRoot::getNumItems() const
  78. {
  79. return nitems;
  80. }
  81. void *PtrListRoot::enumItem( int n ) const
  82. {
  83. if ( items == NULL || n < 0 || n >= nitems )
  84. return NULL;
  85. return items[ n ];
  86. }
  87. void *PtrListRoot::addItem( void *item, int pos, int increment )
  88. {
  89. ASSERT( increment > 0 );
  90. ASSERTPR( item != NULL, "can't put NULLs into ptrlists" );
  91. ASSERT( nitems <= nslots );
  92. #ifdef DECREASE_PTRLISTS_SIZE
  93. // expand or shrink as necessary
  94. if ( items == NULL || nslots == nitems )
  95. setMinimumSize( nslots + increment );
  96. else
  97. setMinimumSize( nitems );
  98. #else
  99. // expand if necessary
  100. if ( items == NULL || nslots == nitems )
  101. setMinimumSize( nslots + increment );
  102. #endif
  103. items[ nitems++ ] = item;
  104. if ( pos != PTRLIST_POS_LAST )
  105. moveItem( nitems - 1, pos );
  106. VERIFY_PTRLIST;
  107. #ifdef _DEBUG
  108. ptrlist_totalnitems++;
  109. #endif
  110. return item;
  111. }
  112. // replace what's in the slot with the new value
  113. void *PtrListRoot::setItem( void *item, int pos )
  114. {
  115. ASSERT( nitems >= pos );
  116. items[ pos ] = item;
  117. VERIFY_PTRLIST;
  118. return item;
  119. }
  120. void PtrListRoot::reverse()
  121. {
  122. if ( nitems <= 1 )
  123. return;
  124. MemBlock<void *> block( nitems, items );
  125. void **blockmem = block.getMemory();
  126. for ( int i = 0, j = nitems - 1; j >= 0; i++, j-- )
  127. {
  128. items[ i ] = blockmem[ j ];
  129. }
  130. }
  131. void PtrListRoot::moveItem( int from, int to )
  132. {
  133. if ( from == to )
  134. return;
  135. void *ptr = items[ from ];
  136. if ( nitems > from + 1 ) // if moving from the end, there is nothing to shift behind our src position
  137. {
  138. //IMPORTANT note for future ports: This assumes MEMCPY accepts overlapping segments.
  139. MEMCPY( &items[ from ], &items[ from + 1 ], ( nitems - from ) * sizeof( void * ) );
  140. }
  141. if ( to > from )
  142. to--;
  143. if ( nitems > to ) // if moving to the end, there is nothing to shift behind our target position
  144. MEMCPY( &items[ to + 1 ], &items[ to ], ( nitems - to - 1 ) * sizeof( void * ) );
  145. items[ to ] = ptr;
  146. VERIFY_PTRLIST;
  147. }
  148. int PtrListRoot::removeItem( void *item )
  149. {
  150. int c = 0;
  151. if ( item == NULL || items == NULL || nitems <= 0 )
  152. return 0;
  153. // count occurences of item in items, remember the first one
  154. void **p = items;
  155. int first = -1;
  156. for ( int i = 0; i < nitems; i++, p++ )
  157. {
  158. if ( *p == item )
  159. {
  160. if ( c++ == 0 )
  161. first = i;
  162. }
  163. }
  164. // if we found one, remove it
  165. if ( c > 0 )
  166. {
  167. removeByPos( first ); // delByPos is faaast
  168. c--; // decrease count
  169. }
  170. VERIFY_PTRLIST;
  171. return c; // returns how many occurences of this item left
  172. }
  173. void PtrListRoot::removeEveryItem( void *item )
  174. {
  175. while ( removeItem( item ) );
  176. VERIFY_PTRLIST;
  177. }
  178. void PtrListRoot::removeByPos( int pos )
  179. {
  180. if ( pos < 0 || pos >= nitems )
  181. return; //JC
  182. --nitems;
  183. #ifdef _DEBUG
  184. ptrlist_totalnitems--;
  185. #endif
  186. if ( pos == nitems )
  187. return; // last one? nothing to copy over
  188. MEMCPY( items + pos, items + ( pos + 1 ), sizeof( void * ) * ( nitems - pos ) ); // CT:not (nitems-(pos+1)) as nitems has been decremented earlier
  189. #ifdef DECREASE_PTRLISTS_SIZE
  190. // shrink if necessary
  191. setMinimumSize( nitems );
  192. #endif
  193. VERIFY_PTRLIST;
  194. }
  195. void PtrListRoot::removeLastItem()
  196. {
  197. if ( nitems == 0 || items == NULL ) return;
  198. nitems--; // hee hee
  199. #ifdef _DEBUG
  200. ptrlist_totalnitems--;
  201. #endif
  202. #ifdef DECREASE_PTRLISTS_SIZE
  203. // shrink if necessary
  204. setMinimumSize( nitems );
  205. #endif
  206. VERIFY_PTRLIST;
  207. }
  208. void PtrListRoot::removeAll()
  209. {
  210. FREE( items ); items = NULL;
  211. #ifdef _DEBUG
  212. ptrlist_totalnitems -= nitems;
  213. #endif
  214. #ifdef DECREASE_PTRLISTS_SIZE
  215. // shrink if necessary
  216. setMinimumSize( nitems );
  217. #endif
  218. nitems = 0;
  219. nslots = 0;
  220. VERIFY_PTRLIST;
  221. }
  222. void PtrListRoot::freeAll()
  223. {
  224. for ( int i = 0; i < nitems; i++ ) //JC
  225. if ( items ) FREE( items[ i ] );
  226. removeAll();
  227. VERIFY_PTRLIST;
  228. }
  229. int PtrListRoot::searchItem( void *item ) const
  230. {
  231. for ( int i = 0; i < nitems; i++ )
  232. if ( items[ i ] == item )
  233. return i;
  234. return -1;
  235. }
  236. void PtrListRoot::verify()
  237. {
  238. #ifdef DO_VERIFY_PTRLIST
  239. ASSERT( nitems >= 0 );
  240. ASSERT( nslots >= 0 );
  241. ASSERT( nitems <= nslots );
  242. #endif
  243. }
  244. #if 0
  245. int PtrListRoot::bsearchItem( void *item ) const
  246. {
  247. // do binary search
  248. if ( nitems == 0 || items == NULL ) return -1;
  249. int bot = 0, top = nitems - 1, mid;
  250. for ( int c = 0; c < nitems + 16; c++ )
  251. {
  252. if ( bot > top ) return -1;
  253. mid = ( bot + top ) / 2;
  254. if ( item == items[ mid ] ) return mid;
  255. if ( item < items[ mid ] ) top = mid - 1;
  256. else bot = mid + 1;
  257. }
  258. ASSERTPR( 0, "binary search fucked up" );
  259. return -1;
  260. }
  261. #endif
  262. void PtrListRoot::purge()
  263. {
  264. ASSERT( nitems == 0 );
  265. if ( items != NULL )
  266. {
  267. FREE( items );
  268. items = NULL;
  269. }
  270. }