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