use crate::prelude::{indexed_dict::*, *};
use crate::traits::{AtomicBitVecOps, BitVecOpsMut, TryIntoUnaligned, Word, bit_field_slice::*};
use crate::utils::SelectInWord;
use atomic_primitive::{Atomic, AtomicPrimitive, PrimitiveAtomicUnsigned};
use core::sync::atomic::Ordering;
use mem_dbg::*;
use num_primitive::PrimitiveNumberAs;
use std::borrow::Borrow;
use std::iter::FusedIterator;
use value_traits::slices::{SliceByValue, SliceByValueMut};
pub type EfSeq<V = usize> =
EliasFano<V, SelectAdaptConst<BitVec<Box<[usize]>>, Box<[usize]>, 12, 3>>;
pub type EfDict<V = usize> =
EliasFano<V, SelectZeroAdaptConst<BitVec<Box<[usize]>>, Box<[usize]>, 12, 3>>;
pub type EfSeqDict<V = usize> = EliasFano<
V,
SelectZeroAdaptConst<
SelectAdaptConst<BitVec<Box<[usize]>>, Box<[usize]>, 12, 3>,
Box<[usize]>,
12,
3,
>,
>;
#[derive(Debug, Clone, Hash, MemSize, MemDbg, value_traits::Subslices)]
#[cfg_attr(feature = "epserde", derive(epserde::Epserde))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[value_traits_subslices(bound = "V: Word + PrimitiveNumberAs<usize>")]
#[value_traits_subslices(bound = "H: AsRef<[usize]> + SelectUnchecked")]
#[value_traits_subslices(bound = "L: SliceByValue<Value = V>")]
pub struct EliasFano<V = usize, H = BitVec<Box<[usize]>>, L = BitFieldVec<Box<[V]>>> {
n: usize,
u: V,
l: usize,
first_val: V,
last_val: V,
low_bits: L,
high_bits: H,
}
impl<V, H, L> EliasFano<V, H, L> {
pub fn into_parts(self) -> (usize, V, usize, L, H, V, V) {
(
self.n,
self.u,
self.l,
self.low_bits,
self.high_bits,
self.first_val,
self.last_val,
)
}
pub fn estimate_size(u: u64, n: usize) -> usize {
2 * n + (n * (u as f64 / n as f64).log2().ceil() as usize)
}
#[inline]
pub const fn len(&self) -> usize {
self.n
}
#[inline]
pub fn upper_bound(&self) -> V
where
V: Copy,
{
self.u
}
pub unsafe fn map_high_bits<H2>(self, func: impl FnOnce(H) -> H2) -> EliasFano<V, H2, L> {
EliasFano {
n: self.n,
u: self.u,
l: self.l,
first_val: self.first_val,
last_val: self.last_val,
low_bits: self.low_bits,
high_bits: func(self.high_bits),
}
}
pub unsafe fn map_low_bits<L2>(self, func: impl FnOnce(L) -> L2) -> EliasFano<V, H, L2> {
EliasFano {
n: self.n,
u: self.u,
l: self.l,
first_val: self.first_val,
last_val: self.last_val,
low_bits: func(self.low_bits),
high_bits: self.high_bits,
}
}
}
impl<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>> Types
for EliasFano<V, H, L>
{
type Output<'a> = V;
type Input = V;
}
impl<
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> IndexedSeq for EliasFano<V, H, L>
{
#[inline]
fn len(&self) -> usize {
self.n
}
#[inline(always)]
unsafe fn get_unchecked(&self, index: usize) -> V {
unsafe {
let high_bits = V::as_from(self.high_bits.select_unchecked(index) - index);
let low_bits = self.low_bits.get_value_unchecked(index);
(high_bits << self.l) | low_bits
}
}
#[inline]
fn first_value(&self) -> Option<V> {
(self.n != 0).then_some(self.first_val)
}
#[inline]
fn last_value(&self) -> Option<V> {
(self.n != 0).then_some(self.last_val)
}
}
impl<
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectZeroUnchecked,
L: SliceByValue<Value = V>,
> IndexedDict for EliasFano<V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
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: usize = (value >> self.l).try_into().unwrap();
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 = (V::as_from(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<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
EliasFano<V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
#[inline(always)]
pub fn iter(&self) -> EliasFanoIter<'_, V, H, L> {
EliasFanoIter::new(self)
}
}
impl<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
EliasFano<V, H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = V>,
{
pub fn iter_back(&self) -> EliasFanoBackIter<'_, V, 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<
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> EliasFano<V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
#[inline(always)]
pub fn iter_from(&self, from: usize) -> EliasFanoIter<'_, V, H, L> {
EliasFanoIter::new_from(self, from)
}
}
impl<
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> EliasFano<V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V> + IntoUncheckedBackIterator<Item = V>,
{
#[inline(always)]
pub fn iter_back_from(&self, from: usize) -> EliasFanoBackIter<'_, V, H, L> {
self.iter_from(from).backward()
}
}
impl<
'a,
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> IntoIteratorFrom for &'a EliasFano<V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
type IntoIterFrom = EliasFanoIter<'a, V, H, L>;
#[inline(always)]
fn into_iter_from(self, from: usize) -> EliasFanoIter<'a, V, H, L> {
EliasFanoIter::new_from(self, from)
}
}
impl<
'a,
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> IntoBidiIterator for &'a EliasFano<V, H, L>
{
type Item = V;
type IntoIterBidi = EliasFanoBidiIter<'a, V, H, L>;
#[inline(always)]
fn into_iter_bidi(self) -> EliasFanoBidiIter<'a, V, H, L> {
self.into_iter_bidi_from(0)
}
}
impl<
'a,
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> IntoBidiIteratorFrom for &'a EliasFano<V, H, L>
{
type IntoIterBidiFrom = EliasFanoBidiIter<'a, V, H, L>;
#[inline(always)]
fn into_iter_bidi_from(self, from: usize) -> EliasFanoBidiIter<'a, V, 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, V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
IntoBackIterator for &'a EliasFano<V, H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = V>,
{
type Item = V;
type IntoIterBack = EliasFanoBackIter<'a, V, H, L>;
#[inline(always)]
fn into_iter_back(self) -> EliasFanoBackIter<'a, V, H, L> {
self.iter_back()
}
}
impl<
'a,
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> IntoBackIteratorFrom for &'a EliasFano<V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V> + IntoUncheckedBackIterator<Item = V>,
{
type IntoIterBackFrom = EliasFanoBackIter<'a, V, H, L>;
#[inline(always)]
fn into_iter_back_from(self, from: usize) -> EliasFanoBackIter<'a, V, H, L> {
self.iter_back_from(from + 1)
}
}
impl<
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> EliasFano<V, H, L>
{
#[inline(always)]
pub fn iter_bidi(&self) -> EliasFanoBidiIter<'_, V, H, L> {
self.into_iter_bidi()
}
#[inline(always)]
pub fn iter_bidi_from(&self, from: usize) -> EliasFanoBidiIter<'_, V, H, L> {
self.into_iter_bidi_from(from)
}
}
impl<
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectZeroUnchecked,
L: SliceByValue<Value = V>,
> SuccUnchecked for EliasFano<V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
type Iter<'a>
= EliasFanoIter<'a, V, H, L>
where
Self: 'a;
type BidiIter<'a>
= EliasFanoBidiIter<'a, V, 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: usize = (value >> self.l).try_into().unwrap();
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 = (V::as_from(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: usize = (value >> self.l).try_into().unwrap();
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 = (V::as_from(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: usize = (value >> self.l).try_into().unwrap();
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 = (V::as_from(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<
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectZeroUnchecked,
L: SliceByValue<Value = V>,
> Succ for EliasFano<V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
#[inline]
fn succ(&self, value: impl Borrow<V>) -> Option<(usize, V)> {
if self.n == 0 || *value.borrow() > self.last_val {
None
} else {
Some(unsafe { self.succ_unchecked::<false>(value) })
}
}
#[inline]
fn succ_strict(&self, value: impl Borrow<V>) -> Option<(usize, V)> {
if *value.borrow() >= self.last_val {
None
} else {
Some(unsafe { self.succ_unchecked::<true>(value) })
}
}
#[inline]
fn iter_from_succ(
&self,
value: impl Borrow<V>,
) -> Option<(usize, <Self as SuccUnchecked>::Iter<'_>)> {
if self.n == 0 || *value.borrow() > self.last_val {
None
} else {
Some(unsafe { self.iter_from_succ_unchecked::<false>(value) })
}
}
#[inline]
fn iter_from_succ_strict(
&self,
value: impl Borrow<V>,
) -> Option<(usize, <Self as SuccUnchecked>::Iter<'_>)> {
if *value.borrow() >= self.last_val {
None
} else {
Some(unsafe { self.iter_from_succ_unchecked::<true>(value) })
}
}
#[inline]
fn iter_bidi_from_succ(
&self,
value: impl Borrow<V>,
) -> Option<(usize, <Self as SuccUnchecked>::BidiIter<'_>)> {
if self.n == 0 || *value.borrow() > self.last_val {
None
} else {
Some(unsafe { self.iter_bidi_from_succ_unchecked::<false>(value) })
}
}
#[inline]
fn iter_bidi_from_succ_strict(
&self,
value: impl Borrow<V>,
) -> Option<(usize, <Self as SuccUnchecked>::BidiIter<'_>)> {
if *value.borrow() >= self.last_val {
None
} else {
Some(unsafe { self.iter_bidi_from_succ_unchecked::<true>(value) })
}
}
}
impl<
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectZeroUnchecked,
L: SliceByValue<Value = V>,
> PredUnchecked for EliasFano<V, H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = V>,
{
type BackIter<'a>
= EliasFanoBackIter<'a, V, H, L>
where
Self: 'a;
type BidiIter<'a>
= EliasFanoBidiIter<'a, V, 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: usize = (value >> self.l).try_into().unwrap();
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,
(V::as_from(
(usize::BITS as usize) - 1 + bit_pos
- zeros
- window.leading_zeros() as usize
- rank,
) << self.l)
| lower_bits,
);
}
let low_value = value & ((V::ONE << self.l) - V::ONE);
let found = if STRICT {
lower_bits < low_value
} else {
lower_bits <= low_value
};
if found {
return (rank, (V::as_from(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: usize = (value >> self.l).try_into().unwrap();
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 & ((V::ONE << self.l) - V::ONE);
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: usize = (value >> self.l).try_into().unwrap();
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 & ((V::ONE << self.l) - V::ONE);
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<
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectZeroUnchecked,
L: SliceByValue<Value = V>,
> Pred for EliasFano<V, H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = V>,
{
#[inline]
fn pred(&self, value: impl Borrow<V>) -> Option<(usize, V)> {
if self.n == 0 || *value.borrow() < self.first_val {
None
} else {
Some(unsafe { self.pred_unchecked::<false>(value) })
}
}
#[inline]
fn pred_strict(&self, value: impl Borrow<V>) -> Option<(usize, V)> {
if *value.borrow() <= self.first_val {
None
} else {
Some(unsafe { self.pred_unchecked::<true>(value) })
}
}
#[inline]
fn iter_back_from_pred(
&self,
value: impl Borrow<V>,
) -> Option<(usize, <Self as PredUnchecked>::BackIter<'_>)> {
if self.n == 0 || *value.borrow() < self.first_val {
None
} else {
Some(unsafe { self.iter_back_from_pred_unchecked::<false>(value) })
}
}
#[inline]
fn iter_back_from_pred_strict(
&self,
value: impl Borrow<V>,
) -> Option<(usize, <Self as PredUnchecked>::BackIter<'_>)> {
if *value.borrow() <= self.first_val {
None
} else {
Some(unsafe { self.iter_back_from_pred_unchecked::<true>(value) })
}
}
#[inline]
fn iter_bidi_from_pred(
&self,
value: impl Borrow<V>,
) -> Option<(usize, <Self as PredUnchecked>::BidiIter<'_>)> {
if self.n == 0 || *value.borrow() < self.first_val {
None
} else {
Some(unsafe { self.iter_bidi_from_pred_unchecked::<false>(value) })
}
}
#[inline]
fn iter_bidi_from_pred_strict(
&self,
value: impl Borrow<V>,
) -> Option<(usize, <Self as PredUnchecked>::BidiIter<'_>)> {
if *value.borrow() <= self.first_val {
None
} else {
Some(unsafe { self.iter_bidi_from_pred_unchecked::<true>(value) })
}
}
}
impl<
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> value_traits::slices::SliceByValue for EliasFano<V, H, L>
{
type Value = V;
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,
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> value_traits::iter::IterateByValueGat<'a> for EliasFano<V, H, L>
where
for<'c> &'c L: IntoUncheckedIterator<Item = V>,
{
type Item = V;
type Iter = EliasFanoIter<'a, V, H, L>;
}
impl<
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> value_traits::iter::IterateByValue for EliasFano<V, H, L>
where
for<'c> &'c L: IntoUncheckedIterator<Item = V>,
{
fn iter_value(&self) -> <Self as value_traits::iter::IterateByValueGat<'_>>::Iter {
self.iter_from(0)
}
}
impl<
'a,
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> value_traits::iter::IterateByValueFromGat<'a> for EliasFano<V, H, L>
where
for<'c> &'c L: IntoUncheckedIterator<Item = V>,
{
type Item = V;
type IterFrom = EliasFanoIter<'a, V, H, L>;
}
impl<
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> value_traits::iter::IterateByValueFrom for EliasFano<V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
fn iter_value_from(
&self,
from: usize,
) -> <Self as value_traits::iter::IterateByValueGat<'_>>::Iter {
self.iter_from(from)
}
}
impl<
'a,
'b,
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> value_traits::iter::IterateByValueGat<'a> for EliasFanoSubsliceImpl<'b, V, H, L>
where
for<'c> &'c L: IntoUncheckedIterator<Item = V>,
{
type Item = V;
type Iter = EliasFanoIter<'a, V, H, L>;
}
impl<
'a,
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> value_traits::iter::IterateByValue for EliasFanoSubsliceImpl<'a, V, H, L>
where
for<'c> &'c L: IntoUncheckedIterator<Item = V>,
{
fn iter_value(&self) -> <Self as value_traits::iter::IterateByValueGat<'_>>::Iter {
self.slice.iter_from(0)
}
}
impl<
'a,
'b,
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> value_traits::iter::IterateByValueFromGat<'a> for EliasFanoSubsliceImpl<'b, V, H, L>
where
for<'c> &'c L: IntoUncheckedIterator<Item = V>,
{
type Item = V;
type IterFrom = EliasFanoIter<'a, V, H, L>;
}
impl<
'a,
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> value_traits::iter::IterateByValueFrom for EliasFanoSubsliceImpl<'a, V, H, L>
where
for<'c> &'c L: IntoUncheckedIterator<Item = V>,
{
fn iter_value_from(
&self,
from: usize,
) -> <Self as value_traits::iter::IterateByValueGat<'_>>::Iter {
self.slice.iter_from(from)
}
}
#[derive(MemSize, MemDbg)]
pub struct EliasFanoIter<
'a,
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]>,
L: SliceByValue<Value = V>,
> where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
ef: &'a EliasFano<V, H, L>,
index: usize,
word_idx: usize,
window: usize,
low_bits: <&'a L as IntoUncheckedIterator>::IntoUncheckedIter,
}
impl<'a, V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
EliasFanoIter<'a, V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
pub fn new(ef: &'a EliasFano<V, 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,
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]> + SelectUnchecked,
L: SliceByValue<Value = V>,
> EliasFanoIter<'a, V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
pub fn new_from(ef: &'a EliasFano<V, 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<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
UncheckedIterator for EliasFanoIter<'_, V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
type Item = V;
#[inline(always)]
unsafe fn next_unchecked(&mut self) -> V {
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 = V::as_from(high_bits) << self.ef.l | unsafe { self.low_bits.next_unchecked() };
self.index += 1;
res
}
}
impl<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>> Iterator
for EliasFanoIter<'_, V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
type Item = V;
#[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(V::as_from(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<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
ExactSizeIterator for EliasFanoIter<'_, V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
#[inline(always)]
fn len(&self) -> usize {
self.ef.len() - self.index
}
}
impl<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
FusedIterator for EliasFanoIter<'_, V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
}
impl<'a, V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
EliasFanoIter<'a, V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V> + IntoUncheckedBackIterator<Item = V>,
{
pub fn backward(self) -> EliasFanoBackIter<'a, V, 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(MemSize, MemDbg)]
pub struct EliasFanoBackIter<
'a,
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]>,
L: SliceByValue<Value = V>,
> where
for<'b> &'b L: IntoUncheckedBackIterator<Item = V>,
{
ef: &'a EliasFano<V, H, L>,
index: usize,
word_idx: usize,
window: usize,
low_bits: <&'a L as IntoUncheckedBackIterator>::IntoUncheckedIterBack,
}
impl<'a, V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
EliasFanoBackIter<'a, V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V> + IntoUncheckedBackIterator<Item = V>,
{
pub fn forward(self) -> EliasFanoIter<'a, V, 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<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
UncheckedIterator for EliasFanoBackIter<'_, V, H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = V>,
{
type Item = V;
#[inline(always)]
unsafe fn next_unchecked(&mut self) -> V {
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_usize) << 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() };
V::as_from(high_bits) << self.ef.l | low
}
}
impl<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>> Iterator
for EliasFanoBackIter<'_, V, H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = V>,
{
type Item = V;
#[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(V::as_from(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<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
ExactSizeIterator for EliasFanoBackIter<'_, V, H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = V>,
{
#[inline(always)]
fn len(&self) -> usize {
self.index
}
}
impl<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
FusedIterator for EliasFanoBackIter<'_, V, H, L>
where
for<'b> &'b L: IntoUncheckedBackIterator<Item = V>,
{
}
impl<'a, V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
IntoIterator for &'a EliasFano<V, H, L>
where
for<'b> &'b L: IntoUncheckedIterator<Item = V>,
{
type Item = V;
type IntoIter = EliasFanoIter<'a, V, H, L>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
EliasFanoIter::new(self)
}
}
#[derive(Debug, Clone, MemSize, MemDbg)]
pub struct EliasFanoBidiIter<
'a,
V: Word + PrimitiveNumberAs<usize>,
H: AsRef<[usize]>,
L: SliceByValue<Value = V>,
> {
ef: &'a EliasFano<V, H, L>,
index: usize,
word_idx: usize,
window: usize,
index_in_word: usize,
}
impl<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>> Iterator
for EliasFanoBidiIter<'_, V, H, L>
{
type Item = V;
#[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((V::as_from(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((V::as_from(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, (V::as_from(high_bits) << self.ef.l) | low);
}
accum
}
}
impl<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
ExactSizeIterator for EliasFanoBidiIter<'_, V, H, L>
{
#[inline(always)]
fn len(&self) -> usize {
self.ef.n - self.index
}
}
impl<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
FusedIterator for EliasFanoBidiIter<'_, V, H, L>
{
}
impl<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>> BidiIterator
for EliasFanoBidiIter<'_, V, H, L>
{
type SwappedIter = SwappedIter<Self>;
#[inline(always)]
fn swap(self) -> SwappedIter<Self> {
SwappedIter(self)
}
#[inline(always)]
fn prev(&mut self) -> Option<V> {
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((V::as_from(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<V> {
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((V::as_from(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, (V::as_from(high_bits) << self.ef.l) | low);
}
accum
}
}
impl<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
ExactSizeBidiIterator for EliasFanoBidiIter<'_, V, H, L>
{
#[inline(always)]
fn prev_len(&self) -> usize {
self.index
}
}
impl<V: Word + PrimitiveNumberAs<usize>, H: AsRef<[usize]>, L: SliceByValue<Value = V>>
FusedBidiIterator for EliasFanoBidiIter<'_, V, H, L>
{
}
impl<V: Word + PrimitiveNumberAs<usize>, A: AsRef<[V]>> From<A>
for EliasFano<V, BitVec<Box<[usize]>>, BitFieldVec<Box<[V]>>>
{
fn from(values: A) -> Self {
let values = values.as_ref();
let mut max = V::ZERO;
let mut prev = V::ZERO;
for &value in values {
if value < prev {
panic!("The values provided are not monotone");
}
max = max.max(value);
prev = value;
}
let mut builder = EliasFanoBuilder::<V>::new(values.len(), max);
for &value in values {
unsafe {
builder.push_unchecked(value);
}
}
builder.build()
}
}
#[derive(Debug, Clone, MemSize, MemDbg)]
pub struct EliasFanoBuilder<V: Word = usize> {
n: usize,
u: V,
l: usize,
low_bits: BitFieldVec<Vec<V>>,
high_bits: BitVec,
first_val: V,
last_val: V,
count: usize,
}
impl<V: Word + PrimitiveNumberAs<u128>> EliasFanoBuilder<V> {
#[must_use]
pub fn new(n: usize, u: V) -> Self {
let n_u128 = n as u128;
let u_u128: u128 = u.as_to();
let l = if n_u128 > 0 && u_u128 >= n_u128 {
(u_u128 / n_u128).ilog2() as usize
} else {
0
};
let u_high: usize = (u >> l).try_into().unwrap_or(usize::MAX);
let num_high_bits = n
.checked_add(1)
.unwrap_or_else(|| panic!("n ({n}) is too large"))
.checked_add(u_high)
.unwrap_or_else(|| panic!("n ({n}) and/or u {u} is too large"));
Self {
n,
u,
l,
low_bits: BitFieldVec::<Vec<V>>::new(l, n),
high_bits: BitVec::new(num_high_bits),
first_val: V::MAX,
last_val: V::MIN,
count: 0,
}
}
pub fn push(&mut self, value: V) {
if self.count == self.n {
panic!("Too many values");
}
if value > self.u {
panic!("Value too large");
}
if value < self.last_val {
panic!("The values provided are not monotone");
}
unsafe {
self.push_unchecked(value);
}
}
pub unsafe fn push_unchecked(&mut self, value: V) {
let low = value & ((V::ONE << self.l) - V::ONE);
self.low_bits.set_value(self.count, low);
let high: usize = (value >> self.l).try_into().unwrap_or(usize::MAX);
let high = high + self.count;
self.high_bits.set(high, true);
if self.count == 0 {
self.first_val = value;
}
self.count += 1;
self.last_val = value;
}
pub fn count(&self) -> usize {
self.count
}
#[must_use]
pub fn build(self) -> EliasFano<V> {
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,
first_val: self.first_val,
last_val: self.last_val,
low_bits: self.low_bits.into(),
high_bits,
}
}
}
impl<V: Word + PrimitiveNumberAs<usize>> EliasFanoBuilder<V> {
#[must_use]
pub fn build_with_seq(self) -> EfSeq<V> {
let ef = self.build();
unsafe { ef.map_high_bits(SelectAdaptConst::<_, _, 12, 3>::new) }
}
#[must_use]
pub fn build_with_dict(self) -> EfDict<V> {
let ef = self.build();
unsafe { ef.map_high_bits(SelectZeroAdaptConst::<_, _, 12, 3>::new) }
}
#[must_use]
pub fn build_with_seq_and_dict(self) -> EfSeqDict<V> {
let ef = self.build();
unsafe {
ef.map_high_bits(SelectAdaptConst::<_, _, 12, 3>::new)
.map_high_bits(SelectZeroAdaptConst::<_, _, 12, 3>::new)
}
}
}
impl<V: Word + PrimitiveNumberAs<usize>> Extend<V> for EliasFanoBuilder<V> {
fn extend<T: IntoIterator<Item = V>>(&mut self, iter: T) {
for value in iter {
self.push(value);
}
}
}
#[derive(MemSize, MemDbg)]
pub struct EliasFanoConcurrentBuilder<V: Word + AtomicPrimitive>
where
Atomic<V>: PrimitiveAtomicUnsigned,
{
n: usize,
u: V,
l: usize,
low_bits: AtomicBitFieldVec<Vec<Atomic<V>>>,
high_bits: AtomicBitVec,
}
impl<V: Word + AtomicPrimitive + PrimitiveNumberAs<u128>> EliasFanoConcurrentBuilder<V>
where
Atomic<V>: PrimitiveAtomicUnsigned,
{
#[must_use]
pub fn new(n: usize, u: V) -> Self {
let n_u128 = n as u128;
let u_u128: u128 = u.as_to();
let l = if n_u128 > 0 && u_u128 >= n_u128 {
(u_u128 / n_u128).ilog2() as usize
} else {
0
};
let u_high: usize = (u >> l).try_into().unwrap_or(usize::MAX);
let num_high_bits = n
.checked_add(1)
.unwrap_or_else(|| panic!("n ({n}) is too large"))
.checked_add(u_high)
.unwrap_or_else(|| panic!("n ({n}) and/or u ({u}) is too large"));
Self {
n,
u,
l,
low_bits: AtomicBitFieldVec::<Vec<Atomic<V>>>::new(l, n),
high_bits: AtomicBitVec::new(num_high_bits),
}
}
pub unsafe fn set(&self, index: usize, value: V)
where
V: PrimitiveNumberAs<usize>,
{
let low = value & ((V::ONE << self.l) - V::ONE);
unsafe {
self.low_bits
.set_atomic_unchecked(index, low, Ordering::Relaxed)
};
let high = (value >> self.l).as_to::<usize>() + index;
self.high_bits.set(high, true, Ordering::Relaxed);
}
#[must_use]
pub fn build(self) -> EliasFano<V> {
let high_bits: BitVec<Box<[usize]>> = self.high_bits.into();
let low_bits: BitFieldVec<Vec<V>> = self.low_bits.into();
let low_bits: BitFieldVec<Box<[V]>> = low_bits.into();
let (first_val, last_val) = if self.n == 0 {
(V::MAX, V::MIN)
} else {
let words = high_bits.as_ref();
let mut w = 0;
while unsafe { *words.get_unchecked(w) } == 0 {
w += 1;
}
let first_high = w * usize::BITS as usize
+ unsafe { *words.get_unchecked(w) }.trailing_zeros() as usize;
let first_low = unsafe { low_bits.get_value_unchecked(0) };
let first = (V::as_from(first_high) << self.l) | first_low;
let mut w = words.len() - 1;
while unsafe { *words.get_unchecked(w) } == 0 {
w -= 1;
}
let last_high = w * usize::BITS as usize + usize::BITS as usize
- 1
- unsafe { *words.get_unchecked(w) }.leading_zeros() as usize
- (self.n - 1);
let last_low = unsafe { low_bits.get_value_unchecked(self.n - 1) };
let last = (V::as_from(last_high) << self.l) | last_low;
(first, last)
};
EliasFano {
n: self.n,
u: self.u,
l: self.l,
first_val,
last_val,
low_bits,
high_bits,
}
}
#[must_use]
pub fn build_with_seq(self) -> EfSeq<V> {
let ef = self.build();
unsafe { ef.map_high_bits(SelectAdaptConst::<_, _, 12, 3>::new) }
}
#[must_use]
pub fn build_with_dict(self) -> EfDict<V> {
let ef = self.build();
unsafe { ef.map_high_bits(SelectZeroAdaptConst::<_, _, 12, 3>::new) }
}
#[must_use]
pub fn build_with_seq_and_dict(self) -> EfSeqDict<V> {
let ef = self.build();
unsafe {
ef.map_high_bits(SelectAdaptConst::<_, _, 12, 3>::new)
.map_high_bits(SelectZeroAdaptConst::<_, _, 12, 3>::new)
}
}
}
use crate::traits::Unaligned;
impl<V: Word, H> TryIntoUnaligned for EliasFano<V, H, BitFieldVec<Box<[V]>>> {
type Unaligned = EliasFano<V, H, Unaligned<BitFieldVec<Box<[V]>>>>;
fn try_into_unaligned(
self,
) -> Result<Self::Unaligned, crate::traits::UnalignedConversionError> {
Ok(EliasFano {
n: self.n,
u: self.u,
l: self.l,
first_val: self.first_val,
last_val: self.last_val,
low_bits: self.low_bits.try_into_unaligned()?,
high_bits: self.high_bits,
})
}
}
impl<V: Word, H> From<Unaligned<EliasFano<V, H, BitFieldVec<Box<[V]>>>>>
for EliasFano<V, H, BitFieldVec<Box<[V]>>>
{
fn from(ef: Unaligned<EliasFano<V, H, BitFieldVec<Box<[V]>>>>) -> Self {
EliasFano {
n: ef.n,
u: ef.u,
l: ef.l,
first_val: ef.first_val,
last_val: ef.last_val,
low_bits: ef.low_bits.into(),
high_bits: ef.high_bits,
}
}
}