/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #ifndef __NLIST__ #define __NLIST__ #include "alloc/ialloc.h" #include "assert/nassert.h" namespace GS { /* @short List. @author Emmanuel Julien (ejulien@gsworks.fr) */ template class List { public: //---------------------------------------------------------------------- class Item { friend class List ; T o; Item *p, *n; public: NPLACEMENT_NEW(ListItem) /// Return the previous list link. inline Item *Previous() const { return p; } /// Return the next list link. inline Item *Next() const { return n; } /// Retrieve a reference to the item object. inline T &Object() { return o; } Item(const T &obj) { o = obj; p = n = 0; } }; //---------------------------------------------------------------------- //---------------------------------------------------------------------- class Iterator { Item *c, *n; public: inline void operator++() { if ((c = c ? n : 0) != 0) n = c->n; } inline bool IsOver() const { return c ? false : true; } inline Item *Next() const { return n; } inline Item *GetItem() const { return c; } inline T &Object() { return c->Object(); } /// Only use when using a pointer type. inline T ObjectPtr() { return c ? c->Object() : 0; } void Reset(Item *start = 0) { c = start; n = c ? c->Next() : 0; } Iterator(Item *start = 0) { Reset(start); } }; //---------------------------------------------------------------------- protected: uint count; Item *root, *last; public: /// Get item count in list. inline uint GetCount() const { return count; } /// Get root item. inline Item *GetRoot() const { return root; } /// Get last item. inline Item *GetLast() const { return last; } /// Clone list. void Clone(List &clone_list) const { clone_list.Clear(); for (Item *_i = root; _i; _i = _i->Next()) clone_list.Add(_i->Object()); } /// Get item from position. Item *ItemAt(uint n) const { if (n > count) return 0; Item *p = root; while (n--) p = p->n; return p; } inline T &ObjectAt(uint n) const { return ItemAt(n)->Object(); } inline T &operator[] (uint n) const { return ItemAt(n)->Object(); } /// Get index of a given item. int Index(const T &o) const { int pos = 0; for (Item *p = root; p; p = p->n) { if (p->Object() == o) return pos; pos++; } return -1; } /// Check whether a given item belongs to this list or not. bool Belongs(Item *i) const { for (Item *s = root; s; s = s->n) if (s == i) return true; return false; } /// Insert item after a given reference item (defaults to last). virtual Item *Append(const T &o, Item *rfr = 0) { Item *i = new Item(o); if (!i) return 0; if (!rfr) { i->p = last; if (last) last->n = i; else root = i; last = i; } else { if (rfr->n) rfr->n->p = i; i->n = rfr->n; rfr->n = i; i->p = rfr; if (last == rfr) // Update last. last = i; } count++; return i; } /// Insert item before a given reference item (defaults to root). virtual Item *Prepend(const T &o, Item *rfr = 0) { Item *i = new Item(o); if (!i) return 0; if (!rfr) { i->n = root; if (root) root->p = i; else last = i; root = i; } else { if (rfr->p) rfr->p->n = i; i->p = rfr->p; rfr->p = i; i->n = rfr; if (root == rfr) // Update root. root = i; } count++; return i; } /// Insert a value at a given position. Item *Insert(const T &v, uint at) { Item *rfr = ItemAt(at); return rfr ? Prepend(v, rfr) : 0; } /// Add item to list. Item *Add(const T &o, bool append, bool allow_duplicate) { if (!allow_duplicate) if (Item *i = Find(o)) return i; return append ? Append(o) : Prepend(o); } /// Add item to list. Item *Add(const T &o) { return Append(o); } /// Add item to list. List &operator << (const T &o) { Add(o); return *this; } /// Find item by reference to object. Item *Find(const T &o) const { for (Item *p = root; p; p = p->n) if (p->Object() == o) return p; return 0; } /// Find item by object value. Item *FindByValue(const T &o) const { for (Item *p = root; p; p = p->n) if (*p->Object() == *o) return p; return 0; } /*! @short Subtract two given lists by object value. @warning The resulting list holds pointers to the original objects. */ static List *SubtractByValue(const List &what, const List &from) { List *list = new List ; if (list) for (Item *f_p = from.root; f_p; f_p = f_p->n) if (!what.FindByValue(f_p->Object())) list->Add(f_p->Object()); return list; } /*! @short Subtract two given lists by object address. @warning The resulting list holds pointers to the original objects. */ static List *SubtractByAddress(const List &what, const List &from) { List *list = new List ; if (list) for (Item *f_p = from.root; f_p; f_p = f_p->n) if (!what.Find(f_p->Object())) list->Add(f_p->Object()); return list; } /// Filter out linked-list item function. template void FilterOut(F filter) { for (Item *c = GetRoot(); c; ) { Item *n = c->Next(); if (filter(c->Object())) Remove(c); c = n; } } /// Build a new list from select items. template uint Select(List &out, F filter, const P &filter_param) const { out.Clear(); for (Item *c = GetRoot(); c; ) if (filter(c->Object(), filter_param)) out.Add(c->Object()); return out.GetCount(); } /// Sort linked-list function. template void Sort(C compare) { for (bool swapped = true; swapped; ) { swapped = false; for (Item *c = GetRoot(); c; ) { Item *n = c->Next(); if (!n) break; if (compare(c->Object(), n->Object()) < 0) { swapped = true; c->n = n->n; n->n = c; n->p = c->p; c->p = n; if (n->p) n->p->n = n; else root = n; if (c->n) c->n->p = c; else last = c; } else c = n; } } } /// Merge sort linked-list function. template void MergeSort(C compare) { Item *list = root, *tail = 0; if (!list) return; for (int insize = 1; ; insize *= 2) { Item *p = list; list = 0; tail = 0; int merge_count = 0; // Count number of merges we do in this pass. while (p) { merge_count++; // Step along from p. Item *q = p; int psize = 0; for ( ; q && (psize < insize); ++psize) q = q->Next(); // If q hasn't fallen off end, we have two lists to merge. int qsize = insize; // Now we have two lists, merge them. while (psize > 0 || (qsize > 0 && q)) { Item *e; if (!psize) // p is empty, e must come from q. { e = q; q = q->Next(); qsize--; } else if (!qsize || !q) // q is empty, e must come from p. { e = p; p = p->Next(); psize--; } else if (compare(p->Object(), q->Object()) <= 0) // First element of p is lower (or same), e must come from p. { e = p; p = p->Next(); psize--; } else // First element of q is lower; e must come from q. { e = q; q = q->Next(); qsize--; } // Add the next element to the merged list. if (tail) tail->n = e; else list = e; e->p = tail; tail = e; } // Now p has stepped `insize' places along, and q has too. p = q; } tail->n = 0; // If we have done only one merge, we're done. if (merge_count <= 1) break; } root = list; last = tail; } /// Extract object from list. Item *ExtractItem(const T &o) { Item*i = Find(o); return i ? ExtractItem(i) : 0; } /// Extract item from list. Item *ExtractItem(Item *i) { if (!i) return 0; __ASSERT__(Belongs(i)); if (i->p) i->p->n = i->n; else { if (i->n) i->n->p = 0; root = i->n; } if (i->n) i->n->p = i->p; else { if (i->p) i->p->n = 0; last = i->p; } i->p = i->n = 0; --count; return i; } /// Extract item at position. Item *ExtractAt(uint n) { Item *i = ItemAt(n); return i ? ExtractItem(i) : 0; } /// Remove item from list. virtual bool Remove(Item *i) { if (ExtractItem(i) == 0) return false; delete i; return true; } /// Remove item from list. virtual bool Remove(const T &o) { return Remove(Find(o)); } /// Remove item at position. bool RemoveAt(uint n) { Item *i = ItemAt(n); return i ? Remove(i) : false; } /// Remove all items from the list. virtual void Clear() { for (Item *p = root, *n; p; p = n) { n = p->n; delete p; } count = 0; root = last = 0; } List() { count = 0; root = last = 0; } virtual ~List() { Clear(); } }; /* @short Auto linked-list. @author Emmanuel Julien (ejulien@gsworks.fr) */ template struct AutoList : public List { virtual bool Remove(class List ::Item *i) { T o = i->Object(); if (!List ::Remove(i)) return false; delete o; return true; } virtual bool Remove(const T &o) { class List ::Item *i = this->Find(o); return i ? this->Remove(i) : false; } virtual void Clear() { for (class List ::Item *p = this->root; p; p = p->Next()) delete p->Object(); List ::Clear(); } virtual ~AutoList() { this->Clear(); } }; /* @short Shared object linked-list. @author Emmanuel Julien (ejulien@gsworks.fr) */ template struct SharedList : public List { virtual class List ::Item *Append(const T &o, class List ::Item *rfr = 0) { class List ::Item *i = List ::Append(o, rfr); if (i) o->AddRef(); return i; } virtual class List ::Item *Prepend(const T &o, class List ::Item *rfr = 0) { class List ::Item *i = List ::Prepend(o, rfr); if (i) o->AddRef(); return i; } virtual bool Remove(class List ::Item *i) { T o = i->Object(); if (!List ::Remove(i)) return false; o->RemoveRef(); return true; } virtual bool Remove(const T &o) { class List ::Item *i = this->Find(o); return i ? this->Remove(i) : false; } virtual void Clear() { for (class List ::Item *p = this->root; p; p = p->Next()) p->Object()->RemoveRef(); List ::Clear(); } virtual ~SharedList() { Clear(); } }; //------------------------------------------------------------------------------ // Delete all list entries. #define ListDeleteAllPtr(T, L) { class GS::List ::Item *t; while ((t = (L).GetRoot()) != 0) { T _o = t->Object(); (L).Remove(t); delete(_o); } } // Iterate over a list of pointers. #define ListForeachPtr(T, V, L) \ for (class GS::List ::Iterator iterator((L).GetRoot()); T V = iterator.ObjectPtr(); ++iterator) // Iterate over a list of objects. #define ListForeach(T, V, L) \ for (class GS::List ::Iterator V((L).GetRoot()); V.IsOver() == false; ++V) /// Find item by using a template identification class. template T ListFindEx(const List &list, F filter, const P &what) { for (class List ::Item *p = list.GetRoot(); p; p = p->Next()) if (filter(p->Object(), what)) return p->Object(); return 0; } /// Remove all items with a reference count of 1 from a shared list. template uint PurgeSharedList(SharedList &list) { uint c = list.GetCount(); ListForeachPtr(T *, t, list) if (t->GetRefCount() == 1) list.Remove(iterator.GetItem()); return c - list.GetCount(); } //------------------------------------------------------------------------------ } // GS #endif // __NLIST__