use std::collections::BTreeSet;
use std::sync::Arc;
use std::{iter, ops};
use itertools::Itertools;
use super::iter_gaps;
use crate::entity::raw::Atomic as _;
use crate::entity::Raw;
#[derive(Debug, Clone)]
pub struct Snapshot<E> {
pub(super) gauge: E,
pub(super) recyclable: Arc<BTreeSet<E>>,
}
impl<E: Raw> Snapshot<E> {
pub fn iter_allocated_chunks(&self) -> impl iter::FusedIterator<Item = ops::Range<E>> + '_ {
iter_gaps(self.gauge, self.recyclable.iter().copied())
}
pub(crate) fn as_slice(&self) -> Slice<'_, E> {
Slice {
start: E::new().load_mut(),
end: self.gauge,
recyclable: &self.recyclable,
}
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct Slice<'t, E> {
pub(crate) start: E,
pub(crate) end: E,
pub(crate) recyclable: &'t BTreeSet<E>,
}
impl<'t, E: Raw> Slice<'t, E> {
pub(crate) fn midpoint_for_split(self) -> Option<E> {
let midpt = self.start.approx_midpoint(self.end);
let is_far = self.end.sub(midpt) >= 8;
is_far.then_some(midpt)
}
pub(crate) fn split_at(self, midpt: E) -> (Self, Self) {
(
Self { start: self.start, end: midpt, recyclable: self.recyclable },
Self { start: midpt, end: self.end, recyclable: self.recyclable },
)
}
pub(crate) fn split(self) -> (Self, Option<Self>) {
let Some(midpt) = self.midpoint_for_split() else { return (self, None) };
let (left, right) = self.split_at(midpt);
(left, Some(right))
}
#[auto_enums::auto_enum(Iterator, marker = auto_enum_marker)]
pub(crate) fn iter_chunks(self) -> impl Iterator<Item = ops::Range<E>> + 't {
let first = match self.recyclable.first() {
Some(&first) => first,
None => return iter::once(self.start..self.end),
};
let gaps = self.recyclable.range(self.start..self.end).copied().chain(iter::once(self.end));
let pairs = gaps.tuple_windows();
let ret = iter::once(self.start..first)
.chain(pairs.map(|(start, end)| (start.add(1))..end))
.filter(|range| range.start != range.end);
auto_enum_marker!(ret)
}
}