358 lines
6.3 KiB
C++
358 lines
6.3 KiB
C++
/*
|
|
* Copyright 2013 Haiku, Inc. All rights reserved.
|
|
* Distributed under the terms of the MIT License.
|
|
*
|
|
* Authors:
|
|
* Paweł Dziepak, pdziepak@quarnos.org
|
|
*/
|
|
#ifndef KERNEL_UTIL_HEAP_H
|
|
#define KERNEL_UTIL_HEAP_H
|
|
|
|
|
|
#include <debug.h>
|
|
|
|
#include <SupportDefs.h>
|
|
|
|
|
|
template<typename Element, typename Key>
|
|
struct HeapLink {
|
|
HeapLink();
|
|
|
|
int fIndex;
|
|
Key fKey;
|
|
};
|
|
|
|
template<typename Element, typename Key>
|
|
class HeapLinkImpl {
|
|
private:
|
|
typedef HeapLink<Element, Key> Link;
|
|
|
|
public:
|
|
inline Link* GetHeapLink();
|
|
|
|
private:
|
|
Link fHeapLink;
|
|
};
|
|
|
|
template<typename Element, typename Key>
|
|
class HeapStandardGetLink {
|
|
private:
|
|
typedef HeapLink<Element, Key> Link;
|
|
|
|
public:
|
|
inline Link* operator()(Element* element) const;
|
|
};
|
|
|
|
template<typename Element, typename Key,
|
|
HeapLink<Element, Key> Element::*LinkMember>
|
|
class HeapMemberGetLink {
|
|
private:
|
|
typedef HeapLink<Element, Key> Link;
|
|
|
|
public:
|
|
inline Link* operator()(Element* element) const;
|
|
};
|
|
|
|
template<typename Key>
|
|
class HeapLesserCompare {
|
|
public:
|
|
inline bool operator()(Key a, Key b);
|
|
};
|
|
|
|
template<typename Key>
|
|
class HeapGreaterCompare {
|
|
public:
|
|
inline bool operator()(Key a, Key b);
|
|
};
|
|
|
|
#define HEAP_TEMPLATE_LIST \
|
|
template<typename Element, typename Key, typename Compare, typename GetLink>
|
|
#define HEAP_CLASS_NAME Heap<Element, Key, Compare, GetLink>
|
|
|
|
template<typename Element, typename Key,
|
|
typename Compare = HeapLesserCompare<Key>,
|
|
typename GetLink = HeapStandardGetLink<Element, Key> >
|
|
class Heap {
|
|
public:
|
|
Heap();
|
|
Heap(int initialSize);
|
|
~Heap();
|
|
|
|
inline Element* PeekRoot() const;
|
|
|
|
static const Key& GetKey(Element* element);
|
|
|
|
inline void ModifyKey(Element* element, Key newKey);
|
|
|
|
inline void RemoveRoot();
|
|
inline status_t Insert(Element* element, Key key);
|
|
|
|
private:
|
|
status_t _GrowHeap(int minimalSize = 0);
|
|
|
|
void _MoveUp(HeapLink<Element, Key>* link);
|
|
void _MoveDown(HeapLink<Element, Key>* link);
|
|
|
|
Element** fElements;
|
|
int fLastElement;
|
|
int fSize;
|
|
|
|
static Compare sCompare;
|
|
static GetLink sGetLink;
|
|
};
|
|
|
|
|
|
#if KDEBUG
|
|
template<typename Element, typename Key>
|
|
HeapLink<Element, Key>::HeapLink()
|
|
:
|
|
fIndex(-1)
|
|
{
|
|
}
|
|
#else
|
|
template<typename Element, typename Key>
|
|
HeapLink<Element, Key>::HeapLink()
|
|
{
|
|
}
|
|
#endif
|
|
|
|
|
|
template<typename Element, typename Key>
|
|
HeapLink<Element, Key>*
|
|
HeapLinkImpl<Element, Key>::GetHeapLink()
|
|
{
|
|
return &fHeapLink;
|
|
}
|
|
|
|
|
|
template<typename Element, typename Key>
|
|
HeapLink<Element, Key>*
|
|
HeapStandardGetLink<Element, Key>::operator()(Element* element) const
|
|
{
|
|
return element->GetHeapLink();
|
|
}
|
|
|
|
|
|
template<typename Element, typename Key,
|
|
HeapLink<Element, Key> Element::*LinkMember>
|
|
HeapLink<Element, Key>*
|
|
HeapMemberGetLink<Element, Key, LinkMember>::operator()(Element* element) const
|
|
{
|
|
return &(element->*LinkMember);
|
|
}
|
|
|
|
|
|
template<typename Key>
|
|
bool
|
|
HeapLesserCompare<Key>::operator()(Key a, Key b)
|
|
{
|
|
return a < b;
|
|
}
|
|
|
|
|
|
template<typename Key>
|
|
bool
|
|
HeapGreaterCompare<Key>::operator()(Key a, Key b)
|
|
{
|
|
return a > b;
|
|
}
|
|
|
|
|
|
HEAP_TEMPLATE_LIST
|
|
HEAP_CLASS_NAME::Heap()
|
|
:
|
|
fElements(NULL),
|
|
fLastElement(0),
|
|
fSize(0)
|
|
{
|
|
}
|
|
|
|
|
|
HEAP_TEMPLATE_LIST
|
|
HEAP_CLASS_NAME::Heap(int initialSize)
|
|
:
|
|
fElements(NULL),
|
|
fLastElement(0),
|
|
fSize(0)
|
|
{
|
|
_GrowHeap(initialSize);
|
|
}
|
|
|
|
|
|
HEAP_TEMPLATE_LIST
|
|
HEAP_CLASS_NAME::~Heap()
|
|
{
|
|
free(fElements);
|
|
}
|
|
|
|
|
|
HEAP_TEMPLATE_LIST
|
|
Element*
|
|
HEAP_CLASS_NAME::PeekRoot() const
|
|
{
|
|
if (fLastElement > 0)
|
|
return fElements[0];
|
|
return NULL;
|
|
}
|
|
|
|
|
|
HEAP_TEMPLATE_LIST
|
|
const Key&
|
|
HEAP_CLASS_NAME::GetKey(Element* element)
|
|
{
|
|
return sGetLink(element)->fKey;
|
|
}
|
|
|
|
|
|
HEAP_TEMPLATE_LIST
|
|
void
|
|
HEAP_CLASS_NAME::ModifyKey(Element* element, Key newKey)
|
|
{
|
|
HeapLink<Element, Key>* link = sGetLink(element);
|
|
|
|
ASSERT(link->fIndex >= 0 && link->fIndex < fLastElement);
|
|
Key oldKey = link->fKey;
|
|
link->fKey = newKey;
|
|
|
|
if (sCompare(newKey, oldKey))
|
|
_MoveUp(link);
|
|
else if (sCompare(oldKey, newKey))
|
|
_MoveDown(link);
|
|
}
|
|
|
|
|
|
HEAP_TEMPLATE_LIST
|
|
void
|
|
HEAP_CLASS_NAME::RemoveRoot()
|
|
{
|
|
ASSERT(fLastElement > 0);
|
|
|
|
#if KDEBUG
|
|
Element* element = PeekRoot();
|
|
HeapLink<Element, Key>* link = sGetLink(element);
|
|
ASSERT(link->fIndex != -1);
|
|
link->fIndex = -1;
|
|
#endif
|
|
|
|
fLastElement--;
|
|
if (fLastElement > 0) {
|
|
Element* lastElement = fElements[fLastElement];
|
|
fElements[0] = lastElement;
|
|
sGetLink(lastElement)->fIndex = 0;
|
|
_MoveDown(sGetLink(lastElement));
|
|
}
|
|
}
|
|
|
|
|
|
HEAP_TEMPLATE_LIST
|
|
status_t
|
|
HEAP_CLASS_NAME::Insert(Element* element, Key key)
|
|
{
|
|
if (fLastElement == fSize) {
|
|
status_t result = _GrowHeap();
|
|
if (result != B_OK)
|
|
return result;
|
|
}
|
|
|
|
ASSERT(fLastElement != fSize);
|
|
|
|
HeapLink<Element, Key>* link = sGetLink(element);
|
|
|
|
ASSERT(link->fIndex == -1);
|
|
|
|
fElements[fLastElement] = element;
|
|
link->fIndex = fLastElement++;
|
|
link->fKey = key;
|
|
_MoveUp(link);
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
HEAP_TEMPLATE_LIST
|
|
status_t
|
|
HEAP_CLASS_NAME::_GrowHeap(int minimalSize)
|
|
{
|
|
int newSize = max_c(max_c(fSize * 2, 4), minimalSize);
|
|
|
|
size_t arraySize = newSize * sizeof(Element*);
|
|
Element** newBuffer
|
|
= reinterpret_cast<Element**>(realloc(fElements, arraySize));
|
|
if (newBuffer == NULL)
|
|
return B_NO_MEMORY;
|
|
|
|
fElements = newBuffer;
|
|
fSize = newSize;
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
HEAP_TEMPLATE_LIST
|
|
void
|
|
HEAP_CLASS_NAME::_MoveUp(HeapLink<Element, Key>* link)
|
|
{
|
|
while (true) {
|
|
int parent = (link->fIndex - 1) / 2;
|
|
if (link->fIndex > 0
|
|
&& sCompare(link->fKey, sGetLink(fElements[parent])->fKey)) {
|
|
|
|
sGetLink(fElements[parent])->fIndex = link->fIndex;
|
|
|
|
Element* element = fElements[link->fIndex];
|
|
fElements[link->fIndex] = fElements[parent];
|
|
fElements[parent] = element;
|
|
|
|
link->fIndex = parent;
|
|
} else
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
HEAP_TEMPLATE_LIST
|
|
void
|
|
HEAP_CLASS_NAME::_MoveDown(HeapLink<Element, Key>* link)
|
|
{
|
|
int current;
|
|
|
|
while (true) {
|
|
current = link->fIndex;
|
|
|
|
int child = 2 * link->fIndex + 1;
|
|
if (child < fLastElement
|
|
&& sCompare(sGetLink(fElements[child])->fKey, link->fKey)) {
|
|
current = child;
|
|
}
|
|
|
|
child = 2 * link->fIndex + 2;
|
|
if (child < fLastElement
|
|
&& sCompare(sGetLink(fElements[child])->fKey,
|
|
sGetLink(fElements[current])->fKey)) {
|
|
current = child;
|
|
}
|
|
|
|
if (link->fIndex == current)
|
|
break;
|
|
|
|
sGetLink(fElements[current])->fIndex = link->fIndex;
|
|
|
|
Element* element = fElements[link->fIndex];
|
|
fElements[link->fIndex] = fElements[current];
|
|
fElements[current] = element;
|
|
|
|
link->fIndex = current;
|
|
}
|
|
}
|
|
|
|
|
|
HEAP_TEMPLATE_LIST
|
|
Compare HEAP_CLASS_NAME::sCompare;
|
|
|
|
HEAP_TEMPLATE_LIST
|
|
GetLink HEAP_CLASS_NAME::sGetLink;
|
|
|
|
|
|
#endif // KERNEL_UTIL_HEAP_H
|
|
|