#![feature(allocator_api, extend_one, btreemap_alloc)] //! [`BTreeSet`](std::collections::BTreeSet) but with duplicates. use std::alloc::{Allocator, Global}; use std::collections::BTreeMap; use std::collections::btree_map::{self, Entry}; use std::fmt::Debug; use std::iter::FlatMap; use smallvec::SmallVec; #[derive(Clone)] /// Like a btree set, but with duplicates. /// Currently immutable cause i havent thought about it yet. pub struct BTreeMultiset< T: ToK, const N: usize = 4, A: Allocator + Clone = Global, > { inner: BTreeMap, A>, } pub trait ToK { type K; fn to_key(&self) -> Self::K; } macro_rules! primitive { ($($t:ty)+) => { $( impl ToK for $t { type K = Self; fn to_key(&self) -> Self::K { *self } } )+ }; } primitive!(i8 i16 i32 i64 i128 u8 u16 u32 u64 u128); impl ToK for Vec { type K = Self; fn to_key(&self) -> Self::K { self.clone() } } impl, A: Allocator + Clone> Debug for BTreeMultiset { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_set().entries(self.iter()).finish() } } impl, A: Allocator + Clone> IntoIterator for BTreeMultiset { type Item = T; type IntoIter = FlatMap< btree_map::IntoIter<::K, SmallVec<[T; N]>, A>, SmallVec<[T; N]>, fn((::K, SmallVec<[T; N]>)) -> SmallVec<[T; N]>, >; fn into_iter(self) -> Self::IntoIter { self.inner.into_iter().flat_map(|x| x.1) } } impl> FromIterator for BTreeMultiset { fn from_iter>(iter: I) -> Self { let mut x = Self::default(); x.extend(iter); x } } impl, A: Allocator + Clone> Extend for BTreeMultiset { #[inline] fn extend>(&mut self, iter: I) { iter.into_iter().for_each(move |x| { self.insert(x); }); } #[inline] fn extend_one(&mut self, x: T) { self.insert(x); } } impl> BTreeMultiset { pub fn new() -> Self { Self { inner: BTreeMap::new() } } } impl> Default for BTreeMultiset { fn default() -> Self { Self::new() } } type Iter<'a, const N: usize, T> = FlatMap< btree_map::Iter<'a, ::K, SmallVec<[T; N]>>, &'a SmallVec<[T; N]>, fn((&'a ::K, &'a SmallVec<[T; N]>)) -> &'a SmallVec<[T; N]>, >; type Range<'a, const N: usize, T> = FlatMap< btree_map::Range<'a, ::K, SmallVec<[T; N]>>, &'a SmallVec<[T; N]>, fn((&'a ::K, &'a SmallVec<[T; N]>)) -> &'a SmallVec<[T; N]>, >; impl BTreeMultiset { pub fn into_inner(self) -> BTreeMap, A> { self.inner } } impl, A: Allocator + Clone> BTreeMultiset { pub fn new_in(a: A) -> Self { Self { inner: BTreeMap::new_in(a) } } /// Gets an iterator that visits the elements in the [`BTreeMultiset`] in ascending order. /// Similar to `range(..)`. pub fn iter(&'_ self) -> Iter<'_, N, T> { self.inner.iter().flat_map(|x| x.1) } /// Adds a value to the multi set. pub fn insert(&mut self, t: T) -> bool { match self.inner.entry(t.to_key()) { Entry::Vacant(vacant_entry) => { vacant_entry.insert(SmallVec::from_iter([t])); false } Entry::Occupied(occupied_entry) => { occupied_entry.into_mut().push(t); true } } } /// Constructs a double-ended iterator over a sub-range of elements in the multiset. /// The simplest way is to use the range syntax `min..max`, thus `range(min..max)` will /// yield elements from min (inclusive) to max (exclusive). /// The range may also be entered as `(Bound, Bound)`, so for example /// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive /// range from 4 to 10. /// /// # Panics /// /// Panics if range `start > end`. /// Panics if range `start == end` and both bounds are `Excluded`. pub fn range( &'_ self, r: impl std::ops::RangeBounds, ) -> Range<'_, N, T> { self.inner.range(r).flat_map(|x| x.1) } // pub fn range_mut<'a, R>( // &'a mut self, // r: impl std::ops::RangeBounds, // ) -> FlatMap< // RangeMut<'a, K, SmallVec>, // &'a mut SmallVec, // fn((&'a K, &'a mut SmallVec)) -> &'a mut SmallVec, // > { // self.inner.range_mut(r).flat_map(|x| x.1) // } } #[test] fn works() { let mut x: BTreeMultiset = BTreeMultiset::new(); x.insert(4); x.insert(3); x.insert(7); x.insert(3); assert_eq!(x.iter().copied().collect::>(), vec![3, 3, 4, 7]); assert_eq!(x.range(0..=4).copied().collect::>(), vec![3, 3, 4]); }