use rand::{prelude::ThreadRng, Rng};
use std::{collections::HashMap, hash::Hash, slice::Iter};
#[derive(Default, Debug)]
pub struct SampleHashMap<K: Hash + Eq, V> {
items: Vec<(K, V)>,
index: HashMap<K, usize>,
}
impl<K: Hash + Eq + Clone, V> SampleHashMap<K, V> {
pub fn get(&self, k: &K) -> Option<&V> {
let pos = self.index.get(k)?;
Some(&self.items[*pos].1)
}
pub fn get_mut(&mut self, k: &K) -> Option<&mut V> {
let pos = self.index.get(k)?;
Some(&mut self.items[*pos].1)
}
pub fn get_mut_or_insert_with<F: FnOnce() -> V>(
&mut self, k: K, default: F,
) -> &mut V {
let pos = match self.index.get(&k) {
Some(pos) => *pos,
None => {
self.index.insert(k.clone(), self.items.len());
self.items.push((k, default()));
self.items.len() - 1
}
};
&mut self.items[pos].1
}
pub fn remove(&mut self, k: &K) -> Option<V> {
let index = self.index.remove(k)?;
let (_, removed) = self.items.swap_remove(index);
if let Some((swapped, _)) = self.items.get(index) {
self.index.insert(swapped.clone(), index);
}
Some(removed)
}
pub fn sample(&self, rng: &mut ThreadRng) -> Option<&V> {
if self.items.is_empty() {
return None;
}
let index = rng.gen_range(0, self.items.len());
Some(&self.items[index].1)
}
pub fn is_empty(&self) -> bool { self.items.is_empty() }
}
#[derive(Default, Debug)]
pub struct SampleHashSet<T: Hash + Eq> {
items: Vec<T>,
index: HashMap<T, usize>,
}
impl<T: Hash + Eq + Clone> SampleHashSet<T> {
pub fn insert(&mut self, value: T) -> bool {
if self.index.contains_key(&value) {
return false;
}
self.index.insert(value.clone(), self.items.len());
self.items.push(value);
true
}
pub fn remove(&mut self, value: &T) -> bool {
let index = match self.index.remove(value) {
Some(pos) => pos,
None => return false,
};
self.items.swap_remove(index);
if let Some(swapped) = self.items.get(index) {
self.index.insert(swapped.clone(), index);
}
true
}
pub fn sample(&self, rng: &mut ThreadRng) -> Option<T> {
if self.items.is_empty() {
return None;
}
let index = rng.gen_range(0, self.items.len());
Some(self.items[index].clone())
}
#[inline]
pub fn is_empty(&self) -> bool { self.items.is_empty() }
#[inline]
pub fn len(&self) -> usize { self.items.len() }
#[inline]
pub fn iter(&self) -> Iter<T> { self.items.iter() }
}