use rayon::iter::plumbing::{bridge_unindexed, Folder, UnindexedConsumer, UnindexedProducer};
use rayon::iter::ParallelIterator;
use iter::{BitIter, BitSetLike, Index, BITS, LAYERS};
use util::average_ones;
#[derive(Debug)]
pub struct BitParIter<T>(T, u8);
impl<T> BitParIter<T> {
pub fn new(set: T) -> Self {
BitParIter(set, 3)
}
pub fn layers_split(mut self, layers: u8) -> Self {
assert!(layers >= 1);
assert!(layers <= 3);
self.1 = layers;
self
}
}
impl<T> ParallelIterator for BitParIter<T>
where
T: BitSetLike + Send + Sync,
{
type Item = Index;
fn drive_unindexed<C>(self, consumer: C) -> C::Result
where
C: UnindexedConsumer<Self::Item>,
{
bridge_unindexed(BitProducer((&self.0).iter(), self.1), consumer)
}
}
#[derive(Debug)]
pub struct BitProducer<'a, T: 'a + Send + Sync>(pub BitIter<&'a T>, pub u8);
impl<'a, T: 'a + Send + Sync> UnindexedProducer for BitProducer<'a, T>
where
T: BitSetLike,
{
type Item = Index;
fn split(mut self) -> (Self, Option<Self>) {
let splits = self.1;
let other = {
let mut handle_level = |level: usize| {
if self.0.masks[level] == 0 {
None
} else {
let level_prefix = self.0.prefix.get(level).cloned().unwrap_or(0);
let first_bit = self.0.masks[level].trailing_zeros();
average_ones(self.0.masks[level])
.and_then(|average_bit| {
let mask = (1 << average_bit) - 1;
let mut other = BitProducer(
BitIter::new(self.0.set, [0; LAYERS], [0; LAYERS - 1]),
splits,
);
other.0.masks[level] = self.0.masks[level] & !mask;
other.0.prefix[level - 1] = (level_prefix | average_bit as u32) << BITS;
other.0.prefix[level..].copy_from_slice(&self.0.prefix[level..]);
self.0.masks[level] &= mask;
self.0.prefix[level - 1] = (level_prefix | first_bit) << BITS;
Some(other)
})
.or_else(|| {
let idx = level_prefix as usize | first_bit as usize;
self.0.prefix[level - 1] = (idx as u32) << BITS;
self.0.masks[level] = 0;
self.0.masks[level - 1] = self.0.set.get_from_layer(level - 1, idx);
None
})
}
};
let top_layer = LAYERS - 1;
let mut h = handle_level(top_layer);
for i in 1..splits {
h = h.or_else(|| handle_level(top_layer - i as usize));
}
h
};
(self, other)
}
fn fold_with<F>(self, folder: F) -> F
where
F: Folder<Self::Item>,
{
folder.consume_iter(self.0)
}
}
#[cfg(test)]
mod test_bit_producer {
use rayon::iter::plumbing::UnindexedProducer;
use super::BitProducer;
use iter::BitSetLike;
use util::BITS;
fn test_splitting(split_levels: u8) {
fn visit<T>(mut us: BitProducer<T>, d: usize, i: usize, mut trail: String, c: &mut usize)
where
T: Send + Sync + BitSetLike,
{
if d == 0 {
assert!(us.split().1.is_none(), "{}", trail);
*c += 1;
} else {
for j in 1..(i + 1) {
let (new_us, them) = us.split();
us = new_us;
let them = them.expect(&trail);
let mut trail = trail.clone();
trail.push_str(&i.to_string());
visit(them, d, i - j, trail, c);
}
trail.push_str("u");
visit(us, d - 1, BITS, trail, c);
}
}
let usize_bits = ::std::mem::size_of::<usize>() * 8;
let mut c = ::BitSet::new();
for i in 0..(usize_bits.pow(3) * 2) {
assert!(!c.add(i as u32));
}
let us = BitProducer((&c).iter(), split_levels);
let (us, them) = us.split();
let mut count = 0;
visit(
us,
split_levels as usize - 1,
BITS,
"u".to_owned(),
&mut count,
);
visit(
them.expect("Splitting top level"),
split_levels as usize - 1,
BITS,
"t".to_owned(),
&mut count,
);
assert_eq!(usize_bits.pow(split_levels as u32 - 1) * 2, count);
}
#[test]
fn max_3_splitting_of_two_top_bits() {
test_splitting(3);
}
#[test]
fn max_2_splitting_of_two_top_bits() {
test_splitting(2);
}
#[test]
fn max_1_splitting_of_two_top_bits() {
test_splitting(1);
}
}