changed void* operator new (qse_size_t size, QSE::Mpool* mp) to fall back to mmgr upon size mismatch.

finished primitive BinaryHeap code.
renamed Array::get() to Array::getValueAt()
renamed Array::set() to Array::setValueAt()
This commit is contained in:
hyung-hwan 2015-03-07 03:55:40 +00:00
parent fc316009b6
commit efc997750e
5 changed files with 88 additions and 187 deletions

View File

@ -57,6 +57,8 @@ class Array: public Mmged
public: public:
typedef Array<T,RESIZER> SelfType; typedef Array<T,RESIZER> SelfType;
typedef ArrayResizer DefaultResizer;
enum enum
{ {
DEFAULT_CAPACITY = 128, DEFAULT_CAPACITY = 128,
@ -229,21 +231,20 @@ public:
return this->buffer[index]; return this->buffer[index];
} }
T& get (qse_size_t index) T& getValueAtgetValueAt (qse_size_t index)
{ {
QSE_ASSERT (index < this->count); QSE_ASSERT (index < this->count);
return this->buffer[index]; return this->buffer[index];
} }
const T& get (qse_size_t index) const const T& getValueAt (qse_size_t index) const
{ {
QSE_ASSERT (index < this->count); QSE_ASSERT (index < this->count);
return this->buffer[index]; return this->buffer[index];
} }
void set (qse_size_t index, const T& value) void setValueAt (qse_size_t index, const T& value)
{ {
QSE_ASSERT (index < this->count);
this->insert (index, value); this->insert (index, value);
} }
@ -383,6 +384,8 @@ public:
void setCapacity (qse_size_t capa) void setCapacity (qse_size_t capa)
{ {
if (capa == this->capacity) return;
if (capa <= 0) if (capa <= 0)
{ {
this->clear (true); this->clear (true);
@ -395,15 +398,7 @@ public:
if (cnt > capa) cnt = capa; if (cnt > capa) cnt = capa;
T* tmp = this->clone_buffer (this->buffer, capa, cnt); T* tmp = this->clone_buffer (this->buffer, capa, cnt);
this->clear (true);
// don't call this->clear(true) here. clear items only.
this->clear_all_items ();
// deallocate the current buffer;
::operator delete (this->buffer, this->getMmgr());
this->capacity = 0;
this->buffer = QSE_NULL;
this->buffer = tmp; this->buffer = tmp;
this->capacity = capa; this->capacity = capa;
this->count = cnt; this->count = cnt;
@ -418,7 +413,8 @@ public:
} }
} }
void trimToSize () // The compact() function
void compact ()
{ {
this->setCapacity (this->size); this->setCapacity (this->size);
} }

View File

