use core::hash::BuildHasher;
use core::hash::Hash;
use crate::Arena;
use crate::collections::HashMap;
use crate::collections::HashSet;
use crate::vec::Vec;
pub trait FromIteratorIn<T> {
type Alloc;
fn from_iter_in<I>(iter: I, alloc: Self::Alloc) -> Self
where
I: IntoIterator<Item = T>;
}
impl<'arena, T, A: Arena> FromIteratorIn<T> for Vec<'arena, T, A> {
type Alloc = &'arena A;
#[inline]
fn from_iter_in<I>(iter: I, alloc: Self::Alloc) -> Self
where
I: IntoIterator<Item = T>,
{
let mut collection = Self::new_in(alloc);
collection.extend(iter);
collection
}
}
impl<'arena, K, V, A, S> FromIteratorIn<(K, V)> for HashMap<'arena, K, V, A, S>
where
K: Eq + Hash,
S: BuildHasher + Default,
A: Arena,
{
type Alloc = &'arena A;
#[inline]
fn from_iter_in<I>(iter: I, alloc: Self::Alloc) -> Self
where
I: IntoIterator<Item = (K, V)>,
{
let mut collection = Self::with_hasher_in(S::default(), alloc);
collection.extend(iter);
collection
}
}
impl<'arena, T, A, S> FromIteratorIn<T> for HashSet<'arena, T, A, S>
where
T: Eq + Hash,
S: BuildHasher + Default,
A: Arena,
{
type Alloc = &'arena A;
#[inline]
fn from_iter_in<I>(iter: I, alloc: Self::Alloc) -> Self
where
I: IntoIterator<Item = T>,
{
let mut collection = Self::with_hasher_in(S::default(), alloc);
collection.extend(iter);
collection
}
}
pub trait CollectIn: Iterator + Sized {
#[inline]
fn collect_in<C>(self, alloc: C::Alloc) -> C
where
C: FromIteratorIn<Self::Item>,
{
C::from_iter_in(self, alloc)
}
}
impl<I: Iterator> CollectIn for I {}
#[cfg(feature = "rayon")]
pub use parallel::ParallelCollectIn;
#[cfg(feature = "rayon")]
mod parallel {
use rayon::iter::IndexedParallelIterator;
use rayon::iter::IntoParallelRefMutIterator;
use rayon::iter::ParallelIterator;
use crate::Arena;
use crate::vec::Vec;
pub trait ParallelCollectIn: IndexedParallelIterator
where
Self::Item: Send,
{
fn collect_in<A>(self, arena: &A) -> Vec<'_, Self::Item, A>
where
A: Arena + Sync,
{
let length = self.len();
let mut collection = Vec::with_capacity_in(length, arena);
collection.spare_capacity_mut()[..length].par_iter_mut().zip(self).for_each(|(slot, item)| {
slot.write(item);
});
unsafe { collection.set_len(length) };
collection
}
}
impl<I: IndexedParallelIterator> ParallelCollectIn for I where I::Item: Send {}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::arena::LocalArena;
#[test]
fn collect_in_vec() {
let arena = LocalArena::new();
let collected: Vec<'_, i32, LocalArena> = (0..5).collect_in(&arena);
assert_eq!(collected.as_slice(), &[0, 1, 2, 3, 4]);
}
#[test]
fn collect_in_hashset_deduplicates() {
let arena = LocalArena::new();
let collected: HashSet<'_, i32, LocalArena> = [1, 2, 2, 3].into_iter().collect_in(&arena);
assert_eq!(collected.len(), 3);
assert!(collected.contains(&2));
}
#[test]
fn collect_in_hashmap() {
let arena = LocalArena::new();
let collected: HashMap<'_, i32, i32, LocalArena> = [(1, 10), (2, 20)].into_iter().collect_in(&arena);
assert_eq!(collected.get(&2), Some(&20));
}
}