#![deny(clippy::cargo)]
use std::cmp::Reverse;
use std::collections::BinaryHeap;
#[derive(Debug, Clone)]
pub struct Shortlist<T> {
heap: BinaryHeap<Reverse<T>>,
}
impl<T: Ord> Shortlist<T> {
pub fn new(capacity: usize) -> Shortlist<T> {
assert!(capacity > 0, "Cannot create a Shortlist with capacity 0.");
Shortlist {
heap: BinaryHeap::with_capacity(capacity),
}
}
pub fn from_slice(capacity: usize, contents: &[T]) -> Shortlist<T>
where
T: Clone,
{
let mut shortlist = Shortlist::new(capacity);
shortlist.append_slice(contents);
shortlist
}
pub fn from_iter(capacity: usize, contents: impl IntoIterator<Item = T>) -> Shortlist<T> {
let mut shortlist = Shortlist::new(capacity);
shortlist.append(contents);
shortlist
}
pub fn push(&mut self, item: T) {
if self.heap.len() < self.heap.capacity() {
self.heap.push(Reverse(item));
} else {
if let Some(current_min) = self.heap.peek() {
if item <= current_min.0 {
return;
}
}
let popped = self.heap.pop();
debug_assert!(popped.is_some());
self.heap.push(Reverse(item));
}
}
pub fn clone_push(&mut self, item: &T)
where
T: Clone,
{
if self.heap.len() < self.heap.capacity() {
self.heap.push(Reverse(item.clone()));
} else {
if let Some(current_min) = self.heap.peek() {
if item <= ¤t_min.0 {
return;
}
}
let popped = self.heap.pop();
debug_assert!(popped.is_some());
self.heap.push(Reverse(item.clone()));
}
}
pub fn peek_min(&self) -> Option<&T> {
self.heap.peek().map(|x| &x.0)
}
#[inline]
pub fn append(&mut self, contents: impl IntoIterator<Item = T>) {
for i in contents {
self.push(i);
}
}
#[inline]
pub fn append_slice(&mut self, contents: &[T])
where
T: Clone,
{
for i in contents {
self.clone_push(i);
}
}
pub fn into_sorted_vec(self) -> Vec<T> {
let mut vec: Vec<T> = self
.heap
.into_vec()
.into_iter()
.map(|Reverse(v)| v)
.collect();
vec.sort();
vec
}
pub fn sorted_cloned_vec(&self) -> Vec<T>
where
T: Clone,
{
let mut vec: Vec<T> = self.heap.iter().map(|Reverse(v)| v.clone()).collect();
vec.sort();
vec
}
}
impl<T> Shortlist<T> {
#[inline]
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a T> + 'a {
self.heap.iter().map(|x| &x.0)
}
#[inline]
pub fn capacity(&self) -> usize {
self.heap.capacity()
}
pub fn into_vec(self) -> Vec<T> {
self.heap
.into_vec()
.into_iter()
.map(|Reverse(v)| v)
.collect()
}
#[inline]
pub fn len(&self) -> usize {
self.heap.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.heap.is_empty()
}
#[inline]
pub fn drain<'a>(&'a mut self) -> impl Iterator<Item = T> + 'a {
self.heap.drain().map(|Reverse(x)| x)
}
#[inline]
pub fn clear(&mut self) {
self.heap.clear();
}
}
#[cfg(test)]
mod tests {
use super::Shortlist;
use rand::prelude::*;
fn check_sorted_vecs<T: Ord + Eq + std::fmt::Debug>(
sorted_input_values: Vec<T>,
shortlist_vec: Vec<T>,
capacity: usize,
) {
let mut debug_lines = Vec::with_capacity(1000);
debug_lines.push("".to_string());
debug_lines.push(format!("Input length : {}", sorted_input_values.len()));
debug_lines.push(format!("Shortlist capacity: {}", capacity));
debug_lines.push(format!("Shortlist length : {}", shortlist_vec.len()));
if shortlist_vec.len() != capacity.min(sorted_input_values.len()) {
debug_lines.push(format!("Input values: {:?}", sorted_input_values));
debug_lines.push(format!("Shortlisted values: {:?}", shortlist_vec));
for line in debug_lines {
println!("{}", line);
}
panic!();
}
for (val, exp_val) in shortlist_vec
.iter()
.rev()
.zip(sorted_input_values.iter().rev())
{
if val == exp_val {
debug_lines.push(format!("{:?} == {:?}", val, exp_val));
} else {
debug_lines.push(format!("{:?} != {:?}", val, exp_val));
for line in debug_lines {
println!("{}", line);
}
panic!();
}
}
}
fn gen_sample_input(rng: &mut impl Rng) -> (usize, Vec<usize>) {
let capacity = rng.gen_range(1, 100);
let mut input_values: Vec<usize> = Vec::new();
for _ in 0..rng.gen_range(1, 1000) {
let val = rng.gen_range(0, 1000);
input_values.push(val);
}
(capacity, input_values)
}
fn generate_input_and_shortlist(rng: &mut impl Rng) -> (Vec<usize>, Shortlist<usize>) {
let (capacity, mut input_values) = gen_sample_input(rng);
let shortlist: Shortlist<usize> = Shortlist::from_slice(capacity, &input_values);
input_values.sort();
(input_values, shortlist)
}
fn check_correctness(check: impl Fn(Vec<usize>, Shortlist<usize>) -> ()) {
let mut rng = thread_rng();
for _ in 1..10_000 {
let (input_values, shortlist) = generate_input_and_shortlist(&mut rng);
check(input_values, shortlist);
}
}
#[test]
fn iter() {
check_correctness(|values, shortlist| {
let capacity = shortlist.capacity();
let mut shortlist_vec: Vec<usize> = shortlist.iter().copied().collect();
shortlist_vec.sort();
check_sorted_vecs(values, shortlist_vec, capacity);
});
}
#[test]
fn into_sorted_vec() {
check_correctness(|values, shortlist| {
let capacity = shortlist.capacity();
let shortlist_vec = shortlist.into_sorted_vec();
check_sorted_vecs(values, shortlist_vec, capacity);
});
}
#[test]
fn sorted_cloned_vec() {
check_correctness(|values, shortlist| {
let capacity = shortlist.capacity();
let shortlist_vec = shortlist.sorted_cloned_vec();
check_sorted_vecs(values, shortlist_vec, capacity);
});
}
#[test]
fn into_vec() {
check_correctness(|values, shortlist| {
let capacity = shortlist.capacity();
let mut shortlist_vec = shortlist.into_vec();
shortlist_vec.sort();
check_sorted_vecs(values, shortlist_vec, capacity);
});
}
#[test]
fn drain() {
check_correctness(|values, mut shortlist| {
let capacity = shortlist.capacity();
let mut shortlist_vec: Vec<usize> = shortlist.drain().collect();
assert!(shortlist.is_empty());
shortlist_vec.sort();
check_sorted_vecs(values, shortlist_vec, capacity);
});
}
#[test]
fn clear() {
check_correctness(|_values, mut shortlist| {
shortlist.clear();
assert!(shortlist.is_empty());
});
}
#[test]
fn append() {
let mut rng = thread_rng();
for _ in 1..10_000 {
let (capacity, mut input_values) = gen_sample_input(&mut rng);
let shortlist: Shortlist<usize> =
Shortlist::from_iter(capacity, input_values.iter().copied());
input_values.sort();
let mut shortlist_vec = shortlist.into_vec();
shortlist_vec.sort();
check_sorted_vecs(input_values, shortlist_vec, capacity);
}
}
#[test]
fn capacity_and_len() {
let mut rng = thread_rng();
for _ in 1..10_000 {
let (capacity, mut input_values) = gen_sample_input(&mut rng);
let mut shortlist: Shortlist<usize> = Shortlist::new(capacity);
for (i, val) in input_values.iter().copied().enumerate() {
assert_eq!(shortlist.len(), i.min(capacity));
assert_eq!(shortlist.capacity(), capacity);
shortlist.push(val);
assert!(!shortlist.is_empty());
}
input_values.sort();
let mut shortlist_vec = shortlist.into_vec();
shortlist_vec.sort();
check_sorted_vecs(input_values, shortlist_vec, capacity);
}
}
}