use std::marker::PhantomData;
use crate::{Key, TinyMap};
use super::{
iter_many::{IterMany, IterManyPtr, IterManyPtrMut},
IterManyMut,
};
pub struct Chunks<'a, K: Key, V, IO, II>
where
IO: Iterator<Item = II> + Send,
II: Iterator<Item = K> + Send,
{
ptr: *const V,
keys: IO,
_marker: PhantomData<&'a V>,
}
unsafe impl<'a, K: Key, V, IO, II> Send for Chunks<'a, K, V, IO, II>
where
IO: Iterator<Item = II> + Send,
II: Iterator<Item = K> + Send,
{
}
impl<'a, K, V, IO, II> Iterator for Chunks<'a, K, V, IO, II>
where
IO: Iterator<Item = II> + Send,
II: Iterator<Item = K> + Send,
K: Key,
{
type Item = IterMany<'a, K, V, II>;
fn next(&mut self) -> Option<Self::Item> {
self.keys.next().map(|keys| IterMany::new(self.ptr, keys))
}
}
impl<'a, K, V, IO, II> ExactSizeIterator for Chunks<'a, K, V, IO, II>
where
IO: Iterator<Item = II> + ExactSizeIterator + Send,
II: Iterator<Item = K> + ExactSizeIterator + Send,
K: Key,
{
fn len(&self) -> usize {
self.keys.len()
}
}
pub struct PtrChunks<'a, K: Key, V, IO, II>(Chunks<'a, K, V, IO, II>)
where
IO: Iterator<Item = II> + Send,
II: Iterator<Item = K> + Send;
impl<'a, K: Key, V, IO, II> Iterator for PtrChunks<'a, K, V, IO, II>
where
IO: Iterator<Item = II> + Send,
II: Iterator<Item = K> + Send,
{
type Item = IterManyPtr<'a, K, V, II>;
fn next(&mut self) -> Option<Self::Item> {
self.0
.keys
.next()
.map(|keys| IterManyPtr(IterMany::new(self.0.ptr, keys)))
}
}
pub struct ChunksMut<'a, K: Key, V, IO, II>
where
IO: Iterator<Item = II> + Send,
II: Iterator<Item = K> + Send,
{
ptr: *mut V,
keys: IO,
_marker: PhantomData<&'a mut V>,
}
unsafe impl<'a, K: Key, V, IO, II> Send for ChunksMut<'a, K, V, IO, II>
where
IO: Iterator<Item = II> + Send,
II: Iterator<Item = K> + Send,
{
}
impl<'a, K, V, IO, II> Iterator for ChunksMut<'a, K, V, IO, II>
where
IO: Iterator<Item = II> + Send,
II: Iterator<Item = K> + Send,
K: Key,
{
type Item = IterManyMut<'a, K, V, II>;
fn next(&mut self) -> Option<Self::Item> {
self.keys
.next()
.map(|keys| IterManyMut::new(self.ptr, keys))
}
}
impl<'a, K, V, IO, II> ExactSizeIterator for ChunksMut<'a, K, V, IO, II>
where
IO: Iterator<Item = II> + ExactSizeIterator + Send,
II: Iterator<Item = K> + ExactSizeIterator + Send,
K: Key,
{
fn len(&self) -> usize {
self.keys.len()
}
}
pub struct PtrChunksMut<'a, K: Key, V, IO, II>(ChunksMut<'a, K, V, IO, II>)
where
IO: Iterator<Item = II> + Send,
II: Iterator<Item = K> + Send;
impl<'a, K: Key, V, IO, II> Iterator for PtrChunksMut<'a, K, V, IO, II>
where
IO: Iterator<Item = II> + Send,
II: Iterator<Item = K> + Send,
{
type Item = IterManyPtrMut<'a, K, V, II>;
fn next(&mut self) -> Option<Self::Item> {
self.0
.keys
.next()
.map(|keys| IterManyPtrMut(IterManyMut::new(self.0.ptr, keys)))
}
}
pub type SplitChunks<'a, K, V, IO1, IO2, II> =
(Chunks<'a, K, V, IO1, II>, ChunksMut<'a, K, V, IO2, II>);
pub type SplitPtrChunks<'a, K, V, IO1, IO2, II> = (
PtrChunksMut<'a, K, V, IO1, II>,
PtrChunksMut<'a, K, V, IO2, II>,
);
impl<K: Key, V: Send> TinyMap<K, V> {
pub unsafe fn iter_chunks_split_unchecked<IO1, IO2, II>(
&mut self,
keys: IO1,
keys_mut: IO2,
) -> SplitChunks<'_, K, V, IO1, IO2, II>
where
IO1: Iterator<Item = II> + ExactSizeIterator + Send,
IO2: Iterator<Item = II> + ExactSizeIterator + Send,
II: Iterator<Item = K> + ExactSizeIterator + Send,
{
(
Chunks {
ptr: self.data.as_ptr(),
keys,
_marker: PhantomData,
},
ChunksMut {
ptr: self.data.as_mut_ptr(),
keys: keys_mut,
_marker: PhantomData,
},
)
}
pub unsafe fn iter_ptr_chunks_split_unchecked<IO1, IO2, II>(
&mut self,
keys: IO1,
keys_mut: IO2,
) -> SplitPtrChunks<'_, K, V, IO1, IO2, II>
where
IO1: Iterator<Item = II> + ExactSizeIterator + Send,
IO2: Iterator<Item = II> + ExactSizeIterator + Send,
II: Iterator<Item = K> + ExactSizeIterator + Send,
{
(
PtrChunksMut(ChunksMut {
ptr: self.data.as_mut_ptr(),
keys,
_marker: PhantomData,
}),
PtrChunksMut(ChunksMut {
ptr: self.data.as_mut_ptr(),
keys: keys_mut,
_marker: PhantomData,
}),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::DefaultKey;
use itertools::Itertools;
fn make_map<const N: usize>() -> (TinyMap<DefaultKey, usize>, Vec<DefaultKey>) {
let map = (0..N).collect();
let keys = (0..N).map(DefaultKey::from).collect();
(map, keys)
}
#[test]
fn test_par_iter_chunks_split_unchecked() {
let (mut map, keys) = make_map::<20>();
let chunked_keys = [
keys.iter().step_by(2).take(4).copied().collect_vec(),
keys.iter()
.skip(1)
.step_by(2)
.take(4)
.copied()
.collect_vec(),
];
let keys_iter = chunked_keys.iter().map(|c| c.iter().copied());
let (_, mut op) = unsafe { map.iter_chunks_split_unchecked(std::iter::empty(), keys_iter) };
let chunk1 = op.next().unwrap();
let chunk2 = op.next().unwrap();
std::thread::scope(|s| {
let v1 = s.spawn(move || chunk1.map(|x| *x).collect_vec());
let v2 = chunk2.map(|x| *x).collect_vec();
let v1 = v1.join().unwrap();
assert_eq!(v1, vec![0, 2, 4, 6]);
assert_eq!(v2, vec![1, 3, 5, 7]);
});
}
#[test]
fn test_iter_chunks_split_unchecked() {
let (mut map, keys) = make_map::<6>();
let c0 = vec![keys[0], keys[5]];
let c1 = vec![keys[2], keys[1], keys[0]];
let keys_select = [c0, c1];
let keys_iter = keys_select.iter().map(|c| c.iter().copied());
let (_ip, mut op) =
unsafe { map.iter_chunks_split_unchecked(std::iter::empty(), keys_iter) };
let o0 = op.next().unwrap().map(|x| *x).collect::<Vec<_>>();
let o1 = op.next().unwrap().map(|x| *x).collect::<Vec<_>>();
assert_eq!(o0, vec![0, 5]);
assert_eq!(o1, vec![2, 1, 0]);
assert!(op.next().is_none());
}
}