wrote mote code for Array

This commit is contained in:
hyung-hwan 2015-03-06 15:51:13 +00:00
parent 0c0f0df7d8
commit bdf3e2652d
5 changed files with 275 additions and 174 deletions

View File

@ -38,6 +38,8 @@ struct ArrayResizer
{ {
qse_size_t operator() (qse_size_t current) const qse_size_t operator() (qse_size_t current) const
{ {
if (current <= 0) current = 1;
return (current < 5000)? (current + current): return (current < 5000)? (current + current):
(current < 50000)? (current + (current / 2)): (current < 50000)? (current + (current / 2)):
(current < 100000)? (current + (current / 4)): (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 class Array: public Mmged
{ {
public: public:
typedef Array<T,RESIZER> SelfType; typedef Array<T,ASSIGNER,RESIZER> SelfType;
enum enum
{ {
@ -79,82 +94,89 @@ public:
this->count = 0; 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->buffer = this->clone_buffer (array, array.capacity, array.count);
this->capacity = 0; this->count = array.count;
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->capacity = array.capacity; this->capacity = array.capacity;
this->grow_factor = array.grow_factor;
this->count = array.this->count;
} }
} }
#endif
~Array () ~Array ()
{ {
if (this->buffer) this->clear (true);
{
for (qse_size_t i = this->count; i > 0; )
{
--i;
this->buffer[i].~T ();
} }
::operator delete (this->buffer, &this->mp);
}
}
#if 0
SelfType& operator= (const SelfType& array) SelfType& operator= (const SelfType& array)
{ {
setSize (array.this->count); this->clear (true);
for (qse_size_t i = 0; i < array.this->count; i++) { if (array.buffer)
this->buffer[i] = array.buffer[i]; {
this->buffer = this->clone_buffer (array, array.capacity, array.count);
this->count = array.count;
this->capacity = array.capacity;
} }
return *this; return *this;
} }
#endif
/* protected:
Array<T>& operator+= (const T& value) T* clone_buffer (const T* srcbuf, qse_size_t capa, qse_size_t count)
{ {
addDatum (value); QSE_ASSERT (capa > 0);
return *this; QSE_ASSERT (count <= capa);
}
Array<T>& operator+ (const T& value) const
{
Array<T> array (*this);
array.addDatum (value);
return array;
}
*/
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 bool isEmpty () const
{ {
return this->count == 0; return this->count == 0;
@ -190,6 +212,19 @@ public:
return this->buffer; 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) T& operator[] (qse_size_t index)
{ {
QSE_ASSERT (index < this->count); QSE_ASSERT (index < this->count);
@ -217,23 +252,15 @@ public:
void set (qse_size_t index, const T& value) void set (qse_size_t index, const T& value)
{ {
QSE_ASSERT (index < this->count); 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) qse_size_t insert (qse_size_t index, const T& value)
{ {
if (index >= this->capacity) 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); qse_size_t new_capa = this->resizer (this->capacity);
if (index < new_capa) if (index < new_capa)
@ -243,18 +270,33 @@ public:
} }
else if (this->count >= this->capacity) 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); qse_size_t new_capa = this->resizer (this->capacity);
this->setCapacity (new_capa); 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--) for (qse_size_t i = this->count; i > index; i--)
{ {
//this->buffer[i] = this->buffer[i - 1]; //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->buffer[index] = value;
this->set_item (index, value); this->put_item (index, value);
if (index > this->count) this->count = index + 1; if (index > this->count) this->count = index + 1;
else this->count++; else this->count++;
@ -273,150 +315,171 @@ public:
qse_size_t j = from_index; qse_size_t j = from_index;
qse_size_t i = to_index + 1; qse_size_t i = to_index + 1;
// replace deleted elements by surviving elements at the back
while (i < this->count) 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; this->count -= to_index - from_index + 1;
} }
#if 0 protected:
qse_size_t addDatum (const T& value) 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) this->count = 0;
{
qse_size_t i = 0, sz = this->size();
while (i < this->count)
{
if (value == this->buffer[i])
{
remove (i);
break;
}
i++;
} }
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_ASSERT (this->capacity == 0);
{ this->mp.dispose ();
qse_size_t i = 0, sz = this->size();
while (i < this->count)
{
if (value == this->buffer[i]) remove (i);
else i++;
} }
return sz - this->size();
}
#endif
void clear ()
{
setSize (0);
}
void trimToSize ()
{
setCapacity (this->size);
} }
void setSize (qse_size_t size) void setSize (qse_size_t size)
{ {
if (size > this->capacity) this->setCapacity (size); if (size < this->count)
QSE_ASSERT (size <= this->capacity); {
for (qse_size_t i = size; i < this->count; ++i)
{
// call the destructor of the items
this->buffer[i].~T ();
}
this->count = size; 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) void setCapacity (qse_size_t capacity)
{ {
if (capacity <= 0) if (capacity <= 0)
{ {
if (this->buffer != QSE_NULL) this->clear (true);
delete[] this->buffer;
this->buffer = QSE_NULL;
this->capacity = 0;
this->count = 0;
} }
else else
{ {
T* tmp = QSE_NULL;
qse_size_t cnt = this->count; qse_size_t cnt = this->count;
try
{
tmp = new T[capacity];
if (cnt > capacity) cnt = 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]; // don't call this->clear (true) here. clear items only.
} // the memory pool may destory the cloned buffer as well.
} this->clear_all_items ();
catch (...)
{ // deallocate the current buffer;
if (tmp != QSE_NULL) delete[] tmp; ::operator delete (this->buffer, &this->mp);
throw; this->capacity = 0;
this->buffer = QSE_NULL;
} }
if (this->buffer != QSE_NULL)
delete[] this->buffer;
this->buffer = tmp; this->buffer = tmp;
this->capacity = capacity; this->capacity = capacity;
this->count = cnt; this->count = cnt;
} }
} }
void trimToSize ()
{
this->setCapacity (this->size);
}
#if 0 #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++) 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; 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++) 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; 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; ) 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; 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; ) 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; return INVALID_INDEX;
} }
#endif #endif
void rotate (int dir, qse_size_t n) void rotate (int dir, qse_size_t n)
{ {
qse_size_t first, last, cnt, index, nk; qse_size_t first, last, cnt, index, nk;
T c; T c;
if (dir == 0) return this->count; if (dir == 0) return;
if ((n %= this->count) == 0) return this->count; if ((n %= this->count) == 0) return;
if (dir > 0) n = this->count - n; if (dir > 0) n = this->count - n;
first = 0; nk = this->count - n; cnt = 0; first = 0; nk = this->count - n; cnt = 0;
@ -425,25 +488,31 @@ public:
{ {
last = first + nk; last = first + nk;
index = first; index = first;
c = this->buffer[first]; //c = this->buffer[first];
this->assigner (c, this->buffer[first], INVALID_INDEX);
while (1) while (1)
{ {
cnt++; cnt++;
while (index < nk) 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; index += n;
} }
if (index == last) break; 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; index -= nk;
} }
this->buffer[last] = c; first++; //this->buffer[last] = c;
this->assigner (this->buffer[last], c, last);
first++;
} }
} }
protected: protected:
Mpool mp; Mpool mp;
ASSIGNER assigner;
RESIZER resizer; RESIZER resizer;
qse_size_t count; qse_size_t count;

