wrote mote code for Array
This commit is contained in:
parent
0c0f0df7d8
commit
bdf3e2652d
@ -38,6 +38,8 @@ struct ArrayResizer
|
||||
{
|
||||
qse_size_t operator() (qse_size_t current) const
|
||||
{
|
||||
if (current <= 0) current = 1;
|
||||
|
||||
return (current < 5000)? (current + current):
|
||||
(current < 50000)? (current + (current / 2)):
|
||||
(current < 100000)? (current + (current / 4)):
|
||||
@ -46,11 +48,24 @@ struct ArrayResizer
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename RESIZER = ArrayResizer>
|
||||
template<typename T>
|
||||
struct ArrayAssigner
|
||||
{
|
||||
// The assignment proxy is used to get the value informed of its position
|
||||
// within the heap. This default implmentation, however, doesn't utilize
|
||||
// the position (index).
|
||||
T& operator() (T& v1, const T& v2, qse_size_t index) const
|
||||
{
|
||||
v1 = v2;
|
||||
return v1;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename ASSIGNER = ArrayAssigner<T>, typename RESIZER = ArrayResizer >
|
||||
class Array: public Mmged
|
||||
{
|
||||
public:
|
||||
typedef Array<T,RESIZER> SelfType;
|
||||
typedef Array<T,ASSIGNER,RESIZER> SelfType;
|
||||
|
||||
enum
|
||||
{
|
||||
@ -79,82 +94,89 @@ public:
|
||||
this->count = 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
Array (const SelfType& array)
|
||||
Array (const SelfType& array):
|
||||
Mmged (array.getMmgr()),
|
||||
mp (array.getMmgr(), array.mp.getDatumSize(), array.mp.getBlockSize()),
|
||||
count (0), capacity (0), buffer (QSE_NULL)
|
||||
{
|
||||
if (array.buffer == QSE_NULL)
|
||||
if (array.buffer)
|
||||
{
|
||||
this->buffer = QSE_NULL;
|
||||
this->capacity = 0;
|
||||
this->grow_factor = array.grow_factor;
|
||||
this->count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
T* tmp = QSE_NULL;
|
||||
QSE_ASSERT (array.capacity > 0 && array.grow_factor > 0);
|
||||
|
||||
try {
|
||||
tmp = new T[array.capacity];
|
||||
for (qse_size_t i = 0; i < array.this->count; i++) {
|
||||
tmp[i] = array.buffer[i];
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
// just in case where the assignment throws an
|
||||
// exception. when T is a class type, the operator =
|
||||
// for the class may throw an exception.
|
||||
if (tmp != QSE_NULL) delete[] tmp;
|
||||
throw;
|
||||
}
|
||||
|
||||
this->buffer = tmp;
|
||||
this->buffer = this->clone_buffer (array, array.capacity, array.count);
|
||||
this->count = array.count;
|
||||
this->capacity = array.capacity;
|
||||
this->grow_factor = array.grow_factor;
|
||||
this->count = array.this->count;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
~Array ()
|
||||
{
|
||||
if (this->buffer)
|
||||
{
|
||||
for (qse_size_t i = this->count; i > 0; )
|
||||
{
|
||||
--i;
|
||||
this->buffer[i].~T ();
|
||||
this->clear (true);
|
||||
}
|
||||
|
||||
::operator delete (this->buffer, &this->mp);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
SelfType& operator= (const SelfType& array)
|
||||
{
|
||||
setSize (array.this->count);
|
||||
for (qse_size_t i = 0; i < array.this->count; i++) {
|
||||
this->buffer[i] = array.buffer[i];
|
||||
this->clear (true);
|
||||
if (array.buffer)
|
||||
{
|
||||
this->buffer = this->clone_buffer (array, array.capacity, array.count);
|
||||
this->count = array.count;
|
||||
this->capacity = array.capacity;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Array<T>& operator+= (const T& value)
|
||||
protected:
|
||||
T* clone_buffer (const T* srcbuf, qse_size_t capa, qse_size_t count)
|
||||
{
|
||||
addDatum (value);
|
||||
return *this;
|
||||
}
|
||||
Array<T>& operator+ (const T& value) const
|
||||
{
|
||||
Array<T> array (*this);
|
||||
array.addDatum (value);
|
||||
return array;
|
||||
}
|
||||
*/
|
||||
QSE_ASSERT (capa > 0);
|
||||
QSE_ASSERT (count <= capa);
|
||||
|
||||
qse_size_t index;
|
||||
|
||||
//T* tmp = new T[capa];
|
||||
T* tmp = (T*)::operator new (capa * QSE_SIZEOF(*tmp), &this->mp);
|
||||
|
||||
try
|
||||
{
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
//tmp[index] = srcbuf[index];
|
||||
// copy-construct each element.
|
||||
new((QSE::Mpool*)QSE_NULL, &tmp[index]) T(srcbuf[index]);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// in case copy-constructor raises an exception.
|
||||
QSE_ASSERT (tmp != QSE_NULL);
|
||||
while (index > 0)
|
||||
{
|
||||
--index;
|
||||
tmp[index].~T ();
|
||||
}
|
||||
::operator delete (tmp, &this->mp);
|
||||
throw;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void put_item (qse_size_t index, const T& value)
|
||||
{
|
||||
if (index >= this->count)
|
||||
{
|
||||
// no value exists in the given position.
|
||||
// i can copy-construct the value.
|
||||
new((QSE::Mpool*)QSE_NULL, &this->buffer[index]) T(value);
|
||||
//this->notify_position (this->buffer[index], index);
|
||||
}
|
||||
else
|
||||
{
|
||||
// there is an old value in the position.
|
||||
this->assigner (this->buffer[index], value, index);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
bool isEmpty () const
|
||||
{
|
||||
return this->count == 0;
|
||||
@ -190,6 +212,19 @@ public:
|
||||
return this->buffer;
|
||||
}
|
||||
|
||||
/// The getBufferIndex() function returns the index of the
|
||||
/// given value \a v if it is one of the values of the array.
|
||||
/// It returns #INVALID_INDEX if not.
|
||||
qse_size_t getIndex (const T& v)
|
||||
{
|
||||
if (&v >= &this->buffer[0] && &v < &this->buffer[this->count])
|
||||
{
|
||||
return &v - &this->buffer[0];
|
||||
}
|
||||
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
T& operator[] (qse_size_t index)
|
||||
{
|
||||
QSE_ASSERT (index < this->count);
|
||||
@ -217,23 +252,15 @@ public:
|
||||
void set (qse_size_t index, const T& value)
|
||||
{
|
||||
QSE_ASSERT (index < this->count);
|
||||
this->buffer[index] = value;
|
||||
this->insert (index, value);
|
||||
}
|
||||
|
||||
protected:
|
||||
void set_item (qse_size_t index, const T& value)
|
||||
{
|
||||
if (index >= this->count)
|
||||
new((QSE::Mpool*)QSE_NULL, &this->buffer[index]) T(value);
|
||||
else
|
||||
this->buffer[index] = value;
|
||||
}
|
||||
|
||||
public:
|
||||
qse_size_t insert (qse_size_t index, const T& value)
|
||||
{
|
||||
if (index >= this->capacity)
|
||||
{
|
||||
// the position to add the element is beyond the
|
||||
// capacity. resize the buffer.
|
||||
qse_size_t new_capa = this->resizer (this->capacity);
|
||||
|
||||
if (index < new_capa)
|
||||
@ -243,18 +270,33 @@ public:
|
||||
}
|
||||
else if (this->count >= this->capacity)
|
||||
{
|
||||
// the array is already full.
|
||||
// insertion requires at least one more slot
|
||||
qse_size_t new_capa = this->resizer (this->capacity);
|
||||
this->setCapacity (new_capa);
|
||||
}
|
||||
|
||||
if (index < this->count)
|
||||
{
|
||||
// shift the existing elements to the back by one slot.
|
||||
for (qse_size_t i = this->count; i > index; i--)
|
||||
{
|
||||
//this->buffer[i] = this->buffer[i - 1];
|
||||
this->set_item (i, this->buffer[i - 1]);
|
||||
this->put_item (i, this->buffer[i - 1]);
|
||||
}
|
||||
}
|
||||
else if (index > this->count)
|
||||
{
|
||||
// the insertion position leaves some gaps in between.
|
||||
// fill the gap with a default value.
|
||||
for (qse_size_t i = this->count; i < index; i++)
|
||||
{
|
||||
new((QSE::Mpool*)QSE_NULL, &this->buffer[i]) T();
|
||||
}
|
||||
}
|
||||
|
||||
//this->buffer[index] = value;
|
||||
this->set_item (index, value);
|
||||
this->put_item (index, value);
|
||||
if (index > this->count) this->count = index + 1;
|
||||
else this->count++;
|
||||
|
||||
@ -273,150 +315,171 @@ public:
|
||||
|
||||
qse_size_t j = from_index;
|
||||
qse_size_t i = to_index + 1;
|
||||
|
||||
// replace deleted elements by surviving elements at the back
|
||||
while (i < this->count)
|
||||
{
|
||||
this->buffer[j++] = this->buffer[i++];
|
||||
//this->buffer[j++] = this->buffer[i++];
|
||||
this->assigner (this->buffer[j], this->buffer[i], j);
|
||||
j++; i++;
|
||||
}
|
||||
|
||||
// call the destructor of deleted elements.
|
||||
while (j < this->count)
|
||||
{
|
||||
this->buffer[j].~T ();
|
||||
j++;
|
||||
}
|
||||
|
||||
// recalculate the number of elements
|
||||
this->count -= to_index - from_index + 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
qse_size_t addDatum (const T& value)
|
||||
protected:
|
||||
void clear_all_items ()
|
||||
{
|
||||
return insert (this->count, value);
|
||||
QSE_ASSERT (this->count <= 0 || (this->count >= 1 && this->buffer));
|
||||
|
||||
for (qse_size_t i = this->count; i > 0; )
|
||||
{
|
||||
--i;
|
||||
this->buffer[i].~T ();
|
||||
}
|
||||
|
||||
qse_size_t removeDatum (const T& value)
|
||||
{
|
||||
qse_size_t i = 0, sz = this->size();
|
||||
while (i < this->count)
|
||||
{
|
||||
if (value == this->buffer[i])
|
||||
{
|
||||
remove (i);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
this->count = 0;
|
||||
}
|
||||
|
||||
return sz - this->size();
|
||||
public:
|
||||
void clear (bool clear_mpool = false)
|
||||
{
|
||||
this->clear_all_items ();
|
||||
|
||||
if (clear_mpool)
|
||||
{
|
||||
if (this->buffer)
|
||||
{
|
||||
// the buffer has been allocated using the memory pool.
|
||||
// if the memory pool should be cleared, the buffer must
|
||||
// not be left over either.
|
||||
QSE_ASSERT (this->capacity > 0);
|
||||
::operator delete (this->buffer, &this->mp);
|
||||
this->capacity = 0;
|
||||
this->buffer = QSE_NULL;
|
||||
}
|
||||
|
||||
qse_size_t removeDatums (const T& value)
|
||||
{
|
||||
qse_size_t i = 0, sz = this->size();
|
||||
|
||||
while (i < this->count)
|
||||
{
|
||||
if (value == this->buffer[i]) remove (i);
|
||||
else i++;
|
||||
QSE_ASSERT (this->capacity == 0);
|
||||
this->mp.dispose ();
|
||||
}
|
||||
|
||||
return sz - this->size();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void clear ()
|
||||
{
|
||||
setSize (0);
|
||||
}
|
||||
|
||||
void trimToSize ()
|
||||
{
|
||||
setCapacity (this->size);
|
||||
}
|
||||
|
||||
void setSize (qse_size_t size)
|
||||
{
|
||||
if (size > this->capacity) this->setCapacity (size);
|
||||
QSE_ASSERT (size <= this->capacity);
|
||||
if (size < this->count)
|
||||
{
|
||||
for (qse_size_t i = size; i < this->count; ++i)
|
||||
{
|
||||
// call the destructor of the items
|
||||
this->buffer[i].~T ();
|
||||
}
|
||||
|
||||
this->count = size;
|
||||
}
|
||||
else if (size > this->count)
|
||||
{
|
||||
if (size > this->capacity) this->setCapacity (size);
|
||||
for (qse_size_t i = this->count; i < size; ++i)
|
||||
{
|
||||
// use the default contructor to set the value.
|
||||
new((QSE::Mpool*)QSE_NULL, &this->buffer[i]) T();
|
||||
}
|
||||
|
||||
this->count = size;
|
||||
}
|
||||
}
|
||||
|
||||
void setCapacity (qse_size_t capacity)
|
||||
{
|
||||
if (capacity <= 0)
|
||||
{
|
||||
if (this->buffer != QSE_NULL)
|
||||
delete[] this->buffer;
|
||||
this->buffer = QSE_NULL;
|
||||
this->capacity = 0;
|
||||
this->count = 0;
|
||||
this->clear (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
T* tmp = QSE_NULL;
|
||||
|
||||
qse_size_t cnt = this->count;
|
||||
|
||||
try
|
||||
{
|
||||
tmp = new T[capacity];
|
||||
if (cnt > capacity) cnt = capacity;
|
||||
for (qse_size_t i = 0; i < cnt; i++)
|
||||
|
||||
T* tmp = clone_buffer (*this, capacity, cnt);
|
||||
|
||||
if (this->buffer)
|
||||
{
|
||||
tmp[i] = this->buffer[i];
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (tmp != QSE_NULL) delete[] tmp;
|
||||
throw;
|
||||
// don't call this->clear (true) here. clear items only.
|
||||
// the memory pool may destory the cloned buffer as well.
|
||||
this->clear_all_items ();
|
||||
|
||||
// deallocate the current buffer;
|
||||
::operator delete (this->buffer, &this->mp);
|
||||
this->capacity = 0;
|
||||
this->buffer = QSE_NULL;
|
||||
}
|
||||
|
||||
if (this->buffer != QSE_NULL)
|
||||
delete[] this->buffer;
|
||||
this->buffer = tmp;
|
||||
this->capacity = capacity;
|
||||
this->count = cnt;
|
||||
}
|
||||
}
|
||||
|
||||
void trimToSize ()
|
||||
{
|
||||
this->setCapacity (this->size);
|
||||
}
|
||||
|
||||
#if 0
|
||||
qse_size_t indexOf (const T& value) const
|
||||
qse_size_t findFirstIndex (const T& value) const
|
||||
{
|
||||
for (qse_size_t i = 0; i < this->count; i++)
|
||||
{
|
||||
if (this->buffer[i] == value) return i;
|
||||
if (this->is_equal (this->buffer[i], value)) return i;
|
||||
}
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
qse_size_t indexOf (const T& value, qse_size_t index) const
|
||||
qse_size_t findFirstIndex (const T& value, qse_size_t index) const
|
||||
{
|
||||
for (qse_size_t i = index; i < this->count; i++)
|
||||
{
|
||||
if (this->buffer[i] == value) return i;
|
||||
if (this->is_equal (this->buffer[i], value)) return i;
|
||||
}
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
qse_size_t lastIndexOf (const T& value) const
|
||||
qse_size_t findLastIndex (const T& value) const
|
||||
{
|
||||
for (qse_size_t i = this->count; i > 0; )
|
||||
{
|
||||
if (this->buffer[--i] == value) return i;
|
||||
if (this->is_equal (this->buffer[--i], value)) return i;
|
||||
}
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
qse_size_t lastIndexOf (const T& value, qse_size_t index) const
|
||||
qse_size_t findLastIndex (const T& value, qse_size_t index) const
|
||||
{
|
||||
for (qse_size_t i = index + 1; i > 0; )
|
||||
{
|
||||
if (this->buffer[--i] == value) return i;
|
||||
if (this->is_equal (this->buffer[--i], value)) return i;
|
||||
}
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void rotate (int dir, qse_size_t n)
|
||||
{
|
||||
qse_size_t first, last, cnt, index, nk;
|
||||
T c;
|
||||
|
||||
if (dir == 0) return this->count;
|
||||
if ((n %= this->count) == 0) return this->count;
|
||||
if (dir == 0) return;
|
||||
if ((n %= this->count) == 0) return;
|
||||
|
||||
if (dir > 0) n = this->count - n;
|
||||
first = 0; nk = this->count - n; cnt = 0;
|
||||
@ -425,25 +488,31 @@ public:
|
||||
{
|
||||
last = first + nk;
|
||||
index = first;
|
||||
c = this->buffer[first];
|
||||
//c = this->buffer[first];
|
||||
this->assigner (c, this->buffer[first], INVALID_INDEX);
|
||||
while (1)
|
||||
{
|
||||
cnt++;
|
||||
while (index < nk)
|
||||
{
|
||||
this->buffer[index] = this->buffer[index + n];
|
||||
//this->buffer[index] = this->buffer[index + n];
|
||||
this->assigner (this->buffer[index], this->buffer[index + n], index);
|
||||
index += n;
|
||||
}
|
||||
if (index == last) break;
|
||||
this->buffer[index] = this->buffer[index - nk];
|
||||
//this->buffer[index] = this->buffer[index - nk];
|
||||
this->assigner (this->buffer[index], this->buffer[index - nk], index);
|
||||
index -= nk;
|
||||
}
|
||||
this->buffer[last] = c; first++;
|
||||
//this->buffer[last] = c;
|
||||
this->assigner (this->buffer[last], c, last);
|
||||
first++;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
Mpool mp;
|
||||
ASSIGNER assigner;
|
||||
RESIZER resizer;
|
||||
|
||||
qse_size_t count;
|
||||
|
@ -92,7 +92,7 @@ struct BinaryHeapAssigner
|
||||
// The assignment proxy is used to get the value informed of its position
|
||||
// within the heap. This default implmentation, however, doesn't utilize
|
||||
// the position (index).
|
||||
T& operator() (T& v1, const T& v2, xp_size_t index) const
|
||||
T& operator() (T& v1, const T& v2, qse_size_t index) const
|
||||
{
|
||||
v1 = v2;
|
||||
return v1;
|
||||
|
@ -220,7 +220,7 @@ public:
|
||||
|
||||
SelfType& operator= (const SelfType& list)
|
||||
{
|
||||
this->clear ();
|
||||
this->clear (false);
|
||||
|
||||
// note that the memory pool itself is not copied.
|
||||
|
||||
@ -620,6 +620,7 @@ protected:
|
||||
mutable DatumList* datum_list;
|
||||
mutable qse_size_t threshold;
|
||||
qse_size_t load_factor;
|
||||
|
||||
HASHER hasher;
|
||||
EQUALER equaler;
|
||||
RESIZER resizer;
|
||||
|
@ -211,14 +211,16 @@ public:
|
||||
this->clear (true);
|
||||
}
|
||||
|
||||
LinkedList (Mmgr* mmgr = QSE_NULL, qse_size_t mpb_size = 0): Mmged(mmgr), mp (mmgr, QSE_SIZEOF(Node), mpb_size)
|
||||
LinkedList (Mmgr* mmgr = QSE_NULL, qse_size_t mpb_size = 0):
|
||||
Mmged(mmgr), mp (mmgr, QSE_SIZEOF(Node), mpb_size)
|
||||
{
|
||||
this->node_count = 0;
|
||||
this->head_node = QSE_NULL;
|
||||
this->tail_node = QSE_NULL;
|
||||
}
|
||||
|
||||
LinkedList (const SelfType& ll): Mmged(ll.getMmgr()), mp (ll.getMmgr(), ll.mp.getDatumSize(), ll.mp.getBlockSize())
|
||||
LinkedList (const SelfType& ll):
|
||||
Mmged(ll.getMmgr()), mp (ll.getMmgr(), ll.mp.getDatumSize(), ll.mp.getBlockSize())
|
||||
{
|
||||
this->node_count = 0;
|
||||
this->head_node = QSE_NULL;
|
||||
|
@ -324,8 +324,15 @@ public:
|
||||
mp (mmgr, QSE_SIZEOF(Node), mpb_size),
|
||||
node_count (0)
|
||||
{
|
||||
// create a nil object
|
||||
this->nil = new(&this->mp) Node();
|
||||
#if defined(QSE_REDBLACKTREE_ALLOCATE_NIL)
|
||||
// create a nil object. note it doesn't go into the memory pool.
|
||||
// the nil node allocated inside the memory pool makes implementation
|
||||
// of this->clear (true) difficult as disposal of memory pool
|
||||
// also deallocates the nil node.
|
||||
this->nil = new(this->getMmgr()) Node();
|
||||
#else
|
||||
this->nil = &this->xnil;
|
||||
#endif
|
||||
|
||||
// set root to nil
|
||||
this->root = this->nil;
|
||||
@ -336,14 +343,20 @@ public:
|
||||
mp (rbt.getMmgr(), rbt.mp.getDatumSize(), rbt.mp.getBlockSize()),
|
||||
node_count (0)
|
||||
{
|
||||
|
||||
// create a nil object
|
||||
this->nil = new(&this->mp) Node();
|
||||
#if defined(QSE_REDBLACKTREE_ALLOCATE_NIL)
|
||||
// create a nil object. note it doesn't go into the memory pool.
|
||||
// the nil node allocated inside the memory pool makes implementation
|
||||
// of this->clear (true) difficult as disposal of memory pool
|
||||
// also deallocates the nil node.
|
||||
this->nil = new(this->getMmgr()) Node();
|
||||
#else
|
||||
this->nil = &this->xnil;
|
||||
#endif
|
||||
|
||||
// set root to nil
|
||||
this->root = this->nil;
|
||||
|
||||
// TODO: do the level-order traversal to minize rebalancing.
|
||||
// TODO: do the level-order traversal to minimize rebalancing.
|
||||
Iterator it = rbt.getIterator();
|
||||
while (it.isLegit())
|
||||
{
|
||||
@ -354,15 +367,22 @@ public:
|
||||
|
||||
~RedBlackTree ()
|
||||
{
|
||||
this->clear ();
|
||||
this->dispose_node (this->nil);
|
||||
this->clear (true);
|
||||
|
||||
#if defined(QSE_REDBLACKTREE_ALLOCATE_NIL)
|
||||
// destroy the nil node.
|
||||
this->nil->~Node ();
|
||||
::operator delete (this->nil, this->getMmgr());
|
||||
#else
|
||||
// do nothing
|
||||
#endif
|
||||
}
|
||||
|
||||
SelfType& operator= (const SelfType& rbt)
|
||||
{
|
||||
this->clear ();
|
||||
this->clear (false);
|
||||
|
||||
// TODO: do the level-order traversal to minize rebalancing.
|
||||
// TODO: do the level-order traversal to minimize rebalancing.
|
||||
Iterator it = rbt.getIterator();
|
||||
while (it.isLegit())
|
||||
{
|
||||
@ -946,6 +966,8 @@ public:
|
||||
while (this->root->notNil()) this->remove_node (this->root);
|
||||
QSE_ASSERT (this->root = this->nil);
|
||||
QSE_ASSERT (this->node_count == 0);
|
||||
|
||||
if (clear_mpool) this->mp.dispose ();
|
||||
}
|
||||
|
||||
Iterator getIterator (typename Iterator::Mode mode = Iterator::ASCENDING) const
|
||||
@ -963,6 +985,13 @@ protected:
|
||||
COMPARATOR comparator;
|
||||
|
||||
qse_size_t node_count;
|
||||
#if defined(QSE_REDBLACKTREE_ALLOCATE_NIL)
|
||||
// nothing. let the constructor allocate it to this->nil.
|
||||
#else
|
||||
// use a statically declared nil object.
|
||||
Node xnil;
|
||||
#endif
|
||||
|
||||
Node* nil; // internal node to present nil
|
||||
Node* root; // root node.
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user