first commit
This commit is contained in:
604
include/platform/container/nlist.h
Normal file
604
include/platform/container/nlist.h
Normal file
@ -0,0 +1,604 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
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 T> class List
|
||||
{
|
||||
public:
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class Item
|
||||
{
|
||||
friend class List <T>;
|
||||
|
||||
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 <T> &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 <T> &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 <T> *SubtractByValue(const List <T> &what, const List <T> &from)
|
||||
{
|
||||
List <T> *list = new List <T>;
|
||||
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 <T> *SubtractByAddress(const List <T> &what, const List <T> &from)
|
||||
{
|
||||
List <T> *list = new List <T>;
|
||||
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 <typename F> 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 <typename F, typename P> uint Select(List <T> &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 <typename C> 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 <typename C> 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 <class T> struct AutoList : public List <T>
|
||||
{
|
||||
virtual bool Remove(class List <T> ::Item *i)
|
||||
{
|
||||
T o = i->Object();
|
||||
if (!List <T> ::Remove(i))
|
||||
return false;
|
||||
delete o;
|
||||
return true;
|
||||
}
|
||||
virtual bool Remove(const T &o)
|
||||
{
|
||||
class List <T> ::Item *i = this->Find(o);
|
||||
return i ? this->Remove(i) : false;
|
||||
}
|
||||
|
||||
virtual void Clear()
|
||||
{
|
||||
for (class List <T> ::Item *p = this->root; p; p = p->Next())
|
||||
delete p->Object();
|
||||
List <T> ::Clear();
|
||||
}
|
||||
virtual ~AutoList()
|
||||
{ this->Clear(); }
|
||||
};
|
||||
|
||||
/*
|
||||
@short Shared object linked-list.
|
||||
@author Emmanuel Julien (ejulien@gsworks.fr)
|
||||
*/
|
||||
template <class T> struct SharedList : public List <T>
|
||||
{
|
||||
virtual class List <T> ::Item *Append(const T &o, class List <T> ::Item *rfr = 0)
|
||||
{
|
||||
class List <T> ::Item *i = List <T> ::Append(o, rfr);
|
||||
if (i)
|
||||
o->AddRef();
|
||||
return i;
|
||||
}
|
||||
virtual class List <T> ::Item *Prepend(const T &o, class List <T> ::Item *rfr = 0)
|
||||
{
|
||||
class List <T> ::Item *i = List <T> ::Prepend(o, rfr);
|
||||
if (i)
|
||||
o->AddRef();
|
||||
return i;
|
||||
}
|
||||
|
||||
virtual bool Remove(class List <T> ::Item *i)
|
||||
{
|
||||
T o = i->Object();
|
||||
if (!List <T> ::Remove(i))
|
||||
return false;
|
||||
o->RemoveRef();
|
||||
return true;
|
||||
}
|
||||
virtual bool Remove(const T &o)
|
||||
{
|
||||
class List <T> ::Item *i = this->Find(o);
|
||||
return i ? this->Remove(i) : false;
|
||||
}
|
||||
|
||||
virtual void Clear()
|
||||
{
|
||||
for (class List <T> ::Item *p = this->root; p; p = p->Next())
|
||||
p->Object()->RemoveRef();
|
||||
List <T> ::Clear();
|
||||
}
|
||||
virtual ~SharedList()
|
||||
{ Clear(); }
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Delete all list entries.
|
||||
#define ListDeleteAllPtr(T, L) { class GS::List <T> ::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 <T> ::Iterator iterator((L).GetRoot()); T V = iterator.ObjectPtr(); ++iterator)
|
||||
// Iterate over a list of objects.
|
||||
#define ListForeach(T, V, L) \
|
||||
for (class GS::List <T> ::Iterator V((L).GetRoot()); V.IsOver() == false; ++V)
|
||||
|
||||
/// Find item by using a template identification class.
|
||||
template <typename T, typename F, typename P> T ListFindEx(const List <T> &list, F filter, const P &what)
|
||||
{
|
||||
for (class List <T> ::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 <class T> uint PurgeSharedList(SharedList <T *> &list)
|
||||
{
|
||||
uint c = list.GetCount();
|
||||
ListForeachPtr(T *, t, list)
|
||||
if (t->GetRefCount() == 1)
|
||||
list.Remove(iterator.GetItem());
|
||||
return c - list.GetCount();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
} // GS
|
||||
|
||||
|
||||
#endif // __NLIST__
|
||||
Reference in New Issue
Block a user