1// Heap implementation -*- C++ -*-
2
3// Copyright (C) 2001-2022 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/*
26 *
27 * Copyright (c) 1994
28 * Hewlett-Packard Company
29 *
30 * Permission to use, copy, modify, distribute and sell this software
31 * and its documentation for any purpose is hereby granted without fee,
32 * provided that the above copyright notice appear in all copies and
33 * that both that copyright notice and this permission notice appear
34 * in supporting documentation. Hewlett-Packard Company makes no
35 * representations about the suitability of this software for any
36 * purpose. It is provided "as is" without express or implied warranty.
37 *
38 * Copyright (c) 1997
39 * Silicon Graphics Computer Systems, Inc.
40 *
41 * Permission to use, copy, modify, distribute and sell this software
42 * and its documentation for any purpose is hereby granted without fee,
43 * provided that the above copyright notice appear in all copies and
44 * that both that copyright notice and this permission notice appear
45 * in supporting documentation. Silicon Graphics makes no
46 * representations about the suitability of this software for any
47 * purpose. It is provided "as is" without express or implied warranty.
48 */
49
50/** @file bits/stl_heap.h
51 * This is an internal header file, included by other library headers.
52 * Do not attempt to use it directly. @headername{queue}
53 */
54
55#ifndef _STL_HEAP_H
56#define _STL_HEAP_H 1
57
58#include <debug/debug.h>
59#include <bits/move.h>
60#include <bits/predefined_ops.h>
61#include <bits/stl_iterator_base_funcs.h>
62
63namespace std _GLIBCXX_VISIBILITY(default)
64{
65_GLIBCXX_BEGIN_NAMESPACE_VERSION
66
67 /**
68 * @defgroup heap_algorithms Heap
69 * @ingroup sorting_algorithms
70 */
71
72 template<typename _RandomAccessIterator, typename _Distance,
73 typename _Compare>
74 _GLIBCXX20_CONSTEXPR
75 _Distance
76 __is_heap_until(_RandomAccessIterator __first, _Distance __n,
77 _Compare& __comp)
78 {
79 _Distance __parent = 0;
80 for (_Distance __child = 1; __child < __n; ++__child)
81 {
82 if (__comp(__first + __parent, __first + __child))
83 return __child;
84 if ((__child & 1) == 0)
85 ++__parent;
86 }
87 return __n;
88 }
89
90 // __is_heap, a predicate testing whether or not a range is a heap.
91 // This function is an extension, not part of the C++ standard.
92 template<typename _RandomAccessIterator, typename _Distance>
93 _GLIBCXX20_CONSTEXPR
94 inline bool
95 __is_heap(_RandomAccessIterator __first, _Distance __n)
96 {
97 __gnu_cxx::__ops::_Iter_less_iter __comp;
98 return std::__is_heap_until(__first, __n, __comp) == __n;
99 }
100
101 template<typename _RandomAccessIterator, typename _Compare,
102 typename _Distance>
103 _GLIBCXX20_CONSTEXPR
104 inline bool
105 __is_heap(_RandomAccessIterator __first, _Compare __comp, _Distance __n)
106 {
107 typedef __decltype(__comp) _Cmp;
108 __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
109 return std::__is_heap_until(__first, __n, __cmp) == __n;
110 }
111
112 template<typename _RandomAccessIterator>
113 _GLIBCXX20_CONSTEXPR
114 inline bool
115 __is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
116 { return std::__is_heap(__first, std::distance(__first, __last)); }
117
118 template<typename _RandomAccessIterator, typename _Compare>
119 _GLIBCXX20_CONSTEXPR
120 inline bool
121 __is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
122 _Compare __comp)
123 {
124 return std::__is_heap(__first, _GLIBCXX_MOVE(__comp),
125 std::distance(__first, __last));
126 }
127
128 // Heap-manipulation functions: push_heap, pop_heap, make_heap, sort_heap,
129 // + is_heap and is_heap_until in C++0x.
130
131 template<typename _RandomAccessIterator, typename _Distance, typename _Tp,
132 typename _Compare>
133 _GLIBCXX20_CONSTEXPR
134 void
135 __push_heap(_RandomAccessIterator __first,
136 _Distance __holeIndex, _Distance __topIndex, _Tp __value,
137 _Compare& __comp)
138 {
139 _Distance __parent = (__holeIndex - 1) / 2;
140 while (__holeIndex > __topIndex && __comp(__first + __parent, __value))
141 {
142 *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent));
143 __holeIndex = __parent;
144 __parent = (__holeIndex - 1) / 2;
145 }
146 *(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
147 }
148
149 /**
150 * @brief Push an element onto a heap.
151 * @param __first Start of heap.
152 * @param __last End of heap + element.
153 * @ingroup heap_algorithms
154 *
155 * This operation pushes the element at last-1 onto the valid heap
156 * over the range [__first,__last-1). After completion,
157 * [__first,__last) is a valid heap.
158 */
159 template<typename _RandomAccessIterator>
160 _GLIBCXX20_CONSTEXPR
161 inline void
162 push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
163 {
164 typedef typename iterator_traits<_RandomAccessIterator>::value_type
165 _ValueType;
166 typedef typename iterator_traits<_RandomAccessIterator>::difference_type
167 _DistanceType;
168
169 // concept requirements
170 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
171 _RandomAccessIterator>)
172 __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)
173 __glibcxx_requires_valid_range(__first, __last);
174 __glibcxx_requires_irreflexive(__first, __last);
175 __glibcxx_requires_heap(__first, __last - 1);
176
177 __gnu_cxx::__ops::_Iter_less_val __comp;
178 _ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
179 std::__push_heap(__first, _DistanceType((__last - __first) - 1),
180 _DistanceType(0), _GLIBCXX_MOVE(__value), __comp);
181 }
182
183 /**
184 * @brief Push an element onto a heap using comparison functor.
185 * @param __first Start of heap.
186 * @param __last End of heap + element.
187 * @param __comp Comparison functor.
188 * @ingroup heap_algorithms
189 *
190 * This operation pushes the element at __last-1 onto the valid
191 * heap over the range [__first,__last-1). After completion,
192 * [__first,__last) is a valid heap. Compare operations are
193 * performed using comp.
194 */
195 template<typename _RandomAccessIterator, typename _Compare>
196 _GLIBCXX20_CONSTEXPR
197 inline void
198 push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
199 _Compare __comp)
200 {
201 typedef typename iterator_traits<_RandomAccessIterator>::value_type
202 _ValueType;
203 typedef typename iterator_traits<_RandomAccessIterator>::difference_type
204 _DistanceType;
205
206 // concept requirements
207 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
208 _RandomAccessIterator>)
209 __glibcxx_requires_valid_range(__first, __last);
210 __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
211 __glibcxx_requires_heap_pred(__first, __last - 1, __comp);
212
213 __decltype(__gnu_cxx::__ops::__iter_comp_val(_GLIBCXX_MOVE(__comp)))
214 __cmp(_GLIBCXX_MOVE(__comp));
215 _ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
216 std::__push_heap(__first, _DistanceType((__last - __first) - 1),
217 _DistanceType(0), _GLIBCXX_MOVE(__value), __cmp);
218 }
219
220 template<typename _RandomAccessIterator, typename _Distance,
221 typename _Tp, typename _Compare>
222 _GLIBCXX20_CONSTEXPR
223 void
224 __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
225 _Distance __len, _Tp __value, _Compare __comp)
226 {
227 const _Distance __topIndex = __holeIndex;
228 _Distance __secondChild = __holeIndex;
229 while (__secondChild < (__len - 1) / 2)
230 {
231 __secondChild = 2 * (__secondChild + 1);
232 if (__comp(__first + __secondChild,
233 __first + (__secondChild - 1)))
234 __secondChild--;
235 *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
236 __holeIndex = __secondChild;
237 }
238 if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2)
239 {
240 __secondChild = 2 * (__secondChild + 1);
241 *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first
242 + (__secondChild - 1)));
243 __holeIndex = __secondChild - 1;
244 }
245 __decltype(__gnu_cxx::__ops::__iter_comp_val(_GLIBCXX_MOVE(__comp)))
246 __cmp(_GLIBCXX_MOVE(__comp));
247 std::__push_heap(__first, __holeIndex, __topIndex,
248 _GLIBCXX_MOVE(__value), __cmp);
249 }
250
251 template<typename _RandomAccessIterator, typename _Compare>
252 _GLIBCXX20_CONSTEXPR
253 inline void
254 __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
255 _RandomAccessIterator __result, _Compare& __comp)
256 {
257 typedef typename iterator_traits<_RandomAccessIterator>::value_type
258 _ValueType;
259 typedef typename iterator_traits<_RandomAccessIterator>::difference_type
260 _DistanceType;
261
262 _ValueType __value = _GLIBCXX_MOVE(*__result);
263 *__result = _GLIBCXX_MOVE(*__first);
264 std::__adjust_heap(__first, _DistanceType(0),
265 _DistanceType(__last - __first),
266 _GLIBCXX_MOVE(__value), __comp);
267 }
268
269 /**
270 * @brief Pop an element off a heap.
271 * @param __first Start of heap.
272 * @param __last End of heap.
273 * @pre [__first, __last) is a valid, non-empty range.
274 * @ingroup heap_algorithms
275 *
276 * This operation pops the top of the heap. The elements __first
277 * and __last-1 are swapped and [__first,__last-1) is made into a
278 * heap.
279 */
280 template<typename _RandomAccessIterator>
281 _GLIBCXX20_CONSTEXPR
282 inline void
283 pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
284 {
285 // concept requirements
286 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
287 _RandomAccessIterator>)
288 __glibcxx_function_requires(_LessThanComparableConcept<
289 typename iterator_traits<_RandomAccessIterator>::value_type>)
290 __glibcxx_requires_non_empty_range(__first, __last);
291 __glibcxx_requires_valid_range(__first, __last);
292 __glibcxx_requires_irreflexive(__first, __last);
293 __glibcxx_requires_heap(__first, __last);
294
295 if (__last - __first > 1)
296 {
297 --__last;
298 __gnu_cxx::__ops::_Iter_less_iter __comp;
299 std::__pop_heap(__first, __last, __last, __comp);
300 }
301 }
302
303 /**
304 * @brief Pop an element off a heap using comparison functor.
305 * @param __first Start of heap.
306 * @param __last End of heap.
307 * @param __comp Comparison functor to use.
308 * @ingroup heap_algorithms
309 *
310 * This operation pops the top of the heap. The elements __first
311 * and __last-1 are swapped and [__first,__last-1) is made into a
312 * heap. Comparisons are made using comp.
313 */
314 template<typename _RandomAccessIterator, typename _Compare>
315 _GLIBCXX20_CONSTEXPR
316 inline void
317 pop_heap(_RandomAccessIterator __first,
318 _RandomAccessIterator __last, _Compare __comp)
319 {
320 // concept requirements
321 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
322 _RandomAccessIterator>)
323 __glibcxx_requires_valid_range(__first, __last);
324 __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
325 __glibcxx_requires_non_empty_range(__first, __last);
326 __glibcxx_requires_heap_pred(__first, __last, __comp);
327
328 if (__last - __first > 1)
329 {
330 typedef __decltype(__comp) _Cmp;
331 __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
332 --__last;
333 std::__pop_heap(__first, __last, __last, __cmp);
334 }
335 }
336
337 template<typename _RandomAccessIterator, typename _Compare>
338 _GLIBCXX20_CONSTEXPR
339 void
340 __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
341 _Compare& __comp)
342 {
343 typedef typename iterator_traits<_RandomAccessIterator>::value_type
344 _ValueType;
345 typedef typename iterator_traits<_RandomAccessIterator>::difference_type
346 _DistanceType;
347
348 if (__last - __first < 2)
349 return;
350
351 const _DistanceType __len = __last - __first;
352 _DistanceType __parent = (__len - 2) / 2;
353 while (true)
354 {
355 _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
356 std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value),
357 __comp);
358 if (__parent == 0)
359 return;
360 __parent--;
361 }
362 }
363
364 /**
365 * @brief Construct a heap over a range.
366 * @param __first Start of heap.
367 * @param __last End of heap.
368 * @ingroup heap_algorithms
369 *
370 * This operation makes the elements in [__first,__last) into a heap.
371 */
372 template<typename _RandomAccessIterator>
373 _GLIBCXX20_CONSTEXPR
374 inline void
375 make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
376 {
377 // concept requirements
378 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
379 _RandomAccessIterator>)
380 __glibcxx_function_requires(_LessThanComparableConcept<
381 typename iterator_traits<_RandomAccessIterator>::value_type>)
382 __glibcxx_requires_valid_range(__first, __last);
383 __glibcxx_requires_irreflexive(__first, __last);
384
385 __gnu_cxx::__ops::_Iter_less_iter __comp;
386 std::__make_heap(__first, __last, __comp);
387 }
388
389 /**
390 * @brief Construct a heap over a range using comparison functor.
391 * @param __first Start of heap.
392 * @param __last End of heap.
393 * @param __comp Comparison functor to use.
394 * @ingroup heap_algorithms
395 *
396 * This operation makes the elements in [__first,__last) into a heap.
397 * Comparisons are made using __comp.
398 */
399 template<typename _RandomAccessIterator, typename _Compare>
400 _GLIBCXX20_CONSTEXPR
401 inline void
402 make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
403 _Compare __comp)
404 {
405 // concept requirements
406 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
407 _RandomAccessIterator>)
408 __glibcxx_requires_valid_range(__first, __last);
409 __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
410
411 typedef __decltype(__comp) _Cmp;
412 __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
413 std::__make_heap(__first, __last, __cmp);
414 }
415
416 template<typename _RandomAccessIterator, typename _Compare>
417 _GLIBCXX20_CONSTEXPR
418 void
419 __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
420 _Compare& __comp)
421 {
422 while (__last - __first > 1)
423 {
424 --__last;
425 std::__pop_heap(__first, __last, __last, __comp);
426 }
427 }
428
429 /**
430 * @brief Sort a heap.
431 * @param __first Start of heap.
432 * @param __last End of heap.
433 * @ingroup heap_algorithms
434 *
435 * This operation sorts the valid heap in the range [__first,__last).
436 */
437 template<typename _RandomAccessIterator>
438 _GLIBCXX20_CONSTEXPR
439 inline void
440 sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
441 {
442 // concept requirements
443 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
444 _RandomAccessIterator>)
445 __glibcxx_function_requires(_LessThanComparableConcept<
446 typename iterator_traits<_RandomAccessIterator>::value_type>)
447 __glibcxx_requires_valid_range(__first, __last);
448 __glibcxx_requires_irreflexive(__first, __last);
449 __glibcxx_requires_heap(__first, __last);
450
451 __gnu_cxx::__ops::_Iter_less_iter __comp;
452 std::__sort_heap(__first, __last, __comp);
453 }
454
455 /**
456 * @brief Sort a heap using comparison functor.
457 * @param __first Start of heap.
458 * @param __last End of heap.
459 * @param __comp Comparison functor to use.
460 * @ingroup heap_algorithms
461 *
462 * This operation sorts the valid heap in the range [__first,__last).
463 * Comparisons are made using __comp.
464 */
465 template<typename _RandomAccessIterator, typename _Compare>
466 _GLIBCXX20_CONSTEXPR
467 inline void
468 sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
469 _Compare __comp)
470 {
471 // concept requirements
472 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
473 _RandomAccessIterator>)
474 __glibcxx_requires_valid_range(__first, __last);
475 __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
476 __glibcxx_requires_heap_pred(__first, __last, __comp);
477
478 typedef __decltype(__comp) _Cmp;
479 __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
480 std::__sort_heap(__first, __last, __cmp);
481 }
482
483#if __cplusplus >= 201103L
484 /**
485 * @brief Search the end of a heap.
486 * @param __first Start of range.
487 * @param __last End of range.
488 * @return An iterator pointing to the first element not in the heap.
489 * @ingroup heap_algorithms
490 *
491 * This operation returns the last iterator i in [__first, __last) for which
492 * the range [__first, i) is a heap.
493 */
494 template<typename _RandomAccessIterator>
495 _GLIBCXX20_CONSTEXPR
496 inline _RandomAccessIterator
497 is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last)
498 {
499 // concept requirements
500 __glibcxx_function_requires(_RandomAccessIteratorConcept<
501 _RandomAccessIterator>)
502 __glibcxx_function_requires(_LessThanComparableConcept<
503 typename iterator_traits<_RandomAccessIterator>::value_type>)
504 __glibcxx_requires_valid_range(__first, __last);
505 __glibcxx_requires_irreflexive(__first, __last);
506
507 __gnu_cxx::__ops::_Iter_less_iter __comp;
508 return __first +
509 std::__is_heap_until(__first, std::distance(__first, __last), __comp);
510 }
511
512 /**
513 * @brief Search the end of a heap using comparison functor.
514 * @param __first Start of range.
515 * @param __last End of range.
516 * @param __comp Comparison functor to use.
517 * @return An iterator pointing to the first element not in the heap.
518 * @ingroup heap_algorithms
519 *
520 * This operation returns the last iterator i in [__first, __last) for which
521 * the range [__first, i) is a heap. Comparisons are made using __comp.
522 */
523 template<typename _RandomAccessIterator, typename _Compare>
524 _GLIBCXX20_CONSTEXPR
525 inline _RandomAccessIterator
526 is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last,
527 _Compare __comp)
528 {
529 // concept requirements
530 __glibcxx_function_requires(_RandomAccessIteratorConcept<
531 _RandomAccessIterator>)
532 __glibcxx_requires_valid_range(__first, __last);
533 __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
534
535 typedef __decltype(__comp) _Cmp;
536 __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
537 return __first
538 + std::__is_heap_until(__first, std::distance(__first, __last), __cmp);
539 }
540
541 /**
542 * @brief Determines whether a range is a heap.
543 * @param __first Start of range.
544 * @param __last End of range.
545 * @return True if range is a heap, false otherwise.
546 * @ingroup heap_algorithms
547 */
548 template<typename _RandomAccessIterator>
549 _GLIBCXX20_CONSTEXPR
550 inline bool
551 is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
552 { return std::is_heap_until(__first, __last) == __last; }
553
554 /**
555 * @brief Determines whether a range is a heap using comparison functor.
556 * @param __first Start of range.
557 * @param __last End of range.
558 * @param __comp Comparison functor to use.
559 * @return True if range is a heap, false otherwise.
560 * @ingroup heap_algorithms
561 */
562 template<typename _RandomAccessIterator, typename _Compare>
563 _GLIBCXX20_CONSTEXPR
564 inline bool
565 is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
566 _Compare __comp)
567 {
568 // concept requirements
569 __glibcxx_function_requires(_RandomAccessIteratorConcept<
570 _RandomAccessIterator>)
571 __glibcxx_requires_valid_range(__first, __last);
572 __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
573
574 const auto __dist = std::distance(__first, __last);
575 typedef __decltype(__comp) _Cmp;
576 __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
577 return std::__is_heap_until(__first, __dist, __cmp) == __dist;
578 }
579#endif
580
581_GLIBCXX_END_NAMESPACE_VERSION
582} // namespace
583
584#endif /* _STL_HEAP_H */
585