@ -28,7 +28,7 @@
#define _QSE_CMN_BINARYHEAP_HPP_ #define _QSE_CMN_BINARYHEAP_HPP_
/// ///
/// This file provides an array-based binary heap. /// This file provides a binary heap implementation.
/// In the heap, each node is greater than or equal to its BinaryHeap /// In the heap, each node is greater than or equal to its BinaryHeap
/// ///
/// #include <qse/cmn/BinaryHeap.hpp> /// #include <qse/cmn/BinaryHeap.hpp>
@ -60,7 +60,7 @@
/// ///
/// while (heap.getSize() > 0) /// while (heap.getSize() > 0)
/// { /// {
/// printf ("%d\n", heap.getRootValue()); /// printf ("%d\n", heap.getValueAt(0));
/// heap.remove (0); /// heap.remove (0);
/// } /// }
/// ///
@ -68,14 +68,13 @@
/// } /// }
/// ///
#include <qse/Types.hpp> #include <qse/cmn/Array.hpp>
#include <qse/cmn/Mpool.hpp>
///////////////////////////////// /////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE) QSE_BEGIN_NAMESPACE(QSE)
///////////////////////////////// /////////////////////////////////
// greater-than comparator
template <typename T> template <typename T>
struct BinaryHeapComparator struct BinaryHeapComparator
{ {
@ -86,170 +85,92 @@ struct BinaryHeapComparator
} }
}; };
template<typename T> typedef ArrayResizer BinaryHeapResizer;
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, qse_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_UP(x) (((x) - 1) / 2)
#define QSE_BINARY_HEAP_LEFT(x) ((x) * 2 + 1) #define QSE_BINARY_HEAP_LEFT(x) ((x) * 2 + 1)
#define QSE_BINARY_HEAP_RIGHT(x) ((x) * 2 + 2) #define QSE_BINARY_HEAP_RIGHT(x) ((x) * 2 + 2)
template <typename T, typename COMPARATOR = BinaryHeapComparator<T>, typename ASSIGNER = BinaryHeapAssigner<T>, RESIZER = TeeeHeapResizer > template <typename T, typename COMPARATOR = BinaryHeapComparator<T>, typename RESIZER = BinaryHeapResizer >
class BinaryHeap: public Mmged class BinaryHeap: protected Array<T,RESIZER>
{ {
public: public:
typedef BinaryHeap<T,COMPARATOR,ASSIGNER,RESIZER> SelfType; typedef BinaryHeap<T,COMPARATOR,RESIZER> SelfType;
typedef Array<T,RESIZER> ParentType;
typedef BinaryHeapComparator<T> DefaultComparator;
typedef BinaryHeapResizer DefaultResizer;
enum enum
{ {
DEFAULT_CAPACITY = 10, DEFAULT_CAPACITY = ParentType::DEFAULT_CAPACITY,
MIN_CAPACITY = 1 INVALID_INDEX = ParentType::INVALID_INDEX
}; };
BinaryHeap (Mmgr* mmgr = QSE_NULL, BinaryHeap (Mmgr* mmgr = QSE_NULL, qse_size_t capacity = DEFAULT_CAPACITY):
qse_size_t capacity = DEFAULT_CAPACITY, ParentType (mmgr, 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): BinaryHeap (const SelfType& heap): ParentType (heap)
Mmged (heap.getMmgr()),
mp (heap.getMmgr(), heap.mp.getDatumSize(), heap.mp.getBlockSize()),
capacity (heap.capacity), count (0)
{ {
// TODO: copy data items.
} }
~BinaryHeap () ~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) SelfType& operator= (const SelfType& heap)
{ {
this->clear (); ParentType::operator= (heap);
// TODO: copy data items
return *this; return *this;
} }
~BinaryHeap using ParentType::isEmpty;
Mpool& getMpool () using ParentType::getSize;
using ParentType::getCapacity;
using ParentType::clear;
using ParentType::compact;
const T& getValueAt (qse_size_t index) const
{ {
return this->mp; return ParentType::getValueAt (index);
} }
const Mpool& getMpool () const qse_size_t insert (const T& value)
{ {
return this->mp; qse_size_t index = this->count;
}
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 // add the item at the back of the array
// i don't use Tree<T>::insert() for this->assign(). ParentType::insert (index, value);
//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 // move the item up to the top if it's greater than the up item
return sift_up (index); return this->sift_up(index);
#endif
} }
#if 0
qse_size_t update (qse_size_t index, const T& value) qse_size_t update (qse_size_t index, const T& value)
{ {
T old = this->data_buffer[index]; T old = this->data_buffer[index];
//this->data_buffer[index] = value; this->buffer[index] = value;
this->assign (this->data_buffer[index], value, index);
return (this->greater_than (value, old))? sift_up (index): sift_down (index); return (this->greater_than(value, old))? this->sift_up(index): this->sift_down(index);
} }
#endif
void remove_node (qse_size_t index) void remove (qse_size_t index)
{ {
QSE_ASSERT (index < this->data_count); QSE_ASSERT (index < this->count);
#if 0
// copy the last item to the position to remove // copy the last item to the position to remove
// note that this->assign() isn't called for temporary assignment. T old = this->buffer[index];
T old = this->data_buffer[index];
//this->data_buffer[index] = this->data_buffer[this->data_count - 1]; this->buffer[index] = this->buffer[this->count - 1];
this->assign (this->data_buffer[index], this->data_buffer[this->data_count - 1], index);
// delete the last item // delete the last item
Tree<T>::remove (this->data_count - 1); ParentType::remove (this->count - 1);
// relocate the item // relocate the item
(this->greater_than (this->data_buffer[index], old))? sift_up (index): sift_down (index); (this->greater_than (this->buffer[index], old))? this->sift_up(index): this->sift_down(index);
#endif
}
void remove ()
{
/* TODO: remove root node */
} }
void clear () void clear ()
@ -260,60 +181,51 @@ public:
} }
protected: protected:
Node* sift_up (qse_size_t index) qse_size_t sift_up (qse_size_t index)
{ {
#if 0
qse_size_t up; qse_size_t up;
up = QSE_ARRAY_HEAP_PARENT (index); up = QSE_BINARY_HEAP_UP(index);
if (index > 0 && this->greater_than (this->data_buffer[index], this->data_buffer[up])) if (index > 0 && this->greater_than(this->buffer[index], this->buffer[up]))
{ {
// note that this->assign() isn't called for temporary assignment. T item = this->buffer[index];
T item = this->data_buffer[index];
do do
{ {
//this->data_buffer[index] = this->data_buffer[up]; this->buffer[index] = this->buffer[up];
this->assign (this->data_buffer[index], this->data_buffer[up], index);
index = up; index = up;
up = QSE_ARRAY_HEAP_PARENT (up); up = QSE_BINARY_HEAP_UP(up);
} }
while (index > 0 && this->greater_than (item, this->data_buffer[up])); while (index > 0 && this->greater_than(item, this->buffer[up]));
//this->data_buffer[index] = item; this->buffer[index] = item;
this->assign (this->data_buffer[index], item, index);
} }
return index; return index;
#endif
return QSE_NULL;
} }
Node* sift_down (qse_size_t index) qse_size_t sift_down (qse_size_t index)
{ {
#if 0 qse_size_t half_data_count = this->count / 2;
qse_size_t half_data_count = this->data_count / 2;
if (index < half_data_count) if (index < half_data_count)
{ {
// if at least 1 child is under the 'index' position // if at least 1 child is under the 'index' position
// perform sifting // perform sifting
// note that this->assign() isn't called for temporary assignment. T item = this->buffer[index];
T item = this->data_buffer[index];
T item = this->data_buffer[index];
do do
{ {
qse_size_t left, right, greater; qse_size_t left, right, greater;
left = QSE_ARRAY_HEAP_LEFT (index); left = QSE_BINARY_HEAP_LEFT(index);
right = QSE_ARRAY_HEAP_RIGHT (index); right = QSE_BINARY_HEAP_RIGHT(index);
// choose the larger one between 2 BinaryHeap // choose the larger one between 2 BinaryHeap
if (right < this->data_count && if (right < this->count &&
this->greater_than (this->data_buffer[right], this->data_buffer[left])) this->greater_than(this->buffer[right], this->buffer[left]))
{ {
// if the right child exists and // if the right child exists and
// the right item is greater than the left item // the right item is greater than the left item
@ -324,32 +236,21 @@ protected:
greater = left; greater = left;
} }
if (this->greater_than (item, this->data_buffer[greater])) break; if (this->greater_than(item, this->buffer[greater])) break;
//this->data_buffer[index] = this->data_buffer[greater]; this->buffer[index] = this->buffer[greater];
this->assign (this->data_buffer[index], this->data_buffer[greater], index);
index = greater; index = greater;
} }
while (index < half_data_count); while (index < half_data_count);
//this->data_buffer[index] = item; this->buffer[index] = item;
this->assign (this->data_buffer[index], item, index);
} }
return index; return index;
#endif
return QSE_NULL;
} }
protected: protected:
Mpool mp;
COMPARATOR greater_than; COMPARATOR greater_than;
ASSIGNER assigner;
RESIZER resizer;
qse_size_t capacity;
qse_size_t count;
T* buffer;
}; };

