use rustc_hash::FxHashMap;
use std::{collections::BTreeSet, fmt::Debug, hash::Hash};
pub struct MultiSet<T> {
pub counter: FxHashMap<T, usize>,
pub items: BTreeSet<(T, usize)>,
}
impl<T> Default for MultiSet<T>
where
T: Ord + Hash + Copy,
{
fn default() -> Self {
Self::new()
}
}
impl<T> MultiSet<T>
where
T: Ord + Hash + Copy,
{
pub fn new() -> Self {
MultiSet {
counter: FxHashMap::default(),
items: BTreeSet::new(),
}
}
pub fn insert(&mut self, x: T) {
let cnt = self.counter.entry(x).or_insert(0);
self.items.insert((x, *cnt));
*cnt += 1;
}
pub fn remove(&mut self, x: &T) -> bool {
if let Some(v) = self.counter.get_mut(x) {
if *v > 0 {
*v -= 1;
self.items.remove(&(*x, *v));
return true;
}
}
false
}
pub fn contains(&self, x: &T) -> bool {
self.counter.get(x).is_some_and(|cnt| *cnt > 0)
}
pub fn first(&self) -> Option<&T> {
self.items.first().map(|(ref x, _)| x)
}
pub fn last(&self) -> Option<&T> {
self.items.last().map(|(ref x, _)| x)
}
pub fn count(&self, x: &T) -> usize {
match self.counter.get(x) {
Some(&v) => v,
None => 0,
}
}
pub fn clear(&mut self) {
self.counter.clear();
self.items.clear();
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<T> MultiSet<T> {
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.items.iter().map(|(ref x, _)| x)
}
}
impl<T: Ord + Hash + Copy> FromIterator<T> for MultiSet<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut multiset = MultiSet::new();
for x in iter {
multiset.insert(x);
}
multiset
}
}
impl<T: Debug> Debug for MultiSet<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_set().entries(self.iter()).finish()
}
}