use crate::bit_vec::fast_rs_vec::{BLOCK_SIZE, SELECT_BLOCK_SIZE, SUPER_BLOCK_SIZE};
use crate::RsVec;
use std::iter::FusedIterator;
use std::num::NonZeroUsize;
impl RsVec {
pub fn select_iter<const ZERO: bool>(&self) -> SelectIter<'_, ZERO> {
SelectIter::new(self)
}
pub fn into_select_iter<const ZERO: bool>(self) -> SelectIntoIter<ZERO> {
SelectIntoIter::new(self)
}
pub fn iter0(&self) -> SelectIter<'_, true> {
self.select_iter()
}
pub fn iter1(&self) -> SelectIter<'_, false> {
self.select_iter()
}
pub fn into_iter0(self) -> SelectIntoIter<true> {
self.into_select_iter()
}
pub fn into_iter1(self) -> SelectIntoIter<false> {
self.into_select_iter()
}
}
macro_rules! gen_iter_impl {
($($life:lifetime, )? $name:ident) => {
impl<$($life,)? const ZERO: bool> $name<$($life,)? ZERO> {
fn new(vec: $(&$life)? RsVec) -> Self {
if vec.is_empty() {
return Self {
vec,
next_rank: 0,
next_rank_back: None,
last_super_block: 0,
last_super_block_back: 0,
last_block: 0,
last_block_back: 0,
};
}
let blocks_len = vec.blocks.len();
let super_blocks_len = vec.super_blocks.len();
let rank0 = vec.rank0;
let rank1 = vec.rank1;
Self {
vec,
next_rank: 0,
next_rank_back: Some(if ZERO { rank0 } else { rank1 }).and_then(|x| if x > 0 { Some(x - 1) } else { None }),
last_super_block: 0,
last_super_block_back: super_blocks_len - 1,
last_block: 0,
last_block_back: blocks_len - 1,
}
}
fn select_next_0(&mut self) -> Option<usize> {
let mut rank = self.next_rank;
if rank >= self.vec.rank0 || self.next_rank_back.is_none() || rank > self.next_rank_back.unwrap() {
return None;
}
let mut super_block = self.vec.select_blocks[rank / SELECT_BLOCK_SIZE].index_0;
let mut block_index = 0;
if self.vec.super_blocks.len() > (self.last_super_block + 1)
&& self.vec.super_blocks[self.last_super_block + 1].zeros > rank
{
super_block = self.last_super_block;
rank -= self.vec.super_blocks[super_block].zeros;
if self.last_block % (SUPER_BLOCK_SIZE / BLOCK_SIZE) == 15
|| self.vec.blocks.len() > self.last_block + 1
&& self.vec.blocks[self.last_block + 1].zeros as usize > rank
{
block_index = self.last_block;
rank -= self.vec.blocks[block_index].zeros as usize;
}
} else {
super_block = self.vec.search_super_block0(super_block, rank);
self.last_super_block = super_block;
rank -= self.vec.super_blocks[super_block].zeros;
}
if block_index == 0 {
block_index = super_block * (SUPER_BLOCK_SIZE / BLOCK_SIZE);
self.vec.search_block0(rank, &mut block_index);
self.last_block = block_index;
rank -= self.vec.blocks[block_index].zeros as usize;
}
self.next_rank += 1;
Some(self.vec.search_word_in_block0(rank, block_index))
}
fn select_next_0_back(&mut self) -> Option<usize> {
let mut rank = self.next_rank_back?;
if self.next_rank_back.is_none() || rank < self.next_rank {
return None;
}
let mut super_block = self.vec.select_blocks[rank / SELECT_BLOCK_SIZE].index_0;
let mut block_index = 0;
if self.vec.super_blocks[self.last_super_block_back].zeros < rank
{
super_block = self.last_super_block_back;
rank -= self.vec.super_blocks[super_block].zeros;
if self.vec.blocks[self.last_block_back].zeros as usize <= rank
{
block_index = self.last_block_back;
rank -= self.vec.blocks[block_index].zeros as usize;
}
} else {
super_block = self.vec.search_super_block0(super_block, rank);
self.last_super_block_back = super_block;
rank -= self.vec.super_blocks[super_block].zeros;
}
if block_index == 0 {
block_index = super_block * (SUPER_BLOCK_SIZE / BLOCK_SIZE);
self.vec.search_block0(rank, &mut block_index);
self.last_block_back = block_index;
rank -= self.vec.blocks[block_index].zeros as usize;
}
self.next_rank_back = self.next_rank_back.and_then(|x| if x > 0 { Some(x - 1) } else { None });
Some(self.vec.search_word_in_block0(rank, block_index))
}
#[must_use]
#[allow(clippy::assertions_on_constants)]
fn select_next_1(&mut self) -> Option<usize> {
let mut rank = self.next_rank;
if rank >= self.vec.rank1 || self.next_rank_back.is_none() || rank > self.next_rank_back.unwrap() {
return None;
}
let mut super_block = self.vec.select_blocks[rank / SELECT_BLOCK_SIZE].index_1;
let mut block_index = 0;
if self.vec.super_blocks.len() > (self.last_super_block + 1)
&& (self.last_super_block + 1) * SUPER_BLOCK_SIZE
- self.vec.super_blocks[self.last_super_block + 1].zeros
> rank
{
super_block = self.last_super_block;
let block_at_super_block = super_block * (SUPER_BLOCK_SIZE / BLOCK_SIZE);
rank -= super_block * SUPER_BLOCK_SIZE - self.vec.super_blocks[super_block].zeros;
if self.last_block % (SUPER_BLOCK_SIZE / BLOCK_SIZE) == 15
|| self.vec.blocks.len() > self.last_block + 1
&& (self.last_block + 1 - block_at_super_block) * BLOCK_SIZE
- self.vec.blocks[self.last_block + 1].zeros as usize
> rank
{
block_index = self.last_block;
let block_at_super_block = super_block * (SUPER_BLOCK_SIZE / BLOCK_SIZE);
rank -= (block_index - block_at_super_block) * BLOCK_SIZE
- self.vec.blocks[block_index].zeros as usize;
}
} else {
super_block = self.vec.search_super_block1(super_block, rank);
self.last_super_block = super_block;
rank -= super_block * SUPER_BLOCK_SIZE - self.vec.super_blocks[super_block].zeros;
}
if block_index == 0 {
let block_at_super_block = super_block * (SUPER_BLOCK_SIZE / BLOCK_SIZE);
block_index = block_at_super_block;
self.vec
.search_block1(rank, block_at_super_block, &mut block_index);
self.last_block = block_index;
rank -= (block_index - block_at_super_block) * BLOCK_SIZE
- self.vec.blocks[block_index].zeros as usize;
}
self.next_rank += 1;
Some(self.vec.search_word_in_block1(rank, block_index))
}
#[must_use]
#[allow(clippy::assertions_on_constants)]
fn select_next_1_back(&mut self) -> Option<usize> {
let mut rank = self.next_rank_back?;
if self.next_rank_back.is_none() || rank < self.next_rank {
return None;
}
let mut super_block = self.vec.select_blocks[rank / SELECT_BLOCK_SIZE].index_1;
let mut block_index = 0;
if (self.last_super_block_back) * SUPER_BLOCK_SIZE
- self.vec.super_blocks[self.last_super_block_back].zeros
< rank
{
super_block = self.last_super_block_back;
let block_at_super_block = super_block * (SUPER_BLOCK_SIZE / BLOCK_SIZE);
rank -= super_block * SUPER_BLOCK_SIZE - self.vec.super_blocks[super_block].zeros;
if (self.last_block_back - block_at_super_block) * BLOCK_SIZE
- self.vec.blocks[self.last_block_back].zeros as usize
<= rank
{
block_index = self.last_block_back;
let block_at_super_block = super_block * (SUPER_BLOCK_SIZE / BLOCK_SIZE);
rank -= (block_index - block_at_super_block) * BLOCK_SIZE
- self.vec.blocks[block_index].zeros as usize;
}
} else {
super_block = self.vec.search_super_block1(super_block, rank);
self.last_super_block_back = super_block;
rank -= super_block * SUPER_BLOCK_SIZE - self.vec.super_blocks[super_block].zeros;
}
if block_index == 0 {
let block_at_super_block = super_block * (SUPER_BLOCK_SIZE / BLOCK_SIZE);
block_index = block_at_super_block;
self.vec
.search_block1(rank, block_at_super_block, &mut block_index);
self.last_block_back = block_index;
rank -= (block_index - block_at_super_block) * BLOCK_SIZE
- self.vec.blocks[block_index].zeros as usize;
}
self.next_rank_back = self.next_rank_back.and_then(|x| if x > 0 { Some(x - 1) } else { None });
Some(self.vec.search_word_in_block1(rank, block_index))
}
pub(super) fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
if self.len() >= n {
self.next_rank += n;
Ok(())
} else {
let len = self.len();
self.next_rank += len;
Err(NonZeroUsize::new(n - len).unwrap())
}
}
pub(super) fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
if self.len() >= n {
self.next_rank_back = self.next_rank_back.map(|x| x - n);
Ok(())
} else {
let len = self.len();
self.next_rank_back = self.next_rank_back.map(|x| x - len);
Err(NonZeroUsize::new(n - len).unwrap())
}
}
}
impl<$($life,)? const ZERO: bool> Iterator for $name<$($life,)? ZERO> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if ZERO {
self.select_next_0()
} else {
self.select_next_1()
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len(), Some(self.len()))
}
fn count(self) -> usize
where
Self: Sized,
{
self.len()
}
fn last(mut self) -> Option<Self::Item>
where
Self: Sized,
{
if self.len() == 0 {
None
} else {
self.advance_by(self.len() - 1)
.ok()
.and_then(|()| self.next())
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
if ZERO {
self.advance_by(n).ok().and_then(|()| self.select_next_0())
} else {
self.advance_by(n).ok().and_then(|()| self.select_next_1())
}
}
}
impl<$($life,)? const ZERO: bool> DoubleEndedIterator for $name<$($life,)? ZERO> {
fn next_back(&mut self) -> Option<Self::Item> {
if ZERO {
self.select_next_0_back()
} else {
self.select_next_1_back()
}
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
if ZERO {
self.advance_back_by(n).ok().and_then(|()| self.select_next_0_back())
} else {
self.advance_back_by(n).ok().and_then(|()| self.select_next_1_back())
}
}
}
impl<$($life,)? const ZERO: bool> FusedIterator for $name<$($life,)? ZERO> {}
impl<$($life,)? const ZERO: bool> ExactSizeIterator for $name<$($life,)? ZERO> {
fn len(&self) -> usize {
self.next_rank_back.map(|x| x + 1).unwrap_or_default().saturating_sub(self.next_rank)
}
}
}
}
#[derive(Clone, Debug)]
#[must_use]
pub struct SelectIter<'a, const ZERO: bool> {
pub(crate) vec: &'a RsVec,
next_rank: usize,
next_rank_back: Option<usize>,
last_super_block: usize,
last_super_block_back: usize,
last_block: usize,
last_block_back: usize,
}
gen_iter_impl!('a, SelectIter);
#[derive(Clone, Debug)]
#[must_use]
pub struct SelectIntoIter<const ZERO: bool> {
pub(crate) vec: RsVec,
next_rank: usize,
next_rank_back: Option<usize>,
last_super_block: usize,
last_super_block_back: usize,
last_block: usize,
last_block_back: usize,
}
gen_iter_impl!(SelectIntoIter);