Nugget
heap.h
1 // Copyright (c) Electronic Arts Inc. All rights reserved.
4 
6 // This file implements heap functionality much like the std C++ heap algorithms.
7 // Such heaps are not the same thing as memory heaps or pools, but rather are
8 // semi-sorted random access containers which have the primary purpose of
9 // supporting the implementation of priority_queue and similar data structures.
10 //
11 // The primary distinctions between this heap functionality and std::heap are:
12 // - This heap exposes some extra functionality such as is_heap and change_heap.
13 // - This heap is more efficient than versions found in typical STL
14 // implementations such as STLPort, Microsoft, and Metrowerks. This comes
15 // about due to better use of array dereferencing and branch prediction.
16 // You should expect of 5-30%, depending on the usage and platform.
18 
20 // The publicly usable functions we define are:
21 // push_heap -- Adds an entry to a heap. Same as C++ std::push_heap.
22 // pop_heap -- Removes the top entry from a heap. Same as C++ std::pop_heap.
23 // make_heap -- Converts an array to a heap. Same as C++ std::make_heap.
24 // sort_heap -- Sorts a heap in place. Same as C++ std::sort_heap.
25 // remove_heap -- Removes an arbitrary entry from a heap.
26 // change_heap -- Changes the priority of an entry in the heap.
27 // is_heap -- Returns true if an array appears is in heap format. Same as C++11 std::is_heap.
28 // is_heap_until -- Returns largest part of the range which is a heap. Same as C++11 std::is_heap_until.
30 
31 
32 
33 #ifndef EASTL_HEAP_H
34 #define EASTL_HEAP_H
35 
36 
37 #include <EASTL/internal/config.h>
38 #include <EASTL/iterator.h>
39 #include <stddef.h>
40 
41 #if defined(EA_PRAGMA_ONCE_SUPPORTED)
42  #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
43 #endif
44 
45 
46 
47 namespace eastl
48 {
49 
51  // promote_heap (internal function)
53 
54  template <typename RandomAccessIterator, typename Distance, typename T, typename ValueType>
55  inline void promote_heap_impl(RandomAccessIterator first, Distance topPosition, Distance position, T value)
56  {
57  for(Distance parentPosition = (position - 1) >> 1; // This formula assumes that (position > 0). // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>.
58  (position > topPosition) && eastl::less<ValueType>()(*(first + parentPosition), value);
59  parentPosition = (position - 1) >> 1)
60  {
61  *(first + position) = eastl::forward<ValueType>(*(first + parentPosition)); // Swap the node with its parent.
62  position = parentPosition;
63  }
64 
65  *(first + position) = eastl::forward<ValueType>(value);
66  }
67 
79  template <typename RandomAccessIterator, typename Distance, typename T>
80  inline void promote_heap(RandomAccessIterator first, Distance topPosition, Distance position, const T& value)
81  {
82  typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
83  promote_heap_impl<RandomAccessIterator, Distance, const T&, const value_type>(first, topPosition, position, value);
84  }
85 
86 
98  template <typename RandomAccessIterator, typename Distance, typename T>
99  inline void promote_heap(RandomAccessIterator first, Distance topPosition, Distance position, T&& value)
100  {
101  typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
102  promote_heap_impl<RandomAccessIterator, Distance, T&&, value_type>(first, topPosition, position, eastl::forward<T>(value));
103  }
104 
105 
106  template <typename RandomAccessIterator, typename Distance, typename T, typename Compare, typename ValueType>
107  inline void promote_heap_impl(RandomAccessIterator first, Distance topPosition, Distance position, T value, Compare compare)
108  {
109  for(Distance parentPosition = (position - 1) >> 1; // This formula assumes that (position > 0). // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>.
110  (position > topPosition) && compare(*(first + parentPosition), value);
111  parentPosition = (position - 1) >> 1)
112  {
113  *(first + position) = eastl::forward<ValueType>(*(first + parentPosition)); // Swap the node with its parent.
114  position = parentPosition;
115  }
116 
117  *(first + position) = eastl::forward<ValueType>(value);
118  }
119 
120 
132  template <typename RandomAccessIterator, typename Distance, typename T, typename Compare>
133  inline void promote_heap(RandomAccessIterator first, Distance topPosition, Distance position, const T& value, Compare compare)
134  {
135  typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
136  promote_heap_impl<RandomAccessIterator, Distance, const T&, Compare, const value_type>(first, topPosition, position, value, compare);
137  }
138 
139 
151  template <typename RandomAccessIterator, typename Distance, typename T, typename Compare>
152  inline void promote_heap(RandomAccessIterator first, Distance topPosition, Distance position, T&& value, Compare compare)
153  {
154  typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
155  promote_heap_impl<RandomAccessIterator, Distance, T&&, Compare, value_type>(first, topPosition, position, eastl::forward<T>(value), compare);
156  }
157 
158 
159 
161  // adjust_heap (internal function)
163 
164  template <typename RandomAccessIterator, typename Distance, typename T, typename ValueType>
165  void adjust_heap_impl(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, T value)
166  {
167  // We do the conventional approach of moving the position down to the
168  // bottom then inserting the value at the back and moving it up.
169  Distance childPosition = (2 * position) + 2;
170 
171  for(; childPosition < heapSize; childPosition = (2 * childPosition) + 2)
172  {
173  if(eastl::less<ValueType>()(*(first + childPosition), *(first + (childPosition - 1)))) // Choose the larger of the two children.
174  --childPosition;
175  *(first + position) = eastl::forward<ValueType>(*(first + childPosition)); // Swap positions with this child.
176  position = childPosition;
177  }
178 
179  if(childPosition == heapSize) // If we are at the very last index of the bottom...
180  {
181  *(first + position) = eastl::forward<ValueType>(*(first + (childPosition - 1)));
182  position = childPosition - 1;
183  }
184 
185  eastl::promote_heap<RandomAccessIterator, Distance, T>(first, topPosition, position, eastl::forward<ValueType>(value));
186  }
187 
198  template <typename RandomAccessIterator, typename Distance, typename T>
199  void adjust_heap(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, const T& value)
200  {
201  typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
202  adjust_heap_impl<RandomAccessIterator, Distance, const T&, const value_type>(first, topPosition, heapSize, position, eastl::forward<const T&>(value));
203  }
204 
205 
216  template <typename RandomAccessIterator, typename Distance, typename T>
217  void adjust_heap(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, T&& value)
218  {
219  typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
220  adjust_heap_impl<RandomAccessIterator, Distance, T&&, value_type>(first, topPosition, heapSize, position, eastl::forward<T>(value));
221  }
222 
223 
224  template <typename RandomAccessIterator, typename Distance, typename T, typename Compare, typename ValueType>
225  void adjust_heap_impl(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, T value, Compare compare)
226  {
227  // We do the conventional approach of moving the position down to the
228  // bottom then inserting the value at the back and moving it up.
229  Distance childPosition = (2 * position) + 2;
230 
231  for(; childPosition < heapSize; childPosition = (2 * childPosition) + 2)
232  {
233  if(compare(*(first + childPosition), *(first + (childPosition - 1)))) // Choose the larger of the two children.
234  --childPosition;
235  *(first + position) = eastl::forward<ValueType>(*(first + childPosition)); // Swap positions with this child.
236  position = childPosition;
237  }
238 
239  if(childPosition == heapSize) // If we are at the bottom...
240  {
241  *(first + position) = eastl::forward<ValueType>(*(first + (childPosition - 1)));
242  position = childPosition - 1;
243  }
244 
245  eastl::promote_heap<RandomAccessIterator, Distance, T, Compare>(first, topPosition, position, eastl::forward<ValueType>(value), compare);
246  }
247 
256  template <typename RandomAccessIterator, typename Distance, typename T, typename Compare>
257  void adjust_heap(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, const T& value, Compare compare)
258  {
259  typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
260  adjust_heap_impl<RandomAccessIterator, Distance, const T&, Compare, const value_type>(first, topPosition, heapSize, position, eastl::forward<const T&>(value), compare);
261  }
262 
263 
272  template <typename RandomAccessIterator, typename Distance, typename T, typename Compare>
273  void adjust_heap(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, T&& value, Compare compare)
274  {
275  typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
276  adjust_heap_impl<RandomAccessIterator, Distance, T&&, Compare, value_type>(first, topPosition, heapSize, position, eastl::forward<T>(value), compare);
277  }
278 
279 
281  // push_heap
283 
296  template <typename RandomAccessIterator>
297  inline void push_heap(RandomAccessIterator first, RandomAccessIterator last)
298  {
299  typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
300  typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
301 
302  const value_type tempBottom(eastl::forward<value_type>(*(last - 1)));
303 
304  eastl::promote_heap<RandomAccessIterator, difference_type, value_type>
305  (first, (difference_type)0, (difference_type)(last - first - 1), eastl::forward<const value_type>(tempBottom));
306  }
307 
308 
319  template <typename RandomAccessIterator, typename Compare>
320  inline void push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare)
321  {
322  typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
323  typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
324 
325  const value_type tempBottom(*(last - 1));
326 
327  eastl::promote_heap<RandomAccessIterator, difference_type, value_type, Compare>
328  (first, (difference_type)0, (difference_type)(last - first - 1), tempBottom, compare);
329  }
330 
331 
332 
333 
335  // pop_heap
337 
353  template <typename RandomAccessIterator>
354  inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last)
355  {
356  typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
357  typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
358 
359  value_type tempBottom(eastl::forward<value_type>(*(last - 1)));
360  *(last - 1) = eastl::forward<value_type>(*first);
361  eastl::adjust_heap<RandomAccessIterator, difference_type, value_type>
362  (first, (difference_type)0, (difference_type)(last - first - 1), 0, eastl::forward<value_type>(tempBottom));
363  }
364 
365 
366 
377  template <typename RandomAccessIterator, typename Compare>
378  inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare)
379  {
380  typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
381  typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
382 
383  value_type tempBottom(eastl::forward<value_type>(*(last - 1)));
384  *(last - 1) = eastl::forward<value_type>(*first);
385  eastl::adjust_heap<RandomAccessIterator, difference_type, value_type, Compare>
386  (first, (difference_type)0, (difference_type)(last - first - 1), 0, eastl::forward<value_type>(tempBottom), compare);
387  }
388 
389 
391  // make_heap
393 
394 
401  template <typename RandomAccessIterator>
402  void make_heap(RandomAccessIterator first, RandomAccessIterator last)
403  {
404  // We do bottom-up heap construction as per Sedgewick. Such construction is O(n).
405  typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
406  typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
407 
408  const difference_type heapSize = last - first;
409 
410  if(heapSize >= 2) // If there is anything to do... (we need this check because otherwise the math fails below).
411  {
412  difference_type parentPosition = ((heapSize - 2) >> 1) + 1; // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>.
413 
414  do{
415  --parentPosition;
416  value_type temp(eastl::forward<value_type>(*(first + parentPosition)));
417  eastl::adjust_heap<RandomAccessIterator, difference_type, value_type>
418  (first, parentPosition, heapSize, parentPosition, eastl::forward<value_type>(temp));
419  } while(parentPosition != 0);
420  }
421  }
422 
423 
424  template <typename RandomAccessIterator, typename Compare>
425  void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare)
426  {
427  typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
428  typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
429 
430  const difference_type heapSize = last - first;
431 
432  if(heapSize >= 2) // If there is anything to do... (we need this check because otherwise the math fails below).
433  {
434  difference_type parentPosition = ((heapSize - 2) >> 1) + 1; // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>.
435 
436  do{
437  --parentPosition;
438  value_type temp(eastl::forward<value_type>(*(first + parentPosition)));
439  eastl::adjust_heap<RandomAccessIterator, difference_type, value_type, Compare>
440  (first, parentPosition, heapSize, parentPosition, eastl::forward<value_type>(temp), compare);
441  } while(parentPosition != 0);
442  }
443  }
444 
445 
447  // sort_heap
449 
462  template <typename RandomAccessIterator>
463  inline void sort_heap(RandomAccessIterator first, RandomAccessIterator last)
464  {
465  for(; (last - first) > 1; --last) // We simply use the heap to sort itself.
466  eastl::pop_heap<RandomAccessIterator>(first, last);
467  }
468 
469 
475  template <typename RandomAccessIterator, typename Compare>
476  inline void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare)
477  {
478  for(; (last - first) > 1; --last) // We simply use the heap to sort itself.
479  eastl::pop_heap<RandomAccessIterator, Compare>(first, last, compare);
480  }
481 
482 
483 
485  // remove_heap
487 
500  template <typename RandomAccessIterator, typename Distance>
501  inline void remove_heap(RandomAccessIterator first, Distance heapSize, Distance position)
502  {
503  typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
504  typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
505 
506  const value_type tempBottom(*(first + heapSize - 1));
507  *(first + heapSize - 1) = *(first + position);
508  eastl::adjust_heap<RandomAccessIterator, difference_type, value_type>
509  (first, (difference_type)0, (difference_type)(heapSize - 1), (difference_type)position, tempBottom);
510  }
511 
512 
523  template <typename RandomAccessIterator, typename Distance, typename Compare>
524  inline void remove_heap(RandomAccessIterator first, Distance heapSize, Distance position, Compare compare)
525  {
526  typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
527  typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
528 
529  const value_type tempBottom(*(first + heapSize - 1));
530  *(first + heapSize - 1) = *(first + position);
531  eastl::adjust_heap<RandomAccessIterator, difference_type, value_type, Compare>
532  (first, (difference_type)0, (difference_type)(heapSize - 1), (difference_type)position, tempBottom, compare);
533  }
534 
535 
536 
538  // change_heap
540 
547  template <typename RandomAccessIterator, typename Distance>
548  inline void change_heap(RandomAccessIterator first, Distance heapSize, Distance position)
549  {
550  typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
551  typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
552 
553  eastl::remove_heap<RandomAccessIterator, Distance>(first, heapSize, position);
554 
555  value_type tempBottom(*(first + heapSize - 1));
556 
557  eastl::promote_heap<RandomAccessIterator, difference_type, value_type>
558  (first, (difference_type)0, (difference_type)(heapSize - 1), tempBottom);
559  }
560 
561 
567  template <typename RandomAccessIterator, typename Distance, typename Compare>
568  inline void change_heap(RandomAccessIterator first, Distance heapSize, Distance position, Compare compare)
569  {
570  typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
571  typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
572 
573  eastl::remove_heap<RandomAccessIterator, Distance, Compare>(first, heapSize, position, compare);
574 
575  value_type tempBottom(*(first + heapSize - 1));
576 
577  eastl::promote_heap<RandomAccessIterator, difference_type, value_type, Compare>
578  (first, (difference_type)0, (difference_type)(heapSize - 1), tempBottom, compare);
579  }
580 
581 
582 
584  // is_heap_until
586 
589  template <typename RandomAccessIterator>
590  inline RandomAccessIterator is_heap_until(RandomAccessIterator first, RandomAccessIterator last)
591  {
592  int counter = 0;
593 
594  for(RandomAccessIterator child = first + 1; child < last; ++child, counter ^= 1)
595  {
596  if(*first < *child) // We must use operator <, and are not allowed to use > or >= here.
597  return child;
598  first += counter; // counter switches between 0 and 1 every time through.
599  }
600 
601  return last;
602  }
603 
604 
610  template <typename RandomAccessIterator, typename Compare>
611  inline RandomAccessIterator is_heap_until(RandomAccessIterator first, RandomAccessIterator last, Compare compare)
612  {
613  int counter = 0;
614 
615  for(RandomAccessIterator child = first + 1; child < last; ++child, counter ^= 1)
616  {
617  if(compare(*first, *child))
618  return child;
619  first += counter; // counter switches between 0 and 1 every time through.
620  }
621 
622  return last;
623  }
624 
625 
626 
628  // is_heap
630 
636  template <typename RandomAccessIterator>
637  inline bool is_heap(RandomAccessIterator first, RandomAccessIterator last)
638  {
639  return (eastl::is_heap_until(first, last) == last);
640  }
641 
642 
648  template <typename RandomAccessIterator, typename Compare>
649  inline bool is_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare)
650  {
651  return (eastl::is_heap_until(first, last, compare) == last);
652  }
653 
654 
655  // To consider: The following may be a faster implementation for most cases.
656  //
657  // template <typename RandomAccessIterator>
658  // inline bool is_heap(RandomAccessIterator first, RandomAccessIterator last)
659  // {
660  // if(((uintptr_t)(last - first) & 1) == 0) // If the range has an even number of elements...
661  // --last;
662  //
663  // RandomAccessIterator parent = first, child = (first + 1);
664  //
665  // for(; child < last; child += 2, ++parent)
666  // {
667  // if((*parent < *child) || (*parent < *(child + 1)))
668  // return false;
669  // }
670  //
671  // if((((uintptr_t)(last - first) & 1) == 0) && (*parent < *child))
672  // return false;
673  //
674  // return true;
675  // }
676 
677 
678 } // namespace eastl
679 
680 
681 #endif // Header include guard
682 
683 
684 
685 
EA Standard Template Library.
Definition: algorithm.h:288
void sort_heap(RandomAccessIterator first, RandomAccessIterator last)
Definition: heap.h:463
void promote_heap(RandomAccessIterator first, Distance topPosition, Distance position, const T &value)
Definition: heap.h:80
void change_heap(RandomAccessIterator first, Distance heapSize, Distance position)
Definition: heap.h:548
bool is_heap(RandomAccessIterator first, RandomAccessIterator last)
Definition: heap.h:637
void adjust_heap(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, const T &value)
Definition: heap.h:199
void make_heap(RandomAccessIterator first, RandomAccessIterator last)
Definition: heap.h:402
RandomAccessIterator is_heap_until(RandomAccessIterator first, RandomAccessIterator last)
Definition: heap.h:590
void push_heap(RandomAccessIterator first, RandomAccessIterator last)
Definition: heap.h:297
void pop_heap(RandomAccessIterator first, RandomAccessIterator last)
Definition: heap.h:354
void remove_heap(RandomAccessIterator first, Distance heapSize, Distance position)
Definition: heap.h:501
less<T>
Definition: functional_base.h:202