/* * 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(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* link); void _MoveDown(HeapLink* link); Element** fElements; int fLastElement; int fSize; static Compare sCompare; static 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(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* 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* 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* 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(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) { 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; } } HEAP_TEMPLATE_LIST Compare HEAP_CLASS_NAME::sCompare; HEAP_TEMPLATE_LIST GetLink HEAP_CLASS_NAME::sGetLink; #endif // KERNEL_UTIL_HEAP_H