11use alloc:: vec:: IntoIter ;
22use core:: cmp:: { Ord , Ordering , Reverse } ;
33use core:: mem:: { replace, transmute, MaybeUninit } ;
4-
4+ use core :: ops :: Range ;
55
66fn k_smallest_dynamic < T , I : Iterator < Item = T > > (
77 iter : I ,
@@ -10,8 +10,8 @@ fn k_smallest_dynamic<T, I: Iterator<Item = T>>(
1010) -> IntoIter < T > {
1111 let mut storage = Vec :: new ( ) ;
1212 storage. resize_with ( k, MaybeUninit :: uninit) ;
13- let num_elements = capped_heapsort ( iter, & mut storage, order) ;
14- storage. truncate ( num_elements ) ;
13+ let Range { end , .. } = capped_heapsort ( iter, & mut storage, order) ;
14+ storage. truncate ( end ) ;
1515 let initialized: Vec < _ > = unsafe { transmute ( storage) } ;
1616 initialized. into_iter ( )
1717}
@@ -61,15 +61,22 @@ where
6161}
6262
6363/// Consumes a given iterator, leaving the minimum elements in the provided storage in **ascending** order.
64- /// Returns the number of elements processed, up to the size of the storage
64+ /// Returns the range of initialized elements
6565fn capped_heapsort < T , I : Iterator < Item = T > > (
6666 iter : I ,
6767 storage : & mut [ MaybeUninit < T > ] ,
6868 order : impl Fn ( & T , & T ) -> Ordering ,
69- ) -> usize {
70- let mut heap = MaxHeap :: new ( & mut storage[ ..] , order) ;
71- heap. extend ( iter) ;
72- heap. total_sort ( )
69+ ) -> Range < usize > {
70+ if storage. is_empty ( ) {
71+ return 0 ..0 ;
72+ }
73+ let mut heap = MaxHeap :: from_iter ( storage, order, iter) ;
74+
75+ let valid_elements = 0 ..heap. len ;
76+ while heap. len > 0 {
77+ heap. pop ( ) ;
78+ }
79+ valid_elements
7380}
7481
7582/// An efficient heapsort requires that the heap ordering is the inverse of the desired sort order
@@ -83,6 +90,7 @@ fn capped_heapsort<T, I: Iterator<Item = T>>(
8390struct MaxHeap < ' a , T , C > {
8491 // It may be not be possible to shrink the storage for smaller sequencess
8592 // so manually manage the initialization
93+ // This is **assumed not to be empty**
8694 storage : & ' a mut [ MaybeUninit < T > ] ,
8795 comparator : C ,
8896 // SAFETY: this must always be less or equal to the count of actually initialized elements
@@ -93,37 +101,31 @@ impl<'a, T, C> MaxHeap<'a, T, C>
93101where
94102 C : Fn ( & T , & T ) -> Ordering ,
95103{
96- fn extend < T : IntoIterator < Item = A > > ( & mut self , iter : T ) {
97- let mut iter = iter. into_iter ( ) ;
98-
99- for initial_item in iter. by_ref ( ) . take ( self . storage . len ( ) - self . len ) {
100- // This is the only point where the length is increased
101- // And the element we are increasing from is always initialized
102- self . storage [ self . len ] = MaybeUninit :: new ( initial_item) ;
103- self . len += 1 ;
104+ fn from_iter < I > ( storage : & ' a mut [ MaybeUninit < T > ] , comparator : C , mut iter : I ) -> Self
105+ where
106+ I : Iterator < Item = T > ,
107+ {
108+ let mut heap = Self {
109+ storage,
110+ comparator,
111+ len : 0 ,
112+ } ;
113+ for ( i, initial_item) in iter. by_ref ( ) . take ( heap. storage . len ( ) ) . enumerate ( ) {
114+ heap. storage [ i] = MaybeUninit :: new ( initial_item) ;
115+ heap. len += 1 ;
104116 }
105117 // Filling up the storage and only afterwards rearranging to form a valid heap is slightly more efficient
106118 // (But only by a factor of lg(k) and I'd love to hear of a usecase where that matters)
107- self . heapify ( ) ;
119+ heap . heapify ( ) ;
108120
109- if self . len == self . storage . len ( ) {
121+ if heap . len == heap . storage . len ( ) {
110122 // Nothing else needs done if we didn't fill the storage in the first place
111123 // Also avoids unexpected behaviour with restartable iterators
112124 for val in iter {
113- let _ = self . push_pop ( val) ;
125+ let _ = heap . push_pop ( val) ;
114126 }
115127 }
116- }
117- }
118-
119- impl < ' a , T , C > MaxHeap < ' a , T , C > {
120- /// Creates an empty [`MaxHeap<T, C>`].
121- fn new ( storage : & ' a mut [ MaybeUninit < T > ] , comparator : C ) -> Self {
122- Self {
123- storage,
124- comparator,
125- len : 0 ,
126- }
128+ heap
127129 }
128130
129131 /// Retrieves the element at the given index.
@@ -169,9 +171,21 @@ impl<'a, T, C> MaxHeap<'a, T, C> {
169171 }
170172 }
171173
174+ /// Pop the greatest element by putting it at the back of the storage
175+ /// shrinking the heap by 1, and reordering if needed
176+ fn pop ( & mut self ) {
177+ debug_assert ! ( self . len > 0 ) ;
178+ self . storage . swap ( 0 , self . len - 1 ) ;
179+ // Leaves the length shorter than the number of initialized elements
180+ // so that sifting does not disturb already popped elements
181+ self . len -= 1 ;
182+ self . sift_down ( 0 ) ;
183+ }
184+
172185 /// Insert the given element into the heap without changing its size
173186 /// The displaced element is returned, i.e. either the input or previous max
174187 fn push_pop ( & mut self , val : T ) -> Option < T > {
188+ if self . compare ( self . get ( 0 ) , Some ( & val) ) == Some ( Ordering :: Greater ) {
175189 let out = replace ( & mut self . storage [ 0 ] , MaybeUninit :: new ( val) ) ;
176190 self . sift_down ( 0 ) ;
177191 // SAFETY: This has been moved out of storage[0]
@@ -195,23 +209,6 @@ impl<'a, T, C> MaxHeap<'a, T, C> {
195209 fn compare ( & self , a : Option < & T > , b : Option < & T > ) -> Option < Ordering > {
196210 ( self . comparator ) ( a?, b?) . into ( )
197211 }
198-
199- /// Heapsorts the storage into **ascending** order by repeatedly popping.
200- /// The number of elements in the heap is returned.
201- fn total_sort ( mut self ) -> usize
202- where
203- C : Fn ( & T , & T ) -> Ordering ,
204- {
205- let original_len = self . len ;
206- while self . len > 1 {
207- self . storage . swap ( 0 , self . len - 1 ) ;
208- // Leaves the length shorter than the number of initialized elements
209- // so that sifting does not disturb already popped elements
210- self . len -= 1 ;
211- self . sift_down ( 0 ) ;
212- }
213- original_len
214- }
215212}
216213
217214struct Pair < K , T > ( K , T ) ;
0 commit comments