1
0

ptrlist.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. #ifndef _PTRLIST_H
  2. #define _PTRLIST_H
  3. #include <bfc/std_math.h>
  4. //#include <bfc/memblock.h>
  5. #include <bfc/bfc_assert.h>
  6. #include <bfc/platform/platform.h>
  7. //#include <wasabicfg.h>
  8. #ifdef _DEBUG
  9. extern int ptrlist_totalnitems;
  10. #endif
  11. // Disable the "identifier was truncated to '255' characters..." warning.
  12. #pragma warning( disable : 4786 )
  13. /*
  14. a generic pointer list template. only takes up 12 bytes when empty. auto-grows
  15. the array as necessary, NEVER shrinks it unless you removeAll() or equivalent
  16. Use, PtrList<typename>, never PtrListRoot
  17. */
  18. // yes, this really should be an enum or something
  19. #define PTRLIST_POS_LAST -1
  20. // 4k each, leaving 16 bytes for MALLOC overhead
  21. //#define DEF_PTRLIST_INCREMENT (4096/sizeof(void*)-16)
  22. // in average, 4k doubles the VM working set of a skin, 128bytes (32 elements) seems most optimal
  23. #define DEF_PTRLIST_INCREMENT (128)
  24. class __foreach;
  25. // base class, to share as much code as possible
  26. class NOVTABLE PtrListRoot
  27. {
  28. friend class __foreach;
  29. protected:
  30. PtrListRoot(int initial_size = 0);
  31. PtrListRoot(const PtrListRoot *from);
  32. virtual ~PtrListRoot();
  33. void copyFrom(const PtrListRoot *from);
  34. void appendFrom(const PtrListRoot *from);
  35. void setMinimumSize(int nslots); // expand to at least this many slots
  36. int getNumItems() const;
  37. int size() const { return nitems; }
  38. bool empty() { return nitems == 0; }
  39. void *enumItem(int n) const;
  40. void moveItem(int from, int to);
  41. int removeItem(void *item);
  42. void removeEveryItem(void *item);
  43. void removeByPos(int pos);
  44. void removeLastItem();
  45. void removeAll();
  46. void freeAll();
  47. void purge();
  48. // gross-ass linear search to find index of item
  49. // note that PtrListSorted provides a binary search version
  50. int searchItem(void *item) const;
  51. #if 0//fuct
  52. // speedy binary search. although it'll be fuct if it's not sorted right
  53. int bsearchItem(void *item) const;
  54. #endif
  55. void *addItem(void *item, int pos, int inc);
  56. void *setItem(void *item, int pos); // replace what's in the slot with the new value
  57. void reverse();
  58. void **getItemList() const { return items; } // try to avoid! this is inline to make q() fast
  59. private:
  60. #undef verify // for Mac
  61. void verify();
  62. int nitems, nslots;
  63. void **items;
  64. };
  65. // now we add the methods that refer specifically to the pointer type
  66. template <class T>
  67. class PtrList : public PtrListRoot
  68. {
  69. friend class __foreach;
  70. public:
  71. PtrList(int initial_size = 0) {}
  72. PtrList(const PtrList<T> &r) { copyFrom(&r); }
  73. PtrList(const PtrList<T> *r) { copyFrom(r); }
  74. ~PtrList() {}
  75. // copy another PtrList
  76. // deletes previous contents
  77. void copyFrom(const PtrList<T> *from) { PtrListRoot::copyFrom(from); }
  78. // append contents of another PtrList to the end of this one
  79. // preserves previous contents
  80. void appendFrom(const PtrList<T> *from) { PtrListRoot::appendFrom(from); }
  81. // adding
  82. // expand freelist to at least this many slots, even if 0 items in list
  83. void setMinimumSize(int nslots) { PtrListRoot::setMinimumSize(nslots); }
  84. // provide a public addItem for the pointer type
  85. T *addItem(const T *item, int pos = PTRLIST_POS_LAST, int inc = DEF_PTRLIST_INCREMENT)
  86. {
  87. return static_cast<T *>(PtrListRoot::addItem(const_cast<T*>(item), pos, inc));
  88. }
  89. void push_back(const T* item) { return addItem(item); }
  90. // replace what's in the slot with the new value
  91. T *setItem(const T *item, int pos) { return static_cast<T *>(PtrListRoot::setItem(const_cast<T*>(item), pos)); }
  92. // reverse the order of the list in place
  93. void reverse() { PtrListRoot::reverse(); }
  94. // enumerating
  95. // returns # of items in list
  96. int getNumItems() const { return PtrListRoot::getNumItems(); }
  97. // basic list enumerator. returns NULL for out of bounds
  98. T *enumItem(int n) const { return static_cast<T *>(PtrListRoot::enumItem(n)); }
  99. T *operator[](int n) const { return enumItem(n); }
  100. // this will safely return NULL if 0 items due to enumItems's boundscheck
  101. T *getFirst() const { return enumItem(0); }
  102. T *getLast() const { return enumItem(getNumItems() - 1); }
  103. // this is a NON-BOUNDS-CHECKING lookup
  104. T *q(int n) { return static_cast<T*>(getItemList()[n]); }
  105. // gross-ass linear search to find index of item
  106. // note that PtrListSorted provides a binary search version
  107. int searchItem(T *item) const { return PtrListRoot::searchItem(item); }
  108. int haveItem(T *item) const { return searchItem(item) >= 0; }
  109. // deleteing
  110. // removes first instance of a pointer in list, returns how many are left
  111. int removeItem(T *item) { return PtrListRoot::removeItem(item); }
  112. //DEPRECATED
  113. int delItem(T *item) { return removeItem(item); }
  114. // removes all instances of this pointer
  115. void removeEveryItem(const T *item) { PtrListRoot::removeEveryItem(const_cast<T*>(item)); }
  116. // removes pointer at specified position regardless of value
  117. void removeByPos(int pos) { PtrListRoot::removeByPos(pos); }
  118. // DEPRECATED
  119. void delByPos(int pos) { removeByPos(pos); }
  120. // removes last item
  121. void removeLastItem() { PtrListRoot::removeLastItem(); }
  122. // removes all entries, also deletes memory space
  123. void removeAll() { PtrListRoot::removeAll(); }
  124. // removes all entries, calling FREE on the pointers
  125. void freeAll() { PtrListRoot::freeAll(); }
  126. // removes all entries, calling delete on the pointers
  127. void deleteAll()
  128. {
  129. int i, nitems = getNumItems();
  130. for (i = 0; i < nitems; i++)
  131. delete enumItem(i);
  132. removeAll();
  133. }
  134. // removes all entries, calling delete on the pointers
  135. // FG>this version removes each entry as it deletes it so if
  136. // one of the object uses this list in its destructor, it will
  137. // still work. It is MUCH slower than deleteAll tho.
  138. void deleteAllSafe()
  139. {
  140. //CUT ASSERT(!(nitems != 0 && items == NULL));
  141. while (getNumItems())
  142. {
  143. T *i = enumItem(0);
  144. delete i;
  145. removeItem(i);
  146. }
  147. }
  148. void deleteItem(int item)
  149. {
  150. if (item < getNumItems())
  151. {
  152. deleteItem(enumItem(item));
  153. }
  154. }
  155. void deleteItem(T *item)
  156. {
  157. delete item;
  158. removeItem(item);
  159. }
  160. void moveItem(int from, int to) { PtrListRoot::moveItem(from, to); }
  161. static T *castFor(void *ptr) { return static_cast<T*>(ptr); }
  162. using PtrListRoot::purge;
  163. protected:
  164. T **getItemList()
  165. {
  166. return reinterpret_cast<T **>(PtrListRoot::getItemList());
  167. }
  168. };
  169. class NotSorted
  170. {
  171. public:
  172. // comparator for searching -- override
  173. static int compareAttrib(const wchar_t *attrib, void *item) { return 0; }
  174. // comparator for sorting -- override , -1 p1 < p2, 0 eq, 1 p1 > p2
  175. static int compareItem(void *p1, void* p2) { return CMP3(p1, p2); }
  176. };
  177. //template <class T, class C> class NoSort {
  178. // static void _sort(T **, int) {}
  179. //};
  180. // a base class to sort the pointers
  181. // you must implement the comparisons (C) and the sort algorithm (S)
  182. template < class T, class C, class S >
  183. class PtrListSorted : public PtrList<T>
  184. {
  185. public:
  186. PtrListSorted(int initial_size = 0) : PtrList<T>(initial_size)
  187. {
  188. need_sorting = 0;
  189. auto_sort = true;
  190. dups_low = dups_hi = dups_pos = 0;
  191. }
  192. void copyFrom(const PtrList<T> *from)
  193. {
  194. PtrList<T>::copyFrom(from);
  195. need_sorting = 1;
  196. if (auto_sort) sort();
  197. }
  198. T *addItem(T *item, int pos = PTRLIST_POS_LAST, int inc = DEF_PTRLIST_INCREMENT)
  199. {
  200. #if 1
  201. // check for appending in sorted order
  202. if (pos == PTRLIST_POS_LAST && !need_sorting && auto_sort)
  203. {
  204. int n = PtrList<T>::getNumItems();
  205. if (n > 0 && C::compareItem(item, q(n - 1)) < 0) need_sorting = 1;
  206. }
  207. else
  208. #endif
  209. need_sorting = 1;
  210. return PtrList<T>::addItem(item, pos, inc);
  211. }
  212. void sort(bool force_sort = false)
  213. {
  214. if (need_sorting || force_sort)
  215. S::_sort(PtrList<T>::getItemList(), PtrList<T>::getNumItems());
  216. need_sorting = 0;
  217. }
  218. T *enumItem(int n)
  219. { // NOT const since we might call sort()
  220. if (auto_sort) sort();
  221. return PtrList<T>::enumItem(n);
  222. }
  223. T *operator[](int n) { return PtrListSorted<T, C, S>::enumItem(n); }
  224. T *q(int n)
  225. {
  226. if (auto_sort) sort();
  227. return static_cast<T*>(PtrList<T>::getItemList()[n]);
  228. }
  229. T *findItem(const wchar_t *attrib, int *pos = NULL)
  230. {
  231. ASSERTPR(!(!auto_sort && need_sorting), "must call sort() first if auto-sorting is disabled");
  232. sort();
  233. #if 1 // do binary search
  234. if (PtrList<T>::getNumItems() == 0) return NULL;
  235. int bot = 0, top = PtrList<T>::getNumItems() - 1, mid;
  236. for (int c = 0; c < PtrList<T>::getNumItems() + 1; c++)
  237. {
  238. if (bot > top) return NULL;
  239. mid = (bot + top) / 2;
  240. int r = C::compareAttrib(attrib, PtrList<T>::getItemList()[mid]);
  241. if (r == 0)
  242. {
  243. if (pos != NULL) *pos = mid;
  244. return PtrList<T>::getItemList()[mid];
  245. }
  246. if (r < 0)
  247. {
  248. top = mid - 1;
  249. }
  250. else
  251. {
  252. bot = mid + 1;
  253. }
  254. }
  255. ASSERTPR(0, "binary search fucked up");
  256. #else
  257. // re-enable this in case of fuckup
  258. for (int i = 0; i < nitems; i++)
  259. {
  260. if (C::compareAttrib(attrib, static_cast<T *>(items[i])) == 0)
  261. return static_cast<T *>items[i];
  262. }
  263. #endif
  264. return NULL;
  265. }
  266. T *findItem(T *attrib, int *pos = NULL)
  267. {
  268. return findItem((const wchar_t *)attrib, pos);
  269. }
  270. int beginEnumDups(const char *attrib)
  271. {
  272. int pos;
  273. findItem(attrib, &pos);
  274. if (pos < 0)
  275. return -1;
  276. dups_hi = pos;
  277. dups_low = pos;
  278. int i;
  279. for (i = pos - 1;i >= 0;i--)
  280. {
  281. if (C::compareAttrib(attrib, static_cast<T *>(enumItem(i))) == 0)
  282. break;
  283. dups_low = i;
  284. }
  285. for (i = pos + 1;i < PtrList<T>::getNumItems();i++)
  286. {
  287. if (C::compareAttrib(attrib, static_cast<T *>(enumItem(i))) == 0)
  288. break;
  289. dups_hi = i;
  290. }
  291. dups_pos = dups_low;
  292. return dups_pos;
  293. }
  294. int getNextDup()
  295. { // returns -1 when done
  296. if (dups_pos >= dups_hi)
  297. return -1;
  298. return ++dups_pos;
  299. }
  300. #if 0
  301. // replace search with binary search
  302. int searchItem(T *item) const
  303. {
  304. ASSERTPR(!(!auto_sort && need_sorting), "must call sort() first if auto-sorting is disabled");
  305. sort();
  306. return bsearchItem(item);
  307. }
  308. #endif
  309. void setAutoSort(bool as) { auto_sort = as; }
  310. bool getAutoSort() const { return auto_sort; }
  311. void removeDups()
  312. {
  313. ASSERTPR(!(!auto_sort && need_sorting), "must call sort() first if auto-sorting is disabled");
  314. sort();
  315. for (int i = 1; i < PtrList<T>::getNumItems(); i++)
  316. {
  317. if (C::compareItem(enumItem(i - 1), enumItem(i)) == 0)
  318. {
  319. PtrList<T>::delByPos(i);
  320. i--;
  321. }
  322. }
  323. }
  324. private:
  325. int need_sorting;
  326. bool auto_sort;
  327. int dups_low, dups_hi, dups_pos;
  328. };
  329. // quicksort -- you still need to override the compare fns
  330. template <class T, class C>
  331. class QuickSorted
  332. {
  333. public:
  334. static void _sort(T **items, int nitems)
  335. {
  336. if (items == NULL || nitems <= 1)
  337. return ;
  338. Qsort(items, 0, nitems - 1);
  339. }
  340. private:
  341. static void swapItem(T **items, int a, int b)
  342. { // no bounds checking!
  343. T *tmp = items[a];
  344. items[a] = items[b];
  345. items[b] = tmp;
  346. }
  347. static void Qsort(T **items, int lo0, int hi0)
  348. {
  349. int lo = lo0, hi = hi0;
  350. if (hi0 > lo0)
  351. {
  352. T *mid = items[(lo0 + hi0) / 2];
  353. while (lo <= hi)
  354. {
  355. while ((lo < hi0) && (C::compareItem(items[lo], mid) < 0))
  356. lo++;
  357. while ((hi > lo0) && (C::compareItem(items[hi], mid) > 0))
  358. hi--;
  359. if (lo <= hi)
  360. {
  361. swapItem(items, lo, hi);
  362. lo++;
  363. hi--;
  364. }
  365. }
  366. if (lo0 < hi)
  367. Qsort(items, lo0, hi);
  368. if (lo < hi0)
  369. Qsort(items, lo, hi0);
  370. }
  371. }
  372. };
  373. // easy way to specify quicksorting, just data type and comparison class
  374. template <class T, class C> class PtrListQuickSorted : public PtrListSorted<T, C, QuickSorted<T, C> >
  375. {
  376. public:
  377. PtrListQuickSorted(int initial_size = 0) : PtrListSorted<T, C, QuickSorted<T, C> >(initial_size) {}
  378. };
  379. // easy way to get a list sorted by pointer val
  380. class SortByPtrVal
  381. {
  382. public:
  383. static int compareItem(void *p1, void *p2) { return CMP3(p1, p2); }
  384. static int compareAttrib(const wchar_t *attrib, void *item) { return CMP3((void *)attrib, item); }
  385. };
  386. template <class T> class PtrListQuickSortedByPtrVal : public PtrListQuickSorted<T, SortByPtrVal > {};
  387. // this class automatically inserts at the correct position, so
  388. // the binary searches are very fast if you need to insert and search often (no need to sort)
  389. template < class T, class C >
  390. class PtrListInsertSorted : public PtrList<T>
  391. {
  392. public:
  393. PtrListInsertSorted() : last_insert_pos(0) { disable_sort = 0; }
  394. T *addItem(T *item)
  395. {
  396. int numItems = PtrList<T>::getNumItems();
  397. if (numItems == 0)
  398. {
  399. last_insert_pos = 0;
  400. return PtrList<T>::addItem(item);
  401. }
  402. int insertpoint = -1;
  403. if (!disable_sort)
  404. {
  405. int bot = 0, top = numItems - 1, mid;
  406. // benski>
  407. // optimization based on profiler info. Too many string compares!
  408. // Most of the use of this comes from GuiObjectWnd's constructor (and derived classes)
  409. // so I've changed GuiObjectWnd to add things in alphabetical order.
  410. // Before we start the binary search, we'll check the new item against the LAST item inserted
  411. // Most of the time, we'll finish the insert in O(1)
  412. // Even if we fail, we mitigate the loss somewhat by limiting the binary search
  413. if (last_insert_pos >= numItems) // the list may have shrunk since last time
  414. last_insert_pos = numItems - 1;
  415. int quickTest = C::compareItem(item, PtrList<T>::getItemList()[last_insert_pos]);
  416. if (quickTest == 0) // right on the money.. we'll go ahead and insert ourselves next
  417. return PtrList<T>::addItem(item, last_insert_pos);
  418. if (quickTest > 0) // ok we go after the last inserted item (good), but we need to make sure we go before the next one
  419. {
  420. last_insert_pos++;
  421. if (last_insert_pos == numItems) // we're at the end? cool...
  422. return PtrList<T>::addItem(item, PTRLIST_POS_LAST);
  423. quickTest = C::compareItem(item, PtrList<T>::getItemList()[last_insert_pos]); // test against the next item
  424. if (quickTest <= 0) // and we're not bigger than the next one... perfect!
  425. return PtrList<T>::addItem(item, last_insert_pos);
  426. else // too bad
  427. bot = last_insert_pos; // help out the binary search ... We're at least bigger than everything before last_insert_pos
  428. }
  429. else // ok our optimization failed, but we can still help out the binary search
  430. top = last_insert_pos - 1; // we're at least smaller than everything before last_insert_pos
  431. // end optimization code
  432. for (int c = 0; c < numItems + 1; c++)
  433. {
  434. if (bot > top)
  435. {
  436. // insert here
  437. insertpoint = bot;
  438. break;
  439. }
  440. mid = (bot + top) / 2;
  441. int r = C::compareItem(item, PtrList<T>::getItemList()[mid]);
  442. if (r == 0)
  443. {
  444. // insert here
  445. insertpoint = mid;
  446. break;
  447. }
  448. if (r < 0)
  449. {
  450. top = mid - 1;
  451. }
  452. else
  453. {
  454. bot = mid + 1;
  455. }
  456. }
  457. last_insert_pos = insertpoint;
  458. ASSERTPR(insertpoint != -1, "insertsort/binary search fucked up");
  459. }
  460. else // no sorting
  461. {
  462. last_insert_pos = numItems;
  463. insertpoint = PTRLIST_POS_LAST;
  464. }
  465. return PtrList<T>::addItem(item, insertpoint);
  466. }
  467. T *getInsertionPoint(T *item, int *pos)
  468. {
  469. if (PtrList<T>::getNumItems() == 0)
  470. {
  471. if (pos)
  472. *pos = 0;
  473. return NULL;
  474. }
  475. int bot = 0, top = PtrList<T>::getNumItems() - 1, mid;
  476. int insertpoint = -1;
  477. if (!disable_sort )
  478. {
  479. for (int c = 0; c < PtrList<T>::getNumItems() + 1; c++)
  480. {
  481. if (bot > top)
  482. {
  483. // insert here
  484. insertpoint = bot;
  485. break;
  486. }
  487. mid = (bot + top) / 2;
  488. int r = C::compareItem(item, PtrList<T>::getItemList()[mid]);
  489. if (r == 0)
  490. {
  491. // insert here
  492. insertpoint = mid;
  493. break;
  494. }
  495. if (r < 0)
  496. {
  497. top = mid - 1;
  498. }
  499. else
  500. {
  501. bot = mid + 1;
  502. }
  503. }
  504. ASSERTPR(insertpoint != -1, "insertsort/binary search fucked up");
  505. }
  506. else
  507. insertpoint = PTRLIST_POS_LAST;
  508. if (pos)
  509. *pos = insertpoint;
  510. return PtrList<T>::enumItem(insertpoint);
  511. }
  512. T *findItem(const wchar_t *attrib, int *pos = NULL)
  513. {
  514. if (isSorted())
  515. {
  516. // binary search
  517. if (PtrList<T>::getNumItems() == 0)
  518. return NULL;
  519. int bot = 0, top = PtrList<T>::getNumItems() - 1, mid;
  520. for (int c = 0; c < PtrList<T>::getNumItems() + 1; c++)
  521. {
  522. if (bot > top)
  523. return NULL;
  524. mid = (bot + top) / 2;
  525. int r = C::compareAttrib(attrib, PtrList<T>::getItemList()[mid]);
  526. if (r == 0)
  527. {
  528. if (pos != NULL)
  529. *pos = mid;
  530. return PtrList<T>::getItemList()[mid];
  531. }
  532. if (r < 0)
  533. {
  534. top = mid - 1;
  535. }
  536. else
  537. {
  538. bot = mid + 1;
  539. }
  540. }
  541. ASSERTPR(0, "binary search fucked up");
  542. }
  543. else
  544. {
  545. // linear search
  546. for (int i = 0; i < PtrList<T>::getNumItems(); i++)
  547. {
  548. int r = C::compareAttrib(attrib, PtrList<T>::getItemList()[i]);
  549. if (r == 0)
  550. {
  551. if (pos != NULL)
  552. *pos = i;
  553. return PtrList<T>::getItemList()[i];
  554. }
  555. }
  556. }
  557. return NULL;
  558. }
  559. T *findItem(T *attrib, int *pos = NULL) { return findItem((const wchar_t *)attrib, pos); }
  560. void setSorted(int dosort) { disable_sort = !dosort; }
  561. int isSorted() { return !disable_sort; }
  562. int disable_sort;
  563. int last_insert_pos;
  564. };
  565. // this list allows you to have multiple items with same attrib and adds findLastItem so you can
  566. // sort on more than just one item. this can be used to make autosorting lists of overriding items
  567. // which you can add and remove at will.
  568. template <class T, class C> class PtrListQuickMultiSorted : public PtrListQuickSorted<T, C>
  569. {
  570. public:
  571. PtrListQuickMultiSorted(int initial_size = 0) : PtrListQuickSorted<T, C>(initial_size) {}
  572. T *findLastItem(const wchar_t *attrib, int *pos = NULL)
  573. {
  574. PtrListQuickSorted<T, C>::sort();
  575. int p = 0;
  576. int fp = 0;
  577. T *item = PtrListQuickSorted<T, C>::findItem(attrib, &fp);
  578. if (!item)
  579. return NULL;
  580. p = fp;
  581. for(;;)
  582. {
  583. p++;
  584. if (p >= PtrListQuickSorted<T, C>::getNumItems())
  585. break;
  586. T* i = PtrListQuickSorted<T, C>::enumItem(p);
  587. if (!C::compareAttrib(attrib, i))
  588. {
  589. fp = p;
  590. item = i;
  591. }
  592. else
  593. break;
  594. }
  595. if (pos != NULL)
  596. *pos = fp;
  597. return item;
  598. }
  599. };
  600. //same thing but Insert sorted. use this one if you insert and search items often (no need to sort on findItem)
  601. template <class T, class C> class PtrListInsertMultiSorted : public PtrListInsertSorted<T, C>
  602. {
  603. public:
  604. PtrListInsertMultiSorted() : PtrListInsertSorted<T, C>() {}
  605. T *findLastItem(const wchar_t *attrib, int *pos = NULL)
  606. {
  607. //sort();
  608. int p = 0;
  609. int fp = 0;
  610. T *item = PtrListInsertSorted<T, C>::findItem(attrib, &fp);
  611. if (!item)
  612. return NULL;
  613. p = fp;
  614. for (;;)
  615. {
  616. p++;
  617. if (p >= PtrListInsertSorted<T, C>::getNumItems())
  618. break;
  619. T* i = PtrListInsertSorted<T, C>::enumItem(p);
  620. if (!C::compareAttrib(attrib, i))
  621. {
  622. fp = p;
  623. item = i;
  624. }
  625. else
  626. break;
  627. }
  628. if (pos != NULL)
  629. *pos = fp;
  630. return item;
  631. }
  632. };
  633. #include <bfc/foreach.h>
  634. #endif