use std::hash::Hash;
use rustc_hash::FxHashSet;
use std::collections::BTreeSet;
use std::collections::hash_set::{ Iter, IntoIter };
use std::iter::FromIterator;
use num::traits::Unsigned;
use num::Num;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MexSet<T: Ord + Hash + Copy + Unsigned + Num> {
set: FxHashSet<T>,
complement: BTreeSet<T>,
mex_upper_bound: T,
}
impl<T: Ord + Hash + Copy + Unsigned + Num> MexSet<T> {
#[inline]
pub fn new() -> Self {
let mut compl: BTreeSet<T> = BTreeSet::new();
compl.insert(T::zero());
MexSet {
set: FxHashSet::default(),
complement: compl,
mex_upper_bound: T::zero(),
}
}
#[inline]
pub fn len(&self) -> usize {
self.set.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.mex_upper_bound.is_zero()
}
#[inline]
pub fn clear(&mut self) {
*self = MexSet::new();
}
#[inline]
pub fn insert(&mut self, item: T) -> bool {
if self.set.insert(item) {
self.complement.remove(&item);
self.mex_upper_bound = self.mex_upper_bound + T::one();
if !self.set.contains(&self.mex_upper_bound) {
self.complement.insert(self.mex_upper_bound);
}
return true;
}
false
}
#[inline]
pub fn minimum_excluded(&self) -> T {
*self.complement.iter().next().unwrap()
}
#[inline]
pub fn contains(&self, value: &T) -> bool {
self.set.contains(value)
}
#[inline]
pub fn remove(&mut self, value: &T) -> bool {
if self.set.remove(value) {
if *value < self.mex_upper_bound {
self.complement.insert(*value);
self.mex_upper_bound = self.mex_upper_bound - T::one();
}
return true;
}
false
}
#[inline]
pub fn iter(&self) -> Iter<'_, T> {
self.set.iter()
}
pub fn with_range(n: T) -> Self {
let mut elements = FxHashSet::default();
let mut x = T::zero();
while x < n {
elements.insert(x);
x = x + T::one();
}
MexSet {
set: elements,
complement: BTreeSet::from_iter(vec![n].into_iter()),
mex_upper_bound: n,
}
}
}
impl<T: Ord + Hash + Copy + Unsigned + Num> IntoIterator for MexSet<T> {
type Item = T;
type IntoIter = IntoIter<T>;
#[inline]
fn into_iter(self) -> IntoIter<T> {
self.set.into_iter()
}
}
impl<T: Ord + Hash + Copy + Unsigned + Num> Extend<T> for MexSet<T> {
fn extend<I: IntoIterator<Item=T>>(&mut self, iter: I) {
iter.into_iter().for_each(move |elem| {
self.insert(elem);
});
}
}
impl<T: Ord + Hash + Copy + Unsigned + Num> FromIterator<T> for MexSet<T> {
#[inline]
fn from_iter<I: IntoIterator<Item=T>>(iter: I) -> Self {
let mut mexset = MexSet::new();
mexset.extend(iter);
mexset
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashSet;
#[test]
fn basics() {
let mut mex = MexSet::<u32>::new();
assert_eq!(mex.minimum_excluded(), 0);
assert_eq!(mex.len(), 0);
assert!(mex.insert(1));
assert_eq!(mex.minimum_excluded(), 0);
assert_eq!(mex.len(), 1);
assert!(mex.insert(2));
assert_eq!(mex.minimum_excluded(), 0);
assert_eq!(mex.len(), 2);
assert!(mex.insert(0));
assert_eq!(mex.minimum_excluded(), 3);
assert_eq!(mex.len(), 3);
assert!(mex.insert(4));
assert_eq!(mex.minimum_excluded(), 3);
assert_eq!(mex.len(), 4);
assert!(mex.insert(7));
assert_eq!(mex.minimum_excluded(), 3);
assert_eq!(mex.len(), 5);
assert!(mex.insert(3));
assert_eq!(mex.minimum_excluded(), 5);
assert_eq!(mex.len(), 6);
assert!(!mex.insert(4));
assert_eq!(mex.minimum_excluded(), 5);
assert_eq!(mex.len(), 6);
assert!(!mex.insert(4));
assert_eq!(mex.minimum_excluded(), 5);
assert_eq!(mex.len(), 6);
assert!(mex.insert(40));
assert_eq!(mex.minimum_excluded(), 5);
assert_eq!(mex.len(), 7);
assert!(mex.contains(&2));
assert!(mex.contains(&0));
assert!(mex.contains(&7));
assert!(!mex.contains(&15));
mex.clear();
assert_eq!(mex.minimum_excluded(), 0);
assert!(!mex.contains(&2));
assert!(!mex.contains(&0));
}
#[test]
fn test_extend_and_remove() {
let mut mex: MexSet<u32> = MexSet::new();
mex.extend(vec![5, 5, 5, 2, 4, 7, 2, 3, 4, 5, 5, 5, 6, 7].into_iter());
assert_eq!(mex.len(), 6);
assert_eq!(mex.minimum_excluded(), 0);
mex.extend(vec![0, 0, 1].into_iter());
assert_eq!(mex.len(), 8);
assert_eq!(mex.minimum_excluded(), 8);
mex.extend(vec![9, 8, 9]);
assert_eq!(mex.len(), 10);
assert_eq!(mex.minimum_excluded(), 10);
assert!(mex.remove(&5));
assert_eq!(mex.len(), 9);
assert_eq!(mex.minimum_excluded(), 5);
assert!(!mex.remove(&5));
assert_eq!(mex.len(), 9);
assert_eq!(mex.minimum_excluded(), 5);
assert!(mex.remove(&4));
assert_eq!(mex.len(), 8);
assert_eq!(mex.minimum_excluded(), 4);
assert!(mex.remove(&2));
assert_eq!(mex.len(), 7);
assert_eq!(mex.minimum_excluded(), 2);
mex.extend(vec![5, 4, 4, 2, 5].into_iter());
assert_eq!(mex.len(), 10);
assert_eq!(mex.minimum_excluded(), 10);
assert!(!mex.remove(&10));
assert_eq!(mex.len(), 10);
assert_eq!(mex.minimum_excluded(), 10);
assert!(!mex.remove(&30));
assert_eq!(mex.len(), 10);
assert_eq!(mex.minimum_excluded(), 10);
assert!(mex.remove(&7));
assert_eq!(mex.len(), 9);
assert_eq!(mex.minimum_excluded(), 7);
assert!(mex.remove(&9));
assert_eq!(mex.len(), 8);
assert_eq!(mex.minimum_excluded(), 7);
assert!(mex.remove(&8));
assert_eq!(mex.len(), 7);
assert_eq!(mex.minimum_excluded(), 7);
assert!(mex.remove(&6));
assert_eq!(mex.len(), 6);
assert_eq!(mex.minimum_excluded(), 6);
assert!(mex.remove(&0));
assert_eq!(mex.len(), 5);
assert_eq!(mex.minimum_excluded(), 0);
}
#[test]
fn test_iterators() {
let mex: MexSet<u32> = MexSet::from_iter(
vec![5, 1, 4, 2, 3].into_iter()
);
assert_eq!(mex.len(), 5);
assert_eq!(
mex.into_iter().collect::<HashSet<u32>>(),
HashSet::from_iter(vec![5, 1, 4, 2, 3].into_iter()),
);
let mex: MexSet<u32> = vec![5, 1, 4, 2, 3].into_iter().collect();
assert_eq!(mex.len(), 5);
assert_eq!(
mex.into_iter().collect::<HashSet<u32>>(),
HashSet::from_iter(vec![5, 1, 4, 2, 3].into_iter()),
);
let mex: MexSet<u32> = MexSet::from_iter(
vec![5, 1, 4, 2, 3].into_iter()
);
println!("{:?}", mex);
assert_eq!(
mex.iter().collect::<HashSet<&u32>>(),
vec![&1, &2, &3, &4, &5].into_iter().collect::<HashSet<&u32>>(),
);
assert_eq!(
mex.into_iter().collect::<HashSet<u32>>(),
vec![1, 2, 3, 4, 5].into_iter().collect::<HashSet<u32>>(),
);
}
#[test]
fn test_clone_eq() {
let mex: MexSet<u32> = MexSet::from_iter(
vec![5, 1, 4, 2, 3].into_iter()
);
let mut cmex = mex.clone();
assert_eq!(mex, cmex);
cmex.remove(&2);
assert_ne!(mex, cmex);
}
#[test]
fn test_with_range() {
let mex: MexSet<u32> = MexSet::from_iter(
vec![5, 1, 4, 2, 0, 3].into_iter()
);
assert_eq!(
MexSet::with_range(6u32),
mex,
)
}
}