View File

@ -55,7 +55,6 @@ public:
typedef qse_mmgr_t mmgr_t; typedef qse_mmgr_t mmgr_t;
QSE_EXCEPTION (MemoryError); QSE_EXCEPTION (MemoryError);
QSE_EXCEPTION (InvalidArgumentError);
protected: protected:
bool raise_exception; bool raise_exception;

View File

@ -170,7 +170,7 @@ protected:
{ {
if (this->previous == this->current->getUpNode()) if (this->previous == this->current->getUpNode())
{ {
/* the previous node is the up of the current node. /* the previous node is the parent 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())
{ {
@ -194,7 +194,7 @@ 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 up */ /* just move up to the parent */
this->previous = this->current; this->previous = this->current;
this->current = this->current->getUpNode(); this->current = this->current->getUpNode();
} }
@ -213,7 +213,7 @@ protected:
} }
else else
{ {
/* otherwise, move up to the up */ /* otherwise, move up to the parent */
this->previous = this->current; this->previous = this->current;
this->current = this->current->getUpNode(); this->current = this->current->getUpNode();
} }
@ -228,7 +228,7 @@ protected:
} }
else else
{ {
/* otherwise, move up to the up */ /* otherwise, move up to the parent */
this->previous = this->current; this->previous = this->current;
this->current = this->current->getUpNode(); this->current = this->current->getUpNode();
} }
@ -478,7 +478,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.
* up up * parent parent
* | | (left or right?) | | * | | (left or right?) | |
* pivot y * pivot y
* / \ / \ * / \ / \
@ -492,7 +492,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.
* *
* up up * parent parent
* | | (left or right?) | | * | | (left or right?) | |
* pivot x * pivot x
* / \ / \ * / \ / \
@ -502,8 +502,8 @@ protected:
* *
* *
* the actual implementation here resolves the pivot's relationship to * the actual implementation here resolves the pivot's relationship to
* its up by comparaing pointers as it is not known if the pivot pair * its parent by comparaing pointers as it is not known if the pivot pair
* is the left child or the right child of its up, * is the left child or the right child of its parent,
*/ */
Node* up, * z, * c; Node* up, * z, * c;

