/* Copyright (c) <2003-2019> * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source distribution. */ /**************************************************************************** * * Visual C++ 6.0 created by: Julio Jerez * ****************************************************************************/ #ifndef __dgHeapBase__ #define __dgHeapBase__ #include "dgStdafx.h" #include "dgMemory.h" //#define DG_HEAP_DEBUG_CHECK template class dgHeapBase { protected: struct RECORD { KEY m_key; OBJECT m_obj; RECORD (KEY key, const OBJECT& obj) :m_key(key), m_obj(obj) { } }; dgHeapBase (dgInt32 maxElements, dgMemoryAllocator* const allocator); dgHeapBase (const void * const buffer, dgInt32 sizeInBytes); ~dgHeapBase (); public: DG_CLASS_ALLOCATOR(allocator) void Flush (); KEY MaxValue() const; KEY Value(dgInt32 i = 0) const; dgInt32 GetCount() const; dgInt32 GetMaxCount() const; const OBJECT& operator[] (dgInt32 i) const; dgInt32 Find (OBJECT &obj); dgInt32 Find (KEY key); dgInt32 m_curCount; dgInt32 m_maxCount; dgMemoryAllocator* m_allocator; RECORD *m_pool; }; template class dgDownHeap: public dgHeapBase { public: dgDownHeap (dgInt32 maxElements, dgMemoryAllocator* const allocator); dgDownHeap (const void * const buffer, dgInt32 sizeInBytes); void Pop () {Remove (0);} void Push (OBJECT &obj, KEY key); void Sort (); void Remove (dgInt32 Index); bool SanityCheck(); }; template class dgUpHeap: public dgHeapBase { public: dgUpHeap (dgInt32 maxElements, dgMemoryAllocator* const allocator); dgUpHeap (const void * const buffer, dgInt32 sizeInBytes); void Pop () {Remove (0);} void Push (OBJECT &obj, KEY key); void Sort (); void Remove (dgInt32 Index); bool SanityCheck(); }; template dgHeapBase::dgHeapBase (dgInt32 maxElements, dgMemoryAllocator* const allocator) { m_allocator = allocator; m_pool = (RECORD *)m_allocator->Malloc (maxElements * sizeof (RECORD)); m_maxCount = maxElements; Flush(); } template dgHeapBase::dgHeapBase (const void * const buffer, dgInt32 sizeInBytes) { m_allocator = NULL; m_pool = (RECORD *) buffer; m_maxCount = dgInt32 (sizeInBytes / sizeof (RECORD)); Flush(); } template dgHeapBase::~dgHeapBase () { if (m_allocator) { m_allocator->Free (m_pool); } } template KEY dgHeapBase::Value(dgInt32 i) const { return m_pool[i].m_key; } template dgInt32 dgHeapBase::GetCount() const { return m_curCount; } template void dgHeapBase::Flush () { m_curCount = 0; #ifdef _DEBUG // dgHeapBase::m_pool[dgHeapBase::m_curCount].m_key = KEY (0); #endif } template KEY dgHeapBase::MaxValue() const { return m_pool[0].m_key; } template dgInt32 dgHeapBase::GetMaxCount() const { return m_maxCount; } template dgInt32 dgHeapBase::Find (OBJECT &obj) { // For now let perform a linear search // this is efficient if the size of the heap is small // ex: m_curCount < 32 // this will be change to a binary search in the heap should the // the size of the heap get larger than 32 // dgAssert (m_curCount <= 32); for (dgInt32 i = 0; i < m_curCount; i ++) { if (m_pool[i].obj == obj) { return i; } } return - 1; } template dgInt32 dgHeapBase::Find (KEY key) { // ex: m_curCount < 32 // this will be change to a binary search in the heap shoud the // the size of the heap get larger than 32 dgAssert (m_curCount <= 32); for (dgInt32 i = 0; i < m_curCount; i ++) { if (m_pool[i].m_key == key) { return i; } } return - 1; } template const OBJECT& dgHeapBase::operator[] (dgInt32 i) const { dgAssert (i<= m_curCount); return m_pool[i].m_obj; } // ************************************************************************** // // down Heap // // ************************************************************************** template dgDownHeap::dgDownHeap (dgInt32 maxElements, dgMemoryAllocator* const allocator) :dgHeapBase (maxElements, allocator) { } template dgDownHeap::dgDownHeap (const void * const buffer, dgInt32 sizeInBytes) :dgHeapBase (buffer, sizeInBytes) { } template void dgDownHeap::Push (OBJECT &obj, KEY key) { dgHeapBase::m_curCount ++; dgInt32 j; dgInt32 i = dgHeapBase::m_curCount; for (; i; i = j) { j = i >> 1; if (!j || (dgHeapBase::m_pool[j - 1].m_key > key)) { break; } dgHeapBase::m_pool[i - 1] = dgHeapBase::m_pool[j - 1]; } dgAssert (i); dgHeapBase::m_pool[i - 1].m_key = key; dgHeapBase::m_pool[i - 1].m_obj = obj; dgAssert (SanityCheck()); } template void dgDownHeap::Remove (dgInt32 index) { dgHeapBase::m_curCount--; dgHeapBase::m_pool[index] = dgHeapBase::m_pool[dgHeapBase::m_curCount]; while (index && dgHeapBase::m_pool[(index - 1) >> 1].m_key < dgHeapBase::m_pool[index].m_key) { dgSwap(dgHeapBase::m_pool[(index - 1) >> 1], dgHeapBase::m_pool[index]); index = (index - 1) >> 1; } while ((2 * index + 1) < dgHeapBase::m_curCount) { dgInt32 i0 = 2 * index + 1; dgInt32 i1 = 2 * index + 2; if (i1 < dgHeapBase::m_curCount) { i0 = (dgHeapBase::m_pool[i0].m_key > dgHeapBase::m_pool[i1].m_key) ? i0 : i1; if (dgHeapBase::m_pool[i0].m_key <= dgHeapBase::m_pool[index].m_key) { break; } dgSwap(dgHeapBase::m_pool[i0], dgHeapBase::m_pool[index]); index = i0; } else { if (dgHeapBase::m_pool[i0].m_key > dgHeapBase::m_pool[index].m_key) { dgSwap(dgHeapBase::m_pool[i0], dgHeapBase::m_pool[index]); } index = i0; } } dgAssert (SanityCheck()); } template void dgDownHeap::Sort () { dgInt32 count = dgHeapBase::m_curCount; for (dgInt32 i = 1; i < count; i ++) { KEY key (dgHeapBase::m_pool[0].m_key); OBJECT obj (dgHeapBase::m_pool[0].m_obj); Pop(); dgHeapBase::m_pool[dgHeapBase::m_curCount].m_key = key; dgHeapBase::m_pool[dgHeapBase::m_curCount].m_obj = obj; } dgHeapBase::m_curCount = count; for (dgInt32 i = 0; i < count / 2; i ++) { KEY key (dgHeapBase::m_pool[i].m_key); OBJECT obj (dgHeapBase::m_pool[i].m_obj); dgHeapBase::m_pool[i].m_key = dgHeapBase::m_pool[count - i - 1].m_key; dgHeapBase::m_pool[i].m_obj = dgHeapBase::m_pool[count - i - 1].m_obj; dgHeapBase::m_pool[count - i - 1].m_key = key; dgHeapBase::m_pool[count - i - 1].m_obj = obj; } dgAssert (SanityCheck()); } template bool dgDownHeap::SanityCheck() { #ifdef DG_HEAP_DEBUG_CHECK for (dgInt32 i = 0; i < m_curCount; i++) { dgInt32 i1 = 2 * i + 1; dgInt32 i2 = 2 * i + 2; if ((i1 < m_curCount) && (dgHeapBase::m_pool[i].m_key < dgHeapBase::m_pool[i1].m_key)) { return false; } if ((i2 < m_curCount) && (dgHeapBase::m_pool[i].m_key < dgHeapBase::m_pool[i2].m_key)) { return false; } } #endif return true; } // ************************************************************************** // // down Heap // // ************************************************************************** template dgUpHeap::dgUpHeap (dgInt32 maxElements, dgMemoryAllocator* const allocator) :dgHeapBase (maxElements, allocator) { } template dgUpHeap::dgUpHeap (const void * const buffer, dgInt32 sizeInBytes) :dgHeapBase (buffer, sizeInBytes) { } template bool dgUpHeap::SanityCheck() { #ifdef DG_HEAP_DEBUG_CHECK for (dgInt32 i = 0; i < m_curCount; i ++) { dgInt32 i1 = 2 * i + 1; dgInt32 i2 = 2 * i + 2; if ((i1 < m_curCount) && (dgHeapBase::m_pool[i].m_key > dgHeapBase::m_pool[i1].m_key)) { return false; } if ((i2 < m_curCount) && (dgHeapBase::m_pool[i].m_key > dgHeapBase::m_pool[i2].m_key)) { return false; } } #endif return true; } template void dgUpHeap::Push (OBJECT &obj, KEY key) { dgHeapBase::m_curCount ++; dgInt32 j; dgInt32 i = dgHeapBase::m_curCount; for (; i; i = j) { j = i >> 1; if (!j || (dgHeapBase::m_pool[j - 1].m_key < key)) { break; } dgHeapBase::m_pool[i - 1] = dgHeapBase::m_pool[j - 1]; } dgAssert (i); dgHeapBase::m_pool[i - 1].m_key = key; dgHeapBase::m_pool[i - 1].m_obj = obj; dgAssert (SanityCheck()); } template void dgUpHeap::Sort () { dgInt32 count = dgHeapBase::m_curCount; for (dgInt32 i = 1; i < count; i ++) { KEY key (dgHeapBase::m_pool[0].m_key); OBJECT obj (dgHeapBase::m_pool[0].m_obj); Pop(); dgHeapBase::m_pool[dgHeapBase::m_curCount].m_key = key; dgHeapBase::m_pool[dgHeapBase::m_curCount].m_obj = obj; } dgHeapBase::m_curCount = count; for (dgInt32 i = 0; i < count / 2; i ++) { KEY key (dgHeapBase::m_pool[i].m_key); OBJECT obj (dgHeapBase::m_pool[i].m_obj); dgHeapBase::m_pool[i].m_key = dgHeapBase::m_pool[count - i - 1].m_key; dgHeapBase::m_pool[i].m_obj = dgHeapBase::m_pool[count - i - 1].m_obj; dgHeapBase::m_pool[count - i - 1].m_key = key; dgHeapBase::m_pool[count - i - 1].m_obj = obj; } dgAssert (SanityCheck()); } template void dgUpHeap::Remove (dgInt32 index) { dgHeapBase::m_curCount--; dgHeapBase::m_pool[index] = dgHeapBase::m_pool[dgHeapBase::m_curCount]; while (index && dgHeapBase::m_pool[(index - 1) >> 1].m_key > dgHeapBase::m_pool[index].m_key) { dgSwap(dgHeapBase::m_pool[(index - 1) >> 1], dgHeapBase::m_pool[index]); index = (index - 1) >> 1; } while ((2 * index + 1) < dgHeapBase::m_curCount) { dgInt32 i0 = 2 * index + 1; dgInt32 i1 = 2 * index + 2; if (i1 < dgHeapBase::m_curCount) { i0 = (dgHeapBase::m_pool[i0].m_key < dgHeapBase::m_pool[i1].m_key) ? i0 : i1; if (dgHeapBase::m_pool[i0].m_key >= dgHeapBase::m_pool[index].m_key) { break; } dgSwap(dgHeapBase::m_pool[i0], dgHeapBase::m_pool[index]); index = i0; } else { if (dgHeapBase::m_pool[i0].m_key < dgHeapBase::m_pool[index].m_key) { dgSwap(dgHeapBase::m_pool[i0], dgHeapBase::m_pool[index]); } index = i0; } } dgAssert (SanityCheck()); } #endif