topset/
heap.rs

1use std::cmp::Ordering;
2use std::fmt::{Debug, Formatter};
3use std::mem;
4use crate::TopSet;
5
6impl<X,C> TopSet<X,C>
7    where C: Fn(&X,&X) -> bool
8{
9    /// Creates a new top set with a selecting closure.
10    ///
11    /// The size corresponds to the maximum number of items
12    /// allowed in the top set.
13    ///
14    /// The function `C` is the challenge to decide if an
15    /// element beats another one and so takes its place.
16    /// It should corresponds to a total ordering.
17    ///
18    /// If the first one beats the second one then `true` should
19    /// be returned and if `false' corresponds to the case when
20    /// the second item beats the first one.
21    /// This function should always returns the same result
22    /// when dealing with the same items or results are unpredictable.
23    ///
24    /// # Example
25    /// Collecting the 5 greatest integers is performed by using a
26    /// topset with `n = 5` and `beat = i32::gt`.
27    /// ```
28    /// # use topset::TopSet;
29    /// let mut topset = TopSet::new(5, i32::gt);
30    /// ```
31    pub fn new(n: usize, beat: C) -> Self
32    {
33        Self {
34            heap: Vec::with_capacity(n),
35            count: n,
36            beat
37        }
38    }
39
40    /// Creates a new top set with a selecting closure and an initial set of items.
41    ///
42    /// If the initial set contains more than `n` elements, only the `n` greatest ones
43    /// (according to `beat` challenging function) are stored.
44    ///
45    /// # Example
46    /// ```
47    /// # use topset::TopSet;
48    /// let mut topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3]);
49    /// assert_eq!( topset.pop(), Some(7));
50    /// assert_eq!( topset.pop(), Some(9));
51    /// assert_eq!( topset.pop(), None);
52    /// ```
53    pub fn with_init<I: IntoIterator<Item=X>>(n: usize, beat: C, init: I) -> Self
54    {
55        let mut top = Self::new(n, beat);
56        top.extend(init);
57        top
58    }
59
60    /// Check if the top set is empty
61    /// # Example
62    /// ```
63    /// # use topset::TopSet;
64    /// let mut topset = TopSet::new(2, u32::gt);
65    /// assert!( topset.is_empty() );
66    /// topset.extend( vec![7,5,6,9,4,2,3] );
67    /// assert!( ! topset.is_empty() );
68    /// ```
69    #[inline]
70    pub fn is_empty(&self) -> bool { self.heap.is_empty() }
71
72    /// Get the number of stored items.
73    ///
74    /// It never exceeds the predefined capacity
75    /// (the capacity does not grow by itself, only by calling [`Self::resize`]).
76    ///
77    /// # Example
78    /// ```
79    /// # use topset::TopSet;
80    /// let mut topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
81    /// assert_eq!( topset.len(), 2 );
82    /// topset.pop();
83    /// assert_eq!( topset.len(), 1 );
84    /// ```
85    #[inline]
86    pub fn len(&self) -> usize { self.heap.len() }
87
88    /// Get the capacity of this top set
89    ///
90    /// The capacity limits the number of elements to keep.
91    /// This capacity could only change by calling [`resize`].
92    ///
93    /// # Example
94    /// ```
95    /// # use topset::TopSet;
96    /// let mut topset = TopSet::new(4, u32::gt);
97    /// assert_eq!( topset.capacity(), 4 );
98    /// assert_eq!( topset.len(), 0 );
99    /// ```
100    #[inline]
101    pub fn capacity(&self) -> usize { self.count }
102
103    /// Read access to the lowest item of the top set
104    ///
105    /// Notice that it actually returned the _lowest_ one and
106    /// so all the others are better (or equal) this one.
107    ///
108    /// To access to this _lowest_ element and removing it,
109    /// consider [`Self::pop`].
110    ///
111    /// # Example
112    /// ```
113    /// # use topset::TopSet;
114    /// let mut topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
115    /// assert_eq!( topset.peek(), Some(&7) );
116    /// assert_eq!( topset.pop(), Some(7) );
117    /// assert_eq!( topset.peek(), Some(&9) );
118    /// ```
119    #[inline]
120    pub fn peek(&self) -> Option<&X>
121    {
122        self.heap.first()
123    }
124
125    /// Checks if an item will be inserted or not
126    ///
127    /// If it `true` is returned, it means that a call to [`Self::insert`]
128    /// will actually insert the candidate. If `false`, then the insertion
129    /// will be a non-op.
130    ///
131    /// Note that in any case the insertion is not done. See [`Self::insert`] to
132    /// perform the test and the insertion in one time.
133    ///
134    /// # Example
135    /// ```
136    /// # use topset::TopSet;
137    /// // this topset contains { 7, 9 }
138    /// let topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
139    /// assert!( topset.is_candidate(&10) );
140    /// assert!( topset.is_candidate(&8) );
141    /// assert!( ! topset.is_candidate(&7) );
142    /// assert!( ! topset.is_candidate(&6) );
143    /// ```
144    #[inline]
145    pub fn is_candidate(&self, x: &X) -> bool {
146        self.heap.len() < self.count || self.beat(x, self.peek().unwrap())
147    }
148
149    /// Iterate over all the top selected items.
150    ///
151    /// The iterator is **not** sorted. A sorted iteration
152    /// could be obtained by iterative call to [`Self::pop`]
153    /// or by using [`Self::into_iter_sorted`].
154    ///
155    /// To get a vector with all elements, instead of using this
156    /// iterator, consider [`Self::into_vec`].
157    ///
158    /// # Example
159    /// ```
160    /// # use topset::TopSet;
161    /// // this topset contains { 7, 9 }
162    /// let topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
163    /// let elts = topset.iter().cloned().collect::<Vec<_>>();
164    /// ```
165    #[inline]
166    pub fn iter(&self) -> impl Iterator<Item=&X>
167    {
168        self.heap.iter()
169    }
170
171    /// Gets all the top set elements in a vector.
172    ///
173    /// This vector is **not** sorted.
174    /// See [`Self::into_sorted_vec`] if a sorted result is expected.
175    ///
176    /// # Example
177    /// ```
178    /// # use topset::TopSet;
179    /// // this topset contains { 7, 9 }
180    /// let topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
181    /// let elts = topset.into_vec();
182    /// ```
183    #[inline]
184    pub fn into_vec(self) -> Vec<X> { self.heap }
185
186    /// Insert a new item.
187    ///
188    /// If the top set is not filled (i.e. its length is less than its capacity),
189    /// the item is simply added and `None` is returned.
190    ///
191    /// If there is no more room, then one item should be rejected:
192    /// * if the new item is better than some already stored ones, it is added
193    /// and the removed item is returned
194    /// * if the new item is worse than all the stored ones, it is returned
195    ///
196    /// # Example
197    /// ```
198    /// # use topset::TopSet;
199    /// let mut topset = TopSet::new(2, u32::gt);
200    /// assert_eq!( topset.insert(7), None);
201    /// assert_eq!( topset.insert(8), None);
202    /// assert_eq!( topset.insert(9), Some(7));
203    /// assert_eq!( topset.insert(6), Some(6));
204    /// ```
205    pub fn insert(&mut self, mut x: X) -> Option<X>
206    {
207        if self.heap.len() < self.count {
208            // some room left, so nothing to remove
209            self.heap.push(x);
210            self.percolate_up(self.heap.len()-1);
211            None
212        } else {
213            // SAFETY: if the heap is empty when self.count != 0, then we fall
214            // in the previous if condition (so, here, get_unchecked is safe)
215            if self.count != 0 && self.beat(&x, unsafe { self.heap.get_unchecked(0) }) {
216                // put the greatest the deepest: the new one should be kept
217                mem::swap(&mut x, &mut self.heap[0]);
218                self.percolate_down(0);
219            }
220            Some(x)
221        }
222    }
223
224    /// Converts this topset into a sorted iterator
225    ///
226    /// Notice that the _lowest_ item of the top set is the
227    /// first one. The _greatest_ item is the last one.
228    ///
229    /// # Example
230    /// ```
231    /// # use topset::TopSet;
232    /// // this topset contains { 7, 9 }
233    /// let topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
234    /// let mut iter = topset.into_iter_sorted();
235    /// assert_eq!( iter.next(), Some(7));
236    /// assert_eq!( iter.next(), Some(9));
237    /// assert_eq!( iter.next(), None);
238    /// ```
239    #[inline]
240    pub fn into_iter_sorted(self) -> crate::iter::IntoIterSorted<X,C> {
241        self.into()
242    }
243
244    /// Returns the topset in a sorted vector.
245    ///
246    /// The first element of the vector is the _lowest_ item of the top set
247    /// and the last one is the _greatest_ one.
248    ///
249    /// # Example
250    /// ```
251    /// # use topset::TopSet;
252    /// // this topset contains { 7, 9 }
253    /// let topset = TopSet::with_init(3, u32::gt, vec![1,2,7,4,7,5,6,9,4,2,3] );
254    /// assert_eq!( topset.into_sorted_vec(), vec![7,7,9]);
255    /// ```
256    pub fn into_sorted_vec(mut self) -> Vec<X>
257        where X:PartialEq
258    {
259        self.heap.sort_unstable_by(|a,b| {
260            if *a == *b {
261                Ordering::Equal
262            } else if (self.beat)(a,b) {
263                Ordering::Greater
264            } else {
265                Ordering::Less
266            }
267        });
268        self.heap
269    }
270
271    /// Clears the binary heap, returning an iterator over the removed elements in arbitrary order.
272    /// If the iterator is dropped before being fully consumed, it drops the remaining elements in arbitrary order.
273    ///
274    /// The returned iterator keeps a mutable borrow on the heap to optimize its implementation.
275    ///
276    /// # Example
277    /// ```
278    /// # use topset::TopSet;
279    /// let mut topset = TopSet::with_init(4, u32::gt, vec![7,5,6,9,4,2,3] );
280    /// let _ = topset.drain();
281    /// assert! (topset.is_empty());
282    /// ```
283    #[inline]
284    pub fn drain(&mut self) -> std::vec::Drain<X> {
285        self.heap.drain(..)
286    }
287
288    /// Resize the top set
289    ///
290    /// If the size decreases, then the lowest items are removed.
291    /// If the size increases, nothing else happens but there is still more room
292    /// for next insertions.
293    ///
294    /// # Example
295    /// ```
296    /// # use topset::TopSet;
297    /// let mut topset = TopSet::with_init(4, u32::gt, vec![7,5,6,9,4,2,3] );
298    ///
299    /// // the topset contains { 7, 5, 6, 9 }
300    /// assert_eq! (topset.peek(), Some(&5));
301    ///
302    /// topset.resize(2);
303    /// // the topset contains { 7, 9 }
304    /// assert_eq! (topset.peek(), Some(&7));
305    ///
306    /// // try to add 1 but no more room left
307    /// assert_eq!( topset.insert(1), Some(1) );
308    ///
309    /// topset.resize(3); // grows by one
310    /// assert_eq!( topset.insert(1), None ); // one room left
311    /// assert_eq!( topset.insert(2), Some(1) ); // but now, is full
312    /// // at this point, the topset contains { 7, 9, 2 }
313    /// ```
314    pub fn resize(&mut self, n: usize)
315    {
316        if self.count < n {
317            self.heap.reserve(n - self.count);
318        } else {
319            while self.heap.len() > n {
320                self.pop();
321            }
322        }
323        self.count = n;
324    }
325
326    /// Pop the lowest item of the top set
327    ///
328    /// Remove and return the _lowest_ item of the top set.
329    /// After this call, there is one more room for a item.
330    ///
331    /// This method is the only way to get the top elements
332    /// in a sorted way (from the lowest to the best).
333    /// Resize the top set
334    ///
335    /// If the size decreases, then the lowest items are removed.
336    /// If the size increases, nothing else happens but there is still more room
337    /// for next insertions.
338    ///
339    /// # Example
340    /// ```
341    /// # use topset::TopSet;
342    /// let mut topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
343    ///
344    /// assert_eq! (topset.pop(), Some(7));
345    /// assert_eq! (topset.pop(), Some(9));
346    /// assert_eq! (topset.pop(), None);
347    /// ```
348    pub fn pop(&mut self) -> Option<X>
349    {
350        match self.heap.len() {
351            0 => None,
352            1|2 => Some(self.heap.swap_remove(0)),
353            _ => {
354                let pop = self.heap.swap_remove(0);
355                self.percolate_down(0);
356                Some(pop)
357            }
358        }
359    }
360
361    /// Removes all the elements in the top set
362    /// # Example
363    /// ```
364    /// # use topset::TopSet;
365    /// let mut topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
366    ///
367    /// assert_eq! (topset.len(), 2);
368    /// topset.clear();
369    /// assert_eq!( topset.len(), 0)
370    /// ```
371    #[inline] pub fn clear(&mut self) { self.heap.clear() }
372
373    /// Checks if an element beats the other.
374    ///
375    /// It does not related to the current elements in the topset but
376    /// refers only to the comparing function (the _beat_).
377    ///
378    /// # Example
379    /// ```
380    /// # use topset::TopSet;
381    /// let mut topset = TopSet::with_init(2, u32::gt, vec![7,5,6,9,4,2,3] );
382    ///
383    /// assert! ( topset.beat(&4, &3));
384    /// assert! ( ! topset.beat(&4, &7));
385    /// ```
386    #[inline] pub fn beat(&self, a:&X, b:&X) -> bool { (self.beat)(a,b) }
387
388    // internal stuff
389    // move i up (to the best)
390    fn percolate_up(&mut self, mut i: usize)
391    {
392        while i > 0 { // so has a parent (not root)
393            let parent = (i-1)/2;
394            // put the greatest the deepest
395            if self.beat(&self.heap[parent], &self.heap[i]) {
396                self.heap.swap(parent, i);
397                i = parent;
398            } else {
399                break;
400            }
401        }
402    }
403
404    // internal stuff
405    // move i as deep as possible
406    fn percolate_down(&mut self, mut i: usize)
407    {
408        loop {
409            let mut child = 2*i+1;
410            if child < self.heap.len()-1 {
411                // to put the greatest the deepest -> select the greatest child
412                if self.beat(&self.heap[child], &self.heap[child+1]) {
413                    child += 1;
414                }
415                // put the greatest the deepest
416                if self.beat(&self.heap[i], &self.heap[child]) {
417                    self.heap.swap(i, child);
418                    i = child;
419                } else {
420                    break;
421                }
422            } else {
423                if (child == self.heap.len() - 1) && self.beat(&self.heap[i], &self.heap[child]) {
424                    // only one child
425                    self.heap.swap(i, child);
426                }
427                // end of heap
428                break;
429            }
430        }
431    }
432}
433
434
435impl<X,C> IntoIterator for TopSet<X,C>
436    where C: Fn(&X,&X) -> bool
437{
438    type Item = X;
439    type IntoIter = <Vec<X> as IntoIterator>::IntoIter;
440
441    #[inline]
442    fn into_iter(self) -> Self::IntoIter {
443        self.heap.into_iter()
444    }
445}
446
447impl<'a,X,C> IntoIterator for &'a TopSet<X,C>
448    where C: Fn(&X,&X) -> bool
449{
450    type Item = &'a X;
451    type IntoIter = <&'a Vec<X> as IntoIterator>::IntoIter;
452
453    #[inline]
454    fn into_iter(self) -> Self::IntoIter {
455        self.heap.iter()
456    }
457}
458
459impl<X,C> Extend<X> for TopSet<X,C>
460    where C: Fn(&X,&X) -> bool
461{
462    #[inline]
463    fn extend<T: IntoIterator<Item=X>>(&mut self, iter: T) {
464        iter.into_iter().for_each(|x| { self.insert(x); } )
465    }
466}
467
468
469impl<X,C> Debug for TopSet<X,C>
470    where X:Debug, C: Fn(&X,&X) -> bool
471{
472    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
473        self.heap.fmt(f)
474    }
475}
476
477
478
479#[cfg(test)]
480mod tests {
481    use crate::iter::TopSetReducing;
482    use crate::TopSet;
483
484    #[test]
485    fn lowest_cost()
486    {
487        let mut top = TopSet::<f32,_>::new(5, f32::lt);
488        top.extend(vec![81.5, 4.5, 4., 1., 45., 22., 11.]);
489        top.extend(vec![81.5, 4.5, 4., 1., 45., 22., 11.]);
490
491        assert_eq![ top.pop(), Some(4.5) ];
492        assert_eq![ top.pop(), Some(4.) ];
493        assert_eq![ top.pop(), Some(4.) ];
494        assert_eq![ top.pop(), Some(1.) ];
495        assert_eq![ top.pop(), Some(1.) ];
496        assert_eq![ top.pop(), None ];
497    }
498
499    #[test]
500    fn greatest_score()
501    {
502        assert_eq![
503            vec![81,5, 4,5,4,1,45,22,1,5,97,5,877,12,0]
504                .topset(5, u32::gt)
505                .into_iter()
506                .last(),
507            Some(877)];
508    }
509}