From 4ade765cabf092840feb3771fdde2b37deaf5f27 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 9 Oct 2013 04:26:09 +0200 Subject: [PATCH] kernel/util: Add heap implementation --- headers/private/kernel/util/Heap.h | 325 +++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 headers/private/kernel/util/Heap.h diff --git a/headers/private/kernel/util/Heap.h b/headers/private/kernel/util/Heap.h new file mode 100644 index 0000000000..a39e236ef1 --- /dev/null +++ b/headers/private/kernel/util/Heap.h @@ -0,0 +1,325 @@ +/* + * 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 + +#include + + +template +struct HeapLink { + HeapLink(); + + int fIndex; + Key fKey; +}; + +template +class HeapLinkImpl { +private: + typedef HeapLink Link; + +public: + inline Link* GetHeapLink(); + +private: + Link fHeapLink; +}; + +template +class HeapStandardGetLink { +private: + typedef HeapLink Link; + +public: + inline Link* operator()(Element* element) const; +}; + +template Element::*LinkMember> +class HeapMemberGetLink { +private: + typedef HeapLink Link; + +public: + inline Link* operator()(Element* element) const; +}; + +template +class HeapLesserCompare { +public: + inline bool operator()(Key a, Key b); +}; + +template +class HeapGreaterCompare { +public: + inline bool operator()(Key a, Key b); +}; + +#define HEAP_TEMPLATE_LIST \ + template +#define HEAP_CLASS_NAME Heap + +template, + typename GetLink = HeapStandardGetLink > +class Heap { +public: + Heap(); + ~Heap(); + + inline Element* PeekRoot(); + + inline void ModifyKey(Element* element, Key newKey); + + inline void RemoveRoot(); + inline status_t Insert(Element* element, Key key); + +private: + status_t _GrowHeap(); + + void _MoveUp(HeapLink* link); + void _MoveDown(HeapLink* link); + + Element** fElements; + int fLastElement; + int fSize; + + Compare sCompare; + GetLink sGetLink; + +}; + + +#if KDEBUG +template +HeapLink::HeapLink() + : + fIndex(-1) +{ +} +#else +template +HeapLink::HeapLink() +{ +} +#endif + + +template +HeapLink* +HeapLinkImpl::GetHeapLink() +{ + return &fHeapLink; +} + + +template +HeapLink* +HeapStandardGetLink::operator()(Element* element) const +{ + return element->GetHeapLink(); +} + + +template Element::*LinkMember> +HeapLink* +HeapMemberGetLink::operator()(Element* element) const +{ + return &(element->*LinkMember); +} + + +template +bool +HeapLesserCompare::operator()(Key a, Key b) +{ + return a < b; +} + + +template +bool +HeapGreaterCompare::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() +{ + free(fElements); +} + + +HEAP_TEMPLATE_LIST +Element* +HEAP_CLASS_NAME::PeekRoot() +{ + if (fLastElement > 0) + return fElements[0]; + return NULL; +} + + +HEAP_TEMPLATE_LIST +void +HEAP_CLASS_NAME::ModifyKey(Element* element, Key newKey) +{ + HeapLink link = sGetLink(element); + + ASSERT(link->fIndex >= 0 && link->fIndex < fLastElement); + Key oldKey = link->fKey; + link->fKey = newKey; + + if (sCompare(newKey, oldKey)) + _MoveUp(link); + else + _MoveDown(link); +} + + +HEAP_TEMPLATE_LIST +void +HEAP_CLASS_NAME::RemoveRoot() +{ + ASSERT(fLastElement > 0); + +#if KDEBUG + Element* element = PeekRoot(); + HeapLink link = sGetLink(element); + 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* link = sGetLink(element); + + fElements[fLastElement] = element; + link->fIndex = fLastElement++; + link->fKey = key; + _MoveUp(link); +} + + +HEAP_TEMPLATE_LIST +status_t +HEAP_CLASS_NAME::_GrowHeap() +{ + int newSize = max_c(fSize * 2, 4); + + size_t arraySize = newSize * sizeof(Element*); + Element** newBuffer + = reinterpret_cast(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* link) +{ + int i = link->fIndex; + 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* 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; + } +} + + +#endif // KERNEL_UTIL_HEAP_H +