diff --git a/qse/include/qse/cmn/Array.hpp b/qse/include/qse/cmn/Array.hpp index 59581620..700aac78 100644 --- a/qse/include/qse/cmn/Array.hpp +++ b/qse/include/qse/cmn/Array.hpp @@ -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 +template +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 RESIZER = ArrayResizer > class Array: public Mmged { public: - typedef Array SelfType; + typedef Array SelfType; enum { @@ -59,8 +74,8 @@ public: }; Array (Mmgr* mmgr = QSE_NULL, - qse_size_t capacity = DEFAULT_CAPACITY, - qse_size_t mpb_size = 0): + qse_size_t capacity = DEFAULT_CAPACITY, + qse_size_t mpb_size = 0): Mmged (mmgr), mp (mmgr, QSE_SIZEOF(T), mpb_size) { @@ -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 (); - } - - ::operator delete (this->buffer, &this->mp); - } + this->clear (true); } -#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& operator+= (const T& value) +protected: + T* clone_buffer (const T* srcbuf, qse_size_t capa, qse_size_t count) { - addDatum (value); - return *this; - } - Array& operator+ (const T& value) const - { - Array 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); } - for (qse_size_t i = this->count; i > index; i--) + if (index < this->count) { - //this->buffer[i] = this->buffer[i - 1]; - this->set_item (i, this->buffer[i - 1]); + // 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->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 (); + } + + this->count = 0; } - qse_size_t removeDatum (const T& value) +public: + void clear (bool clear_mpool = false) { - qse_size_t i = 0, sz = this->size(); - while (i < this->count) + this->clear_all_items (); + + if (clear_mpool) { - if (value == this->buffer[i]) + if (this->buffer) { - remove (i); - break; + // 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; } - i++; + + QSE_ASSERT (this->capacity == 0); + this->mp.dispose (); } - - return sz - this->size(); - } - - 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++; - } - - 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); - this->count = size; + 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; + if (cnt > capacity) cnt = capacity; - try + T* tmp = clone_buffer (*this, capacity, cnt); + + if (this->buffer) { - tmp = new T[capacity]; - if (cnt > capacity) cnt = capacity; - for (qse_size_t i = 0; i < cnt; i++) - { - 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 findLastIndex (const T& value) const + { + for (qse_size_t i = this->count; i > 0; ) + { + if (this->is_equal (this->buffer[--i], value)) return i; } return INVALID_INDEX; } - qse_size_t lastIndexOf (const T& value) const - { - for (qse_size_t i = this->count; i > 0; ) - { - if (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,30 +488,36 @@ 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; qse_size_t capacity; - T* buffer; + T* buffer; }; ///////////////////////////////// diff --git a/qse/include/qse/cmn/BinaryHeap.hpp b/qse/include/qse/cmn/BinaryHeap.hpp index 04ba754d..0d5ff709 100644 --- a/qse/include/qse/cmn/BinaryHeap.hpp +++ b/qse/include/qse/cmn/BinaryHeap.hpp @@ -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; diff --git a/qse/include/qse/cmn/HashList.hpp b/qse/include/qse/cmn/HashList.hpp index 40f83677..5bea1754 100644 --- a/qse/include/qse/cmn/HashList.hpp +++ b/qse/include/qse/cmn/HashList.hpp @@ -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; diff --git a/qse/include/qse/cmn/LinkedList.hpp b/qse/include/qse/cmn/LinkedList.hpp index cabbe5f3..30b24e32 100644 --- a/qse/include/qse/cmn/LinkedList.hpp +++ b/qse/include/qse/cmn/LinkedList.hpp @@ -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; diff --git a/qse/include/qse/cmn/RedBlackTree.hpp b/qse/include/qse/cmn/RedBlackTree.hpp index a1c34ab6..f1b0dd14 100644 --- a/qse/include/qse/cmn/RedBlackTree.hpp +++ b/qse/include/qse/cmn/RedBlackTree.hpp @@ -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. };