btrfs: [] on the end of a struct field is a variable length array.
[haiku.git] / headers / private / kernel / util / MinMaxHeap.h
blob3eb47e260f81b3fe4e654c06299cda1266b46880
1 /*
2 * Copyright 2013 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Paweł Dziepak, pdziepak@quarnos.org
7 */
8 #ifndef KERNEL_UTIL_MIN_MAX_HEAP_H
9 #define KERNEL_UTIL_MIN_MAX_HEAP_H
12 #include <debug.h>
14 #include <SupportDefs.h>
17 template<typename Element, typename Key>
18 struct MinMaxHeapLink {
19 MinMaxHeapLink();
21 bool fMinTree;
22 int fIndex;
23 Key fKey;
26 template<typename Element, typename Key>
27 class MinMaxHeapLinkImpl {
28 private:
29 typedef MinMaxHeapLink<Element, Key> Link;
31 public:
32 inline Link* GetMinMaxHeapLink();
34 private:
35 Link fMinMaxHeapLink;
38 template<typename Element, typename Key>
39 class MinMaxHeapStandardGetLink {
40 private:
41 typedef MinMaxHeapLink<Element, Key> Link;
43 public:
44 inline Link* operator()(Element* element) const;
47 template<typename Element, typename Key,
48 MinMaxHeapLink<Element, Key> Element::*LinkMember>
49 class MinMaxHeapMemberGetLink {
50 private:
51 typedef MinMaxHeapLink<Element, Key> Link;
53 public:
54 inline Link* operator()(Element* element) const;
57 template<typename Key>
58 class MinMaxHeapCompare {
59 public:
60 inline bool operator()(Key a, Key b);
63 #define MIN_MAX_HEAP_TEMPLATE_LIST \
64 template<typename Element, typename Key, typename Compare, typename GetLink>
65 #define MIN_MAX_HEAP_CLASS_NAME MinMaxHeap<Element, Key, Compare, GetLink>
67 template<typename Element, typename Key,
68 typename Compare = MinMaxHeapCompare<Key>,
69 typename GetLink = MinMaxHeapStandardGetLink<Element, Key> >
70 class MinMaxHeap {
71 public:
72 MinMaxHeap();
73 MinMaxHeap(int initialSize);
74 ~MinMaxHeap();
76 inline Element* PeekMinimum() const;
77 inline Element* PeekMaximum() const;
79 static const Key& GetKey(Element* element);
81 inline void ModifyKey(Element* element, Key newKey);
83 inline void RemoveMinimum();
84 inline void RemoveMaximum();
86 inline status_t Insert(Element* element, Key key);
88 private:
89 status_t _GrowHeap(int minimalSize = 0);
91 void _MoveUp(MinMaxHeapLink<Element, Key>* link);
92 void _MoveDown(MinMaxHeapLink<Element, Key>* link);
93 bool _ChangeTree(MinMaxHeapLink<Element, Key>* link);
95 void _RemoveLast(bool minTree);
97 Element** fMinElements;
98 int fMinLastElement;
100 Element** fMaxElements;
101 int fMaxLastElement;
103 int fSize;
105 static Compare sCompare;
106 static GetLink sGetLink;
110 #if KDEBUG
111 template<typename Element, typename Key>
112 MinMaxHeapLink<Element, Key>::MinMaxHeapLink()
114 fIndex(-1)
117 #else
118 template<typename Element, typename Key>
119 MinMaxHeapLink<Element, Key>::MinMaxHeapLink()
122 #endif
125 template<typename Element, typename Key>
126 MinMaxHeapLink<Element, Key>*
127 MinMaxHeapLinkImpl<Element, Key>::GetMinMaxHeapLink()
129 return &fMinMaxHeapLink;
133 template<typename Element, typename Key>
134 MinMaxHeapLink<Element, Key>*
135 MinMaxHeapStandardGetLink<Element, Key>::operator()(Element* element) const
137 return element->GetMinMaxHeapLink();
141 template<typename Element, typename Key,
142 MinMaxHeapLink<Element, Key> Element::*LinkMember>
143 MinMaxHeapLink<Element, Key>*
144 MinMaxHeapMemberGetLink<Element, Key, LinkMember>::operator()(
145 Element* element) const
147 return &(element->*LinkMember);
151 template<typename Key>
152 bool
153 MinMaxHeapCompare<Key>::operator()(Key a, Key b)
155 return a < b;
159 MIN_MAX_HEAP_TEMPLATE_LIST
160 MIN_MAX_HEAP_CLASS_NAME::MinMaxHeap()
162 fMinElements(NULL),
163 fMinLastElement(0),
164 fMaxElements(NULL),
165 fMaxLastElement(0),
166 fSize(0)
171 MIN_MAX_HEAP_TEMPLATE_LIST
172 MIN_MAX_HEAP_CLASS_NAME::MinMaxHeap(int initialSize)
174 fMinElements(NULL),
175 fMinLastElement(0),
176 fMaxElements(NULL),
177 fMaxLastElement(0),
178 fSize(0)
180 _GrowHeap(initialSize);
184 MIN_MAX_HEAP_TEMPLATE_LIST
185 MIN_MAX_HEAP_CLASS_NAME::~MinMaxHeap()
187 free(fMinElements);
191 MIN_MAX_HEAP_TEMPLATE_LIST
192 Element*
193 MIN_MAX_HEAP_CLASS_NAME::PeekMinimum() const
195 if (fMinLastElement > 0)
196 return fMinElements[0];
197 else if (fMaxLastElement > 0) {
198 ASSERT(fMaxLastElement == 1);
199 return fMaxElements[0];
202 return NULL;
206 MIN_MAX_HEAP_TEMPLATE_LIST
207 Element*
208 MIN_MAX_HEAP_CLASS_NAME::PeekMaximum() const
210 if (fMaxLastElement > 0)
211 return fMaxElements[0];
212 else if (fMinLastElement > 0) {
213 ASSERT(fMinLastElement == 1);
214 return fMinElements[0];
217 return NULL;
221 MIN_MAX_HEAP_TEMPLATE_LIST
222 const Key&
223 MIN_MAX_HEAP_CLASS_NAME::GetKey(Element* element)
225 return sGetLink(element)->fKey;
229 MIN_MAX_HEAP_TEMPLATE_LIST
230 void
231 MIN_MAX_HEAP_CLASS_NAME::ModifyKey(Element* element, Key newKey)
233 MinMaxHeapLink<Element, Key>* link = sGetLink(element);
235 Key oldKey = link->fKey;
236 link->fKey = newKey;
238 if (!sCompare(newKey, oldKey) && !sCompare(oldKey, newKey))
239 return;
241 if (sCompare(newKey, oldKey) ^ !link->fMinTree)
242 _MoveUp(link);
243 else
244 _MoveDown(link);
248 MIN_MAX_HEAP_TEMPLATE_LIST
249 void
250 MIN_MAX_HEAP_CLASS_NAME::RemoveMinimum()
252 if (fMinLastElement == 0) {
253 ASSERT(fMaxLastElement == 1);
254 RemoveMaximum();
255 return;
258 #if KDEBUG
259 Element* element = PeekMinimum();
260 MinMaxHeapLink<Element, Key>* link = sGetLink(element);
261 ASSERT(link->fIndex != -1);
262 link->fIndex = -1;
263 #endif
265 _RemoveLast(true);
269 MIN_MAX_HEAP_TEMPLATE_LIST
270 void
271 MIN_MAX_HEAP_CLASS_NAME::RemoveMaximum()
273 if (fMaxLastElement == 0) {
274 ASSERT(fMinLastElement == 1);
275 RemoveMinimum();
276 return;
279 #if KDEBUG
280 Element* element = PeekMaximum();
281 MinMaxHeapLink<Element, Key>* link = sGetLink(element);
282 ASSERT(link->fIndex != -1);
283 link->fIndex = -1;
284 #endif
286 _RemoveLast(false);
290 MIN_MAX_HEAP_TEMPLATE_LIST
291 status_t
292 MIN_MAX_HEAP_CLASS_NAME::Insert(Element* element, Key key)
294 if (min_c(fMinLastElement, fMaxLastElement) == fSize) {
295 ASSERT(max_c(fMinLastElement, fMaxLastElement) == fSize);
296 status_t result = _GrowHeap();
297 if (result != B_OK)
298 return result;
301 ASSERT(fMinLastElement < fSize || fMaxLastElement < fSize);
303 MinMaxHeapLink<Element, Key>* link = sGetLink(element);
305 ASSERT(link->fIndex == -1);
307 link->fMinTree = fMinLastElement < fMaxLastElement;
309 int& lastElement = link->fMinTree ? fMinLastElement : fMaxLastElement;
310 Element** tree = link->fMinTree ? fMinElements : fMaxElements;
312 tree[lastElement] = element;
313 link->fIndex = lastElement++;
314 link->fKey = key;
316 if (!_ChangeTree(link))
317 _MoveUp(link);
319 return B_OK;
323 MIN_MAX_HEAP_TEMPLATE_LIST
324 status_t
325 MIN_MAX_HEAP_CLASS_NAME::_GrowHeap(int minimalSize)
327 minimalSize = minimalSize % 2 == 0 ? minimalSize : minimalSize + 1;
328 int newSize = max_c(max_c(fSize * 4, 4), minimalSize);
330 size_t arraySize = newSize * sizeof(Element*);
331 Element** newBuffer
332 = reinterpret_cast<Element**>(realloc(fMinElements, arraySize));
333 if (newBuffer == NULL)
334 return B_NO_MEMORY;
335 fMinElements = newBuffer;
337 newBuffer += newSize / 2;
338 if (fMaxLastElement > 0)
339 memcpy(newBuffer, fMinElements + fSize, fSize * sizeof(Element*));
340 fMaxElements = newBuffer;
342 fSize = newSize / 2;
343 return B_OK;
347 MIN_MAX_HEAP_TEMPLATE_LIST
348 void
349 MIN_MAX_HEAP_CLASS_NAME::_MoveUp(MinMaxHeapLink<Element, Key>* link)
351 Element** tree = link->fMinTree ? fMinElements : fMaxElements;
352 while (true) {
353 if (link->fIndex <= 0)
354 break;
356 int parent = (link->fIndex - 1) / 2;
357 bool isSmaller = sCompare(link->fKey, sGetLink(tree[parent])->fKey);
358 if (isSmaller ^ !link->fMinTree) {
359 ASSERT(sGetLink(tree[parent])->fIndex == parent);
360 sGetLink(tree[parent])->fIndex = link->fIndex;
362 Element* element = tree[link->fIndex];
363 tree[link->fIndex] = tree[parent];
364 tree[parent] = element;
366 link->fIndex = parent;
367 } else
368 break;
373 MIN_MAX_HEAP_TEMPLATE_LIST
374 void
375 MIN_MAX_HEAP_CLASS_NAME::_MoveDown(MinMaxHeapLink<Element, Key>* link)
377 int current;
379 int lastElement = link->fMinTree ? fMinLastElement : fMaxLastElement;
380 Element** tree = link->fMinTree ? fMinElements : fMaxElements;
381 while (true) {
382 current = link->fIndex;
384 int child = 2 * link->fIndex + 1;
385 if (child < lastElement) {
386 bool isSmaller = sCompare(sGetLink(tree[child])->fKey, link->fKey);
387 if (isSmaller ^ !link->fMinTree)
388 current = child;
391 child = 2 * link->fIndex + 2;
392 if (child < lastElement) {
393 bool isSmaller = sCompare(sGetLink(tree[child])->fKey,
394 sGetLink(tree[current])->fKey);
395 if (isSmaller ^ !link->fMinTree)
396 current = child;
399 if (link->fIndex == current)
400 break;
402 ASSERT(sGetLink(tree[current])->fIndex == current);
403 sGetLink(tree[current])->fIndex = link->fIndex;
405 Element* element = tree[link->fIndex];
406 tree[link->fIndex] = tree[current];
407 tree[current] = element;
409 link->fIndex = current;
412 if (2 * link->fIndex + 1 >= lastElement)
413 _ChangeTree(link);
417 MIN_MAX_HEAP_TEMPLATE_LIST
418 bool
419 MIN_MAX_HEAP_CLASS_NAME::_ChangeTree(MinMaxHeapLink<Element, Key>* link)
421 int otherLastElement = link->fMinTree ? fMaxLastElement : fMinLastElement;
423 Element** currentTree = link->fMinTree ? fMinElements : fMaxElements;
424 Element** otherTree = link->fMinTree ? fMaxElements : fMinElements;
426 if (otherLastElement <= 0) {
427 ASSERT(link->fMinTree ? fMinLastElement : fMaxLastElement == 1);
428 return false;
431 ASSERT((link->fIndex - 1) / 2 < otherLastElement);
433 Element* predecessor;
434 if (2 * link->fIndex + 1 < otherLastElement) {
435 predecessor = otherTree[2 * link->fIndex + 1];
436 ASSERT(sGetLink(predecessor)->fIndex == 2 * link->fIndex + 1);
437 } else if (link->fIndex < otherLastElement) {
438 predecessor = otherTree[link->fIndex];
439 ASSERT(sGetLink(predecessor)->fIndex == link->fIndex);
440 } else {
441 predecessor = otherTree[(link->fIndex - 1) / 2];
442 ASSERT(sGetLink(predecessor)->fIndex == (link->fIndex - 1) / 2);
444 MinMaxHeapLink<Element, Key>* predecessorLink = sGetLink(predecessor);
446 bool isSmaller = sCompare(predecessorLink->fKey, link->fKey);
447 if (isSmaller ^ !link->fMinTree) {
448 Element* element = currentTree[link->fIndex];
449 currentTree[link->fIndex] = otherTree[predecessorLink->fIndex];
450 otherTree[predecessorLink->fIndex] = element;
452 int index = link->fIndex;
453 link->fIndex = predecessorLink->fIndex;
454 predecessorLink->fIndex = index;
456 predecessorLink->fMinTree = !predecessorLink->fMinTree;
457 link->fMinTree = !link->fMinTree;
459 _MoveUp(link);
460 return true;
463 return false;
467 MIN_MAX_HEAP_TEMPLATE_LIST
468 void
469 MIN_MAX_HEAP_CLASS_NAME::_RemoveLast(bool minTree)
471 bool deleteMin = fMaxLastElement < fMinLastElement;
473 Element** tree = deleteMin ? fMinElements : fMaxElements;
474 int& lastElement = deleteMin ? fMinLastElement : fMaxLastElement;
476 ASSERT(lastElement > 0);
477 lastElement--;
478 if (lastElement == 0 && deleteMin == minTree)
479 return;
481 Element* element = tree[lastElement];
483 if (minTree)
484 fMinElements[0] = element;
485 else
486 fMaxElements[0] = element;
488 MinMaxHeapLink<Element, Key>* link = sGetLink(element);
489 link->fIndex = 0;
490 link->fMinTree = minTree;
491 _MoveDown(link);
495 MIN_MAX_HEAP_TEMPLATE_LIST
496 Compare MIN_MAX_HEAP_CLASS_NAME::sCompare;
498 MIN_MAX_HEAP_TEMPLATE_LIST
499 GetLink MIN_MAX_HEAP_CLASS_NAME::sGetLink;
502 #endif // KERNEL_UTIL_MIN_MAX_HEAP_H