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
{
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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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.
};