use alloc::collections::btree_set::{IntoIter, Iter};
use alloc::collections::BTreeSet;
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::num::NonZeroUsize;
use crate::{Capacity, OverCapacityPolicy};
#[derive(Debug, Clone)]
pub struct Insert<T> {
pub inserted: bool,
pub pop: Option<T>,
}
#[derive(Debug, Clone)]
pub struct BTreeCapSet<T> {
set: BTreeSet<T>,
capacity: Capacity,
}
impl<T> Default for BTreeCapSet<T>
where
T: Ord,
{
#[inline]
fn default() -> Self {
Self::unbounded()
}
}
impl<T> PartialEq for BTreeCapSet<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.set == other.set
}
}
impl<T> Eq for BTreeCapSet<T> where T: Eq {}
impl<T> PartialOrd for BTreeCapSet<T>
where
T: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.set.partial_cmp(&other.set)
}
}
impl<T> Ord for BTreeCapSet<T>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
self.set.cmp(&other.set)
}
}
impl<T> Hash for BTreeCapSet<T>
where
T: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.set.hash(state);
}
}
impl<T> BTreeCapSet<T>
where
T: Ord,
{
#[inline]
pub const fn with_capacity(capacity: Capacity) -> Self {
Self {
set: BTreeSet::new(),
capacity,
}
}
#[inline]
pub fn bounded(max: NonZeroUsize) -> Self {
Self::with_capacity(Capacity::bounded(max))
}
#[inline]
pub const fn unbounded() -> Self {
Self::with_capacity(Capacity::Unbounded)
}
#[inline]
pub const fn capacity(&self) -> Capacity {
self.capacity
}
pub fn change_capacity(&mut self, capacity: Capacity) {
match capacity {
Capacity::Bounded { max, policy } if self.set.len() > max.get() => {
while self.set.len() != max.get() {
match policy {
OverCapacityPolicy::First => self.set.pop_first(),
OverCapacityPolicy::Last => self.set.pop_last(),
};
}
}
_ => self.capacity = capacity,
}
}
#[inline]
pub fn len(&self) -> usize {
self.set.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.set.is_empty()
}
#[inline]
pub fn contains<Q>(&self, value: &Q) -> bool
where
T: Borrow<Q> + Ord,
Q: Ord,
{
self.set.contains(value)
}
pub fn insert(&mut self, value: T) -> Insert<T> {
match self.capacity {
Capacity::Bounded { max, policy } if self.set.len() >= max.get() => {
let should_insert: bool = match policy {
OverCapacityPolicy::First => match self.set.first() {
Some(first) => &value > first,
None => true,
},
OverCapacityPolicy::Last => match self.set.last() {
Some(last) => &value < last,
None => true,
},
};
if should_insert {
Insert {
inserted: self.set.insert(value),
pop: match policy {
OverCapacityPolicy::First => self.set.pop_first(),
OverCapacityPolicy::Last => self.set.pop_last(),
},
}
} else {
Insert {
inserted: false,
pop: None,
}
}
}
_ => {
Insert {
inserted: self.set.insert(value),
pop: None,
}
}
}
}
pub fn force_insert(&mut self, value: T) -> Insert<T> {
let inserted: bool = self.set.insert(value);
if inserted {
if let Capacity::Bounded { max, .. } = self.capacity {
let max: usize = max.get();
if self.set.len() >= max {
let new_max: usize = max.saturating_add(1);
let new_max: NonZeroUsize =
NonZeroUsize::new(new_max).expect("BUG: new_max must be non-zero");
self.capacity = Capacity::bounded(new_max);
}
}
}
Insert {
inserted,
pop: None,
}
}
pub fn extend<I>(&mut self, values: I)
where
I: IntoIterator<Item = T>,
{
match self.capacity {
Capacity::Bounded { .. } => {
for value in values.into_iter() {
self.insert(value);
}
}
Capacity::Unbounded => {
self.set.extend(values);
}
}
}
#[inline]
pub fn remove<Q>(&mut self, value: &Q) -> bool
where
T: Borrow<Q> + Ord,
Q: Ord,
{
self.set.remove(value)
}
#[inline]
pub fn first(&self) -> Option<&T>
where
T: Ord,
{
self.set.first()
}
#[inline]
pub fn last(&self) -> Option<&T>
where
T: Ord,
{
self.set.last()
}
#[inline]
pub fn iter(&self) -> Iter<'_, T> {
self.set.iter()
}
}
impl<T> From<BTreeSet<T>> for BTreeCapSet<T> {
fn from(set: BTreeSet<T>) -> Self {
Self {
set,
capacity: Capacity::Unbounded,
}
}
}
impl<T> IntoIterator for BTreeCapSet<T> {
type Item = T;
type IntoIter = IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.set.into_iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_insert() {
let mut set = BTreeCapSet::bounded(NonZeroUsize::new(2).unwrap());
let res = set.insert(1);
assert!(res.inserted);
assert!(res.pop.is_none());
assert_eq!(set.len(), 1);
let res = set.insert(2);
assert!(res.inserted);
assert!(res.pop.is_none());
assert_eq!(set.len(), 2);
let res = set.insert(3);
assert!(res.inserted);
assert_eq!(res.pop, Some(1));
assert_eq!(set.len(), 2);
let res = set.insert(1);
assert!(!res.inserted); assert_eq!(res.pop, None);
assert_eq!(set.len(), 2);
}
#[test]
fn test_insert_inverted() {
let mut set = BTreeCapSet::with_capacity(Capacity::Bounded {
max: NonZeroUsize::new(2).unwrap(),
policy: OverCapacityPolicy::Last,
});
let res = set.insert(1);
assert!(res.inserted);
assert!(res.pop.is_none());
assert_eq!(set.len(), 1);
let res = set.insert(2);
assert!(res.inserted);
assert!(res.pop.is_none());
assert_eq!(set.len(), 2);
let res = set.insert(0);
assert!(res.inserted);
assert_eq!(res.pop, Some(2));
assert_eq!(set.len(), 2);
let res = set.insert(3);
assert!(!res.inserted); assert_eq!(res.pop, None);
assert_eq!(set.len(), 2);
}
#[test]
fn test_remove() {
let mut set = BTreeCapSet::bounded(NonZeroUsize::new(3).unwrap());
set.insert(1);
set.insert(2);
set.insert(3);
assert!(set.remove(&1));
assert_eq!(set.len(), 2);
}
#[test]
fn test_change_capacity() {
let mut set = BTreeCapSet::bounded(NonZeroUsize::new(3).unwrap());
set.insert(1);
set.insert(2);
set.insert(3);
set.change_capacity(Capacity::bounded(NonZeroUsize::new(2).unwrap()));
assert_eq!(set.len(), 2);
assert!(!set.remove(&1));
}
#[test]
fn test_iter() {
let mut set = BTreeCapSet::bounded(NonZeroUsize::new(3).unwrap());
set.insert(1);
set.insert(2);
set.insert(3);
let mut iter = set.iter();
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next(), Some(&3));
}
#[test]
fn test_cmp_capacity() {
assert!(Capacity::Unbounded > Capacity::bounded(NonZeroUsize::new(1000).unwrap()));
assert!(
Capacity::bounded(NonZeroUsize::new(1).unwrap())
< Capacity::bounded(NonZeroUsize::new(1000).unwrap())
);
assert_eq!(Capacity::Unbounded, Capacity::Unbounded);
}
}