mod utils;
mod select;
use std::ops::Deref;
use self::select::{U64_PER_L1_ENTRY, U64_PER_L2_ENTRY, U64_PER_L2_RECORDS};
pub use self::select::{Select, Select0, BinaryRankSearch, CombinedSampling,
ConstCombinedSamplingDensity, AdaptiveCombinedSamplingDensity, SelectForRank101111, Select0ForRank101111,
select64, optimal_combined_sampling};
use super::{ceiling_div, n_lowest_bits};
use dyn_size_of::GetSize;
pub trait Rank {
fn try_rank(&self, index: usize) -> Option<usize>;
#[inline] fn rank(&self, index: usize) -> usize {
self.try_rank(index).expect("rank index out of bound")
}
#[inline] unsafe fn rank_unchecked(&self, index: usize) -> usize {
self.rank(index)
}
#[inline] fn try_rank0(&self, index: usize) -> Option<usize> {
self.try_rank(index).map(|r| index-r)
}
#[inline] fn rank0(&self, index: usize) -> usize { index - self.rank(index) }
#[inline] unsafe fn rank0_unchecked(&self, index: usize) -> usize {
index - self.rank_unchecked(index)
}
}
#[inline] fn count_bits_in(content: &[u64]) -> usize {
let mut it = content.iter().map(|v| v.count_ones() as usize);
let mut result = 0;
if let Some(v) = it.next() { result += v; } else { return result; }
if let Some(v) = it.next() { result += v; } else { return result; }
if let Some(v) = it.next() { result += v; } else { return result; }
if let Some(v) = it.next() { result += v; } else { return result; }
if let Some(v) = it.next() { result += v; } else { return result; }
if let Some(v) = it.next() { result += v; } else { return result; }
if let Some(v) = it.next() { result += v; } else { return result; }
if let Some(v) = it.next() { result += v; }
return result;
}
#[derive(Clone)]
pub struct RankSelect101111<Select = BinaryRankSearch, Select0 = BinaryRankSearch, BV = Box::<[u64]>> {
pub content: BV, #[cfg(target_pointer_width = "64")] pub l1ranks: Box<[usize]>, pub l2ranks: Box<[u64]>, select: Select, select0: Select0, }
impl<S, S0, BV> RankSelect101111<S, S0, BV> {
#[inline] pub fn select_support(&self) -> &S { &self.select }
#[inline] pub fn select0_support(&self) -> &S0 { &self.select0 }
}
impl<S: GetSize, S0: GetSize, BV: GetSize> GetSize for RankSelect101111<S, S0, BV> {
#[cfg(target_pointer_width = "64")]
fn size_bytes_dyn(&self) -> usize {
self.content.size_bytes_dyn() + self.l2ranks.size_bytes_dyn() + self.l1ranks.size_bytes_dyn() + self.select.size_bytes_dyn() + self.select0.size_bytes_dyn()
}
#[cfg(target_pointer_width = "32")]
fn size_bytes_dyn(&self) -> usize {
self.content.size_bytes_dyn() + self.l2ranks.size_bytes_dyn() + self.select.size_bytes_dyn() + self.select0.size_bytes_dyn()
}
const USES_DYN_MEM: bool = true;
}
impl<S: SelectForRank101111, S0: Select0ForRank101111, BV: Deref<Target = [u64]>> From<BV> for RankSelect101111<S, S0, BV> {
#[inline] fn from(value: BV) -> Self { Self::build(value).0 }
}
impl<S: SelectForRank101111, S0, BV: Deref<Target = [u64]>> Select for RankSelect101111<S, S0, BV> {
#[inline] fn try_select(&self, rank: usize) -> Option<usize> {
self.select.select(&self.content, #[cfg(target_pointer_width = "64")] &self.l1ranks, &self.l2ranks, rank)
}
#[inline] unsafe fn select_unchecked(&self, rank: usize) -> usize {
self.select.select_unchecked(&self.content, #[cfg(target_pointer_width = "64")] &self.l1ranks, &self.l2ranks, rank)
}
}
impl<S, S0: Select0ForRank101111, BV: Deref<Target = [u64]>> Select0 for RankSelect101111<S, S0, BV> {
#[inline] fn try_select0(&self, rank: usize) -> Option<usize> {
self.select0.select0(&self.content, #[cfg(target_pointer_width = "64")] &self.l1ranks, &self.l2ranks, rank)
}
#[inline] unsafe fn select0_unchecked(&self, rank: usize) -> usize {
self.select0.select0_unchecked(&self.content, #[cfg(target_pointer_width = "64")] &self.l1ranks, &self.l2ranks, rank)
}
}
impl<S: SelectForRank101111, S0: Select0ForRank101111, BV: Deref<Target = [u64]>> Rank for RankSelect101111<S, S0, BV> {
#[inline] fn try_rank(&self, index: usize) -> Option<usize> {
let block = index / 512;
let word_idx = index / 64;
let mut r = (self.content.get(word_idx)? & n_lowest_bits(index as u8 % 64)).count_ones() as usize;
let block_content = *unsafe{ self.l2ranks.get_unchecked(index/2048) }; #[cfg(target_pointer_width = "64")] { r += unsafe{ *self.l1ranks.get_unchecked(index >> 32) } + (block_content & 0xFFFFFFFFu64) as usize; } #[cfg(target_pointer_width = "32")] { r += (block_content & 0xFFFFFFFFu64) as usize; }
r += (((block_content >> (11 * (!block & 3))) >> 32) & 0b1_11111_11111) as usize;
Some(r + count_bits_in(unsafe {self.content.get_unchecked(word_idx&!7..word_idx)}))
}
#[inline] unsafe fn rank_unchecked(&self, index: usize) -> usize {
let block = index / 512;
let word_idx = index / 64;
let block_content = *unsafe{ self.l2ranks.get_unchecked(index/2048) };
#[cfg(target_pointer_width = "64")] let mut r = *self.l1ranks.get_unchecked(index >> 32) + (block_content & 0xFFFFFFFFu64) as usize; #[cfg(target_pointer_width = "32")] let mut r = (block_content & 0xFFFFFFFFu64) as usize;
r += (self.content.get_unchecked(word_idx) & n_lowest_bits(index as u8 % 64)).count_ones() as usize;
r += (((block_content >> (11 * (!block & 3))) >> 32) & 0b1_11111_11111) as usize;
r + count_bits_in(self.content.get_unchecked(word_idx&!7..word_idx))
}
}
impl<S: SelectForRank101111, S0: Select0ForRank101111, BV: Deref<Target = [u64]>> RankSelect101111<S, S0, BV> {
pub fn build(content: BV) -> (Self, usize) {
#[cfg(target_pointer_width = "64")] let mut l1ranks = Vec::with_capacity(ceiling_div(content.len(), U64_PER_L1_ENTRY));
let mut l2ranks = Vec::with_capacity(ceiling_div(content.len(), U64_PER_L2_ENTRY));
let mut current_total_rank: usize = 0;
for content in content.chunks(U64_PER_L1_ENTRY) { #[cfg(target_pointer_width = "64")] l1ranks.push(current_total_rank);
let mut current_rank: u64 = 0;
for chunk in content.chunks(U64_PER_L2_ENTRY) { let mut to_append = current_rank;
let mut vals = chunk.chunks(U64_PER_L2_RECORDS).map(|c| count_bits_in(c)); if let Some(v) = vals.next() {
let mut chunk_sum = v as u64; to_append |= chunk_sum << (32+11+11);
if let Some(v) = vals.next() {
chunk_sum += v as u64; to_append |= chunk_sum << (32+11);
if let Some(v) = vals.next() {
chunk_sum += v as u64; to_append |= chunk_sum << 32;
if let Some(v) = vals.next() { chunk_sum += v as u64; }
} else {
to_append |= chunk_sum << 32; }
} else {
to_append |= (chunk_sum << 32) | (chunk_sum << (32+11)); }
current_rank += chunk_sum;
} l2ranks.push(to_append);
}
current_total_rank += current_rank as usize;
}
#[cfg(target_pointer_width = "64")] let l1ranks = l1ranks.into_boxed_slice();
let l2ranks = l2ranks.into_boxed_slice();
let select = S::new(&content, #[cfg(target_pointer_width = "64")] &l1ranks, &l2ranks, current_total_rank);
let select0 = S0::new0(&content, #[cfg(target_pointer_width = "64")] &l1ranks, &l2ranks, current_total_rank);
(Self{content, #[cfg(target_pointer_width = "64")] l1ranks, l2ranks, select, select0}, current_total_rank)
}
}
impl<S: SelectForRank101111, S0: Select0ForRank101111, BV: Deref<Target = [u64]>> AsRef<[u64]> for RankSelect101111<S, S0, BV> {
#[inline] fn as_ref(&self) -> &[u64] { &self.content }
}
pub type ArrayWithRank101111 = RankSelect101111<BinaryRankSearch, BinaryRankSearch>;
#[derive(Clone)]
pub struct RankSimple<BV = Box<[u64]>> {
content: BV,
ranks: Box<[u32]>,
}
impl<BV: GetSize> GetSize for RankSimple<BV> {
fn size_bytes_dyn(&self) -> usize {
self.content.size_bytes_dyn() + self.ranks.size_bytes_dyn()
}
const USES_DYN_MEM: bool = true;
}
impl<BV: Deref<Target = [u64]>> From<BV> for RankSimple<BV> {
#[inline] fn from(value: BV) -> Self { Self::build(value).0 }
}
impl<BV: Deref<Target = [u64]>> RankSimple<BV> {
pub fn build(content: BV) -> (Self, u32) {
let mut result = Vec::with_capacity(ceiling_div(content.len(), 8usize));
let mut current_rank: u32 = 0;
for seg_nr in 0..content.len() {
if seg_nr % 8 == 0 { result.push(current_rank); }
current_rank += content[seg_nr].count_ones();
}
(Self{content, ranks: result.into_boxed_slice()}, current_rank)
}
pub fn try_rank(&self, index: usize) -> Option<u32> {
let word_idx = index / 64;
let word_offset = index as u8 % 64;
let block = index / 512;
let mut r = (self.content.get(word_idx)? & n_lowest_bits(word_offset)).count_ones() as u32;
r += unsafe{self.ranks.get_unchecked(block)}; for w in block * (512 / 64)..word_idx {
r += unsafe{self.content.get_unchecked(w)}.count_ones(); }
Some(r)
}
pub fn rank(&self, index: usize) -> u32 {
let word_idx = index / 64;
let word_offset = index as u8 % 64;
let block = index / 512;
let mut r = self.ranks[block];
for w in block * (512 / 64)..word_idx {
r += self.content[w].count_ones();
}
r + (self.content[word_idx] & n_lowest_bits(word_offset)).count_ones() as u32
}
}
impl<BV: Deref<Target = [u64]>> AsRef<[u64]> for RankSimple<BV> {
#[inline] fn as_ref(&self) -> &[u64] { &self.content }
}
impl<BV: Deref<Target = [u64]>> Rank for RankSimple<BV> {
#[inline] fn try_rank(&self, index: usize) -> Option<usize> {
Self::try_rank(self, index).map(|r| r as usize)
}
#[inline] fn rank(&self, index: usize) -> usize {
Self::rank(self, index) as usize
}
}
pub type ArrayWithRankSimple = RankSimple;
#[cfg(test)]
mod tests {
use crate::BitAccess;
use super::*;
fn check_all_ones<ArrayWithRank: AsRef<[u64]> + Rank + Select>(a: &ArrayWithRank) {
let mut rank = 0;
for index in a.as_ref().bit_ones() {
assert_eq!(a.rank(index), rank, "rank({}) should be {}", index, rank);
assert_eq!(a.select(rank), index, "select({}) should be {}", rank, index);
assert_eq!(unsafe{a.rank_unchecked(index)}, rank, "rank({}) should be {}", index, rank);
assert_eq!(unsafe{a.select_unchecked(rank)}, index, "select({}) should be {}", rank, index);
rank += 1;
}
assert_eq!(a.try_select(rank), None, "select({}) should be None", rank);
}
fn check_all_zeros<ArrayWithRank: AsRef<[u64]> + Rank + Select0>(a: &ArrayWithRank) {
let mut rank = 0;
for index in a.as_ref().bit_zeros() {
assert_eq!(a.rank0(index), rank, "rank0({}) should be {}", index, rank);
assert_eq!(a.select0(rank), index, "select0({}) should be {}", rank, index);
assert_eq!(unsafe{a.rank0_unchecked(index)}, rank, "rank0({}) should be {}", index, rank);
assert_eq!(unsafe{a.select0_unchecked(rank)}, index, "select0({}) should be {}", rank, index);
rank += 1;
}
assert_eq!(a.try_select0(rank), None, "select0({}) should be None", rank);
}
fn test_empty_array_rank<ArrayWithRank: From<Box<[u64]>> + AsRef<[u64]> + Rank + Select + Select0>() {
let a: ArrayWithRank = vec![].into_boxed_slice().into();
assert_eq!(a.try_rank(0), None);
assert_eq!(a.try_select(0), None);
}
#[test]
fn test_empty_array_rank_101111() {
test_empty_array_rank::<ArrayWithRank101111>();
}
#[test]
fn test_empty_array_rank_101111_combined() {
test_empty_array_rank::<RankSelect101111::<CombinedSampling, CombinedSampling>>();
}
fn test_array_with_rank<ArrayWithRank: From<Box<[u64]>> + AsRef<[u64]> + Rank + Select + Select0>() {
let a: ArrayWithRank = vec![0b1101, 0b110].into_boxed_slice().into();
assert_eq!(a.try_select(0), Some(0));
assert_eq!(a.try_select(1), Some(2));
assert_eq!(a.try_select(2), Some(3));
assert_eq!(a.try_select(3), Some(65));
assert_eq!(a.try_select(4), Some(66));
assert_eq!(a.try_select(5), None);
#[cfg(target_pointer_width = "64")] assert_eq!(a.try_select(1+(1<<32)), None);
#[cfg(target_pointer_width = "64")] assert_eq!(a.try_select(1+(1<<33)), None);
assert_eq!(a.rank(0), 0);
assert_eq!(a.rank(1), 1);
assert_eq!(a.rank(2), 1);
assert_eq!(a.rank(3), 2);
assert_eq!(a.rank(4), 3);
assert_eq!(a.rank(8), 3);
assert_eq!(a.rank(64), 3);
assert_eq!(a.rank(65), 3);
assert_eq!(a.rank(66), 4);
assert_eq!(a.rank(67), 5);
assert_eq!(a.rank(70), 5);
assert_eq!(a.try_rank(127), Some(5));
assert_eq!(a.try_rank(128), None);
#[cfg(target_pointer_width = "64")] assert_eq!(a.try_rank(1+(1<<32)), None);
check_all_ones(&a);
check_all_zeros(&a);
}
#[test]
fn array_with_rank_101111() {
test_array_with_rank::<ArrayWithRank101111>();
}
#[test]
fn array_with_rank_101111_combined() {
test_array_with_rank::<RankSelect101111::<CombinedSampling, CombinedSampling>>();
}
fn test_big_array_with_rank<ArrayWithRank: From<Box<[u64]>> + AsRef<[u64]> + Rank + Select + Select0>() {
let a: ArrayWithRank = vec![0b1101; 60].into_boxed_slice().into();
assert_eq!(a.try_select0(488), Some(513));
assert_eq!(a.try_select(0), Some(0));
assert_eq!(a.try_select(1), Some(2));
assert_eq!(a.try_select(2), Some(3));
assert_eq!(a.try_select(3), Some(64));
assert_eq!(a.try_select(4), Some(66));
assert_eq!(a.try_select(5), Some(67));
assert_eq!(a.try_select(6), Some(128));
assert_eq!(a.try_select(7), Some(130));
assert_eq!(a.try_select(3*8), Some(512));
assert_eq!(a.try_select(3*8+1), Some(514));
assert_eq!(a.try_select(2*6*8), Some(2*1024));
assert_eq!(a.try_select(2*6*8+1), Some(2*1024+2));
assert_eq!(a.try_select(2*6*8+2), Some(2*1024+3));
assert_eq!(a.try_select(60*3), None);
assert_eq!(a.rank(0), 0);
assert_eq!(a.rank(1), 1);
assert_eq!(a.rank(2), 1);
assert_eq!(a.rank(3), 2);
assert_eq!(a.rank(4), 3);
assert_eq!(a.rank(8), 3);
assert_eq!(a.rank(64), 3);
assert_eq!(a.rank(65), 4);
assert_eq!(a.rank(66), 4);
assert_eq!(a.rank(67), 5);
assert_eq!(a.rank(68), 6);
assert_eq!(a.rank(69), 6);
assert_eq!(a.rank(128), 6);
assert_eq!(a.rank(129), 7);
assert_eq!(a.rank(512), 3*8);
assert_eq!(a.rank(513), 3*8+1);
assert_eq!(a.rank(514), 3*8+1);
assert_eq!(a.rank(515), 3*8+2);
assert_eq!(a.rank(1024), 6*8);
assert_eq!(a.rank(2*1024), 2*6*8);
assert_eq!(a.rank(2*1024+1), 2*6*8+1);
assert_eq!(a.rank(2*1024+2), 2*6*8+1);
assert_eq!(a.rank(2*1024+3), 2*6*8+2);
assert_eq!(a.try_rank(60*64), None);
check_all_ones(&a);
check_all_zeros(&a);
}
#[test]
fn big_array_with_rank_101111() {
test_big_array_with_rank::<ArrayWithRank101111>();
}
#[test]
fn big_array_with_rank_101111_combined() {
test_big_array_with_rank::<RankSelect101111::<CombinedSampling, CombinedSampling>>();
}
fn test_content<ArrayWithRank: From<Box<[u64]>> + AsRef<[u64]> + Rank + Select + Select0>() {
let a: ArrayWithRank = vec![u64::MAX; 35].into_boxed_slice().into();
check_all_ones(&a);
check_all_zeros(&a);
}
#[test]
fn content_101111() {
test_content::<ArrayWithRank101111>();
}
#[test]
fn content_101111_combined() {
test_content::<RankSelect101111::<CombinedSampling, CombinedSampling>>();
}
#[cfg(target_pointer_width = "64")]
fn array_64bit<ArrayWithRank: From<Box<[u64]>> + AsRef<[u64]> + Rank + Select + Select0>() {
const SEGMENTS: usize = (1<<32)/64 * 2;
let a: ArrayWithRank = vec![0b01_01_01_01; SEGMENTS].into_boxed_slice().into();
assert_eq!(a.try_select(268435456), Some(4294967296));
assert_eq!(a.try_select(268435456+1), Some(4294967296+2));
assert_eq!(a.try_select(268435456+2), Some(4294967296+4));
assert_eq!(a.try_select(268435456+3), Some(4294967296+6));
assert_eq!(a.try_select(0), Some(0));
assert_eq!(a.try_select(1), Some(2));
assert_eq!(a.rank(0), 0);
assert_eq!(a.rank(1), 1);
assert_eq!(a.rank(2), 1);
assert_eq!(a.rank(1<<32), (1<<(32-6)) * 4);
assert_eq!(a.rank((1<<32)+1), (1<<(32-6)) * 4 + 1);
assert_eq!(a.rank((1<<32)+2), (1<<(32-6)) * 4 + 1);
assert_eq!(a.rank((1<<32)+3), (1<<(32-6)) * 4 + 2);
assert_eq!(a.try_rank(SEGMENTS*64), None);
check_all_ones(&a);
check_all_zeros(&a);
}
#[cfg(target_pointer_width = "64")]
#[test]
#[ignore = "uses much memory and time"]
fn array_64bit_101111_binary() {
array_64bit::<ArrayWithRank101111>();
}
#[cfg(target_pointer_width = "64")]
#[test]
#[ignore = "uses much memory and time"]
fn array_64bit_101111_combined() {
array_64bit::<RankSelect101111::<CombinedSampling, CombinedSampling>>();
}
#[cfg(target_pointer_width = "64")]
fn array_64bit_filled<ArrayWithRank: From<Box<[u64]>> + AsRef<[u64]> + Rank + Select>() {
const SEGMENTS: usize = (1<<32)/64 * 2;
let a: ArrayWithRank = vec![u64::MAX; SEGMENTS].into_boxed_slice().into();
assert_eq!(a.select(4294965248), 4294965248);
assert_eq!(a.rank(0), 0);
assert_eq!(a.rank(1), 1);
assert_eq!(a.rank(2), 2);
for i in (1<<32)..(1<<32)+2048 {
assert_eq!(a.rank(i), i);
assert_eq!(a.select(i), i);
}
}
#[cfg(target_pointer_width = "64")]
#[test]
#[ignore = "uses much memory and time"]
fn array_64bit_filled_101111() {
array_64bit_filled::<ArrayWithRank101111>();
}
#[cfg(target_pointer_width = "64")]
#[test]
#[ignore = "uses much memory and time"]
fn array_64bit_filled_101111_combined() {
array_64bit_filled::<RankSelect101111::<CombinedSampling, CombinedSampling>>();
}
#[cfg(target_pointer_width = "64")]
fn array_64bit_halffilled<ArrayWithRank: From<Box<[u64]>> + AsRef<[u64]> + Rank + Select + Select0>() {
const SEGMENTS: usize = (1<<32)/64 * 2;
let a: ArrayWithRank = vec![0x5555_5555_5555_5555; SEGMENTS].into_boxed_slice().into();
check_all_ones(&a);
check_all_zeros(&a);
}
#[cfg(target_pointer_width = "64")]
#[test]
#[ignore = "uses much memory and time"]
fn array_64bit_halffilled_101111_binary() {
array_64bit_halffilled::<ArrayWithRank101111>();
}
#[cfg(target_pointer_width = "64")]
#[test]
#[ignore = "uses much memory and time"]
fn array_64bit_halffilled_101111_combined() {
array_64bit_halffilled::<RankSelect101111::<CombinedSampling, CombinedSampling>>();
}
#[cfg(target_pointer_width = "64")]
fn array_64bit_zeroed_first<ArrayWithRank: From<Box<[u64]>> + AsRef<[u64]> + Rank + Select>() {
const SEGMENTS: usize = (1<<32)/64 + 1;
let mut content = vec![0; SEGMENTS].into_boxed_slice();
content[SEGMENTS-1] = 0b11<<62;
let a: ArrayWithRank = content.into();
assert_eq!(a.rank(0), 0);
assert_eq!(a.rank((1<<32)-1), 0);
assert_eq!(a.rank(1<<32), 0);
assert_eq!(a.rank((1<<32)+62), 0);
assert_eq!(a.rank((1<<32)+63), 1);
assert_eq!(a.select(0), (1<<32)+62);
assert_eq!(a.select(1), (1<<32)+63);
assert_eq!(a.try_select(2), None);
}
#[cfg(target_pointer_width = "64")]
#[test]
#[ignore = "uses much memory and time"]
fn array_64bit_zeroed_first_101111() {
array_64bit_zeroed_first::<ArrayWithRank101111>();
}
#[cfg(target_pointer_width = "64")]
#[test]
#[ignore = "uses much memory and time"]
fn array_64bit_zeroed_first_101111_combined() {
array_64bit_zeroed_first::<RankSelect101111::<CombinedSampling, CombinedSampling>>();
}
}