use super::{IdOrdItem, RefMut, tables::IdOrdMapTables};
use crate::support::{
alloc::Global,
borrow::DormantMutRef,
btree_table,
item_set::{ConsumingItemSet, ItemSet, ItemSlot},
};
use core::{hash::Hash, iter::FusedIterator, marker::PhantomData};
#[derive(Clone, Debug)]
pub struct Iter<'a, T: IdOrdItem> {
items: &'a ItemSet<T, Global>,
iter: btree_table::Iter<'a>,
}
impl<'a, T: IdOrdItem> Iter<'a, T> {
pub(super) fn new(
items: &'a ItemSet<T, Global>,
tables: &'a IdOrdMapTables,
) -> Self {
Self { items, iter: tables.key_to_item.iter() }
}
}
impl<'a, T: IdOrdItem> Iterator for Iter<'a, T> {
type Item = &'a T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let index = self.iter.next()?;
Some(&self.items[index])
}
}
impl<T: IdOrdItem> ExactSizeIterator for Iter<'_, T> {
#[inline]
fn len(&self) -> usize {
self.iter.len()
}
}
impl<T: IdOrdItem> FusedIterator for Iter<'_, T> {}
struct ItemSetPtr<'a, T: IdOrdItem> {
start_ptr: *mut ItemSlot<T>,
slot_count: usize,
_marker: PhantomData<&'a mut ItemSet<T, Global>>,
}
impl<T: IdOrdItem> core::fmt::Debug for ItemSetPtr<'_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ItemSetPtr")
.field("start_ptr", &self.start_ptr)
.field("slot_count", &self.slot_count)
.finish()
}
}
unsafe impl<'a, T: IdOrdItem + Send> Send for ItemSetPtr<'a, T> {}
unsafe impl<'a, T: IdOrdItem + Sync> Sync for ItemSetPtr<'a, T> {}
#[derive(Debug)]
pub struct IterMut<'a, T: IdOrdItem>
where
T::Key<'a>: Hash,
{
items: ItemSetPtr<'a, T>,
tables: &'a IdOrdMapTables,
iter: btree_table::Iter<'a>,
}
impl<'a, T: IdOrdItem> IterMut<'a, T>
where
T::Key<'a>: Hash,
{
pub(super) fn new(
items: &'a mut ItemSet<T, Global>,
tables: &'a IdOrdMapTables,
) -> Self {
let slot_count = items.slot_count();
let start_ptr = items.start_ptr();
Self {
items: ItemSetPtr { start_ptr, slot_count, _marker: PhantomData },
tables,
iter: tables.key_to_item.iter(),
}
}
}
impl<'a, T: IdOrdItem + 'a> Iterator for IterMut<'a, T>
where
T::Key<'a>: Hash,
{
type Item = RefMut<'a, T>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let index = self.iter.next()?;
let raw_index = index.as_u32() as usize;
assert!(
raw_index < self.items.slot_count,
"btree index {raw_index} out of bounds for slot count {}",
self.items.slot_count,
);
let item: &'a mut T = unsafe {
(*self.items.start_ptr.add(raw_index))
.as_mut()
.expect("btree index points at an Occupied slot in ItemSet")
};
let (hash, dormant) = {
let (item, dormant) = DormantMutRef::new(item);
let hash = self.tables.make_hash(item);
(hash, dormant)
};
let item = unsafe { dormant.awaken() };
Some(RefMut::new(self.tables.state().clone(), hash, item))
}
}
impl<'a, T: IdOrdItem + 'a> ExactSizeIterator for IterMut<'a, T>
where
T::Key<'a>: Hash,
{
#[inline]
fn len(&self) -> usize {
self.iter.len()
}
}
impl<'a, T: IdOrdItem + 'a> FusedIterator for IterMut<'a, T> where
T::Key<'a>: Hash
{
}
#[derive(Debug)]
pub struct IntoIter<T: IdOrdItem> {
items: ConsumingItemSet<T, Global>,
iter: btree_table::IntoIter,
}
impl<T: IdOrdItem> IntoIter<T> {
pub(super) fn new(
items: ItemSet<T, Global>,
tables: IdOrdMapTables,
) -> Self {
Self {
items: items.into_consuming(),
iter: tables.key_to_item.into_iter(),
}
}
}
impl<T: IdOrdItem> Iterator for IntoIter<T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let index = self.iter.next()?;
let next = self
.items
.take(index)
.unwrap_or_else(|| panic!("index {index} not found in items"));
Some(next)
}
}