#[derive(Clone, Debug)]
pub struct FixedHammingHeap<T> {
cap: usize,
size: usize,
worst: u32,
distances: Vec<Vec<T>>,
}
impl<T> FixedHammingHeap<T> {
pub fn new() -> Self {
Self::default()
}
pub fn new_distances(distances: usize) -> Self {
let mut s = Self::new();
s.set_distances(distances);
s
}
pub fn set_capacity(&mut self, cap: usize) {
assert_ne!(cap, 0);
self.set_len(cap);
self.cap = cap;
self.worst = self.distances.len() as u32 - 1;
if self.size == self.cap {
self.update_worst();
}
}
pub fn set_len(&mut self, len: usize) {
if len == 0 {
let end = self.end();
for v in &mut self.distances[..=end] {
v.clear();
}
self.size = 0;
self.worst = self.distances.len() as u32 - 1;
} else if len < self.size {
let end = self.end();
let mut remaining = self.size - len;
for vec in &mut self.distances[..=end] {
if vec.len() >= remaining {
vec.drain(vec.len() - remaining..);
break;
} else {
remaining -= vec.len();
vec.clear();
}
}
self.worst = self.distances.len() as u32 - 1;
self.size = len;
}
}
pub fn len(&self) -> usize {
self.size
}
pub fn is_empty(&self) -> bool {
self.size == 0
}
pub fn clear(&mut self) {
assert_ne!(
self.distances.len(),
0,
"you must call set_distances() before calling clear()"
);
let end = self.end();
for v in self.distances[..=end].iter_mut() {
v.clear();
}
self.size = 0;
self.worst = self.distances.len() as u32 - 1;
}
pub fn set_distances(&mut self, distances: usize) {
self.distances.clear();
self.distances.resize_with(distances, || vec![]);
self.worst = self.distances.len() as u32 - 1;
self.size = 0;
}
pub fn push(&mut self, distance: u32, item: T) -> bool {
if self.size != self.cap {
self.distances[distance as usize].push(item);
self.size += 1;
if self.size == self.cap {
self.update_worst();
}
true
} else {
unsafe { self.push_at_cap(distance, item) }
}
}
pub fn fill_slice<'a>(&self, s: &'a mut [T]) -> &'a mut [T]
where
T: Clone,
{
let total_fill = std::cmp::min(s.len(), self.size);
for (ix, f) in self.distances[..=self.end()]
.iter()
.flat_map(|v| v.iter())
.take(total_fill)
.enumerate()
{
s[ix] = f.clone();
}
&mut s[0..total_fill]
}
pub fn worst(&self) -> u32 {
self.worst
}
pub fn at_cap(&self) -> bool {
self.size == self.cap
}
pub fn iter(&mut self) -> impl Iterator<Item = (u32, &T)> {
self.distances[..=self.end()]
.iter()
.enumerate()
.flat_map(|(distance, v)| v.iter().map(move |item| (distance as u32, item)))
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (u32, &mut T)> {
let end = self.end();
self.distances[..=end]
.iter_mut()
.enumerate()
.flat_map(|(distance, v)| v.iter_mut().map(move |item| (distance as u32, item)))
}
pub unsafe fn push_at_cap(&mut self, distance: u32, item: T) -> bool {
if distance < self.worst {
self.distances[distance as usize].push(item);
self.remove_worst();
true
} else {
false
}
}
fn end(&self) -> usize {
if self.at_cap() {
self.worst as usize
} else {
self.distances.len() - 1
}
}
fn update_worst(&mut self) {
self.worst = self.distances[0..=self.worst as usize]
.iter()
.rev()
.position(|v| !v.is_empty())
.map(|n| self.worst - n as u32)
.unwrap_or(self.distances.len() as u32 - 1);
}
fn remove_worst(&mut self) {
self.distances[self.worst as usize].pop();
self.update_worst();
}
}
impl<T> Default for FixedHammingHeap<T> {
fn default() -> Self {
Self {
cap: 0,
size: 0,
worst: 0,
distances: vec![],
}
}
}
#[cfg(test)]
#[test]
fn test_fixed_heap() {
let mut candidates: FixedHammingHeap<u32> = FixedHammingHeap::new();
candidates.set_distances(11);
candidates.set_capacity(3);
assert!(candidates.push(5, 0));
assert!(candidates.push(4, 1));
assert!(candidates.push(3, 2));
assert!(!candidates.push(6, 3));
assert!(!candidates.push(7, 4));
assert!(candidates.push(2, 5));
assert!(candidates.push(3, 6));
assert!(!candidates.push(10, 7));
assert!(!candidates.push(6, 8));
assert!(!candidates.push(4, 9));
assert!(candidates.push(1, 10));
assert!(candidates.push(2, 11));
let mut arr = [0; 3];
candidates.fill_slice(&mut arr);
arr[1..3].sort_unstable();
assert_eq!(arr, [10, 5, 11]);
}