Added a couple of 'operator new()' definitions.
Started adding Array and BinaryHeap
This commit is contained in:
parent
e26a49bcb8
commit
0c0f0df7d8
460
qse/include/qse/cmn/Array.hpp
Normal file
460
qse/include/qse/cmn/Array.hpp
Normal 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
|
||||
|
||||
|
360
qse/include/qse/cmn/BinaryHeap.hpp
Normal file
360
qse/include/qse/cmn/BinaryHeap.hpp
Normal 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
|
@ -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
|
||||
|
||||
|
@ -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/||"`;; \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 <typename T>
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -338,7 +331,7 @@ public:
|
||||
this->root = this->nil;
|
||||
}
|
||||
|
||||
RedBlackTree (const RedBlackTree& rbt):
|
||||
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<MT,MCOMPARATOR> (datum);
|
||||
}
|
||||
|
||||
|
||||
template <typename MT, typename MCOMPARATOR>
|
||||
T* heterofindValue(const MT& datum)
|
||||
{
|
||||
@ -839,6 +833,20 @@ public:
|
||||
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* 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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user