Added a couple of 'operator new()' definitions.

Started adding Array and BinaryHeap
This commit is contained in:
hyung-hwan 2015-03-04 16:30:09 +00:00
parent e26a49bcb8
commit 0c0f0df7d8
9 changed files with 919 additions and 73 deletions

View File

@ -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 <qse/Types.hpp>
#include <qse/cmn/Mpool.hpp>
/////////////////////////////////
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 <typename T, typename RESIZER = ArrayResizer>
class Array: public Mmged
{
public:
typedef Array<T,RESIZER> 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<T>& operator+= (const T& value)
{
addDatum (value);
return *this;
}
Array<T>& operator+ (const T& value) const
{
Array<T> 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

View File

@ -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 <qse/cmn/BinaryHeap.hpp>
/// #include <stdio.h>
///
/// struct IntComparator
/// {
/// bool operator() (int v1, int v2) const
/// {
/// //return !(v1 > v2);
/// return v1 > v2;
/// }
/// };
///
/// int main (int argc, char* argv[])
/// {
/// QSE::BinaryHeap<int,IntComparator> 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 <qse/Types.hpp>
#include <qse/cmn/Mpool.hpp>
/////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE)
/////////////////////////////////
template <typename T>
struct BinaryHeapComparator
{
// this can be used to build a max heap
bool operator() (const T& v1, const T& v2) const
{
return v1 > v2;
}
};
template<typename T>
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 T, typename COMPARATOR = BinaryHeapComparator<T>, typename ASSIGNER = BinaryHeapAssigner<T>, RESIZER = TeeeHeapResizer >
class BinaryHeap: public Mmged
{
public:
typedef BinaryHeap<T,COMPARATOR,ASSIGNER,RESIZER> 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<T>::insert() for this->assign().
//Tree<T>::insert (index, value);
Tree<T>::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<T>::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

View File

@ -53,6 +53,7 @@ if ENABLE_CXX
pkginclude_HEADERS += \ pkginclude_HEADERS += \
Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \ Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \
Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp HashTable.hpp \ Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp HashTable.hpp \
RedBlackTree.hpp RedBlackTable.hpp RedBlackTree.hpp RedBlackTable.hpp \
Array.hpp BinaryHeap.hpp
endif endif

View File

@ -53,7 +53,8 @@ host_triplet = @host@
@ENABLE_CXX_TRUE@am__append_1 = \ @ENABLE_CXX_TRUE@am__append_1 = \
@ENABLE_CXX_TRUE@ Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \ @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@ 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 subdir = include/qse/cmn
DIST_COMMON = $(am__pkginclude_HEADERS_DIST) $(srcdir)/Makefile.am \ 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 \ 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 \ utf8.h xma.h Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \
Mpool.hpp Association.hpp LinkedList.hpp HashList.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_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \ am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \

View File

@ -179,6 +179,8 @@ QSE_END_NAMESPACE(QSE)
void* operator new (qse_size_t size, QSE::Mmgr* mmgr); void* operator new (qse_size_t size, QSE::Mmgr* mmgr);
void operator delete (void* ptr, 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 #if 0
// i found no way to delete an array allocated with // i found no way to delete an array allocated with
// the placement new operator. if the array element is an instance // the placement new operator. if the array element is an instance

View File

@ -117,5 +117,6 @@ QSE_END_NAMESPACE(QSE)
void* operator new (qse_size_t size, QSE::Mpool* mp); void* operator new (qse_size_t size, QSE::Mpool* mp);
void operator delete (void* ptr, 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 #endif

View File

@ -55,19 +55,19 @@ public:
protected: protected:
Color color; Color color;
SelfType* parent; SelfType* up;
SelfType* left; // left child SelfType* left; // left child
SelfType* right; // right 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. // no initialization on 'value' in this constructor.
} }
RedBlackTreeNode(const T& value, Color color, SelfType* parent, SelfType* left, SelfType* right): RedBlackTreeNode(const T& value, Color color, SelfType* up, SelfType* left, SelfType* right):
value (value), color (color), parent (parent), left (left), right (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 (left != this);
QSE_ASSERT (right != this); QSE_ASSERT (right != this);
} }
@ -79,7 +79,7 @@ public:
bool isNil () const 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 bool notNil () const
@ -90,28 +90,21 @@ public:
bool isBlack () const { return this->color == BLACK; } bool isBlack () const { return this->color == BLACK; }
bool isRed () const { return this->color == RED; } bool isRed () const { return this->color == RED; }
SelfType* getParent () { return this->parent; } SelfType* getUpNode () { return this->up; }
const SelfType* getParent () const { return this->parent; } const SelfType* getUpNode () const { return this->up; }
SelfType* getParentNode () { return this->parent; }
const SelfType* getParentNode () const { return this->parent; }
SelfType* getLeft () { return this->left; }
const SelfType* getLeft () const { return this->left; }
SelfType* getLeftNode () { return this->left; } SelfType* getLeftNode () { return this->left; }
const SelfType* getLeftNode () const { 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; } SelfType* getRightNode () { return this->right; }
const SelfType* getRightNode () const { return this->right; } const SelfType* getRightNode () const { return this->right; }
//void setBlack () { this->color = BLACK; } //void setBlack () { this->color = BLACK; }
//void setRed () { this->color = RED; } //void setRed () { this->color = RED; }
//void setParent (SelfType* node) { this->parent = node; } //void setUpNode (SelfType* node) { this->up = node; }
//void setLeft (SelfType* node) { this->left = node; } //void setLeftNode (SelfType* node) { this->left = node; }
//void setRight (SelfType* node) { this->right = node; } //void setRightNode (SelfType* node) { this->right = node; }
}; };
template <typename T> template <typename T>
@ -153,16 +146,16 @@ public:
{ {
QSE_ASSERT (root != QSE_NULL); QSE_ASSERT (root != QSE_NULL);
this->previous = root->getParent(); this->previous = root->getUpNode();
if (mode == DESCENDING) if (mode == DESCENDING)
{ {
this->get_left = &Node::getRight; this->get_left = &Node::getRightNode;
this->get_right = &Node::getLeft; this->get_right = &Node::getLeftNode;
} }
else else
{ {
this->get_left = &Node::getLeft; this->get_left = &Node::getLeftNode;
this->get_right = &Node::getRight; this->get_right = &Node::getRightNode;
} }
this->__move_to_next_node (); this->__move_to_next_node ();
@ -175,9 +168,9 @@ protected:
while (this->current->notNil()) 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) */ * it indicates that we're going down to the getChild(l) */
if ((this->current->*this->get_left)()->notNil()) if ((this->current->*this->get_left)()->notNil())
{ {
@ -201,9 +194,9 @@ protected:
{ {
/* both the left child and the right child have been traversed */ /* both the left child and the right child have been traversed */
QSE_ASSERT (this->previous == (this->current->*this->get_right)()); 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->previous = this->current;
this->current = this->current->getParent(); this->current = this->current->getUpNode();
} }
} }
} }
@ -220,9 +213,9 @@ protected:
} }
else else
{ {
/* otherwise, move up to the parent */ /* otherwise, move up to the up */
this->previous = this->current; this->previous = this->current;
this->current = this->current->getParent(); this->current = this->current->getUpNode();
} }
} }
else if (pending_action == 2) else if (pending_action == 2)
@ -235,9 +228,9 @@ protected:
} }
else else
{ {
/* otherwise, move up to the parent */ /* otherwise, move up to the up */
this->previous = this->current; this->previous = this->current;
this->current = this->current->getParent(); this->current = this->current->getUpNode();
} }
} }
@ -327,7 +320,7 @@ public:
typedef RedBlackTreeComparator<T> DefaultComparator; typedef RedBlackTreeComparator<T> DefaultComparator;
RedBlackTree (Mmgr* mmgr = QSE_NULL, qse_size_t mpb_size = 0): RedBlackTree (Mmgr* mmgr = QSE_NULL, qse_size_t mpb_size = 0):
Mmged(mmgr), Mmged (mmgr),
mp (mmgr, QSE_SIZEOF(Node), mpb_size), mp (mmgr, QSE_SIZEOF(Node), mpb_size),
node_count (0) node_count (0)
{ {
@ -338,8 +331,8 @@ public:
this->root = this->nil; this->root = this->nil;
} }
RedBlackTree (const RedBlackTree& rbt): RedBlackTree (const SelfType& rbt):
Mmged(rbt.getMmgr()), Mmged (rbt.getMmgr()),
mp (rbt.getMmgr(), rbt.mp.getDatumSize(), rbt.mp.getBlockSize()), mp (rbt.getMmgr(), rbt.mp.getDatumSize(), rbt.mp.getBlockSize()),
node_count (0) node_count (0)
{ {
@ -365,7 +358,7 @@ public:
this->dispose_node (this->nil); this->dispose_node (this->nil);
} }
RedBlackTree& operator= (const RedBlackTree& rbt) SelfType& operator= (const SelfType& rbt)
{ {
this->clear (); this->clear ();
@ -400,14 +393,16 @@ public:
return this->node_count <= 0; 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 () Node* getRootNode ()
{ {
return this->root; return this->root->isNil()? QSE_NULL: this->root;
} }
const Node* getRootNode () const const Node* getRootNode () const
{ {
return this->root; return this->root->isNil()? QSE_NULL: this->root;
} }
protected: protected:
@ -463,7 +458,7 @@ protected:
* left child(x). move the pivot's right child(y) to the pivot's original * 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 * position. as 'c1' is between 'y' and 'pivot', move it to the right
* of the new pivot position. * of the new pivot position.
* parent parent * up up
* | | (left or right?) | | * | | (left or right?) | |
* pivot y * pivot y
* / \ / \ * / \ / \
@ -477,7 +472,7 @@ protected:
* position. as 'c2' is between 'x' and 'pivot', move it to the left * position. as 'c2' is between 'x' and 'pivot', move it to the left
* of the new pivot position. * of the new pivot position.
* *
* parent parent * up up
* | | (left or right?) | | * | | (left or right?) | |
* pivot x * pivot x
* / \ / \ * / \ / \
@ -487,15 +482,15 @@ protected:
* *
* *
* the actual implementation here resolves the pivot's relationship to * the actual implementation here resolves the pivot's relationship to
* its parent by comparaing pointers as it is not known if the pivot pair * its up by comparaing pointers as it is not known if the pivot pair
* is the left child or the right child of its parent, * is the left child or the right child of its up,
*/ */
Node* parent, * z, * c; Node* up, * z, * c;
QSE_ASSERT (pivot != QSE_NULL); QSE_ASSERT (pivot != QSE_NULL);
parent = pivot->parent; up = pivot->up;
if (leftwise) if (leftwise)
{ {
// y for leftwise rotation // y for leftwise rotation
@ -511,17 +506,17 @@ protected:
c = z->right; c = z->right;
} }
z->parent = parent; z->up = up;
if (parent->notNil()) if (up->notNil())
{ {
if (parent->left == pivot) if (up->left == pivot)
{ {
parent->left = z; up->left = z;
} }
else else
{ {
QSE_ASSERT (parent->right == pivot); QSE_ASSERT (up->right == pivot);
parent->right = z; up->right = z;
} }
} }
else else
@ -541,8 +536,8 @@ protected:
pivot->left = c; pivot->left = c;
} }
if (pivot->notNil()) pivot->parent = z; if (pivot->notNil()) pivot->up = z;
if (c->notNil()) c->parent = pivot; if (c->notNil()) c->up = pivot;
} }
void rotate_left (Node* pivot) void rotate_left (Node* pivot)
@ -562,12 +557,12 @@ protected:
Node* tmp, * tmp2, * x_par, * x_grand_par; Node* tmp, * tmp2, * x_par, * x_grand_par;
bool leftwise; bool leftwise;
x_par = node->parent; x_par = node->up;
if (x_par->color == Node::BLACK) break; 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) if (x_par == x_grand_par->left)
{ {
tmp = x_grand_par->right; tmp = x_grand_par->right;
@ -594,8 +589,8 @@ protected:
{ {
node = x_par; node = x_par;
this->rotate (node, leftwise); this->rotate (node, leftwise);
x_par = node->parent; x_par = node->up;
x_grand_par = x_par->parent; x_grand_par = x_par->up;
} }
x_par->color = Node::BLACK; x_par->color = Node::BLACK;
@ -627,7 +622,7 @@ protected:
{ {
if (tmp->notNil()) tmp->color = Node::RED; if (tmp->notNil()) tmp->color = Node::RED;
node = par; node = par;
par = node->parent; par = node->up;
} }
else else
{ {
@ -666,7 +661,7 @@ protected:
{ {
if (tmp->notNil()) tmp->color = Node::RED; if (tmp->notNil()) tmp->color = Node::RED;
node = par; node = par;
par = node->parent; par = node->up;
} }
else else
{ {
@ -711,8 +706,8 @@ protected:
x = (y->left->isNil())? y->right: y->left; x = (y->left->isNil())? y->right: y->left;
par = y->parent; par = y->up;
if (x->notNil()) x->parent = par; if (x->notNil()) x->up = par;
if (par->notNil()) // if (par) if (par->notNil()) // if (par)
{ {
@ -738,23 +733,23 @@ protected:
if (y->color == Node::BLACK && x->notNil()) if (y->color == Node::BLACK && x->notNil())
this->rebalance_for_removal (x, par); 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->up->left == node) node->up->left = y;
if (node->parent->right == node) node->parent->right = y; if (node->up->right == node) node->up->right = y;
} }
else else
{ {
this->root = y; this->root = y;
} }
y->parent = node->parent; y->up = node->up;
y->left = node->left; y->left = node->left;
y->right = node->right; y->right = node->right;
y->color = node->color; y->color = node->color;
if (node->left->parent == node) node->left->parent = y; if (node->left->up == node) node->left->up = y;
if (node->right->parent == node) node->right->parent = y; if (node->right->up == node) node->right->up = y;
this->dispose_node (node); this->dispose_node (node);
} }
@ -800,7 +795,6 @@ public:
return this->heterofind_node<MT,MCOMPARATOR> (datum); return this->heterofind_node<MT,MCOMPARATOR> (datum);
} }
template <typename MT, typename MCOMPARATOR> template <typename MT, typename MCOMPARATOR>
T* heterofindValue(const MT& datum) T* heterofindValue(const MT& datum)
{ {
@ -839,6 +833,20 @@ public:
return this->heterofind_node<MT,MCOMPARATOR> (datum); return this->heterofind_node<MT,MCOMPARATOR> (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* inject (const T& datum, int mode, bool* injected = QSE_NULL)
{ {
Node* x_cur = this->root; Node* x_cur = this->root;
@ -881,7 +889,7 @@ public:
x_par->left = x_new; x_par->left = x_new;
} }
x_new->parent = x_par; x_new->up = x_par;
this->rebalance_for_injection (x_new); this->rebalance_for_injection (x_new);
} }

View File

@ -80,6 +80,13 @@ void operator delete (void* ptr, QSE::Mmgr* mmgr)
mmgr->dispose (ptr); 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 #if 0
void* operator new[] (qse_size_t size, QSE::Mmgr* mmgr) void* operator new[] (qse_size_t size, QSE::Mmgr* mmgr)
{ {

View File

@ -182,7 +182,7 @@ QSE_END_NAMESPACE(QSE)
void* operator new (qse_size_t size, QSE::Mpool* mp) 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) 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); if (mp->isEnabled()) mp->dispose (ptr);
else ::operator delete (ptr, mp->getMmgr()); else ::operator delete (ptr, mp->getMmgr());
} }
void* operator new (qse_size_t size, QSE::Mpool* mp, void* existing_ptr)
{
return existing_ptr;
}