use crate::prelude::{indexed_dict::*, *};
use crate::traits::{AtomicBitVecOps, BitVecOpsMut, bit_field_slice::*};
use common_traits::SelectInWord;
use core::sync::atomic::Ordering;
use mem_dbg::*;
use std::borrow::Borrow;
use std::iter::FusedIterator;
use value_traits::slices::{SliceByValue, SliceByValueMut};
pub type EfSeq = EliasFano<SelectAdaptConst<BitVec<Box<[usize]>>, Box<[usize]>, 12, 3>>;
pub type EfDict = EliasFano<SelectZeroAdaptConst<BitVec<Box<[usize]>>, Box<[usize]>, 12, 3>>;
pub type EfSeqDict = EliasFano<
SelectZeroAdaptConst<
SelectAdaptConst<BitVec<Box<[usize]>>, Box<[usize]>, 12, 3>,
Box<[usize]>,
12,
3,
>,
>;
#[derive(Debug, Clone, Copy, Hash, MemDbg, MemSize, value_traits::Subslices)]
#[cfg_attr(feature = "epserde", derive(epserde::Epserde))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[value_traits_subslices(bound = "H: AsRef<[usize]> + SelectUnchecked")]
#[value_traits_subslices(bound = "L: SliceByValue<Value = usize>")]
pub struct EliasFano<H = BitVec<Box<[usize]>>, L = BitFieldVec<usize, Box<[usize]>>> {
n: usize,
u: usize,
l: usize,
low_bits: L,
high_bits: H,
}
impl<H, L> EliasFano<H, L> {
pub fn into_parts(self) -> (usize, usize, usize, L, H) {
(self.n, self.u, self.l, self.low_bits, self.high_bits)
}
pub fn estimate_size(u: usize, n: usize) -> usize {
2 * n + (n * (u as f64 / n as f64).log2().ceil() as usize)
}
#[inline]
pub fn len(&self) -> usize {
self.n
}
#[inline]
pub fn upper_bound(&self) -> usize {
self.u
}
pub unsafe fn map_high_bits<F, H2>(self, func: F) -> EliasFano<H2, L>
where
F: FnOnce(H) -> H2,
{
EliasFano {
n: self.n,
u: self.u,
l: self.l,
low_bits: self.low_bits,
high_bits: func(self.high_bits),
}
}
pub unsafe fn map_low_bits<F, L2>(self, func: F) -> EliasFano<H, L2>
where
F: FnOnce(L) -> L2,
{
EliasFano {
n: self.n,
u: self.u,
l: self.l,
low_bits: func(self.low_bits),
high_bits: self.high_bits,
}
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> Types for EliasFano<H, L> {
type Output<'a> = usize;
type Input = usize;
}
impl<H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>> IndexedSeq
for EliasFano<H, L>
{
#[inline]
fn len(&self) -> usize {
self.n
}
#[inline(always)]
unsafe fn get_unchecked(&self, index: usize) -> usize {
unsafe {
let high_bits = self.high_bits.select_unchecked(index) - index;
let low_bits = self.low_bits.get_value_unchecked(index);
(high_bits << self.l) | low_bits
}
}
}
impl<H: AsRef<[usize]> + SelectZeroUnchecked, L: SliceByValue<Value = usize>> IndexedDict
for EliasFano<H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>,
{
fn index_of(&self, value: impl Borrow<Self::Input>) -> Option<usize> {
let value = *value.borrow();
if value > self.u {
return None;
}
let zeros_to_skip = value >> self.l;
let bit_pos = if zeros_to_skip == 0 {
0
} else {
unsafe { self.high_bits.select_zero_unchecked(zeros_to_skip - 1) + 1 }
};
let mut rank = bit_pos - zeros_to_skip;
let mut iter = self.low_bits.into_unchecked_iter_from(rank);
let mut word_idx = bit_pos / (usize::BITS as usize);
let bits_to_clean = bit_pos % (usize::BITS as usize);
let mut window = unsafe { *self.high_bits.as_ref().get_unchecked(word_idx) }
& (usize::MAX << bits_to_clean);
loop {
while window == 0 {
word_idx += 1;
if word_idx >= self.high_bits.as_ref().len() {
return None;
}
window = unsafe { *self.high_bits.as_ref().get_unchecked(word_idx) };
}
let bit_idx = window.trailing_zeros() as usize;
let high_bits = (word_idx * usize::BITS as usize) + bit_idx - rank;
let res = (high_bits << self.l) | unsafe { iter.next_unchecked() };
if res == value {
return Some(rank);
}
if res > value {
return None;
}
window &= window - 1;
rank += 1;
}
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> EliasFano<H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>,
{
#[inline(always)]
pub fn iter(&self) -> EliasFanoIter<'_, H, L> {
EliasFanoIter::new(self)
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> EliasFano<H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = usize>,
{
pub fn iter_back(&self) -> EliasFanoBackIter<'_, H, L> {
let high = self.high_bits.as_ref();
let (word_idx, window) = if high.is_empty() {
(0, 0)
} else {
let mut word_idx = high.len() - 1;
let mut window = unsafe { *high.get_unchecked(word_idx) };
while window == 0 && word_idx > 0 {
word_idx -= 1;
window = unsafe { *high.get_unchecked(word_idx) };
}
(word_idx, window)
};
EliasFanoBackIter {
ef: self,
index: self.n,
word_idx,
window,
low_bits: self.low_bits.into_unchecked_iter_back_from(self.n),
}
}
}
impl<H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>> EliasFano<H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>,
{
#[inline(always)]
pub fn iter_from(&self, from: usize) -> EliasFanoIter<'_, H, L> {
EliasFanoIter::new_from(self, from)
}
}
impl<H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>> EliasFano<H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize> + IntoUncheckedBackIterator<Item = usize>,
{
#[inline(always)]
pub fn iter_back_from(&self, from: usize) -> EliasFanoBackIter<'_, H, L> {
self.iter_from(from).backward()
}
}
impl<'a, H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>> IntoIteratorFrom
for &'a EliasFano<H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>,
{
type IntoIterFrom = EliasFanoIter<'a, H, L>;
#[inline(always)]
fn into_iter_from(self, from: usize) -> EliasFanoIter<'a, H, L> {
EliasFanoIter::new_from(self, from)
}
}
impl<'a, H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>> IntoBidiIterator
for &'a EliasFano<H, L>
{
type Item = usize;
type IntoIterBidi = EliasFanoBidiIter<'a, H, L>;
#[inline(always)]
fn into_iter_bidi(self) -> EliasFanoBidiIter<'a, H, L> {
self.into_iter_bidi_from(0)
}
}
impl<'a, H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>> IntoBidiIteratorFrom
for &'a EliasFano<H, L>
{
type IntoIterBidiFrom = EliasFanoBidiIter<'a, H, L>;
#[inline(always)]
fn into_iter_bidi_from(self, from: usize) -> EliasFanoBidiIter<'a, H, L> {
if from > self.n {
panic!("Index out of bounds: {} > {}", from, self.n);
}
if self.n == 0 {
return EliasFanoBidiIter {
ef: self,
index: 0,
word_idx: 0,
window: 0,
index_in_word: 0,
};
}
let bit_pos = if from == self.n {
unsafe { self.high_bits.select_unchecked(from - 1) }
} else {
unsafe { self.high_bits.select_unchecked(from) }
};
let word_idx = bit_pos / (usize::BITS as usize);
let window = unsafe { *self.high_bits.as_ref().get_unchecked(word_idx) };
let index_in_word = if from == self.n {
(window & (usize::MAX >> (usize::BITS as usize - 1 - bit_pos % usize::BITS as usize)))
.count_ones() as usize
} else {
(window & ((1_usize << (bit_pos % usize::BITS as usize)) - 1)).count_ones() as usize
};
EliasFanoBidiIter {
ef: self,
index: from,
word_idx,
window,
index_in_word,
}
}
}
impl<'a, H: AsRef<[usize]>, L: SliceByValue<Value = usize>> IntoBackIterator for &'a EliasFano<H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = usize>,
{
type Item = usize;
type IntoIterBack = EliasFanoBackIter<'a, H, L>;
#[inline(always)]
fn into_iter_back(self) -> EliasFanoBackIter<'a, H, L> {
self.iter_back()
}
}
impl<'a, H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>> IntoBackIteratorFrom
for &'a EliasFano<H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize> + IntoUncheckedBackIterator<Item = usize>,
{
type IntoIterBackFrom = EliasFanoBackIter<'a, H, L>;
#[inline(always)]
fn into_iter_back_from(self, from: usize) -> EliasFanoBackIter<'a, H, L> {
self.iter_back_from(from + 1)
}
}
impl<H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>> EliasFano<H, L> {
#[inline(always)]
pub fn iter_bidi(&self) -> EliasFanoBidiIter<'_, H, L> {
self.into_iter_bidi()
}
#[inline(always)]
pub fn iter_bidi_from(&self, from: usize) -> EliasFanoBidiIter<'_, H, L> {
self.into_iter_bidi_from(from)
}
}
impl<H: AsRef<[usize]> + SelectZeroUnchecked, L: SliceByValue<Value = usize>> SuccUnchecked
for EliasFano<H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>,
{
type Iter<'a>
= EliasFanoIter<'a, H, L>
where
Self: 'a;
type BidiIter<'a>
= EliasFanoBidiIter<'a, H, L>
where
Self: 'a;
unsafe fn succ_unchecked<const STRICT: bool>(
&self,
value: impl Borrow<Self::Input>,
) -> (usize, Self::Output<'_>) {
let value = *value.borrow();
let zeros_to_skip = value >> self.l;
let bit_pos = if zeros_to_skip == 0 {
0
} else {
unsafe { self.high_bits.select_zero_unchecked(zeros_to_skip - 1) + 1 }
};
let mut rank = bit_pos - zeros_to_skip;
let mut iter = self.low_bits.into_unchecked_iter_from(rank);
let mut word_idx = bit_pos / (usize::BITS as usize);
let bits_to_clean = bit_pos % (usize::BITS as usize);
let mut window = unsafe { *self.high_bits.as_ref().get_unchecked(word_idx) }
& (usize::MAX << bits_to_clean);
loop {
while window == 0 {
word_idx += 1;
debug_assert!(word_idx < self.high_bits.as_ref().len());
window = unsafe { *self.high_bits.as_ref().get_unchecked(word_idx) };
}
let bit_idx = window.trailing_zeros() as usize;
let high_bits = (word_idx * usize::BITS as usize) + bit_idx - rank;
let res = (high_bits << self.l) | unsafe { iter.next_unchecked() };
let found = if STRICT { res > value } else { res >= value };
if found {
return (rank, res);
}
window &= window - 1;
rank += 1;
}
}
unsafe fn iter_from_succ_unchecked<const STRICT: bool>(
&self,
value: impl Borrow<Self::Input>,
) -> (usize, Self::Iter<'_>) {
let value = *value.borrow();
let zeros_to_skip = value >> self.l;
let bit_pos = if zeros_to_skip == 0 {
0
} else {
unsafe { self.high_bits.select_zero_unchecked(zeros_to_skip - 1) + 1 }
};
let mut rank = bit_pos - zeros_to_skip;
let mut iter = self.low_bits.into_unchecked_iter_from(rank);
let mut word_idx = bit_pos / (usize::BITS as usize);
let bits_to_clean = bit_pos % (usize::BITS as usize);
let mut window = unsafe { *self.high_bits.as_ref().get_unchecked(word_idx) }
& (usize::MAX << bits_to_clean);
loop {
while window == 0 {
word_idx += 1;
debug_assert!(word_idx < self.high_bits.as_ref().len());
window = unsafe { *self.high_bits.as_ref().get_unchecked(word_idx) };
}
let bit_idx = window.trailing_zeros() as usize;
let high_bits = (word_idx * usize::BITS as usize) + bit_idx - rank;
let res = (high_bits << self.l) | unsafe { iter.next_unchecked() };
let found = if STRICT { res > value } else { res >= value };
if found {
return (
rank,
EliasFanoIter {
ef: self,
index: rank,
word_idx,
window,
low_bits: self.low_bits.into_unchecked_iter_from(rank),
},
);
}
window &= window - 1;
rank += 1;
}
}
unsafe fn iter_bidi_from_succ_unchecked<const STRICT: bool>(
&self,
value: impl Borrow<Self::Input>,
) -> (usize, Self::BidiIter<'_>) {
let value = *value.borrow();
let zeros_to_skip = value >> self.l;
let bit_pos = if zeros_to_skip == 0 {
0
} else {
unsafe { self.high_bits.select_zero_unchecked(zeros_to_skip - 1) + 1 }
};
let mut rank = bit_pos - zeros_to_skip;
let mut word_idx = bit_pos / (usize::BITS as usize);
let bits_to_clean = bit_pos % (usize::BITS as usize);
let full_word = unsafe { *self.high_bits.as_ref().get_unchecked(word_idx) };
let mut window = full_word & (usize::MAX << bits_to_clean);
loop {
while window == 0 {
word_idx += 1;
debug_assert!(word_idx < self.high_bits.as_ref().len());
window = unsafe { *self.high_bits.as_ref().get_unchecked(word_idx) };
}
let bit_idx = window.trailing_zeros() as usize;
let high_bits = (word_idx * usize::BITS as usize) + bit_idx - rank;
let low = unsafe { self.low_bits.get_value_unchecked(rank) };
let res = (high_bits << self.l) | low;
let found = if STRICT { res > value } else { res >= value };
if found {
let full_word = unsafe { *self.high_bits.as_ref().get_unchecked(word_idx) };
let index_in_word = (full_word & ((1_usize << bit_idx) - 1)).count_ones() as usize;
return (
rank,
EliasFanoBidiIter {
ef: self,
index: rank,
word_idx,
window: full_word,
index_in_word,
},
);
}
window &= window - 1;
rank += 1;
}
}
}
impl<H: AsRef<[usize]> + SelectUnchecked + SelectZeroUnchecked, L: SliceByValue<Value = usize>> Succ
for EliasFano<H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>,
{
}
impl<H: AsRef<[usize]> + SelectZeroUnchecked, L: SliceByValue<Value = usize>> PredUnchecked
for EliasFano<H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = usize>,
{
type BackIter<'a>
= EliasFanoBackIter<'a, H, L>
where
Self: 'a;
type BidiIter<'a>
= EliasFanoBidiIter<'a, H, L>
where
Self: 'a;
unsafe fn pred_unchecked<const STRICT: bool>(
&self,
value: impl Borrow<Self::Input>,
) -> (usize, Self::Output<'_>) {
let value = *value.borrow();
let zeros_to_skip = value >> self.l;
let mut bit_pos = unsafe { self.high_bits.select_zero_unchecked(zeros_to_skip) } - 1;
let mut rank = bit_pos - zeros_to_skip;
let mut iter = self.low_bits.into_unchecked_iter_back_from(rank + 1);
unsafe {
loop {
let lower_bits = iter.next_unchecked();
let mut word_idx = bit_pos / (usize::BITS as usize);
let bit_idx = bit_pos % (usize::BITS as usize);
if self.high_bits.as_ref().get_unchecked(word_idx) & (1_usize << bit_idx) == 0 {
let mut zeros = bit_idx;
let mut window =
*self.high_bits.as_ref().get_unchecked(word_idx) & !(usize::MAX << bit_idx);
while window == 0 {
word_idx -= 1;
window = *self.high_bits.as_ref().get_unchecked(word_idx);
zeros += usize::BITS as usize;
}
return (
rank,
(((usize::BITS as usize) - 1 + bit_pos
- zeros
- window.leading_zeros() as usize
- rank)
<< self.l)
| lower_bits,
);
}
let low_value = value & ((1 << self.l) - 1);
let found = if STRICT {
lower_bits < low_value
} else {
lower_bits <= low_value
};
if found {
return (rank, ((bit_pos - rank) << self.l) | lower_bits);
}
bit_pos -= 1;
rank -= 1;
}
}
}
unsafe fn iter_back_from_pred_unchecked<const STRICT: bool>(
&self,
value: impl Borrow<Self::Input>,
) -> (usize, Self::BackIter<'_>) {
let value = *value.borrow();
let zeros_to_skip = value >> self.l;
let mut bit_pos = unsafe { self.high_bits.select_zero_unchecked(zeros_to_skip) } - 1;
let mut rank = bit_pos - zeros_to_skip;
let mut iter_back = self.low_bits.into_unchecked_iter_back_from(rank + 1);
unsafe {
loop {
let lower_bits = iter_back.next_unchecked();
let mut word_idx = bit_pos / (usize::BITS as usize);
let bit_idx = bit_pos % (usize::BITS as usize);
if self.high_bits.as_ref().get_unchecked(word_idx) & (1_usize << bit_idx) == 0 {
let mut window =
*self.high_bits.as_ref().get_unchecked(word_idx) & !(usize::MAX << bit_idx);
while window == 0 {
word_idx -= 1;
window = *self.high_bits.as_ref().get_unchecked(word_idx);
}
return (
rank,
EliasFanoBackIter {
ef: self,
index: rank + 1,
word_idx,
window,
low_bits: self.low_bits.into_unchecked_iter_back_from(rank + 1),
},
);
}
let low_value = value & ((1 << self.l) - 1);
let found = if STRICT {
lower_bits < low_value
} else {
lower_bits <= low_value
};
if found {
let window = *self.high_bits.as_ref().get_unchecked(word_idx)
& (usize::MAX >> (usize::BITS as usize - 1 - bit_idx));
return (
rank,
EliasFanoBackIter {
ef: self,
index: rank + 1,
word_idx,
window,
low_bits: self.low_bits.into_unchecked_iter_back_from(rank + 1),
},
);
}
bit_pos -= 1;
rank -= 1;
}
}
}
unsafe fn iter_bidi_from_pred_unchecked<const STRICT: bool>(
&self,
value: impl Borrow<Self::Input>,
) -> (usize, Self::BidiIter<'_>) {
let value = *value.borrow();
let zeros_to_skip = value >> self.l;
let mut bit_pos = unsafe { self.high_bits.select_zero_unchecked(zeros_to_skip) } - 1;
let mut rank = bit_pos - zeros_to_skip;
unsafe {
loop {
let mut word_idx = bit_pos / (usize::BITS as usize);
let bit_idx = bit_pos % (usize::BITS as usize);
if self.high_bits.as_ref().get_unchecked(word_idx) & (1_usize << bit_idx) == 0 {
let mut masked =
*self.high_bits.as_ref().get_unchecked(word_idx) & !(usize::MAX << bit_idx);
while masked == 0 {
word_idx -= 1;
masked = *self.high_bits.as_ref().get_unchecked(word_idx);
}
let pred_bit = usize::BITS as usize - 1 - masked.leading_zeros() as usize;
let full_word = *self.high_bits.as_ref().get_unchecked(word_idx);
let index_in_word =
(full_word & ((1_usize << pred_bit) - 1)).count_ones() as usize;
return (
rank,
EliasFanoBidiIter {
ef: self,
index: rank,
word_idx,
window: full_word,
index_in_word,
},
);
}
let low = self.low_bits.get_value_unchecked(rank);
let low_value = value & ((1 << self.l) - 1);
let found = if STRICT {
low < low_value
} else {
low <= low_value
};
if found {
let full_word = *self.high_bits.as_ref().get_unchecked(word_idx);
let index_in_word =
(full_word & ((1_usize << bit_idx) - 1)).count_ones() as usize;
return (
rank,
EliasFanoBidiIter {
ef: self,
index: rank,
word_idx,
window: full_word,
index_in_word,
},
);
}
bit_pos -= 1;
rank -= 1;
}
}
}
}
impl<H: AsRef<[usize]> + SelectUnchecked + SelectZeroUnchecked, L: SliceByValue<Value = usize>> Pred
for EliasFano<H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = usize>,
{
}
impl<H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>>
value_traits::slices::SliceByValue for EliasFano<H, L>
{
type Value = usize;
fn len(&self) -> usize {
self.n
}
unsafe fn get_value_unchecked(&self, index: usize) -> Self::Value {
unsafe { <Self as IndexedSeq>::get_unchecked(self, index) }
}
}
impl<'a, H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>>
value_traits::iter::IterateByValueGat<'a> for EliasFano<H, L>
where
for<'c> &'c L: IntoUncheckedIterator<Item = usize>,
{
type Item = usize;
type Iter = EliasFanoIter<'a, H, L>;
}
impl<H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>>
value_traits::iter::IterateByValue for EliasFano<H, L>
where
for<'c> &'c L: IntoUncheckedIterator<Item = usize>,
{
fn iter_value(&self) -> <Self as value_traits::iter::IterateByValueGat<'_>>::Iter {
self.iter_from(0)
}
}
impl<'a, H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>>
value_traits::iter::IterateByValueFromGat<'a> for EliasFano<H, L>
where
for<'c> &'c L: IntoUncheckedIterator<Item = usize>,
{
type Item = usize;
type IterFrom = EliasFanoIter<'a, H, L>;
}
impl<H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>>
value_traits::iter::IterateByValueFrom for EliasFano<H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>,
{
fn iter_value_from(
&self,
from: usize,
) -> <Self as value_traits::iter::IterateByValueGat<'_>>::Iter {
self.iter_from(from)
}
}
impl<'a, 'b, H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>>
value_traits::iter::IterateByValueGat<'a> for EliasFanoSubsliceImpl<'b, H, L>
where
for<'c> &'c L: IntoUncheckedIterator<Item = usize>,
{
type Item = usize;
type Iter = EliasFanoIter<'a, H, L>;
}
impl<'a, H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>>
value_traits::iter::IterateByValue for EliasFanoSubsliceImpl<'a, H, L>
where
for<'c> &'c L: IntoUncheckedIterator<Item = usize>,
{
fn iter_value(&self) -> <Self as value_traits::iter::IterateByValueGat<'_>>::Iter {
self.slice.iter_from(0)
}
}
impl<'a, 'b, H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>>
value_traits::iter::IterateByValueFromGat<'a> for EliasFanoSubsliceImpl<'b, H, L>
where
for<'c> &'c L: IntoUncheckedIterator<Item = usize>,
{
type Item = usize;
type IterFrom = EliasFanoIter<'a, H, L>;
}
impl<'a, H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>>
value_traits::iter::IterateByValueFrom for EliasFanoSubsliceImpl<'a, H, L>
where
for<'c> &'c L: IntoUncheckedIterator<Item = usize>,
{
fn iter_value_from(
&self,
from: usize,
) -> <Self as value_traits::iter::IterateByValueGat<'_>>::Iter {
self.slice.iter_from(from)
}
}
#[derive(MemDbg, MemSize)]
pub struct EliasFanoIter<'a, H: AsRef<[usize]>, L: SliceByValue<Value = usize>>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>,
{
ef: &'a EliasFano<H, L>,
index: usize,
word_idx: usize,
window: usize,
low_bits: <&'a L as IntoUncheckedIterator>::IntoUncheckedIter,
}
impl<'a, H: AsRef<[usize]>, L: SliceByValue<Value = usize>> EliasFanoIter<'a, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>,
{
pub fn new(ef: &'a EliasFano<H, L>) -> Self {
let window = if ef.high_bits.as_ref().is_empty() {
0
} else {
unsafe { *ef.high_bits.as_ref().get_unchecked(0) }
};
Self {
ef,
index: 0,
word_idx: 0,
window,
low_bits: ef.low_bits.into_unchecked_iter(),
}
}
}
impl<'a, H: AsRef<[usize]> + SelectUnchecked, L: SliceByValue<Value = usize>>
EliasFanoIter<'a, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>,
{
pub fn new_from(ef: &'a EliasFano<H, L>, start_index: usize) -> Self {
if start_index > ef.len() {
panic!("Index out of bounds: {} > {}", start_index, ef.len());
}
if start_index == ef.len() {
return Self {
ef,
index: start_index,
word_idx: 0,
window: 0,
low_bits: ef.low_bits.into_unchecked_iter_from(start_index),
};
}
let bit_pos = unsafe { ef.high_bits.select_unchecked(start_index) };
let word_idx = bit_pos / (usize::BITS as usize);
let bits_to_clean = bit_pos % (usize::BITS as usize);
let window = if ef.high_bits.as_ref().is_empty() {
0
} else {
let word = unsafe { *ef.high_bits.as_ref().get_unchecked(word_idx) };
word & (usize::MAX << bits_to_clean)
};
Self {
ef,
index: start_index,
word_idx,
window,
low_bits: ef.low_bits.into_unchecked_iter_from(start_index),
}
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> UncheckedIterator
for EliasFanoIter<'_, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>,
{
type Item = usize;
#[inline(always)]
unsafe fn next_unchecked(&mut self) -> usize {
while self.window == 0 {
self.word_idx += 1;
debug_assert!(self.word_idx < self.ef.high_bits.as_ref().len());
self.window = unsafe { *self.ef.high_bits.as_ref().get_unchecked(self.word_idx) };
}
let bit_idx = self.window.trailing_zeros() as usize;
let high_bits = (self.word_idx * usize::BITS as usize) + bit_idx - self.index;
self.window &= self.window - 1;
let res = (high_bits << self.ef.l) | unsafe { self.low_bits.next_unchecked() };
self.index += 1;
res
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> Iterator for EliasFanoIter<'_, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>,
{
type Item = usize;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.ef.len() {
return None;
}
Some(unsafe { self.next_unchecked() })
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len(), Some(self.len()))
}
#[inline(always)]
fn count(self) -> usize {
self.ef.len() - self.index
}
#[inline(always)]
fn last(self) -> Option<Self::Item> {
if self.index >= self.ef.n {
return None;
}
let words = self.ef.high_bits.as_ref();
let mut word_idx = words.len() - 1;
while unsafe { *words.get_unchecked(word_idx) } == 0 {
debug_assert!(word_idx > 0);
word_idx -= 1;
}
let word = unsafe { *words.get_unchecked(word_idx) };
let bit_idx = usize::BITS as usize - 1 - word.leading_zeros() as usize;
let high_bits = (word_idx * usize::BITS as usize) + bit_idx - (self.ef.n - 1);
let low = unsafe { self.ef.low_bits.get_value_unchecked(self.ef.n - 1) };
Some((high_bits << self.ef.l) | low)
}
#[inline(always)]
fn fold<B, F>(mut self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
let mut accum = init;
let n = self.ef.len();
while self.index < n {
accum = f(accum, unsafe { self.next_unchecked() });
}
accum
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> ExactSizeIterator
for EliasFanoIter<'_, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>,
{
#[inline(always)]
fn len(&self) -> usize {
self.ef.len() - self.index
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> FusedIterator for EliasFanoIter<'_, H, L> where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>
{
}
impl<'a, H: AsRef<[usize]>, L: SliceByValue<Value = usize>> EliasFanoIter<'a, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize> + IntoUncheckedBackIterator<Item = usize>,
{
pub fn backward(self) -> EliasFanoBackIter<'a, H, L> {
if self.index >= self.ef.n {
return self.ef.iter_back();
}
let original = unsafe { *self.ef.high_bits.as_ref().get_unchecked(self.word_idx) };
EliasFanoBackIter {
ef: self.ef,
index: self.index,
word_idx: self.word_idx,
window: self.window ^ original,
low_bits: self.ef.low_bits.into_unchecked_iter_back_from(self.index),
}
}
}
#[derive(MemDbg, MemSize)]
pub struct EliasFanoBackIter<'a, H: AsRef<[usize]>, L: SliceByValue<Value = usize>>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = usize>,
{
ef: &'a EliasFano<H, L>,
index: usize,
word_idx: usize,
window: usize,
low_bits: <&'a L as IntoUncheckedBackIterator>::IntoUncheckedIterBack,
}
impl<'a, H: AsRef<[usize]>, L: SliceByValue<Value = usize>> EliasFanoBackIter<'a, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize> + IntoUncheckedBackIterator<Item = usize>,
{
pub fn forward(self) -> EliasFanoIter<'a, H, L> {
let window = if self.ef.high_bits.as_ref().is_empty() {
self.window
} else {
self.window ^ unsafe { *self.ef.high_bits.as_ref().get_unchecked(self.word_idx) }
};
EliasFanoIter {
ef: self.ef,
index: self.index,
word_idx: self.word_idx,
window,
low_bits: self.ef.low_bits.into_unchecked_iter_from(self.index),
}
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> UncheckedIterator
for EliasFanoBackIter<'_, H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = usize>,
{
type Item = usize;
#[inline(always)]
unsafe fn next_unchecked(&mut self) -> usize {
while self.window == 0 {
self.word_idx -= 1;
self.window = unsafe { *self.ef.high_bits.as_ref().get_unchecked(self.word_idx) };
}
let bit_idx = usize::BITS as usize - 1 - self.window.leading_zeros() as usize;
self.window ^= 1 << bit_idx;
self.index -= 1;
let high_bits = (self.word_idx * usize::BITS as usize) + bit_idx - self.index;
let low = unsafe { self.low_bits.next_unchecked() };
(high_bits << self.ef.l) | low
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> Iterator for EliasFanoBackIter<'_, H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = usize>,
{
type Item = usize;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.index == 0 {
return None;
}
Some(unsafe { self.next_unchecked() })
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len(), Some(self.len()))
}
#[inline(always)]
fn count(self) -> usize {
self.index
}
#[inline(always)]
fn last(self) -> Option<Self::Item> {
if self.index == 0 {
return None;
}
let words = self.ef.high_bits.as_ref();
let mut word_idx = 0;
while unsafe { *words.get_unchecked(word_idx) } == 0 {
debug_assert!(word_idx + 1 < words.len());
word_idx += 1;
}
let bit_idx = unsafe { *words.get_unchecked(word_idx) }.trailing_zeros() as usize;
let high_bits = (word_idx * usize::BITS as usize) + bit_idx;
let low = unsafe { self.ef.low_bits.get_value_unchecked(0) };
Some((high_bits << self.ef.l) | low)
}
#[inline(always)]
fn fold<B, F>(mut self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
let mut accum = init;
while self.index > 0 {
accum = f(accum, unsafe { self.next_unchecked() });
}
accum
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> ExactSizeIterator
for EliasFanoBackIter<'_, H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = usize>,
{
#[inline(always)]
fn len(&self) -> usize {
self.index
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> FusedIterator
for EliasFanoBackIter<'_, H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = usize>,
{
}
impl<'a, H: AsRef<[usize]>, L: SliceByValue<Value = usize>> IntoIterator for &'a EliasFano<H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = usize>,
{
type Item = usize;
type IntoIter = EliasFanoIter<'a, H, L>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
EliasFanoIter::new(self)
}
}
#[derive(MemDbg, MemSize)]
pub struct EliasFanoBidiIter<'a, H: AsRef<[usize]>, L: SliceByValue<Value = usize>> {
ef: &'a EliasFano<H, L>,
index: usize,
word_idx: usize,
window: usize,
index_in_word: usize,
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> Iterator for EliasFanoBidiIter<'_, H, L> {
type Item = usize;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.ef.n {
return None;
}
while self.index_in_word >= self.window.count_ones() as usize {
self.index_in_word -= self.window.count_ones() as usize;
self.word_idx += 1;
self.window = unsafe { *self.ef.high_bits.as_ref().get_unchecked(self.word_idx) };
}
let bit_idx = self.window.select_in_word(self.index_in_word);
let high_bits = (self.word_idx * usize::BITS as usize) + bit_idx - self.index;
let low = unsafe { self.ef.low_bits.get_value_unchecked(self.index) };
self.index += 1;
self.index_in_word += 1;
Some((high_bits << self.ef.l) | low)
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.ef.n - self.index;
(remaining, Some(remaining))
}
#[inline(always)]
fn count(self) -> usize {
self.ef.n - self.index
}
#[inline(always)]
fn last(self) -> Option<Self::Item> {
if self.index >= self.ef.n {
return None;
}
let words = self.ef.high_bits.as_ref();
let mut word_idx = words.len() - 1;
while unsafe { *words.get_unchecked(word_idx) } == 0 {
debug_assert!(word_idx > 0);
word_idx -= 1;
}
let word = unsafe { *words.get_unchecked(word_idx) };
let bit_idx = usize::BITS as usize - 1 - word.leading_zeros() as usize;
let high_bits = (word_idx * usize::BITS as usize) + bit_idx - (self.ef.n - 1);
let low = unsafe { self.ef.low_bits.get_value_unchecked(self.ef.n - 1) };
Some((high_bits << self.ef.l) | low)
}
#[inline(always)]
fn fold<B, F>(mut self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
let mut accum = init;
while self.index < self.ef.n {
while self.index_in_word >= self.window.count_ones() as usize {
self.index_in_word -= self.window.count_ones() as usize;
self.word_idx += 1;
self.window = unsafe { *self.ef.high_bits.as_ref().get_unchecked(self.word_idx) };
}
let bit_idx = self.window.select_in_word(self.index_in_word);
let high_bits = (self.word_idx * usize::BITS as usize) + bit_idx - self.index;
let low = unsafe { self.ef.low_bits.get_value_unchecked(self.index) };
self.index += 1;
self.index_in_word += 1;
accum = f(accum, (high_bits << self.ef.l) | low);
}
accum
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> ExactSizeIterator
for EliasFanoBidiIter<'_, H, L>
{
#[inline(always)]
fn len(&self) -> usize {
self.ef.n - self.index
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> FusedIterator
for EliasFanoBidiIter<'_, H, L>
{
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> BidiIterator
for EliasFanoBidiIter<'_, H, L>
{
type SwappedIter = SwappedIter<Self>;
#[inline(always)]
fn swap(self) -> SwappedIter<Self> {
SwappedIter(self)
}
#[inline(always)]
fn prev(&mut self) -> Option<usize> {
if self.index == 0 {
return None;
}
while self.index_in_word == 0 {
self.word_idx -= 1;
self.window = unsafe { *self.ef.high_bits.as_ref().get_unchecked(self.word_idx) };
self.index_in_word = self.window.count_ones() as usize;
}
self.index -= 1;
self.index_in_word -= 1;
let bit_idx = self.window.select_in_word(self.index_in_word);
let high_bits = (self.word_idx * usize::BITS as usize) + bit_idx - self.index;
let low = unsafe { self.ef.low_bits.get_value_unchecked(self.index) };
Some((high_bits << self.ef.l) | low)
}
#[inline(always)]
fn prev_size_hint(&self) -> (usize, Option<usize>) {
(self.index, Some(self.index))
}
#[inline(always)]
fn prev_count(self) -> usize {
self.index
}
#[inline(always)]
fn prev_last(self) -> Option<usize> {
if self.index == 0 {
return None;
}
let words = self.ef.high_bits.as_ref();
let mut word_idx = 0;
while unsafe { *words.get_unchecked(word_idx) } == 0 {
debug_assert!(word_idx + 1 < words.len());
word_idx += 1;
}
let bit_idx = unsafe { *words.get_unchecked(word_idx) }.trailing_zeros() as usize;
let high_bits = (word_idx * usize::BITS as usize) + bit_idx;
let low = unsafe { self.ef.low_bits.get_value_unchecked(0) };
Some((high_bits << self.ef.l) | low)
}
#[inline(always)]
fn prev_fold<B, F>(mut self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
let mut accum = init;
while self.index > 0 {
while self.index_in_word == 0 {
self.word_idx -= 1;
self.window = unsafe { *self.ef.high_bits.as_ref().get_unchecked(self.word_idx) };
self.index_in_word = self.window.count_ones() as usize;
}
self.index -= 1;
self.index_in_word -= 1;
let bit_idx = self.window.select_in_word(self.index_in_word);
let high_bits = (self.word_idx * usize::BITS as usize) + bit_idx - self.index;
let low = unsafe { self.ef.low_bits.get_value_unchecked(self.index) };
accum = f(accum, (high_bits << self.ef.l) | low);
}
accum
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> ExactSizeBidiIterator
for EliasFanoBidiIter<'_, H, L>
{
#[inline(always)]
fn prev_len(&self) -> usize {
self.index
}
}
impl<H: AsRef<[usize]>, L: SliceByValue<Value = usize>> FusedBidiIterator
for EliasFanoBidiIter<'_, H, L>
{
}
impl<A: AsRef<[usize]>> From<A> for EliasFano {
fn from(values: A) -> Self {
let values = values.as_ref();
let mut max = 0;
let mut prev = 0;
for &value in values {
if value < prev {
panic!("The values provided are not monotone: {} < {}", value, prev);
}
max = max.max(value);
prev = value;
}
let mut builder = EliasFanoBuilder::new(values.len(), max);
for &value in values {
unsafe {
builder.push_unchecked(value);
}
}
builder.build()
}
}
#[derive(Debug, Clone, MemDbg, MemSize)]
pub struct EliasFanoBuilder {
n: usize,
u: usize,
l: usize,
low_bits: BitFieldVec,
high_bits: BitVec,
last_value: usize,
count: usize,
}
impl EliasFanoBuilder {
pub fn new(n: usize, u: usize) -> Self {
let l = if n > 0 && u >= n {
(u as f64 / n as f64).log2().floor() as usize
} else {
0
};
let num_high_bits = n
.checked_add(1)
.unwrap_or_else(|| panic!("n ({n}) is too large"))
.checked_add(u >> l)
.unwrap_or_else(|| panic!("n ({n}) and/or u ({u}) is too large"));
Self {
n,
u,
l,
low_bits: BitFieldVec::new(l, n),
high_bits: BitVec::new(num_high_bits),
last_value: 0,
count: 0,
}
}
pub fn push(&mut self, value: usize) {
if self.count == self.n {
panic!("Too many values");
}
if value > self.u {
panic!("Value too large: {} > {}", value, self.u);
}
if value < self.last_value {
panic!(
"The values provided are not monotone: {} < {}",
value, self.last_value
);
}
unsafe {
self.push_unchecked(value);
}
}
pub unsafe fn push_unchecked(&mut self, value: usize) {
let low = value & ((1 << self.l) - 1);
self.low_bits.set_value(self.count, low);
let high = (value >> self.l) + self.count;
self.high_bits.set(high, true);
self.count += 1;
self.last_value = value;
}
pub fn count(&self) -> usize {
self.count
}
pub fn build(self) -> EliasFano {
assert!(
self.count == self.n,
"The declared size ({}) is not equal to the number of values ({})",
self.n,
self.count
);
let high_bits: BitVec<Box<[usize]>> = self.high_bits.into();
EliasFano {
n: self.n,
u: self.u,
l: self.l,
low_bits: self.low_bits.into(),
high_bits,
}
}
pub fn build_with_seq(self) -> EfSeq {
let ef = self.build();
unsafe { ef.map_high_bits(SelectAdaptConst::<_, _, 12, 3>::new) }
}
pub fn build_with_dict(self) -> EfDict {
let ef = self.build();
unsafe { ef.map_high_bits(SelectZeroAdaptConst::<_, _, 12, 3>::new) }
}
pub fn build_with_seq_and_dict(self) -> EfSeqDict {
let ef = self.build();
unsafe {
ef.map_high_bits(SelectAdaptConst::<_, _, 12, 3>::new)
.map_high_bits(SelectZeroAdaptConst::<_, _, 12, 3>::new)
}
}
}
impl Extend<usize> for EliasFanoBuilder {
fn extend<T: IntoIterator<Item = usize>>(&mut self, iter: T) {
for value in iter {
self.push(value);
}
}
}
#[derive(MemDbg, MemSize)]
pub struct EliasFanoConcurrentBuilder {
n: usize,
u: usize,
l: usize,
low_bits: AtomicBitFieldVec,
high_bits: AtomicBitVec,
}
impl EliasFanoConcurrentBuilder {
pub fn new(n: usize, u: usize) -> Self {
let l = if n > 0 && u >= n {
(u as f64 / n as f64).log2().floor() as usize
} else {
0
};
Self {
u,
n,
l,
low_bits: AtomicBitFieldVec::new(l, n),
high_bits: AtomicBitVec::new(n + (u >> l) + 1),
}
}
pub unsafe fn set(&self, index: usize, value: usize) {
let low = value & ((1 << self.l) - 1);
unsafe {
self.low_bits
.set_atomic_unchecked(index, low, Ordering::Relaxed)
};
let high = (value >> self.l) + index;
self.high_bits.set(high, true, Ordering::Relaxed);
}
pub fn build(self) -> EliasFano {
let high_bits: BitVec<Box<[usize]>> = self.high_bits.into();
let low_bits: BitFieldVec<usize, Vec<usize>> = self.low_bits.into();
let low_bits: BitFieldVec<usize, Box<[usize]>> = low_bits.into();
EliasFano {
n: self.n,
u: self.u,
l: self.l,
low_bits,
high_bits,
}
}
pub fn build_with_seq(self) -> EfSeq {
let ef = self.build();
unsafe { ef.map_high_bits(SelectAdaptConst::<_, _, 12, 3>::new) }
}
pub fn build_with_dict(self) -> EfDict {
let ef = self.build();
unsafe { ef.map_high_bits(SelectZeroAdaptConst::<_, _, 12, 3>::new) }
}
pub fn build_with_seq_and_dict(self) -> EfSeqDict {
let ef = self.build();
unsafe {
ef.map_high_bits(SelectAdaptConst::<_, _, 12, 3>::new)
.map_high_bits(SelectZeroAdaptConst::<_, _, 12, 3>::new)
}
}
}