NVBIO
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
interval_heap.hpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*\
2 | Copyright (C) 2013 Nathaniel McClatchey |
3 | Released under the Boost Software License Version 1.0, which may be found |
4 | at http://www.boost.org/LICENSE_1_0.txt |
5 \*----------------------------------------------------------------------------*/
6 
27 #ifndef BOOST_HEAP_INTERVAL_HEAP_HPP_
28 #define BOOST_HEAP_INTERVAL_HEAP_HPP_
29 
30 #ifndef __cplusplus
31 #error interval_heap.hpp requires a C++ compiler.
32 #endif
33 
34 // Grab std::swap and std::move, while avoiding as much baggage as possible.
35 #if (__cplusplus >= 201103L)
36 #include <utility>
37 #else
38 #include <algorithm>
39 #endif
40 // Grab iterator data, for better use of templates.
41 #include <iterator>
42 
43 namespace boost {
44 namespace heap {
45 //------------------------------User-Accessible---------------------------------
47 template <typename Iterator, typename Compare>
48 void make_interval_heap (Iterator first, Iterator last, Compare compare);
49 
51 template <typename Iterator, typename Compare = std::less<typename
52  std::iterator_traits<Iterator>::value_type> >
53 void push_interval_heap (Iterator first, Iterator last, Compare compare);
54 
57 template <typename Iterator, typename Compare>
58 void pop_interval_heap_min (Iterator first, Iterator last, Compare compare);
60 template <typename Iterator, typename Compare>
61 void pop_interval_heap_max (Iterator first, Iterator last, Compare compare);
62 
64 template <typename Iterator, typename Compare>
65 void pop_interval_heap (Iterator first, Iterator last,
66  typename std::iterator_traits<Iterator>::difference_type index,
67  Compare compare);
70 template <typename Iterator, typename Compare>
71 void update_interval_heap (Iterator first, Iterator last,
72  typename std::iterator_traits<Iterator>::difference_type index,
73  Compare compare);
74 
76 template <typename Iterator, typename Compare>
77 void sort_interval_heap (Iterator first, Iterator last, Compare compare);
79 template <typename Iterator, typename Compare>
80 Iterator is_interval_heap_until (Iterator first, Iterator last,Compare compare);
82 template <typename Iterator, typename Compare>
83 bool is_interval_heap (Iterator first, Iterator last, Compare compare);
84 
85 
86 //-------------------------------Book-Keeping-----------------------------------
87 namespace interval_heap_internal {
89 template <typename Iterator, typename Compare>
90 void sift_leaf (Iterator first, Iterator last,
91  typename std::iterator_traits<Iterator>::difference_type index,
92  Compare compare);
94 template <bool left_bound, typename Iterator, typename Offset, typename Compare>
95 void sift_up (Iterator first, Offset index, Compare compare,Offset limit_child);
97 template <typename Iterator, typename Offset, typename Compare>
98 void sift_leaf_max (Iterator first, Iterator last, Offset index,
99  Compare compare, Offset limit_child);
101 template <typename Iterator, typename Offset, typename Compare>
102 void sift_leaf_min (Iterator first, Iterator last, Offset index,
103  Compare compare, Offset limit_child);
105 template <bool left_bound, typename Iterator, typename Offset, typename Compare>
106 void sift_down (Iterator first, Iterator last, Offset index, Compare compare,
107  Offset limit_child);
108 } // Namespace interval_heap_internal
109 
124 template <typename Iterator, typename Compare>
125 void update_interval_heap (Iterator first, Iterator last,
126  typename std::iterator_traits<Iterator>::difference_type index,
127  Compare compare)
128 {
129  using namespace std;
131  typedef typename iterator_traits<Iterator>::difference_type Offset;
132  if (index & 1)
133  sift_down<false, Iterator, Offset, Compare>(first, last, index, compare,2);
134  else
135  sift_down<true, Iterator, Offset, Compare>(first, last, index, compare, 2);
136 }
137 
149 template <typename Iterator, typename Compare>
150 void push_interval_heap (Iterator first, Iterator last, Compare compare) {
152  sift_leaf<Iterator, Compare>(first, last, (last - first) - 1, compare);
153 }
154 
170 template <typename Iterator, typename Compare>
171 void pop_interval_heap (Iterator first, Iterator last,
172  typename std::iterator_traits<Iterator>::difference_type index,
173  Compare compare)
174 {
175  using namespace std;
176  --last;
177  swap(*(first + index), *last);
178  try {
179  update_interval_heap<Iterator, Compare>(first, last, index, compare);
180  } catch (...) {
181 // Roll back for strong guarantee.
182  swap(*last, *(first + index));
183  throw;
184  }
185 }
186 
200 template <typename Iterator, typename Compare>
201 void pop_interval_heap_min (Iterator first, Iterator last, Compare compare) {
202  using namespace std;
204  typedef typename iterator_traits<Iterator>::difference_type Offset;
205  --last;
206  swap(*first, *last);
207  try {
208  sift_down<true, Iterator, Offset, Compare>(first, last, 0, compare, 2);
209  } catch (...) {
210 // Roll back for strong guarantee.
211  swap(*last, *first);
212  throw;
213  }
214 }
215 
229 template <typename Iterator, typename Compare>
230 void pop_interval_heap_max (Iterator first, Iterator last, Compare compare) {
231  using namespace std;
233  typedef typename iterator_traits<Iterator>::difference_type Offset;
234 // Nothing to be done.
235  if (last - first <= 2)
236  return;
237  --last;
238  swap(*(first + 1), *last);
239  try {
240  sift_down<false, Iterator, Offset, Compare>(first, last, 1, compare, 2);
241  } catch (...) {
242 // Roll back for strong guarantee.
243  swap(*last, *(first + 1));
244  throw;
245  }
246 }
247 
258 template <typename Iterator, typename Compare>
259 void sort_interval_heap (Iterator first, Iterator last, Compare compare) {
260  Iterator cursor = last;
261  while (cursor != first) {
262 // If this throws, anything I do to try to fix it is also likely to throw.
263  pop_interval_heap_max<Iterator, Compare>(first, cursor, compare);
264  --cursor;
265  }
266 }
267 
270 template <typename Iterator, typename Compare>
271 Iterator is_interval_heap_until (Iterator first, Iterator last, Compare compare)
272 {
273  using namespace std;
274  typedef typename iterator_traits<Iterator>::difference_type Offset;
275 
276  Offset index = static_cast<Offset>(0);
277 
278  try {
279  Offset index_end = last - first;
280  while (index < index_end) {
281  Iterator cursor = first + index;
282 // Check whether it is a valid interval.
283  if ((index & 1) && compare(*cursor, *(cursor - 1)))
284  return cursor;
285  if (index >= 2) {
286 // If there exists a parent interval, check for containment.
287  Iterator parent = first + ((index / 2 - 1) | 1);
288  if (index & 1) {
289  if (compare(*parent, *cursor))
290  return cursor;
291  } else {
292  if (compare(*parent, *cursor))
293  return cursor;
294  if (compare(*cursor, *(parent - 1)))
295  return cursor;
296  }
297  }
298  ++index;
299  }
300  } catch (...) {
301  return first + index;
302  }
303  return last;
304 }
305 
308 template <typename Iterator, typename Compare>
309 bool is_interval_heap (Iterator first, Iterator last, Compare compare) {
310  try {
311  return (is_interval_heap_until<Iterator,Compare>(first, last, compare)
312  == last);
313  } catch (...) {
314  return false;
315  }
316 }
317 
325 
326 template <typename Iterator, typename Compare>
327 void make_interval_heap (Iterator first, Iterator last, Compare compare) {
328  using namespace std;
330  typedef typename iterator_traits<Iterator>::difference_type Offset;
331 
332  Offset index_end = last - first;
333 // Double-heap property holds vacuously.
334  if (index_end <= 1)
335  return;
336 // Prevents overflow when number of elements approaches maximum possible index.
337  const Offset end_parent = index_end / 2 - 1;
338 // If the final interval is a singleton, it's already OK. Skip it.
339  Offset index = index_end ^ (index_end & 1);
340  do {
341  index -= 2;
342  const Offset stop = (index <= end_parent) ? (index * 2 + 2) : index_end;
343 // If compare throws, heap property cannot be verified or enforced.
344 // If swap throws, heap property is violated and cannot be enforced.
345  if (compare(*(first + index + 1), *(first + index)))
346  swap(*(first + index + 1), *(first + index));
347 
348  sift_down<false, Iterator, Offset, Compare>(first, last, index + 1,
349  compare, stop);
350  sift_down<true , Iterator, Offset, Compare>(first, last, index,
351  compare, stop);
352 
353  } while (index >= 2);
354 }
355 
356 namespace interval_heap_internal {
358 template <bool left_bound, typename Iterator, typename Offset, typename Compare>
359 void sift_up (Iterator first, Offset origin, Compare compare, Offset limit_child)
360 {
361 // Use the most specialized available functions.
362  using namespace std;
363  typedef typename iterator_traits<Iterator>::value_type Value;
364 // Keeping the information about the origin permits strong exception guarantee.
365  Offset index = origin;
366 #if (__cplusplus >= 201103L) // C++11
367  Value swap_space = std::move_if_noexcept(*(first + index));
368 #endif
369  try {
370  while (index >= limit_child) {
371  const Offset parent = ((index / 2 - 1) | 1) ^ (left_bound ? 1 : 0);
372 #if (__cplusplus >= 201103L) // C++11
373  if (compare((left_bound ? swap_space : *(first + parent)),
374  (left_bound ? *(first + parent) : swap_space))) {
375  *(first + index) = std::move_if_noexcept(*(first + parent));
376 #else
377  if (compare(*(first + (left_bound ? index : parent)),
378  *(first + (left_bound ? parent : index)))) {
379  swap(*(first + index), *(first + parent));
380 #endif
381  index = parent;
382  } else
383  break;
384  }
385  } catch (...) {
386 // Note: This rolls back comparison exceptions. Move exceptions can't be fixed.
387 #if (__cplusplus < 201103L) // Not C++11
388 // I need the extra space because elements are being moved in the direction of
389 // travel.
390  Value swap_space;
391  swap(*(first + index), swap_space);
392 #endif
393  swap(*(first + origin), swap_space);
394  while (origin > index) {
395  origin = ((origin / 2 - 1) | 1) ^ (left_bound ? 1 : 0);
396  swap(*(first + origin), swap_space);
397  }
398  throw;
399  }
400 #if (__cplusplus >= 201103L) // C++11
401  *(first + index) = std::move_if_noexcept(swap_space);
402 #endif
403 }
404 
406 template <typename Iterator, typename Offset, typename Compare>
407 void sift_leaf_max (Iterator first, Iterator last, Offset index,
408  Compare compare, Offset limit_child)
409 {
410 // Use the most specialized swap function.
411  using namespace std;
412  const Offset index_end = last - first;
413 
414 // Index of corresponding element
415  const Offset co_index = (index * 2 < index_end) ? (index * 2) : (index ^ 1);
416  if (compare(*(first + index), *(first + co_index))) {
417  swap(*(first + index), *(first + co_index));
418  try {
419  sift_up<true, Iterator, Offset, Compare>(first, co_index, compare,
420  limit_child);
421  } catch (...) { // Rollback for strong guarantee.
422  swap(*(first + index), *(first + co_index));
423  throw;
424  }
425  } else
426  sift_up<false, Iterator, Offset, Compare>(first, index, compare,
427  limit_child);
428 }
429 
431 template <typename Iterator, typename Offset, typename Compare>
432 void sift_leaf_min (Iterator first, Iterator last, Offset index,
433  Compare compare, Offset limit_child)
434 {
435 // Use the most specialized swap function.
436  using namespace std;
437  const Offset index_end = last - first;
438 
439 // Index of corresponding element (initial assumption)
440  Offset co_index = index | 1;
441 // Co-index is past the end of the heap. Move to its parent, if possible.
442  if (co_index >= index_end) {
443 // Only one element.
444  if (co_index == 1)
445  return;
446  co_index = (co_index / 2 - 1) | 1;
447  }
448  if (compare(*(first + co_index), *(first + index))) {
449  swap(*(first + index), *(first + co_index));
450  try {
451  sift_up<false, Iterator, Offset, Compare>(first, co_index, compare,
452  limit_child);
453  } catch (...) { // Rollback for strong guarantee.
454  swap(*(first + index), *(first + co_index));
455  throw;
456  }
457  } else
458  sift_up<true, Iterator, Offset, Compare>(first, index, compare, limit_child);
459 }
460 
462 template <bool left_bound, typename Iterator, typename Offset, typename Compare>
463 void sift_down (Iterator first, Iterator last, Offset origin, Compare compare,
464  Offset limit_child)
465 {
466 // Use the most specialized available functions.
467  using namespace std;
468  typedef typename iterator_traits<Iterator>::value_type Value;
469 // By keeping track of where I started, I can roll back all changes.
470  Offset index = origin;
471 #if (__cplusplus >= 201103L) // C++11
472  Value limbo = std::move_if_noexcept(*(first + index));
473 #endif
474 
475  const Offset index_end = last - first;
476 // One past the last element with two children.
477  const Offset end_parent = index_end / 2 -
478  ((left_bound && ((index_end & 3) == 0)) ? 2 : 1);
479  try { // This try-catch block rolls back after exceptions.
480  while (index < end_parent) {
481  Offset child = index * 2 + (left_bound ? 2 : 1);
482 // If compare throws, heap property cannot be verified or enforced.
483  try { // This try-catch block ensures no element is left in limbo.
484  if (compare(*(first + child + (left_bound ? 2 : 0)),
485  *(first + child + (left_bound ? 0 : 2))))
486  child += 2;
487  } catch (...) {
488 #if (__cplusplus >= 201103L) // C++11
489 // Pull the moving element out of limbo, to avoid leaks.
490  *(first + index) = std::move_if_noexcept(limbo);
491 #endif
492  throw;
493  }
494 #if (__cplusplus >= 201103L) // C++11
495  *(first + index) = std::move_if_noexcept(*(first + child));
496 #else
497  swap(*(first + index), *(first + child));
498 #endif
499  index = child;
500  }
501 // Special case when index has exactly one child.
502  if (index <= end_parent + (left_bound ? 0 : 1)) {
503  Offset child = index * 2 + (left_bound ? 2 : 1);
504  if (child < index_end) {
505 // Need to treat singletons (child + 1) as both upper and lower bounds.
506  if (!left_bound && (child + 1 < index_end)) {
507 // Calculating this outside the if-statement simplifies exception-handling.
508  bool swap_required;
509  try {
510  swap_required = compare(*(first + child), *(first + child + 1));
511  } catch (...) {
512 // Pull the moving element out of limbo.
513 #if (__cplusplus >= 201103L)
514  *(first + index) = std::move_if_noexcept(limbo);
515 #endif
516  throw;
517  }
518  if (swap_required) {
519  ++child;
520 #if (__cplusplus >= 201103L) // C++11
521  *(first + index) = std::move_if_noexcept(*(first + child));
522  *(first + child) = std::move_if_noexcept(limbo);
523 #else
524  swap(*(first + index), *(first + child));
525 #endif
526 // Important for the rollback.
527  index = child;
528  sift_leaf_min<Iterator, Offset, Compare>(first, last, index,
529  compare, limit_child);
530  return;
531  }
532  }
533 #if (__cplusplus >= 201103L) // C++11
534  *(first + index) = std::move_if_noexcept(*(first + child));
535 #else
536  swap(*(first + index), *(first + child));
537 #endif
538  index = child;
539  }
540  }
541 // Pull the moving element out of limbo.
542 #if (__cplusplus >= 201103L) // C++11
543  *(first + index) = std::move_if_noexcept(limbo);
544 #endif
545  if (left_bound)
546  sift_leaf_min<Iterator, Offset, Compare>(first, last, index, compare,
547  limit_child);
548  else
549  sift_leaf_max<Iterator, Offset, Compare>(first, last, index, compare,
550  limit_child);
551  } catch (...) {
552 // Rolls back comparison exceptions. Move exceptions can't be reliably fixed.
553  while (index > origin) {
554  const Offset parent = ((index / 2 - 1) | 1) ^ (left_bound ? 1 : 0);
555  swap(*(first + parent), *(first + index));
556  index = parent;
557  }
558  throw;
559  }
560 }
561 
563 template <typename Iterator, typename Compare>
564 void sift_leaf (Iterator first, Iterator last,
565  typename std::iterator_traits<Iterator>::difference_type index,
566  Compare compare)
567 {
568  using namespace std;
569  typedef typename iterator_traits<Iterator>::difference_type Offset;
570  if (index & 1)
571  sift_leaf_max<Iterator, Offset, Compare>(first, last, index, compare, 2);
572  else
573  sift_leaf_min<Iterator, Offset, Compare>(first, last, index, compare, 2);
574 }
575 } // Namespace interval_heap_internal
576 } // Namespace heap
577 } // Namespace boost
578 
579 #endif // BOOST_HEAP_INTERVAL_HEAP_HPP_