View File

@ -184,19 +184,24 @@ void* operator new (qse_size_t size, QSE::Mpool* mp)
{ {
if (mp->isEnabled()) if (mp->isEnabled())
{ {
QSE_ASSERT (size == mp->getDatumSize()); QSE_ASSERTX (size == mp->getDatumSize(),
"Pass the right allocation size for the given memory pool");
// the size argument is not really used. you must make sure that // the size argument is not really used. you must make sure that
// the given size matches the datum size of the memory pool. // the given size matches the datum size of the memory pool.
if (size != mp->getDatumSize()) if (size != mp->getDatumSize())
{ {
//QSE::Mmgr* mmgr = mp->getMmgr(); // when the assertion above is excluded during the build,
QSE_THROW (QSE::Mmgr::InvalidArgumentError); // bypass the memory pool if a wrong size is passed in.
// debug your application properly so that this block
// is never reached.
goto use_mmgr;
} }
return mp->allocate (); return mp->allocate ();
} }
else else
{ {
// but when the memory pool is not enabled, it goes through use_mmgr:
// when the memory pool is not enabled, it goes through
// the memory manager directly and it honors the size argument. // the memory manager directly and it honors the size argument.
return ::operator new(size, mp->getMmgr()); return ::operator new(size, mp->getMmgr());
} }