View File

@ -92,7 +92,7 @@ struct BinaryHeapAssigner
// The assignment proxy is used to get the value informed of its position // The assignment proxy is used to get the value informed of its position
// within the heap. This default implmentation, however, doesn't utilize // within the heap. This default implmentation, however, doesn't utilize
// the position (index). // 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; v1 = v2;
return v1; return v1;

View File

@ -220,7 +220,7 @@ public:
SelfType& operator= (const SelfType& list) SelfType& operator= (const SelfType& list)
{ {
this->clear (); this->clear (false);
// note that the memory pool itself is not copied. // note that the memory pool itself is not copied.
@ -620,6 +620,7 @@ protected:
mutable DatumList* datum_list; mutable DatumList* datum_list;
mutable qse_size_t threshold; mutable qse_size_t threshold;
qse_size_t load_factor; qse_size_t load_factor;
HASHER hasher; HASHER hasher;
EQUALER equaler; EQUALER equaler;
RESIZER resizer; RESIZER resizer;

View File

@ -211,14 +211,16 @@ public:
this->clear (true); 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->node_count = 0;
this->head_node = QSE_NULL; this->head_node = QSE_NULL;
this->tail_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->node_count = 0;
this->head_node = QSE_NULL; this->head_node = QSE_NULL;

View File

@ -324,8 +324,15 @@ public:
mp (mmgr, QSE_SIZEOF(Node), mpb_size), mp (mmgr, QSE_SIZEOF(Node), mpb_size),
node_count (0) node_count (0)
{ {
// create a nil object #if defined(QSE_REDBLACKTREE_ALLOCATE_NIL)
this->nil = new(&this->mp) Node(); // 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 // set root to nil
this->root = this->nil; this->root = this->nil;
@ -336,14 +343,20 @@ public:
mp (rbt.getMmgr(), rbt.mp.getDatumSize(), rbt.mp.getBlockSize()), mp (rbt.getMmgr(), rbt.mp.getDatumSize(), rbt.mp.getBlockSize()),
node_count (0) node_count (0)
{ {
#if defined(QSE_REDBLACKTREE_ALLOCATE_NIL)
// create a nil object // create a nil object. note it doesn't go into the memory pool.
this->nil = new(&this->mp) Node(); // 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 // set root to nil
this->root = this->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(); Iterator it = rbt.getIterator();
while (it.isLegit()) while (it.isLegit())
{ {
@ -354,15 +367,22 @@ public:
~RedBlackTree () ~RedBlackTree ()
{ {
this->clear (); this->clear (true);
this->dispose_node (this->nil);
#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) 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(); Iterator it = rbt.getIterator();
while (it.isLegit()) while (it.isLegit())
{ {
@ -946,6 +966,8 @@ public:
while (this->root->notNil()) this->remove_node (this->root); while (this->root->notNil()) this->remove_node (this->root);
QSE_ASSERT (this->root = this->nil); QSE_ASSERT (this->root = this->nil);
QSE_ASSERT (this->node_count == 0); QSE_ASSERT (this->node_count == 0);
if (clear_mpool) this->mp.dispose ();
} }
Iterator getIterator (typename Iterator::Mode mode = Iterator::ASCENDING) const Iterator getIterator (typename Iterator::Mode mode = Iterator::ASCENDING) const
@ -963,6 +985,13 @@ protected:
COMPARATOR comparator; COMPARATOR comparator;
qse_size_t node_count; 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* nil; // internal node to present nil
Node* root; // root node. Node* root; // root node.
}; };