269 lines
6.9 KiB
C++
269 lines
6.9 KiB
C++
/* -----------------------------------------------------------------------------
|
|
GSFramework
|
|
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
|
----------------------------------------------------------------------------- */
|
|
|
|
|
|
#ifndef __NARRAYLIST__
|
|
#define __NARRAYLIST__
|
|
|
|
|
|
#include "container/narray.h"
|
|
#include "log/log.h"
|
|
|
|
|
|
namespace GS {
|
|
|
|
/*!
|
|
@short Array list.
|
|
|
|
A flexible structure with faster access time (both linear and random) and
|
|
tighter memory usage than lists.
|
|
|
|
Especially suited for small types such as pointers.
|
|
|
|
@author Emmanuel Julien (ejulien@gsworks.fr)
|
|
*/
|
|
template <class T> class ArrayList
|
|
{
|
|
Array <T> array;
|
|
Array <uint> usage_map;
|
|
|
|
uint usage; ///< Array usage.
|
|
uint grow_step;
|
|
|
|
//----------------------------------------------------------------------
|
|
inline bool Grow()
|
|
{
|
|
if (int(usage) >= int(array.GetCount() - 1))
|
|
return Resize(array.GetCount() + grow_step);
|
|
return true;
|
|
}
|
|
inline bool Shrink()
|
|
{
|
|
if (((int)array.GetCount() - 1) > (int)grow_step)
|
|
if ((int)usage < ((int)array.GetCount() - 1 - (int)grow_step))
|
|
return Resize(array.GetCount() - grow_step);
|
|
return true;
|
|
}
|
|
//----------------------------------------------------------------------
|
|
|
|
public:
|
|
|
|
//----------------------------------------------------------------------
|
|
class Iterator
|
|
{
|
|
const ArrayList <T> &list;
|
|
uint i;
|
|
|
|
public:
|
|
|
|
inline void Reset(uint from = 0) { i = from; }
|
|
inline bool IsOver() const { return i < list.GetCount() ? false : true; }
|
|
|
|
inline void operator++() { ++i; }
|
|
|
|
inline T &Object() { return list[i]; }
|
|
inline T ObjectPtr() { return list[i]; }
|
|
|
|
Iterator(const ArrayList <T> &_list, uint from = 0) : list(_list), i(from) {}
|
|
};
|
|
//----------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------
|
|
inline uint GetCount() const
|
|
{ return usage; }
|
|
|
|
inline T &ObjectAt(int n) const
|
|
{ return array[usage_map[n]]; }
|
|
inline T &ObjectAt(uint n) const
|
|
{ return array[usage_map[n]]; }
|
|
|
|
inline T &operator [] (int n) const
|
|
{ return array[usage_map[n]]; }
|
|
inline T &operator [] (uint n) const
|
|
{ return array[usage_map[n]]; }
|
|
|
|
inline void SetGrowStep(uint step)
|
|
{ grow_step = step; }
|
|
//----------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------
|
|
/// Insert a new value in the list.
|
|
virtual bool Insert(const T &v, uint at)
|
|
{
|
|
Grow();
|
|
|
|
// Claim entry...
|
|
uint claimed = usage_map[usage];
|
|
|
|
// ...and shift usage map.
|
|
for (int n = (int)usage - 1; n >= (int)at; --n)
|
|
usage_map[n + 1] = usage_map[n];
|
|
|
|
usage_map[at] = claimed;
|
|
usage++;
|
|
|
|
array[claimed] = v;
|
|
array[usage_map[usage]] = 0; // enforce terminator
|
|
return true;
|
|
}
|
|
/// Add a new value to the end of the list.
|
|
bool Add(const T &v)
|
|
{
|
|
return Insert(v, usage);
|
|
}
|
|
/// Return the index at which a value is first found in the list.
|
|
int IndexOf(const T &v, uint from = 0)
|
|
{
|
|
for (uint i = from; i < usage; ++i)
|
|
if (array[usage_map[i]] == v)
|
|
return i;
|
|
return -1;
|
|
}
|
|
/// Remove an entry from the list.
|
|
virtual bool RemoveAt(uint i)
|
|
{
|
|
if (usage == 0)
|
|
return false;
|
|
|
|
// Reclaim entry...
|
|
uint reclaimed = usage_map[i];
|
|
|
|
// ...and shift usage map.
|
|
for (uint n = i + 1; n < usage; ++n)
|
|
usage_map[n - 1] = usage_map[n];
|
|
|
|
usage_map[usage - 1] = reclaimed;
|
|
usage--;
|
|
|
|
array[reclaimed] = 0; // enforce terminator
|
|
|
|
Shrink();
|
|
return true;
|
|
}
|
|
bool Remove(const T &v)
|
|
{
|
|
int i = IndexOf(v);
|
|
return i != -1 ? RemoveAt(i) : false;
|
|
}
|
|
//----------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------
|
|
ArrayList <T> &operator = (const T &v)
|
|
{
|
|
if (this != &v)
|
|
{
|
|
Clear();
|
|
for (uint n = 0; n < v.GetCount(); ++n)
|
|
Add(v[n]);
|
|
}
|
|
return *this;
|
|
}
|
|
ArrayList <T> &operator << (const T &v)
|
|
{
|
|
Add(v);
|
|
return *this;
|
|
}
|
|
//----------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------
|
|
bool Resize(uint new_size)
|
|
{
|
|
if ((int)new_size == (int)array.GetCount() - 1)
|
|
return true;
|
|
|
|
Array <T> _array(new_size + 1);
|
|
if (_array.IsNull())
|
|
__ERR__(__LOG_E__ << "Failed to allocate new array.\n", false)
|
|
|
|
for (uint n = 0; n < usage; ++n)
|
|
_array[n] = array[usage_map[n]];
|
|
array.Transfer(_array);
|
|
|
|
if (!usage_map.Allocate(new_size + 1))
|
|
__ERR__(__LOG_E__ << "Failed to allocate array bookkeeping structures.\n", false)
|
|
|
|
for (uint n = 0; n < (new_size + 1); ++n)
|
|
usage_map[n] = n;
|
|
|
|
array[usage_map[usage]] = 0; // enforce terminator
|
|
return true;
|
|
}
|
|
/*!
|
|
@short Clear the container.
|
|
|
|
Pass false to prevent the internal structures from being released,
|
|
the array list will keep its current capacity and only its usage map
|
|
will be reset.
|
|
*/
|
|
virtual void Clear(bool free_internals = true)
|
|
{
|
|
usage = 0;
|
|
|
|
if (free_internals)
|
|
Resize(0);
|
|
else
|
|
{
|
|
for (uint n = 0; n < array.GetCount(); ++n)
|
|
usage_map[n] = n;
|
|
array[0] = 0; // enforce terminator
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------
|
|
|
|
ArrayList(uint initial_size = 0, uint step = 64) : usage(0), grow_step(step) { Resize(initial_size); }
|
|
virtual ~ArrayList() {}
|
|
};
|
|
|
|
/*
|
|
@short Shared object array list.
|
|
@author Emmanuel Julien (ejulien@gsworks.fr)
|
|
*/
|
|
template <class T> struct SharedArrayList : public ArrayList <T>
|
|
{
|
|
virtual bool Insert(const T &v, uint at)
|
|
{
|
|
v->AddRef();
|
|
return ArrayList <T> ::Insert(v, at);
|
|
}
|
|
virtual bool RemoveAt(uint i)
|
|
{
|
|
(*this)[i]->RemoveRef();
|
|
return ArrayList <T> :: RemoveAt(i);
|
|
}
|
|
virtual void Clear(bool free_internals = true)
|
|
{
|
|
for (uint n = 0; n < this->GetCount(); ++n)
|
|
(*this)[n]->RemoveRef();
|
|
return ArrayList <T> ::Clear(free_internals);
|
|
}
|
|
virtual ~SharedArrayList()
|
|
{ Clear(); }
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Delete all list entries.
|
|
#define ArrayListDeleteAllPtr(T, L) { for (uint __n = 0; __n < (L).GetCount(); ++__n) delete (L)[__n]; (L).Clear(); }
|
|
// Iterate over a list of pointers.
|
|
#define ArrayListForeachPtr(T, V, L) \
|
|
for (ArrayList <T> ::Iterator iterator(L); T V = iterator.ObjectPtr(); ++iterator)
|
|
// Iterate over a list of objects.
|
|
#define ArrayListForeach(T, V, L) \
|
|
for (ArrayList <T> ::Iterator V(L); V.IsOver() == false; ++V)
|
|
|
|
/// Find item by using a template identification class.
|
|
template <typename T, typename F, typename P> T ArrayListFindEx(const ArrayList <T> &list, F filter, const P &what)
|
|
{
|
|
for (uint __n = 0; __n < list.GetCount(); ++__n)
|
|
if (filter(list[__n], what))
|
|
return list[__n];
|
|
return 0;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
} // GS
|
|
|
|
|
|
#endif // __NARRAYLIST__
|