1// Heap implementation -*- C++ -*-
2
3// Copyright (C) 2001-2020 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
62namespace std _GLIBCXX_VISIBILITY(default)
63{
64_GLIBCXX_BEGIN_NAMESPACE_VERSION
65
66  /**
67   * @defgroup heap_algorithms Heap
68   * @ingroup sorting_algorithms
69   */
70
71  template<typename _RandomAccessIterator, typename _Distance,
72	   typename _Compare>
73    _GLIBCXX20_CONSTEXPR
74    _Distance
75    __is_heap_until(_RandomAccessIterator __first, _Distance __n,
76		    _Compare& __comp)
77    {
78      _Distance __parent = 0;
79      for (_Distance __child = 1; __child < __n; ++__child)
80	{
81	  if (__comp(__first + __parent, __first + __child))
82	    return __child;
83	  if ((__child & 1) == 0)
84	    ++__parent;
85	}
86      return __n;
87    }
88
89  // __is_heap, a predicate testing whether or not a range is a heap.
90  // This function is an extension, not part of the C++ standard.
91  template<typename _RandomAccessIterator, typename _Distance>
92    _GLIBCXX20_CONSTEXPR
93    inline bool
94    __is_heap(_RandomAccessIterator __first, _Distance __n)
95    {
96      __gnu_cxx::__ops::_Iter_less_iter __comp;
97      return std::__is_heap_until(__first, __n, __comp) == __n;
98    }
99
100  template<typename _RandomAccessIterator, typename _Compare,
101	   typename _Distance>
102    _GLIBCXX20_CONSTEXPR
103    inline bool
104    __is_heap(_RandomAccessIterator __first, _Compare __comp, _Distance __n)
105    {
106      typedef __decltype(__comp) _Cmp;
107      __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
108      return std::__is_heap_until(__first, __n, __cmp) == __n;
109    }
110
111  template<typename _RandomAccessIterator>
112    _GLIBCXX20_CONSTEXPR
113    inline bool
114    __is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
115    { return std::__is_heap(__first, std::distance(__first, __last)); }
116
117  template<typename _RandomAccessIterator, typename _Compare>
118    _GLIBCXX20_CONSTEXPR
119    inline bool
120    __is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
121	      _Compare __comp)
122    {
123      return std::__is_heap(__first, _GLIBCXX_MOVE(__comp),
124			    std::distance(__first, __last));
125    }
126
127  // Heap-manipulation functions: push_heap, pop_heap, make_heap, sort_heap,
128  // + is_heap and is_heap_until in C++0x.
129
130  template<typename _RandomAccessIterator, typename _Distance, typename _Tp,
131	   typename _Compare>
132    _GLIBCXX20_CONSTEXPR
133    void
134    __push_heap(_RandomAccessIterator __first,
135		_Distance __holeIndex, _Distance __topIndex, _Tp __value,
136		_Compare& __comp)
137    {
138      _Distance __parent = (__holeIndex - 1) / 2;
139      while (__holeIndex > __topIndex && __comp(__first + __parent, __value))
140	{
141	  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent));
142	  __holeIndex = __parent;
143	  __parent = (__holeIndex - 1) / 2;
144	}
145      *(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
146    }
147
148  /**
149   *  @brief  Push an element onto a heap.
150   *  @param  __first  Start of heap.
151   *  @param  __last   End of heap + element.
152   *  @ingroup heap_algorithms
153   *
154   *  This operation pushes the element at last-1 onto the valid heap
155   *  over the range [__first,__last-1).  After completion,
156   *  [__first,__last) is a valid heap.
157  */
158  template<typename _RandomAccessIterator>
159    _GLIBCXX20_CONSTEXPR
160    inline void
161    push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
162    {
163      typedef typename iterator_traits<_RandomAccessIterator>::value_type
164	  _ValueType;
165      typedef typename iterator_traits<_RandomAccessIterator>::difference_type
166	  _DistanceType;
167
168      // concept requirements
169      __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
170	    _RandomAccessIterator>)
171      __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)
172      __glibcxx_requires_valid_range(__first, __last);
173      __glibcxx_requires_irreflexive(__first, __last);
174      __glibcxx_requires_heap(__first, __last - 1);
175
176      __gnu_cxx::__ops::_Iter_less_val __comp;
177      _ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
178      std::__push_heap(__first, _DistanceType((__last - __first) - 1),
179		       _DistanceType(0), _GLIBCXX_MOVE(__value), __comp);
180    }
181
182  /**
183   *  @brief  Push an element onto a heap using comparison functor.
184   *  @param  __first  Start of heap.
185   *  @param  __last   End of heap + element.
186   *  @param  __comp   Comparison functor.
187   *  @ingroup heap_algorithms
188   *
189   *  This operation pushes the element at __last-1 onto the valid
190   *  heap over the range [__first,__last-1).  After completion,
191   *  [__first,__last) is a valid heap.  Compare operations are
192   *  performed using comp.
193  */
194  template<typename _RandomAccessIterator, typename _Compare>
195    _GLIBCXX20_CONSTEXPR
196    inline void
197    push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
198	      _Compare __comp)
199    {
200      typedef typename iterator_traits<_RandomAccessIterator>::value_type
201	  _ValueType;
202      typedef typename iterator_traits<_RandomAccessIterator>::difference_type
203	  _DistanceType;
204
205      // concept requirements
206      __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
207	    _RandomAccessIterator>)
208      __glibcxx_requires_valid_range(__first, __last);
209      __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
210      __glibcxx_requires_heap_pred(__first, __last - 1, __comp);
211
212      __decltype(__gnu_cxx::__ops::__iter_comp_val(_GLIBCXX_MOVE(__comp)))
213	__cmp(_GLIBCXX_MOVE(__comp));
214      _ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
215      std::__push_heap(__first, _DistanceType((__last - __first) - 1),
216		       _DistanceType(0), _GLIBCXX_MOVE(__value), __cmp);
217    }
218
219  template<typename _RandomAccessIterator, typename _Distance,
220	   typename _Tp, typename _Compare>
221    _GLIBCXX20_CONSTEXPR
222    void
223    __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
224		  _Distance __len, _Tp __value, _Compare __comp)
225    {
226      const _Distance __topIndex = __holeIndex;
227      _Distance __secondChild = __holeIndex;
228      while (__secondChild < (__len - 1) / 2)
229	{
230	  __secondChild = 2 * (__secondChild + 1);
231	  if (__comp(__first + __secondChild,
232		     __first + (__secondChild - 1)))
233	    __secondChild--;
234	  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
235	  __holeIndex = __secondChild;
236	}
237      if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2)
238	{
239	  __secondChild = 2 * (__secondChild + 1);
240	  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first
241						     + (__secondChild - 1)));
242	  __holeIndex = __secondChild - 1;
243	}
244      __decltype(__gnu_cxx::__ops::__iter_comp_val(_GLIBCXX_MOVE(__comp)))
245	__cmp(_GLIBCXX_MOVE(__comp));
246      std::__push_heap(__first, __holeIndex, __topIndex,
247		       _GLIBCXX_MOVE(__value), __cmp);
248    }
249
250  template<typename _RandomAccessIterator, typename _Compare>
251    _GLIBCXX20_CONSTEXPR
252    inline void
253    __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
254	       _RandomAccessIterator __result, _Compare& __comp)
255    {
256      typedef typename iterator_traits<_RandomAccessIterator>::value_type
257	_ValueType;
258      typedef typename iterator_traits<_RandomAccessIterator>::difference_type
259	_DistanceType;
260
261      _ValueType __value = _GLIBCXX_MOVE(*__result);
262      *__result = _GLIBCXX_MOVE(*__first);
263      std::__adjust_heap(__first, _DistanceType(0),
264			 _DistanceType(__last - __first),
265			 _GLIBCXX_MOVE(__value), __comp);
266    }
267
268  /**
269   *  @brief  Pop an element off a heap.
270   *  @param  __first  Start of heap.
271   *  @param  __last   End of heap.
272   *  @pre    [__first, __last) is a valid, non-empty range.
273   *  @ingroup heap_algorithms
274   *
275   *  This operation pops the top of the heap.  The elements __first
276   *  and __last-1 are swapped and [__first,__last-1) is made into a
277   *  heap.
278  */
279  template<typename _RandomAccessIterator>
280    _GLIBCXX20_CONSTEXPR
281    inline void
282    pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
283    {
284      // concept requirements
285      __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
286	    _RandomAccessIterator>)
287      __glibcxx_function_requires(_LessThanComparableConcept<
288	typename iterator_traits<_RandomAccessIterator>::value_type>)
289      __glibcxx_requires_non_empty_range(__first, __last);
290      __glibcxx_requires_valid_range(__first, __last);
291      __glibcxx_requires_irreflexive(__first, __last);
292      __glibcxx_requires_heap(__first, __last);
293
294      if (__last - __first > 1)
295	{
296	  --__last;
297	  __gnu_cxx::__ops::_Iter_less_iter __comp;
298	  std::__pop_heap(__first, __last, __last, __comp);
299	}
300    }
301
302  /**
303   *  @brief  Pop an element off a heap using comparison functor.
304   *  @param  __first  Start of heap.
305   *  @param  __last   End of heap.
306   *  @param  __comp   Comparison functor to use.
307   *  @ingroup heap_algorithms
308   *
309   *  This operation pops the top of the heap.  The elements __first
310   *  and __last-1 are swapped and [__first,__last-1) is made into a
311   *  heap.  Comparisons are made using comp.
312  */
313  template<typename _RandomAccessIterator, typename _Compare>
314    _GLIBCXX20_CONSTEXPR
315    inline void
316    pop_heap(_RandomAccessIterator __first,
317	     _RandomAccessIterator __last, _Compare __comp)
318    {
319      // concept requirements
320      __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
321	    _RandomAccessIterator>)
322      __glibcxx_requires_valid_range(__first, __last);
323      __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
324      __glibcxx_requires_non_empty_range(__first, __last);
325      __glibcxx_requires_heap_pred(__first, __last, __comp);
326
327      if (__last - __first > 1)
328	{
329	  typedef __decltype(__comp) _Cmp;
330	  __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
331	  --__last;
332	  std::__pop_heap(__first, __last, __last, __cmp);
333	}
334    }
335
336  template<typename _RandomAccessIterator, typename _Compare>
337    _GLIBCXX20_CONSTEXPR
338    void
339    __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
340		_Compare& __comp)
341    {
342      typedef typename iterator_traits<_RandomAccessIterator>::value_type
343	  _ValueType;
344      typedef typename iterator_traits<_RandomAccessIterator>::difference_type
345	  _DistanceType;
346
347      if (__last - __first < 2)
348	return;
349
350      const _DistanceType __len = __last - __first;
351      _DistanceType __parent = (__len - 2) / 2;
352      while (true)
353	{
354	  _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
355	  std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value),
356			     __comp);
357	  if (__parent == 0)
358	    return;
359	  __parent--;
360	}
361    }
362
363  /**
364   *  @brief  Construct a heap over a range.
365   *  @param  __first  Start of heap.
366   *  @param  __last   End of heap.
367   *  @ingroup heap_algorithms
368   *
369   *  This operation makes the elements in [__first,__last) into a heap.
370  */
371  template<typename _RandomAccessIterator>
372    _GLIBCXX20_CONSTEXPR
373    inline void
374    make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
375    {
376      // concept requirements
377      __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
378	    _RandomAccessIterator>)
379      __glibcxx_function_requires(_LessThanComparableConcept<
380	    typename iterator_traits<_RandomAccessIterator>::value_type>)
381      __glibcxx_requires_valid_range(__first, __last);
382      __glibcxx_requires_irreflexive(__first, __last);
383
384      __gnu_cxx::__ops::_Iter_less_iter __comp;
385      std::__make_heap(__first, __last, __comp);
386    }
387
388  /**
389   *  @brief  Construct a heap over a range using comparison functor.
390   *  @param  __first  Start of heap.
391   *  @param  __last   End of heap.
392   *  @param  __comp   Comparison functor to use.
393   *  @ingroup heap_algorithms
394   *
395   *  This operation makes the elements in [__first,__last) into a heap.
396   *  Comparisons are made using __comp.
397  */
398  template<typename _RandomAccessIterator, typename _Compare>
399    _GLIBCXX20_CONSTEXPR
400    inline void
401    make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
402	      _Compare __comp)
403    {
404      // concept requirements
405      __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
406	    _RandomAccessIterator>)
407      __glibcxx_requires_valid_range(__first, __last);
408      __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
409
410      typedef __decltype(__comp) _Cmp;
411      __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
412      std::__make_heap(__first, __last, __cmp);
413    }
414
415  template<typename _RandomAccessIterator, typename _Compare>
416    _GLIBCXX20_CONSTEXPR
417    void
418    __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
419		_Compare& __comp)
420    {
421      while (__last - __first > 1)
422	{
423	  --__last;
424	  std::__pop_heap(__first, __last, __last, __comp);
425	}
426    }
427
428  /**
429   *  @brief  Sort a heap.
430   *  @param  __first  Start of heap.
431   *  @param  __last   End of heap.
432   *  @ingroup heap_algorithms
433   *
434   *  This operation sorts the valid heap in the range [__first,__last).
435  */
436  template<typename _RandomAccessIterator>
437    _GLIBCXX20_CONSTEXPR
438    inline void
439    sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
440    {
441      // concept requirements
442      __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
443	    _RandomAccessIterator>)
444      __glibcxx_function_requires(_LessThanComparableConcept<
445	    typename iterator_traits<_RandomAccessIterator>::value_type>)
446      __glibcxx_requires_valid_range(__first, __last);
447      __glibcxx_requires_irreflexive(__first, __last);
448      __glibcxx_requires_heap(__first, __last);
449
450      __gnu_cxx::__ops::_Iter_less_iter __comp;
451      std::__sort_heap(__first, __last, __comp);
452    }
453
454  /**
455   *  @brief  Sort a heap using comparison functor.
456   *  @param  __first  Start of heap.
457   *  @param  __last   End of heap.
458   *  @param  __comp   Comparison functor to use.
459   *  @ingroup heap_algorithms
460   *
461   *  This operation sorts the valid heap in the range [__first,__last).
462   *  Comparisons are made using __comp.
463  */
464  template<typename _RandomAccessIterator, typename _Compare>
465    _GLIBCXX20_CONSTEXPR
466    inline void
467    sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
468	      _Compare __comp)
469    {
470      // concept requirements
471      __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
472	    _RandomAccessIterator>)
473      __glibcxx_requires_valid_range(__first, __last);
474      __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
475      __glibcxx_requires_heap_pred(__first, __last, __comp);
476
477      typedef __decltype(__comp) _Cmp;
478      __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
479      std::__sort_heap(__first, __last, __cmp);
480    }
481
482#if __cplusplus >= 201103L
483  /**
484   *  @brief  Search the end of a heap.
485   *  @param  __first  Start of range.
486   *  @param  __last   End of range.
487   *  @return  An iterator pointing to the first element not in the heap.
488   *  @ingroup heap_algorithms
489   *
490   *  This operation returns the last iterator i in [__first, __last) for which
491   *  the range [__first, i) is a heap.
492  */
493  template<typename _RandomAccessIterator>
494    _GLIBCXX20_CONSTEXPR
495    inline _RandomAccessIterator
496    is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last)
497    {
498      // concept requirements
499      __glibcxx_function_requires(_RandomAccessIteratorConcept<
500	    _RandomAccessIterator>)
501      __glibcxx_function_requires(_LessThanComparableConcept<
502	    typename iterator_traits<_RandomAccessIterator>::value_type>)
503      __glibcxx_requires_valid_range(__first, __last);
504      __glibcxx_requires_irreflexive(__first, __last);
505
506      __gnu_cxx::__ops::_Iter_less_iter __comp;
507      return __first +
508	std::__is_heap_until(__first, std::distance(__first, __last), __comp);
509    }
510
511  /**
512   *  @brief  Search the end of a heap using comparison functor.
513   *  @param  __first  Start of range.
514   *  @param  __last   End of range.
515   *  @param  __comp   Comparison functor to use.
516   *  @return  An iterator pointing to the first element not in the heap.
517   *  @ingroup heap_algorithms
518   *
519   *  This operation returns the last iterator i in [__first, __last) for which
520   *  the range [__first, i) is a heap.  Comparisons are made using __comp.
521  */
522  template<typename _RandomAccessIterator, typename _Compare>
523    _GLIBCXX20_CONSTEXPR
524    inline _RandomAccessIterator
525    is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last,
526		  _Compare __comp)
527    {
528      // concept requirements
529      __glibcxx_function_requires(_RandomAccessIteratorConcept<
530	    _RandomAccessIterator>)
531      __glibcxx_requires_valid_range(__first, __last);
532      __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
533
534      typedef __decltype(__comp) _Cmp;
535      __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
536      return __first
537	+ std::__is_heap_until(__first, std::distance(__first, __last), __cmp);
538    }
539
540  /**
541   *  @brief  Determines whether a range is a heap.
542   *  @param  __first  Start of range.
543   *  @param  __last   End of range.
544   *  @return  True if range is a heap, false otherwise.
545   *  @ingroup heap_algorithms
546  */
547  template<typename _RandomAccessIterator>
548    _GLIBCXX20_CONSTEXPR
549    inline bool
550    is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
551    { return std::is_heap_until(__first, __last) == __last; }
552
553  /**
554   *  @brief  Determines whether a range is a heap using comparison functor.
555   *  @param  __first  Start of range.
556   *  @param  __last   End of range.
557   *  @param  __comp   Comparison functor to use.
558   *  @return  True if range is a heap, false otherwise.
559   *  @ingroup heap_algorithms
560  */
561  template<typename _RandomAccessIterator, typename _Compare>
562    _GLIBCXX20_CONSTEXPR
563    inline bool
564    is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
565	    _Compare __comp)
566    {
567      // concept requirements
568      __glibcxx_function_requires(_RandomAccessIteratorConcept<
569	    _RandomAccessIterator>)
570      __glibcxx_requires_valid_range(__first, __last);
571      __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
572
573      const auto __dist = std::distance(__first, __last);
574      typedef __decltype(__comp) _Cmp;
575      __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
576      return std::__is_heap_until(__first, __dist, __cmp) == __dist;
577    }
578#endif
579
580_GLIBCXX_END_NAMESPACE_VERSION
581} // namespace
582
583#endif /* _STL_HEAP_H */
584