From 0c0f0df7d8957320597b084ff2db0eb03a802d1b Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Wed, 4 Mar 2015 16:30:09 +0000 Subject: [PATCH] Added a couple of 'operator new()' definitions. Started adding Array and BinaryHeap --- qse/include/qse/cmn/Array.hpp | 460 +++++++++++++++++++++++++++ qse/include/qse/cmn/BinaryHeap.hpp | 360 +++++++++++++++++++++ qse/include/qse/cmn/Makefile.am | 3 +- qse/include/qse/cmn/Makefile.in | 6 +- qse/include/qse/cmn/Mmgr.hpp | 2 + qse/include/qse/cmn/Mpool.hpp | 1 + qse/include/qse/cmn/RedBlackTree.hpp | 146 +++++---- qse/lib/cmn/Mmgr.cpp | 7 + qse/lib/cmn/Mpool.cpp | 7 +- 9 files changed, 919 insertions(+), 73 deletions(-) create mode 100644 qse/include/qse/cmn/Array.hpp create mode 100644 qse/include/qse/cmn/BinaryHeap.hpp diff --git a/qse/include/qse/cmn/Array.hpp b/qse/include/qse/cmn/Array.hpp new file mode 100644 index 00000000..59581620 --- /dev/null +++ b/qse/include/qse/cmn/Array.hpp @@ -0,0 +1,460 @@ +/* + * $Id$ + * + Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _QSE_CMN_ARRAY_HPP_ +#define _QSE_CMN_ARRAY_HPP_ + +#include +#include + +///////////////////////////////// +QSE_BEGIN_NAMESPACE(QSE) +///////////////////////////////// + +struct ArrayResizer +{ + qse_size_t operator() (qse_size_t current) const + { + return (current < 5000)? (current + current): + (current < 50000)? (current + (current / 2)): + (current < 100000)? (current + (current / 4)): + (current < 150000)? (current + (current / 8)): + (current + (current / 16)); + } +}; + +template +class Array: public Mmged +{ +public: + typedef Array SelfType; + + enum + { + DEFAULT_CAPACITY = 128, + INVALID_INDEX = ~(qse_size_t)0 + }; + + Array (Mmgr* mmgr = QSE_NULL, + qse_size_t capacity = DEFAULT_CAPACITY, + qse_size_t mpb_size = 0): + Mmged (mmgr), + mp (mmgr, QSE_SIZEOF(T), mpb_size) + { + if (capacity <= 0) + { + this->buffer = QSE_NULL; + this->capacity = 0; + } + else + { + //this->buffer = new T[capacity]; + this->buffer = (T*)::operator new (capacity * QSE_SIZEOF(*this->buffer), &this->mp); + this->capacity = capacity; + } + + this->count = 0; + } + +#if 0 + Array (const SelfType& array) + { + if (array.buffer == QSE_NULL) + { + 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->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); + } + } + +#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]; + } + return *this; + } +#endif + + /* + Array& operator+= (const T& value) + { + addDatum (value); + return *this; + } + Array& operator+ (const T& value) const + { + Array array (*this); + array.addDatum (value); + return array; + } + */ + + bool isEmpty () const + { + return this->count == 0; + } + + qse_size_t getSize () const + { + return this->count; + } + + qse_size_t getCapacity () const + { + return this->capacity; + } + + operator T* () + { + return this->buffer; + } + + operator const T* () const + { + return this->buffer; + } + + T* getBuffer () + { + return this->buffer; + } + + const T* getBuffer () const + { + return this->buffer; + } + + T& operator[] (qse_size_t index) + { + QSE_ASSERT (index < this->count); + return this->buffer[index]; + } + + const T& operator[] (qse_size_t index) const + { + QSE_ASSERT (index < this->count); + return this->buffer[index]; + } + + T& get (qse_size_t index) + { + QSE_ASSERT (index < this->count); + return this->buffer[index]; + } + + const T& get (qse_size_t index) const + { + QSE_ASSERT (index < this->count); + return this->buffer[index]; + } + + void set (qse_size_t index, const T& value) + { + QSE_ASSERT (index < this->count); + this->buffer[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) + { + qse_size_t new_capa = this->resizer (this->capacity); + + if (index < new_capa) + this->setCapacity (new_capa); + else + this->setCapacity (index + 1); + } + else if (this->count >= this->capacity) + { + qse_size_t new_capa = this->resizer (this->capacity); + this->setCapacity (new_capa); + } + + 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->buffer[index] = value; + this->set_item (index, value); + if (index > this->count) this->count = index + 1; + else this->count++; + + return index; + } + + void remove (qse_size_t index) + { + this->remove (index, index); + } + + void remove (qse_size_t from_index, qse_size_t to_index) + { + QSE_ASSERT (from_index < this->count); + QSE_ASSERT (to_index < this->count); + + qse_size_t j = from_index; + qse_size_t i = to_index + 1; + while (i < this->count) + { + this->buffer[j++] = this->buffer[i++]; + } + this->count -= to_index - from_index + 1; + } + +#if 0 + qse_size_t addDatum (const T& value) + { + return insert (this->count, value); + } + + 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++; + } + + 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; + } + + 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; + } + 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++) + { + tmp[i] = this->buffer[i]; + } + } + catch (...) + { + if (tmp != QSE_NULL) delete[] tmp; + throw; + } + + if (this->buffer != QSE_NULL) + delete[] this->buffer; + this->buffer = tmp; + this->capacity = capacity; + this->count = cnt; + } + } + +#if 0 + qse_size_t indexOf (const T& value) const + { + for (qse_size_t i = 0; i < this->count; i++) + { + if (this->buffer[i] == value) return i; + } + return INVALID_INDEX; + } + + qse_size_t indexOf (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; + } + 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 + { + for (qse_size_t i = index + 1; i > 0; ) + { + if (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) n = this->count - n; + first = 0; nk = this->count - n; cnt = 0; + + while (cnt < n) + { + last = first + nk; + index = first; + c = this->buffer[first]; + while (1) + { + cnt++; + while (index < nk) + { + this->buffer[index] = this->buffer[index + n]; + index += n; + } + if (index == last) break; + this->buffer[index] = this->buffer[index - nk]; + index -= nk; + } + this->buffer[last] = c; first++; + } + } + +protected: + Mpool mp; + RESIZER resizer; + + qse_size_t count; + qse_size_t capacity; + T* buffer; +}; + +///////////////////////////////// +QSE_END_NAMESPACE(QSE) +///////////////////////////////// + +#endif + + diff --git a/qse/include/qse/cmn/BinaryHeap.hpp b/qse/include/qse/cmn/BinaryHeap.hpp new file mode 100644 index 00000000..04ba754d --- /dev/null +++ b/qse/include/qse/cmn/BinaryHeap.hpp @@ -0,0 +1,360 @@ +/* + * $Id$ + * + Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _QSE_CMN_BINARYHEAP_HPP_ +#define _QSE_CMN_BINARYHEAP_HPP_ + +/// +/// This file provides an array-based binary heap. +/// In the heap, each node is greater than or equal to its BinaryHeap +/// +/// #include +/// #include +/// +/// struct IntComparator +/// { +/// bool operator() (int v1, int v2) const +/// { +/// //return !(v1 > v2); +/// return v1 > v2; +/// } +/// }; +/// +/// int main (int argc, char* argv[]) +/// { +/// QSE::BinaryHeap heap; +/// +/// heap.insert (70); +/// heap.insert (90); +/// heap.insert (10); +/// heap.insert (5); +/// heap.insert (88); +/// heap.insert (87); +/// heap.insert (300); +/// heap.insert (91); +/// heap.insert (100); +/// heap.insert (200); +/// +/// while (heap.getSize() > 0) +/// { +/// printf ("%d\n", heap.getRootValue()); +/// heap.remove (0); +/// } +/// +/// return 0; +/// } +/// + +#include +#include + + +///////////////////////////////// +QSE_BEGIN_NAMESPACE(QSE) +///////////////////////////////// + +template +struct BinaryHeapComparator +{ + // this can be used to build a max heap + bool operator() (const T& v1, const T& v2) const + { + return v1 > v2; + } +}; + +template +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 + { + v1 = v2; + return v1; + } +}; + +struct BinaryHeapResizer +{ + qse_size_t operator() (qse_size_t current) const + { + return (current < 5000)? (current + current): + (current < 50000)? (current + (current / 2)): + (current < 100000)? (current + (current / 4)): + (current < 150000)? (current + (current / 8)): + (current + (current / 16)); + } +}; + + +#define QSE_BINARY_HEAP_UP(x) (((x) - 1) / 2) +#define QSE_BINARY_HEAP_LEFT(x) ((x) * 2 + 1) +#define QSE_BINARY_HEAP_RIGHT(x) ((x) * 2 + 2) + +template , typename ASSIGNER = BinaryHeapAssigner, RESIZER = TeeeHeapResizer > +class BinaryHeap: public Mmged +{ +public: + typedef BinaryHeap SelfType; + + enum + { + DEFAULT_CAPACITY = 10, + MIN_CAPACITY = 1 + }; + + BinaryHeap (Mmgr* mmgr = QSE_NULL, + qse_size_t capacity = DEFAULT_CAPACITY, + qse_size_t mpb_size = 0): + Mmged (mmgr), + mp (mmgr, QSE_SIZEOF(Node), mpb_size) + { + if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY; + this->capacity = capacity; + this->count = 0; + + this->buffer = (T*)::operator new (this->capacity * QSE_SIZEOF(*this->buffer), &this->mp); + for (qse_size_t i = 0; i < this->capacity; i++) + { + + } + } + + BinaryHeap (const SelfType& heap): + Mmged (heap.getMmgr()), + mp (heap.getMmgr(), heap.mp.getDatumSize(), heap.mp.getBlockSize()), + capacity (heap.capacity), count (0) + { + // TODO: copy data items. + } + + ~BinaryHeap () + { + for (qse_size_t i = this->count; i > 0; ) + { + --i; + this->buffer[i].~T (); + } + + ::operator delete (this->buffer, &this->mp); + } + + SelfType& operator= (const SelfType& heap) + { + this->clear (); + // TODO: copy data items + return *this; + } + + ~BinaryHeap + Mpool& getMpool () + { + return this->mp; + } + + const Mpool& getMpool () const + { + return this->mp; + } + + qse_size_t getCapacity () const + { + return this->capacity; + } + + qse_size_t getSize () const + { + return this->count; + } + + bool isEmpty () const + { + return this->count <= 0; + } + + + + Node* insert (const T& value) + { +#if 0 + qse_size_t index = this->data_count; + + // add the item at the back of the array + // i don't use Tree::insert() for this->assign(). + //Tree::insert (index, value); + Tree::setSize (index + 1); + this->assign (this->data_buffer[index], value, index); + + // move the item up to the top if it's greater than the up item + return sift_up (index); +#endif + } + +#if 0 + qse_size_t update (qse_size_t index, const T& value) + { + T old = this->data_buffer[index]; + + //this->data_buffer[index] = value; + this->assign (this->data_buffer[index], value, index); + + return (this->greater_than (value, old))? sift_up (index): sift_down (index); + } +#endif + + void remove_node (qse_size_t index) + { + QSE_ASSERT (index < this->data_count); + +#if 0 + // copy the last item to the position to remove + // note that this->assign() isn't called for temporary assignment. + T old = this->data_buffer[index]; + + //this->data_buffer[index] = this->data_buffer[this->data_count - 1]; + this->assign (this->data_buffer[index], this->data_buffer[this->data_count - 1], index); + + // delete the last item + Tree::remove (this->data_count - 1); + + // relocate the item + (this->greater_than (this->data_buffer[index], old))? sift_up (index): sift_down (index); +#endif + } + + void remove () + { + /* TODO: remove root node */ + } + + void clear () + { + while (this->root->notNil()) this->remove_node (this->root); + QSE_ASSERT (this->root = this->nil); + QSE_ASSERT (this->node_count == 0); + } + +protected: + Node* sift_up (qse_size_t index) + { +#if 0 + qse_size_t up; + + up = QSE_ARRAY_HEAP_PARENT (index); + if (index > 0 && this->greater_than (this->data_buffer[index], this->data_buffer[up])) + { + // note that this->assign() isn't called for temporary assignment. + T item = this->data_buffer[index]; + + do + { + //this->data_buffer[index] = this->data_buffer[up]; + this->assign (this->data_buffer[index], this->data_buffer[up], index); + + index = up; + up = QSE_ARRAY_HEAP_PARENT (up); + } + while (index > 0 && this->greater_than (item, this->data_buffer[up])); + + //this->data_buffer[index] = item; + this->assign (this->data_buffer[index], item, index); + } + + return index; +#endif + return QSE_NULL; + } + + Node* sift_down (qse_size_t index) + { +#if 0 + qse_size_t half_data_count = this->data_count / 2; + + if (index < half_data_count) + { + // if at least 1 child is under the 'index' position + // perform sifting + + // note that this->assign() isn't called for temporary assignment. + T item = this->data_buffer[index]; + T item = this->data_buffer[index]; + + do + { + qse_size_t left, right, greater; + + left = QSE_ARRAY_HEAP_LEFT (index); + right = QSE_ARRAY_HEAP_RIGHT (index); + + // choose the larger one between 2 BinaryHeap + if (right < this->data_count && + this->greater_than (this->data_buffer[right], this->data_buffer[left])) + { + // if the right child exists and + // the right item is greater than the left item + greater = right; + } + else + { + greater = left; + } + + if (this->greater_than (item, this->data_buffer[greater])) break; + + //this->data_buffer[index] = this->data_buffer[greater]; + this->assign (this->data_buffer[index], this->data_buffer[greater], index); + index = greater; + } + while (index < half_data_count); + + //this->data_buffer[index] = item; + this->assign (this->data_buffer[index], item, index); + } + + return index; +#endif + return QSE_NULL; + } + +protected: + Mpool mp; + COMPARATOR greater_than; + ASSIGNER assigner; + RESIZER resizer; + + qse_size_t capacity; + qse_size_t count; + T* buffer; +}; + + +///////////////////////////////// +QSE_END_NAMESPACE(QSE) +///////////////////////////////// + +#endif diff --git a/qse/include/qse/cmn/Makefile.am b/qse/include/qse/cmn/Makefile.am index 4983d898..637a04c0 100644 --- a/qse/include/qse/cmn/Makefile.am +++ b/qse/include/qse/cmn/Makefile.am @@ -53,6 +53,7 @@ if ENABLE_CXX pkginclude_HEADERS += \ Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \ Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp HashTable.hpp \ - RedBlackTree.hpp RedBlackTable.hpp + RedBlackTree.hpp RedBlackTable.hpp \ + Array.hpp BinaryHeap.hpp endif diff --git a/qse/include/qse/cmn/Makefile.in b/qse/include/qse/cmn/Makefile.in index a03648d0..239c5f18 100644 --- a/qse/include/qse/cmn/Makefile.in +++ b/qse/include/qse/cmn/Makefile.in @@ -53,7 +53,8 @@ host_triplet = @host@ @ENABLE_CXX_TRUE@am__append_1 = \ @ENABLE_CXX_TRUE@ Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \ @ENABLE_CXX_TRUE@ Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp HashTable.hpp \ -@ENABLE_CXX_TRUE@ RedBlackTree.hpp RedBlackTable.hpp +@ENABLE_CXX_TRUE@ RedBlackTree.hpp RedBlackTable.hpp \ +@ENABLE_CXX_TRUE@ Array.hpp BinaryHeap.hpp subdir = include/qse/cmn DIST_COMMON = $(am__pkginclude_HEADERS_DIST) $(srcdir)/Makefile.am \ @@ -93,7 +94,8 @@ am__pkginclude_HEADERS_DIST = alg.h chr.h cp949.h cp950.h dir.h dll.h \ sll.h slmb.h str.h task.h time.h tio.h tmr.h tre.h uni.h uri.h \ utf8.h xma.h Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \ Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp \ - HashTable.hpp RedBlackTree.hpp RedBlackTable.hpp + HashTable.hpp RedBlackTree.hpp RedBlackTable.hpp Array.hpp \ + BinaryHeap.hpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ diff --git a/qse/include/qse/cmn/Mmgr.hpp b/qse/include/qse/cmn/Mmgr.hpp index 0818c471..dab33d23 100644 --- a/qse/include/qse/cmn/Mmgr.hpp +++ b/qse/include/qse/cmn/Mmgr.hpp @@ -179,6 +179,8 @@ QSE_END_NAMESPACE(QSE) void* operator new (qse_size_t size, QSE::Mmgr* mmgr); void operator delete (void* ptr, QSE::Mmgr* mmgr); +void* operator new (qse_size_t size, QSE::Mmgr* mmgr, void* existing_ptr); + #if 0 // i found no way to delete an array allocated with // the placement new operator. if the array element is an instance diff --git a/qse/include/qse/cmn/Mpool.hpp b/qse/include/qse/cmn/Mpool.hpp index 3a375f85..144078e9 100644 --- a/qse/include/qse/cmn/Mpool.hpp +++ b/qse/include/qse/cmn/Mpool.hpp @@ -117,5 +117,6 @@ QSE_END_NAMESPACE(QSE) void* operator new (qse_size_t size, QSE::Mpool* mp); void operator delete (void* ptr, QSE::Mpool* mp); +void* operator new (qse_size_t size, QSE::Mpool* mp, void* existing_ptr); #endif diff --git a/qse/include/qse/cmn/RedBlackTree.hpp b/qse/include/qse/cmn/RedBlackTree.hpp index 7f0c76c8..a1c34ab6 100644 --- a/qse/include/qse/cmn/RedBlackTree.hpp +++ b/qse/include/qse/cmn/RedBlackTree.hpp @@ -55,19 +55,19 @@ public: protected: Color color; - SelfType* parent; + SelfType* up; SelfType* left; // left child SelfType* right; // right child - RedBlackTreeNode(): color (BLACK), parent (this), left (this), right (this) + RedBlackTreeNode(): color (BLACK), up (this), left (this), right (this) { // no initialization on 'value' in this constructor. } - RedBlackTreeNode(const T& value, Color color, SelfType* parent, SelfType* left, SelfType* right): - value (value), color (color), parent (parent), left (left), right (right) + RedBlackTreeNode(const T& value, Color color, SelfType* up, SelfType* left, SelfType* right): + value (value), color (color), up (up), left (left), right (right) { - QSE_ASSERT (parent != this); + QSE_ASSERT (up != this); QSE_ASSERT (left != this); QSE_ASSERT (right != this); } @@ -79,7 +79,7 @@ public: bool isNil () const { - return this->parent == this; // && this->left == this && this->right == this; + return this->up == this; // && this->left == this && this->right == this; } bool notNil () const @@ -90,28 +90,21 @@ public: bool isBlack () const { return this->color == BLACK; } bool isRed () const { return this->color == RED; } - SelfType* getParent () { return this->parent; } - const SelfType* getParent () const { return this->parent; } - SelfType* getParentNode () { return this->parent; } - const SelfType* getParentNode () const { return this->parent; } + SelfType* getUpNode () { return this->up; } + const SelfType* getUpNode () const { return this->up; } - SelfType* getLeft () { return this->left; } - const SelfType* getLeft () const { return this->left; } + SelfType* getLeftNode () { return this->left; } const SelfType* getLeftNode () const { return this->left; } - SelfType* getRight () { return this->right; } - const SelfType* getRight () const { return this->right; } SelfType* getRightNode () { return this->right; } const SelfType* getRightNode () const { return this->right; } //void setBlack () { this->color = BLACK; } //void setRed () { this->color = RED; } - //void setParent (SelfType* node) { this->parent = node; } - //void setLeft (SelfType* node) { this->left = node; } - //void setRight (SelfType* node) { this->right = node; } - - + //void setUpNode (SelfType* node) { this->up = node; } + //void setLeftNode (SelfType* node) { this->left = node; } + //void setRightNode (SelfType* node) { this->right = node; } }; template @@ -153,16 +146,16 @@ public: { QSE_ASSERT (root != QSE_NULL); - this->previous = root->getParent(); + this->previous = root->getUpNode(); if (mode == DESCENDING) { - this->get_left = &Node::getRight; - this->get_right = &Node::getLeft; + this->get_left = &Node::getRightNode; + this->get_right = &Node::getLeftNode; } else { - this->get_left = &Node::getLeft; - this->get_right = &Node::getRight; + this->get_left = &Node::getLeftNode; + this->get_right = &Node::getRightNode; } this->__move_to_next_node (); @@ -175,9 +168,9 @@ protected: while (this->current->notNil()) { - if (this->previous == this->current->getParent()) + if (this->previous == this->current->getUpNode()) { - /* the previous node is the parent of the current node. + /* the previous node is the up of the current node. * it indicates that we're going down to the getChild(l) */ if ((this->current->*this->get_left)()->notNil()) { @@ -201,9 +194,9 @@ protected: { /* both the left child and the right child have been traversed */ QSE_ASSERT (this->previous == (this->current->*this->get_right)()); - /* just move up to the parent */ + /* just move up to the up */ this->previous = this->current; - this->current = this->current->getParent(); + this->current = this->current->getUpNode(); } } } @@ -220,9 +213,9 @@ protected: } else { - /* otherwise, move up to the parent */ + /* otherwise, move up to the up */ this->previous = this->current; - this->current = this->current->getParent(); + this->current = this->current->getUpNode(); } } else if (pending_action == 2) @@ -235,9 +228,9 @@ protected: } else { - /* otherwise, move up to the parent */ + /* otherwise, move up to the up */ this->previous = this->current; - this->current = this->current->getParent(); + this->current = this->current->getUpNode(); } } @@ -327,7 +320,7 @@ public: typedef RedBlackTreeComparator DefaultComparator; RedBlackTree (Mmgr* mmgr = QSE_NULL, qse_size_t mpb_size = 0): - Mmged(mmgr), + Mmged (mmgr), mp (mmgr, QSE_SIZEOF(Node), mpb_size), node_count (0) { @@ -338,8 +331,8 @@ public: this->root = this->nil; } - RedBlackTree (const RedBlackTree& rbt): - Mmged(rbt.getMmgr()), + RedBlackTree (const SelfType& rbt): + Mmged (rbt.getMmgr()), mp (rbt.getMmgr(), rbt.mp.getDatumSize(), rbt.mp.getBlockSize()), node_count (0) { @@ -365,7 +358,7 @@ public: this->dispose_node (this->nil); } - RedBlackTree& operator= (const RedBlackTree& rbt) + SelfType& operator= (const SelfType& rbt) { this->clear (); @@ -400,14 +393,16 @@ public: return this->node_count <= 0; } + /// The getRootNode() function gets the pointer to the root node. + /// If no node exists in the tree, it returns #QSE_NULL. Node* getRootNode () { - return this->root; + return this->root->isNil()? QSE_NULL: this->root; } const Node* getRootNode () const { - return this->root; + return this->root->isNil()? QSE_NULL: this->root; } protected: @@ -463,7 +458,7 @@ protected: * left child(x). move the pivot's right child(y) to the pivot's original * position. as 'c1' is between 'y' and 'pivot', move it to the right * of the new pivot position. - * parent parent + * up up * | | (left or right?) | | * pivot y * / \ / \ @@ -477,7 +472,7 @@ protected: * position. as 'c2' is between 'x' and 'pivot', move it to the left * of the new pivot position. * - * parent parent + * up up * | | (left or right?) | | * pivot x * / \ / \ @@ -487,15 +482,15 @@ protected: * * * the actual implementation here resolves the pivot's relationship to - * its parent by comparaing pointers as it is not known if the pivot pair - * is the left child or the right child of its parent, + * its up by comparaing pointers as it is not known if the pivot pair + * is the left child or the right child of its up, */ - Node* parent, * z, * c; + Node* up, * z, * c; QSE_ASSERT (pivot != QSE_NULL); - parent = pivot->parent; + up = pivot->up; if (leftwise) { // y for leftwise rotation @@ -511,17 +506,17 @@ protected: c = z->right; } - z->parent = parent; - if (parent->notNil()) + z->up = up; + if (up->notNil()) { - if (parent->left == pivot) + if (up->left == pivot) { - parent->left = z; + up->left = z; } else { - QSE_ASSERT (parent->right == pivot); - parent->right = z; + QSE_ASSERT (up->right == pivot); + up->right = z; } } else @@ -541,8 +536,8 @@ protected: pivot->left = c; } - if (pivot->notNil()) pivot->parent = z; - if (c->notNil()) c->parent = pivot; + if (pivot->notNil()) pivot->up = z; + if (c->notNil()) c->up = pivot; } void rotate_left (Node* pivot) @@ -562,12 +557,12 @@ protected: Node* tmp, * tmp2, * x_par, * x_grand_par; bool leftwise; - x_par = node->parent; + x_par = node->up; if (x_par->color == Node::BLACK) break; - QSE_ASSERT (x_par->parent->notNil()); + QSE_ASSERT (x_par->up->notNil()); - x_grand_par = x_par->parent; + x_grand_par = x_par->up; if (x_par == x_grand_par->left) { tmp = x_grand_par->right; @@ -594,8 +589,8 @@ protected: { node = x_par; this->rotate (node, leftwise); - x_par = node->parent; - x_grand_par = x_par->parent; + x_par = node->up; + x_grand_par = x_par->up; } x_par->color = Node::BLACK; @@ -627,7 +622,7 @@ protected: { if (tmp->notNil()) tmp->color = Node::RED; node = par; - par = node->parent; + par = node->up; } else { @@ -666,7 +661,7 @@ protected: { if (tmp->notNil()) tmp->color = Node::RED; node = par; - par = node->parent; + par = node->up; } else { @@ -711,8 +706,8 @@ protected: x = (y->left->isNil())? y->right: y->left; - par = y->parent; - if (x->notNil()) x->parent = par; + par = y->up; + if (x->notNil()) x->up = par; if (par->notNil()) // if (par) { @@ -738,23 +733,23 @@ protected: if (y->color == Node::BLACK && x->notNil()) this->rebalance_for_removal (x, par); - if (node->parent->notNil()) //if (node->parent) + if (node->up->notNil()) //if (node->up) { - if (node->parent->left == node) node->parent->left = y; - if (node->parent->right == node) node->parent->right = y; + if (node->up->left == node) node->up->left = y; + if (node->up->right == node) node->up->right = y; } else { this->root = y; } - y->parent = node->parent; + y->up = node->up; y->left = node->left; y->right = node->right; y->color = node->color; - if (node->left->parent == node) node->left->parent = y; - if (node->right->parent == node) node->right->parent = y; + if (node->left->up == node) node->left->up = y; + if (node->right->up == node) node->right->up = y; this->dispose_node (node); } @@ -800,7 +795,6 @@ public: return this->heterofind_node (datum); } - template T* heterofindValue(const MT& datum) { @@ -839,6 +833,20 @@ public: return this->heterofind_node (datum); } + /// The inject() function inserts a \a datum if no existing datum + /// is found to be equal using the comparator. The \a mode argument + /// determines what action to take when an equal datum is found. + /// - -1: failure + /// - 0: do nothing + /// - 1: overwrite the existing datum + /// + /// if \a injected is not #QSE_NULL, it is set to true when \a datum + /// has been inserted newly and false when an equal datum has been + /// found. + /// + /// The function returns the poniter to the node inserted or + /// affected. It return #QSE_NULL if mode is set to -1 and a duplicate + /// item has been found. Node* inject (const T& datum, int mode, bool* injected = QSE_NULL) { Node* x_cur = this->root; @@ -881,7 +889,7 @@ public: x_par->left = x_new; } - x_new->parent = x_par; + x_new->up = x_par; this->rebalance_for_injection (x_new); } diff --git a/qse/lib/cmn/Mmgr.cpp b/qse/lib/cmn/Mmgr.cpp index ab957381..783becfc 100644 --- a/qse/lib/cmn/Mmgr.cpp +++ b/qse/lib/cmn/Mmgr.cpp @@ -80,6 +80,13 @@ void operator delete (void* ptr, QSE::Mmgr* mmgr) mmgr->dispose (ptr); } +void* operator new (qse_size_t size, QSE::Mmgr* mmgr, void* existing_ptr) +{ + // mmgr unused. i put it in the parameter list to make this function + // less conflicting with the stock ::operator new() that doesn't allocate. + return existing_ptr; +} + #if 0 void* operator new[] (qse_size_t size, QSE::Mmgr* mmgr) { diff --git a/qse/lib/cmn/Mpool.cpp b/qse/lib/cmn/Mpool.cpp index 2e925fd9..1fb4363e 100644 --- a/qse/lib/cmn/Mpool.cpp +++ b/qse/lib/cmn/Mpool.cpp @@ -182,7 +182,7 @@ QSE_END_NAMESPACE(QSE) void* operator new (qse_size_t size, QSE::Mpool* mp) { - return mp->isEnabled()? mp->allocate (): ::operator new (size, mp->getMmgr()); + return mp->isEnabled()? mp->allocate(): ::operator new(size, mp->getMmgr()); } void operator delete (void* ptr, QSE::Mpool* mp) @@ -190,3 +190,8 @@ void operator delete (void* ptr, QSE::Mpool* mp) if (mp->isEnabled()) mp->dispose (ptr); else ::operator delete (ptr, mp->getMmgr()); } + +void* operator new (qse_size_t size, QSE::Mpool* mp, void* existing_ptr) +{ + return existing_ptr; +}