123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777 |
- #ifndef _PTRLIST_H
- #define _PTRLIST_H
- #include <bfc/std_math.h>
- //#include <bfc/memblock.h>
- #include <bfc/bfc_assert.h>
- #include <bfc/platform/platform.h>
- //#include <wasabicfg.h>
- #ifdef _DEBUG
- extern int ptrlist_totalnitems;
- #endif
- // Disable the "identifier was truncated to '255' characters..." warning.
- #pragma warning( disable : 4786 )
- /*
-
- a generic pointer list template. only takes up 12 bytes when empty. auto-grows
- the array as necessary, NEVER shrinks it unless you removeAll() or equivalent
-
- Use, PtrList<typename>, never PtrListRoot
-
- */
- // yes, this really should be an enum or something
- #define PTRLIST_POS_LAST -1
- // 4k each, leaving 16 bytes for MALLOC overhead
- //#define DEF_PTRLIST_INCREMENT (4096/sizeof(void*)-16)
- // in average, 4k doubles the VM working set of a skin, 128bytes (32 elements) seems most optimal
- #define DEF_PTRLIST_INCREMENT (128)
- class __foreach;
- // base class, to share as much code as possible
- class NOVTABLE PtrListRoot
- {
- friend class __foreach;
- protected:
- PtrListRoot(int initial_size = 0);
- PtrListRoot(const PtrListRoot *from);
- virtual ~PtrListRoot();
- void copyFrom(const PtrListRoot *from);
- void appendFrom(const PtrListRoot *from);
- void setMinimumSize(int nslots); // expand to at least this many slots
- int getNumItems() const;
- int size() const { return nitems; }
- bool empty() { return nitems == 0; }
- void *enumItem(int n) const;
- void moveItem(int from, int to);
- int removeItem(void *item);
- void removeEveryItem(void *item);
- void removeByPos(int pos);
- void removeLastItem();
- void removeAll();
- void freeAll();
- void purge();
- // gross-ass linear search to find index of item
- // note that PtrListSorted provides a binary search version
- int searchItem(void *item) const;
- #if 0//fuct
- // speedy binary search. although it'll be fuct if it's not sorted right
- int bsearchItem(void *item) const;
- #endif
- void *addItem(void *item, int pos, int inc);
- void *setItem(void *item, int pos); // replace what's in the slot with the new value
- void reverse();
- void **getItemList() const { return items; } // try to avoid! this is inline to make q() fast
- private:
- #undef verify // for Mac
- void verify();
- int nitems, nslots;
- void **items;
- };
- // now we add the methods that refer specifically to the pointer type
- template <class T>
- class PtrList : public PtrListRoot
- {
- friend class __foreach;
- public:
- PtrList(int initial_size = 0) {}
- PtrList(const PtrList<T> &r) { copyFrom(&r); }
- PtrList(const PtrList<T> *r) { copyFrom(r); }
- ~PtrList() {}
- // copy another PtrList
- // deletes previous contents
- void copyFrom(const PtrList<T> *from) { PtrListRoot::copyFrom(from); }
- // append contents of another PtrList to the end of this one
- // preserves previous contents
- void appendFrom(const PtrList<T> *from) { PtrListRoot::appendFrom(from); }
- // adding
- // expand freelist to at least this many slots, even if 0 items in list
- void setMinimumSize(int nslots) { PtrListRoot::setMinimumSize(nslots); }
- // provide a public addItem for the pointer type
- T *addItem(const T *item, int pos = PTRLIST_POS_LAST, int inc = DEF_PTRLIST_INCREMENT)
- {
- return static_cast<T *>(PtrListRoot::addItem(const_cast<T*>(item), pos, inc));
- }
- void push_back(const T* item) { return addItem(item); }
-
- // replace what's in the slot with the new value
- T *setItem(const T *item, int pos) { return static_cast<T *>(PtrListRoot::setItem(const_cast<T*>(item), pos)); }
- // reverse the order of the list in place
- void reverse() { PtrListRoot::reverse(); }
- // enumerating
- // returns # of items in list
- int getNumItems() const { return PtrListRoot::getNumItems(); }
- // basic list enumerator. returns NULL for out of bounds
- T *enumItem(int n) const { return static_cast<T *>(PtrListRoot::enumItem(n)); }
- T *operator[](int n) const { return enumItem(n); }
- // this will safely return NULL if 0 items due to enumItems's boundscheck
- T *getFirst() const { return enumItem(0); }
- T *getLast() const { return enumItem(getNumItems() - 1); }
- // this is a NON-BOUNDS-CHECKING lookup
- T *q(int n) { return static_cast<T*>(getItemList()[n]); }
- // gross-ass linear search to find index of item
- // note that PtrListSorted provides a binary search version
- int searchItem(T *item) const { return PtrListRoot::searchItem(item); }
- int haveItem(T *item) const { return searchItem(item) >= 0; }
- // deleteing
- // removes first instance of a pointer in list, returns how many are left
- int removeItem(T *item) { return PtrListRoot::removeItem(item); }
-
- //DEPRECATED
- int delItem(T *item) { return removeItem(item); }
-
- // removes all instances of this pointer
- void removeEveryItem(const T *item) { PtrListRoot::removeEveryItem(const_cast<T*>(item)); }
- // removes pointer at specified position regardless of value
- void removeByPos(int pos) { PtrListRoot::removeByPos(pos); }
- // DEPRECATED
- void delByPos(int pos) { removeByPos(pos); }
- // removes last item
- void removeLastItem() { PtrListRoot::removeLastItem(); }
- // removes all entries, also deletes memory space
- void removeAll() { PtrListRoot::removeAll(); }
- // removes all entries, calling FREE on the pointers
- void freeAll() { PtrListRoot::freeAll(); }
- // removes all entries, calling delete on the pointers
- void deleteAll()
- {
- int i, nitems = getNumItems();
- for (i = 0; i < nitems; i++)
- delete enumItem(i);
- removeAll();
- }
- // removes all entries, calling delete on the pointers
- // FG>this version removes each entry as it deletes it so if
- // one of the object uses this list in its destructor, it will
- // still work. It is MUCH slower than deleteAll tho.
- void deleteAllSafe()
- {
- //CUT ASSERT(!(nitems != 0 && items == NULL));
- while (getNumItems())
- {
- T *i = enumItem(0);
- delete i;
- removeItem(i);
- }
- }
- void deleteItem(int item)
- {
- if (item < getNumItems())
- {
- deleteItem(enumItem(item));
- }
- }
- void deleteItem(T *item)
- {
- delete item;
- removeItem(item);
- }
- void moveItem(int from, int to) { PtrListRoot::moveItem(from, to); }
- static T *castFor(void *ptr) { return static_cast<T*>(ptr); }
- using PtrListRoot::purge;
- protected:
- T **getItemList()
- {
- return reinterpret_cast<T **>(PtrListRoot::getItemList());
- }
- };
- class NotSorted
- {
- public:
- // comparator for searching -- override
- static int compareAttrib(const wchar_t *attrib, void *item) { return 0; }
- // comparator for sorting -- override , -1 p1 < p2, 0 eq, 1 p1 > p2
- static int compareItem(void *p1, void* p2) { return CMP3(p1, p2); }
- };
- //template <class T, class C> class NoSort {
- // static void _sort(T **, int) {}
- //};
- // a base class to sort the pointers
- // you must implement the comparisons (C) and the sort algorithm (S)
- template < class T, class C, class S >
- class PtrListSorted : public PtrList<T>
- {
- public:
- PtrListSorted(int initial_size = 0) : PtrList<T>(initial_size)
- {
- need_sorting = 0;
- auto_sort = true;
- dups_low = dups_hi = dups_pos = 0;
- }
- void copyFrom(const PtrList<T> *from)
- {
- PtrList<T>::copyFrom(from);
- need_sorting = 1;
- if (auto_sort) sort();
- }
- T *addItem(T *item, int pos = PTRLIST_POS_LAST, int inc = DEF_PTRLIST_INCREMENT)
- {
- #if 1
- // check for appending in sorted order
- if (pos == PTRLIST_POS_LAST && !need_sorting && auto_sort)
- {
- int n = PtrList<T>::getNumItems();
- if (n > 0 && C::compareItem(item, q(n - 1)) < 0) need_sorting = 1;
- }
- else
- #endif
- need_sorting = 1;
- return PtrList<T>::addItem(item, pos, inc);
- }
- void sort(bool force_sort = false)
- {
- if (need_sorting || force_sort)
- S::_sort(PtrList<T>::getItemList(), PtrList<T>::getNumItems());
- need_sorting = 0;
- }
- T *enumItem(int n)
- { // NOT const since we might call sort()
- if (auto_sort) sort();
- return PtrList<T>::enumItem(n);
- }
- T *operator[](int n) { return PtrListSorted<T, C, S>::enumItem(n); }
- T *q(int n)
- {
- if (auto_sort) sort();
- return static_cast<T*>(PtrList<T>::getItemList()[n]);
- }
- T *findItem(const wchar_t *attrib, int *pos = NULL)
- {
- ASSERTPR(!(!auto_sort && need_sorting), "must call sort() first if auto-sorting is disabled");
- sort();
- #if 1 // do binary search
- if (PtrList<T>::getNumItems() == 0) return NULL;
- int bot = 0, top = PtrList<T>::getNumItems() - 1, mid;
- for (int c = 0; c < PtrList<T>::getNumItems() + 1; c++)
- {
- if (bot > top) return NULL;
- mid = (bot + top) / 2;
- int r = C::compareAttrib(attrib, PtrList<T>::getItemList()[mid]);
- if (r == 0)
- {
- if (pos != NULL) *pos = mid;
- return PtrList<T>::getItemList()[mid];
- }
- if (r < 0)
- {
- top = mid - 1;
- }
- else
- {
- bot = mid + 1;
- }
- }
- ASSERTPR(0, "binary search fucked up");
- #else
- // re-enable this in case of fuckup
- for (int i = 0; i < nitems; i++)
- {
- if (C::compareAttrib(attrib, static_cast<T *>(items[i])) == 0)
- return static_cast<T *>items[i];
- }
- #endif
- return NULL;
- }
- T *findItem(T *attrib, int *pos = NULL)
- {
- return findItem((const wchar_t *)attrib, pos);
- }
- int beginEnumDups(const char *attrib)
- {
- int pos;
- findItem(attrib, &pos);
-
- if (pos < 0)
- return -1;
-
- dups_hi = pos;
- dups_low = pos;
- int i;
- for (i = pos - 1;i >= 0;i--)
- {
- if (C::compareAttrib(attrib, static_cast<T *>(enumItem(i))) == 0)
- break;
-
- dups_low = i;
- }
-
- for (i = pos + 1;i < PtrList<T>::getNumItems();i++)
- {
- if (C::compareAttrib(attrib, static_cast<T *>(enumItem(i))) == 0)
- break;
-
- dups_hi = i;
- }
-
- dups_pos = dups_low;
-
- return dups_pos;
- }
-
- int getNextDup()
- { // returns -1 when done
- if (dups_pos >= dups_hi)
- return -1;
-
- return ++dups_pos;
- }
- #if 0
- // replace search with binary search
- int searchItem(T *item) const
- {
- ASSERTPR(!(!auto_sort && need_sorting), "must call sort() first if auto-sorting is disabled");
- sort();
- return bsearchItem(item);
- }
- #endif
- void setAutoSort(bool as) { auto_sort = as; }
- bool getAutoSort() const { return auto_sort; }
- void removeDups()
- {
- ASSERTPR(!(!auto_sort && need_sorting), "must call sort() first if auto-sorting is disabled");
- sort();
- for (int i = 1; i < PtrList<T>::getNumItems(); i++)
- {
- if (C::compareItem(enumItem(i - 1), enumItem(i)) == 0)
- {
- PtrList<T>::delByPos(i);
- i--;
- }
- }
- }
- private:
- int need_sorting;
- bool auto_sort;
- int dups_low, dups_hi, dups_pos;
- };
- // quicksort -- you still need to override the compare fns
- template <class T, class C>
- class QuickSorted
- {
- public:
- static void _sort(T **items, int nitems)
- {
- if (items == NULL || nitems <= 1)
- return ;
-
- Qsort(items, 0, nitems - 1);
- }
- private:
- static void swapItem(T **items, int a, int b)
- { // no bounds checking!
- T *tmp = items[a];
- items[a] = items[b];
- items[b] = tmp;
- }
- static void Qsort(T **items, int lo0, int hi0)
- {
- int lo = lo0, hi = hi0;
- if (hi0 > lo0)
- {
- T *mid = items[(lo0 + hi0) / 2];
- while (lo <= hi)
- {
- while ((lo < hi0) && (C::compareItem(items[lo], mid) < 0))
- lo++;
-
- while ((hi > lo0) && (C::compareItem(items[hi], mid) > 0))
- hi--;
- if (lo <= hi)
- {
- swapItem(items, lo, hi);
- lo++;
- hi--;
- }
- }
- if (lo0 < hi)
- Qsort(items, lo0, hi);
-
- if (lo < hi0)
- Qsort(items, lo, hi0);
- }
- }
- };
- // easy way to specify quicksorting, just data type and comparison class
- template <class T, class C> class PtrListQuickSorted : public PtrListSorted<T, C, QuickSorted<T, C> >
- {
- public:
- PtrListQuickSorted(int initial_size = 0) : PtrListSorted<T, C, QuickSorted<T, C> >(initial_size) {}
- };
- // easy way to get a list sorted by pointer val
- class SortByPtrVal
- {
- public:
- static int compareItem(void *p1, void *p2) { return CMP3(p1, p2); }
- static int compareAttrib(const wchar_t *attrib, void *item) { return CMP3((void *)attrib, item); }
- };
- template <class T> class PtrListQuickSortedByPtrVal : public PtrListQuickSorted<T, SortByPtrVal > {};
- // this class automatically inserts at the correct position, so
- // the binary searches are very fast if you need to insert and search often (no need to sort)
- template < class T, class C >
- class PtrListInsertSorted : public PtrList<T>
- {
- public:
- PtrListInsertSorted() : last_insert_pos(0) { disable_sort = 0; }
-
- T *addItem(T *item)
- {
- int numItems = PtrList<T>::getNumItems();
- if (numItems == 0)
- {
- last_insert_pos = 0;
-
- return PtrList<T>::addItem(item);
- }
- int insertpoint = -1;
- if (!disable_sort)
- {
- int bot = 0, top = numItems - 1, mid;
- // benski>
- // optimization based on profiler info. Too many string compares!
- // Most of the use of this comes from GuiObjectWnd's constructor (and derived classes)
- // so I've changed GuiObjectWnd to add things in alphabetical order.
- // Before we start the binary search, we'll check the new item against the LAST item inserted
- // Most of the time, we'll finish the insert in O(1)
- // Even if we fail, we mitigate the loss somewhat by limiting the binary search
- if (last_insert_pos >= numItems) // the list may have shrunk since last time
- last_insert_pos = numItems - 1;
-
- int quickTest = C::compareItem(item, PtrList<T>::getItemList()[last_insert_pos]);
- if (quickTest == 0) // right on the money.. we'll go ahead and insert ourselves next
- return PtrList<T>::addItem(item, last_insert_pos);
- if (quickTest > 0) // ok we go after the last inserted item (good), but we need to make sure we go before the next one
- {
- last_insert_pos++;
-
- if (last_insert_pos == numItems) // we're at the end? cool...
- return PtrList<T>::addItem(item, PTRLIST_POS_LAST);
- quickTest = C::compareItem(item, PtrList<T>::getItemList()[last_insert_pos]); // test against the next item
-
- if (quickTest <= 0) // and we're not bigger than the next one... perfect!
- return PtrList<T>::addItem(item, last_insert_pos);
- else // too bad
- bot = last_insert_pos; // help out the binary search ... We're at least bigger than everything before last_insert_pos
- }
- else // ok our optimization failed, but we can still help out the binary search
- top = last_insert_pos - 1; // we're at least smaller than everything before last_insert_pos
- // end optimization code
- for (int c = 0; c < numItems + 1; c++)
- {
- if (bot > top)
- {
- // insert here
- insertpoint = bot;
- break;
- }
- mid = (bot + top) / 2;
- int r = C::compareItem(item, PtrList<T>::getItemList()[mid]);
-
- if (r == 0)
- {
- // insert here
- insertpoint = mid;
- break;
- }
-
- if (r < 0)
- {
- top = mid - 1;
- }
- else
- {
- bot = mid + 1;
- }
- }
- last_insert_pos = insertpoint;
- ASSERTPR(insertpoint != -1, "insertsort/binary search fucked up");
- }
- else // no sorting
- {
- last_insert_pos = numItems;
- insertpoint = PTRLIST_POS_LAST;
- }
- return PtrList<T>::addItem(item, insertpoint);
- }
- T *getInsertionPoint(T *item, int *pos)
- {
- if (PtrList<T>::getNumItems() == 0)
- {
- if (pos)
- *pos = 0;
- return NULL;
- }
- int bot = 0, top = PtrList<T>::getNumItems() - 1, mid;
- int insertpoint = -1;
- if (!disable_sort )
- {
- for (int c = 0; c < PtrList<T>::getNumItems() + 1; c++)
- {
- if (bot > top)
- {
- // insert here
- insertpoint = bot;
- break;
- }
- mid = (bot + top) / 2;
- int r = C::compareItem(item, PtrList<T>::getItemList()[mid]);
-
- if (r == 0)
- {
- // insert here
- insertpoint = mid;
- break;
- }
-
- if (r < 0)
- {
- top = mid - 1;
- }
- else
- {
- bot = mid + 1;
- }
- }
-
- ASSERTPR(insertpoint != -1, "insertsort/binary search fucked up");
- }
- else
- insertpoint = PTRLIST_POS_LAST;
-
- if (pos)
- *pos = insertpoint;
-
- return PtrList<T>::enumItem(insertpoint);
- }
- T *findItem(const wchar_t *attrib, int *pos = NULL)
- {
- if (isSorted())
- {
- // binary search
- if (PtrList<T>::getNumItems() == 0)
- return NULL;
- int bot = 0, top = PtrList<T>::getNumItems() - 1, mid;
- for (int c = 0; c < PtrList<T>::getNumItems() + 1; c++)
- {
- if (bot > top)
- return NULL;
-
- mid = (bot + top) / 2;
- int r = C::compareAttrib(attrib, PtrList<T>::getItemList()[mid]);
-
- if (r == 0)
- {
- if (pos != NULL)
- *pos = mid;
-
- return PtrList<T>::getItemList()[mid];
- }
-
- if (r < 0)
- {
- top = mid - 1;
- }
- else
- {
- bot = mid + 1;
- }
- }
- ASSERTPR(0, "binary search fucked up");
- }
- else
- {
- // linear search
- for (int i = 0; i < PtrList<T>::getNumItems(); i++)
- {
- int r = C::compareAttrib(attrib, PtrList<T>::getItemList()[i]);
- if (r == 0)
- {
- if (pos != NULL)
- *pos = i;
-
- return PtrList<T>::getItemList()[i];
- }
- }
- }
-
- return NULL;
- }
- T *findItem(T *attrib, int *pos = NULL) { return findItem((const wchar_t *)attrib, pos); }
- void setSorted(int dosort) { disable_sort = !dosort; }
- int isSorted() { return !disable_sort; }
- int disable_sort;
- int last_insert_pos;
- };
- // this list allows you to have multiple items with same attrib and adds findLastItem so you can
- // sort on more than just one item. this can be used to make autosorting lists of overriding items
- // which you can add and remove at will.
- template <class T, class C> class PtrListQuickMultiSorted : public PtrListQuickSorted<T, C>
- {
- public:
- PtrListQuickMultiSorted(int initial_size = 0) : PtrListQuickSorted<T, C>(initial_size) {}
- T *findLastItem(const wchar_t *attrib, int *pos = NULL)
- {
- PtrListQuickSorted<T, C>::sort();
- int p = 0;
- int fp = 0;
- T *item = PtrListQuickSorted<T, C>::findItem(attrib, &fp);
-
- if (!item)
- return NULL;
- p = fp;
- for(;;)
- {
- p++;
-
- if (p >= PtrListQuickSorted<T, C>::getNumItems())
- break;
-
- T* i = PtrListQuickSorted<T, C>::enumItem(p);
-
- if (!C::compareAttrib(attrib, i))
- {
- fp = p;
- item = i;
- }
- else
- break;
- }
- if (pos != NULL)
- *pos = fp;
-
- return item;
- }
- };
- //same thing but Insert sorted. use this one if you insert and search items often (no need to sort on findItem)
- template <class T, class C> class PtrListInsertMultiSorted : public PtrListInsertSorted<T, C>
- {
- public:
- PtrListInsertMultiSorted() : PtrListInsertSorted<T, C>() {}
- T *findLastItem(const wchar_t *attrib, int *pos = NULL)
- {
- //sort();
- int p = 0;
- int fp = 0;
- T *item = PtrListInsertSorted<T, C>::findItem(attrib, &fp);
-
- if (!item)
- return NULL;
- p = fp;
- for (;;)
- {
- p++;
-
- if (p >= PtrListInsertSorted<T, C>::getNumItems())
- break;
-
- T* i = PtrListInsertSorted<T, C>::enumItem(p);
-
- if (!C::compareAttrib(attrib, i))
- {
- fp = p;
- item = i;
- }
- else
- break;
- }
- if (pos != NULL)
- *pos = fp;
-
- return item;
- }
- };
- #include <bfc/foreach.h>
- #endif
|