use ambassador::{Delegate, delegatable_trait};
use mem_dbg::*;
use num_primitive::PrimitiveInteger;
use std::{
ops::Deref,
ptr::{addr_of, addr_of_mut, read_unaligned, write_unaligned},
};
use crate::{
prelude::{BitLength, BitVec, Rank, RankHinted, RankUnchecked, RankZero},
traits::{
Backend, BitCount, NumBits, Select, SelectHinted, SelectUnchecked, SelectZero,
SelectZeroHinted, SelectZeroUnchecked, Word,
},
};
use crate::ambassador_impl_Index;
use crate::traits::ambassador_impl_Backend;
use crate::traits::bal_paren::{BalParen, ambassador_impl_BalParen};
use crate::traits::bit_vec_ops::ambassador_impl_BitLength;
use crate::traits::rank_sel::ambassador_impl_RankHinted;
use crate::traits::rank_sel::ambassador_impl_Select;
use crate::traits::rank_sel::ambassador_impl_SelectHinted;
use crate::traits::rank_sel::ambassador_impl_SelectUnchecked;
use crate::traits::rank_sel::ambassador_impl_SelectZero;
use crate::traits::rank_sel::ambassador_impl_SelectZeroHinted;
use crate::traits::rank_sel::ambassador_impl_SelectZeroUnchecked;
use std::ops::Index;
#[delegatable_trait]
pub trait SmallCounters<const NUM_U32S: usize, const COUNTER_WIDTH: usize> {
fn upper_counts(&self) -> &[u64];
fn counts(&self) -> &[Block32Counters<NUM_U32S, COUNTER_WIDTH>];
}
#[derive(Debug, Clone, MemSize, MemDbg, Delegate)]
#[cfg_attr(feature = "epserde", derive(epserde::Epserde))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[delegate(Index<usize>, target = "bits")]
#[delegate(crate::traits::Backend, target = "bits")]
#[delegate(crate::traits::bit_vec_ops::BitLength, target = "bits")]
#[delegate(crate::traits::rank_sel::RankHinted, target = "bits")]
#[delegate(crate::traits::rank_sel::SelectZeroHinted, target = "bits")]
#[delegate(crate::traits::rank_sel::SelectUnchecked, target = "bits")]
#[delegate(crate::traits::rank_sel::Select, target = "bits")]
#[delegate(crate::traits::rank_sel::SelectZeroUnchecked, target = "bits")]
#[delegate(crate::traits::rank_sel::SelectZero, target = "bits")]
#[delegate(crate::traits::rank_sel::SelectHinted, target = "bits")]
#[delegate(crate::bal_paren::BalParen, target = "bits")]
pub struct RankSmall<
const WORD_BITS: usize,
const NUM_U32S: usize,
const COUNTER_WIDTH: usize,
B = BitVec,
C1 = Box<[u64]>,
C2 = Box<[Block32Counters<NUM_U32S, COUNTER_WIDTH>]>,
> {
pub(super) bits: B,
pub(super) upper_counts: C1,
pub(super) counts: C2,
pub(super) num_ones: usize,
}
impl<
const WORD_BITS: usize,
const NUM_U32S: usize,
const COUNTER_WIDTH: usize,
B: Backend + AsRef<[B::Word]>,
C1,
C2,
> AsRef<[B::Word]> for RankSmall<WORD_BITS, NUM_U32S, COUNTER_WIDTH, B, C1, C2>
{
#[inline(always)]
fn as_ref(&self) -> &[B::Word] {
self.bits.as_ref()
}
}
impl<const WORD_BITS: usize, const NUM_U32S: usize, const COUNTER_WIDTH: usize, B> Deref
for RankSmall<WORD_BITS, NUM_U32S, COUNTER_WIDTH, B>
{
type Target = B;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.bits
}
}
#[macro_export]
macro_rules! rank_small {
(u64 : 0 ; $bits:expr) => {
$crate::prelude::RankSmall::<64, 2, 9, _, _, _>::new($bits)
};
(u64 : 1 ; $bits:expr) => {
$crate::prelude::RankSmall::<64, 1, 9, _, _, _>::new($bits)
};
(u64 : 2 ; $bits:expr) => {
$crate::prelude::RankSmall::<64, 1, 10, _, _, _>::new($bits)
};
(u64 : 3 ; $bits:expr) => {
$crate::prelude::RankSmall::<64, 1, 11, _, _, _>::new($bits)
};
(u64 : 4 ; $bits:expr) => {
$crate::prelude::RankSmall::<64, 3, 13, _, _, _>::new($bits)
};
(u64 : $bits:expr) => {
$crate::prelude::RankSmall::<64, 1, 11, _, _, _>::new($bits)
};
(u32 : 0 ; $bits:expr) => {
$crate::prelude::RankSmall::<32, 2, 8, _, _, _>::new($bits)
};
(u32 : 1 ; $bits:expr) => {
$crate::prelude::RankSmall::<32, 1, 8, _, _, _>::new($bits)
};
(u32 : 2 ; $bits:expr) => {
$crate::prelude::RankSmall::<32, 1, 9, _, _, _>::new($bits)
};
(u32 : 3 ; $bits:expr) => {
$crate::prelude::RankSmall::<32, 1, 10, _, _, _>::new($bits)
};
(u32 : 4 ; $bits:expr) => {
$crate::prelude::RankSmall::<32, 1, 11, _, _, _>::new($bits)
};
(u32 : 5 ; $bits:expr) => {
$crate::prelude::RankSmall::<32, 3, 13, _, _, _>::new($bits)
};
(u32 : $bits:expr) => {
$crate::prelude::RankSmall::<32, 1, 11, _, _, _>::new($bits)
};
(0 ; $bits:expr) => {
{
#[cfg(target_pointer_width = "64")]
{ $crate::prelude::RankSmall::<{ usize::BITS as usize }, 2, 9, _, _, _>::new($bits) }
#[cfg(not(target_pointer_width = "64"))]
{ $crate::prelude::RankSmall::<{ usize::BITS as usize }, 2, 8, _, _, _>::new($bits) }
}
};
(1 ; $bits:expr) => {
{
#[cfg(target_pointer_width = "64")]
{ $crate::prelude::RankSmall::<{ usize::BITS as usize }, 1, 9, _, _, _>::new($bits) }
#[cfg(not(target_pointer_width = "64"))]
{ $crate::prelude::RankSmall::<{ usize::BITS as usize }, 1, 8, _, _, _>::new($bits) }
}
};
(2 ; $bits:expr) => {
{
#[cfg(target_pointer_width = "64")]
{ $crate::prelude::RankSmall::<{ usize::BITS as usize }, 1, 10, _, _, _>::new($bits) }
#[cfg(not(target_pointer_width = "64"))]
{ $crate::prelude::RankSmall::<{ usize::BITS as usize }, 1, 9, _, _, _>::new($bits) }
}
};
(3 ; $bits:expr) => {
{
#[cfg(target_pointer_width = "64")]
{ $crate::prelude::RankSmall::<{ usize::BITS as usize }, 1, 11, _, _, _>::new($bits) }
#[cfg(not(target_pointer_width = "64"))]
{ $crate::prelude::RankSmall::<{ usize::BITS as usize }, 1, 10, _, _, _>::new($bits) }
}
};
(4 ; $bits:expr) => {
{
#[cfg(target_pointer_width = "64")]
{ $crate::prelude::RankSmall::<{ usize::BITS as usize }, 3, 13, _, _, _>::new($bits) }
#[cfg(not(target_pointer_width = "64"))]
{ $crate::prelude::RankSmall::<{ usize::BITS as usize }, 1, 11, _, _, _>::new($bits) }
}
};
(5 ; $bits:expr) => {
$crate::prelude::RankSmall::<{ usize::BITS as usize }, 3, 13, _, _, _>::new($bits)
};
(usize : $n:tt ; $bits:expr) => {
$crate::rank_small![$n ; $bits]
};
(usize : $bits:expr) => {
$crate::rank_small![$bits]
};
($bits:expr) => {
$crate::prelude::RankSmall::<{ usize::BITS as usize }, 1, 11, _, _, _>::new($bits)
};
}
#[doc(hidden)]
#[derive(Copy, Debug, Clone, MemSize, MemDbg)]
#[mem_size(flat)]
#[cfg_attr(
feature = "epserde",
derive(epserde::Epserde),
repr(C),
epserde(zero_copy)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Block32Counters<const NUM_U32S: usize, const COUNTER_WIDTH: usize> {
pub(super) absolute: u32,
#[cfg_attr(feature = "serde", serde(with = "serde_arrays"))]
pub(super) relative: [u32; NUM_U32S],
}
impl Block32Counters<2, 9> {
#[inline(always)]
pub fn all_rel(&self) -> u64 {
unsafe { read_unaligned(addr_of!(self.relative) as *const u64) }
}
#[inline(always)]
pub fn rel(&self, word: usize) -> usize {
((self.all_rel() >> (9 * (word ^ 7))) & ((1 << 9) - 1)) as usize
}
#[inline(always)]
pub fn set_rel(&mut self, word: usize, counter: usize) {
let mut packed = unsafe { read_unaligned(addr_of!(self.relative) as *const u64) };
packed |= (counter as u64) << (9 * (word ^ 7));
unsafe { write_unaligned(addr_of_mut!(self.relative) as *mut u64, packed) };
}
}
impl Block32Counters<1, 9> {
#[inline(always)]
pub fn all_rel(&self) -> u64 {
self.relative[0] as u64
}
#[inline(always)]
pub fn rel(&self, word: usize) -> usize {
(self.relative[0] as usize >> (9 * (word ^ 3))) & ((1 << 9) - 1)
}
#[inline(always)]
pub fn set_rel(&mut self, word: usize, counter: usize) {
self.relative[0] |= (counter as u32) << (9 * (word ^ 3));
}
}
impl Block32Counters<1, 10> {
#[inline(always)]
pub fn all_rel(&self) -> u64 {
self.relative[0] as u64
}
#[inline(always)]
pub fn rel(&self, word: usize) -> usize {
(self.relative[0] as u64 >> (10 * (word ^ 3))) as usize & ((1 << 10) - 1)
}
#[inline(always)]
pub fn set_rel(&mut self, word: usize, counter: usize) {
self.relative[0] |= (counter as u32) << (10 * (word ^ 3));
}
}
impl Block32Counters<1, 11> {
#[inline(always)]
pub fn all_rel(&self) -> u64 {
self.relative[0] as u64
}
#[inline(always)]
pub fn rel(&self, word: usize) -> usize {
(self.relative[0] as u64 >> (11 * (word ^ 3))) as usize & ((1 << 11) - 1)
}
#[inline(always)]
pub fn set_rel(&mut self, word: usize, counter: usize) {
self.relative[0] |= (counter as u32) << (11 * (word ^ 3));
}
}
impl Block32Counters<2, 8> {
#[inline(always)]
pub fn all_rel(&self) -> u64 {
unsafe { read_unaligned(addr_of!(self.relative) as *const u64) }
}
#[inline(always)]
pub fn rel(&self, word: usize) -> usize {
((self.all_rel() >> (8 * (word ^ 7))) & ((1 << 8) - 1)) as usize
}
#[inline(always)]
pub fn set_rel(&mut self, word: usize, counter: usize) {
let mut packed = unsafe { read_unaligned(addr_of!(self.relative) as *const u64) };
packed |= (counter as u64) << (8 * (word ^ 7));
unsafe { write_unaligned(addr_of_mut!(self.relative) as *mut u64, packed) };
}
}
impl Block32Counters<1, 8> {
#[inline(always)]
pub fn all_rel(&self) -> u64 {
self.relative[0] as u64
}
#[inline(always)]
pub fn rel(&self, word: usize) -> usize {
(self.relative[0] as usize >> (8 * (word ^ 3))) & ((1 << 8) - 1)
}
#[inline(always)]
pub fn set_rel(&mut self, word: usize, counter: usize) {
self.relative[0] |= (counter as u32) << (8 * (word ^ 3));
}
}
impl Block32Counters<3, 13> {
#[inline(always)]
pub fn all_rel(&self) -> u128 {
#[cfg(target_endian = "little")]
unsafe {
read_unaligned(addr_of!(*self) as *const u128) >> 32
}
#[cfg(target_endian = "big")]
unsafe {
read_unaligned(addr_of!(*self) as *const u128) & ((1 << 96) - 1)
}
}
#[inline(always)]
pub fn rel(&self, word: usize) -> usize {
((self.all_rel() >> (13 * (word ^ 7))) & ((1 << 13) - 1)) as usize
}
#[inline(always)]
pub fn set_rel(&mut self, word: usize, counter: usize) {
let mut packed = self.all_rel();
packed |= (counter as u128) << (13 * (word ^ 7));
#[cfg(target_endian = "little")]
unsafe {
write_unaligned(
addr_of_mut!(*self) as *mut u128,
(packed << 32) | self.absolute as u128,
)
};
#[cfg(target_endian = "big")]
unsafe {
write_unaligned(
addr_of_mut!(*self) as *mut u128,
packed | (self.absolute as u128) << 96,
);
};
}
}
impl<const NUM_U32S: usize, const COUNTER_WIDTH: usize> Default
for Block32Counters<NUM_U32S, COUNTER_WIDTH>
{
fn default() -> Self {
Self {
absolute: 0,
relative: [0; NUM_U32S],
}
}
}
impl<const WORD_BITS: usize, const NUM_U32S: usize, const COUNTER_WIDTH: usize, B, C1, C2>
RankSmall<WORD_BITS, NUM_U32S, COUNTER_WIDTH, B, C1, C2>
{
pub(super) const WORD_BIT_LOG2: usize = match WORD_BITS {
32 => 5,
64 => 6,
_ => panic!("Unsupported word size"),
};
pub(super) const WORDS_PER_BLOCK: usize = 1 << (COUNTER_WIDTH - Self::WORD_BIT_LOG2);
pub(super) const WORDS_PER_SUBBLOCK: usize = match NUM_U32S {
1 => Self::WORDS_PER_BLOCK / 4, 2 => Self::WORDS_PER_BLOCK / 8, 3 => Self::WORDS_PER_BLOCK / 8, _ => panic!("Unsupported number of u32s"),
};
}
macro_rules! impl_rank_small {
($WORD_BITS: literal; $NUM_U32S: literal; $COUNTER_WIDTH: literal) => {
impl<B: Backend<Word: Word> + AsRef<[B::Word]> + BitLength + RankHinted>
RankSmall<
$WORD_BITS,
$NUM_U32S,
$COUNTER_WIDTH,
B,
Box<[u64]>,
Box<[Block32Counters<$NUM_U32S, $COUNTER_WIDTH>]>,
>
{
#[must_use]
pub fn new(bits: B) -> Self {
const {
assert!(
size_of::<B::Word>() * 8 == $WORD_BITS,
concat!(
"RankSmall<",
stringify!($WORD_BITS),
", ",
stringify!($NUM_U32S),
", ",
stringify!($COUNTER_WIDTH),
"> requires ",
stringify!($WORD_BITS),
"-bit words"
)
)
}
let bits_per_word = B::Word::BITS as usize;
let num_bits = bits.len();
let num_words = num_bits.div_ceil(bits_per_word);
let num_upper_counts = (num_bits as u64).div_ceil(1u64 << 32) as usize;
let num_counts = num_bits.div_ceil(bits_per_word * Self::WORDS_PER_BLOCK);
let mut upper_counts: Vec<u64> = Vec::with_capacity(num_upper_counts);
let mut counts = Vec::with_capacity(num_counts);
let mut past_ones: usize = 0;
let mut upper_count: usize = 0;
let words_per_superblock = 1usize << (32 - Self::WORD_BIT_LOG2);
for i in (0..num_words).step_by(Self::WORDS_PER_BLOCK) {
if i % words_per_superblock == 0 {
upper_count = past_ones;
upper_counts.push(upper_count as u64);
}
let mut count = Block32Counters::<$NUM_U32S, $COUNTER_WIDTH>::default();
count.absolute = (past_ones - upper_count) as u32;
past_ones += bits.as_ref()[i].count_ones() as usize;
for j in 1..Self::WORDS_PER_BLOCK {
#[allow(clippy::modulo_one)]
if j % Self::WORDS_PER_SUBBLOCK == 0 {
let rel_count = past_ones - upper_count - count.absolute as usize;
count.set_rel(j / Self::WORDS_PER_SUBBLOCK, rel_count);
}
if i + j < num_words {
past_ones += bits.as_ref()[i + j].count_ones() as usize;
}
}
counts.push(count);
}
assert_eq!(upper_counts.len(), num_upper_counts);
assert_eq!(counts.len(), num_counts);
let upper_counts = upper_counts.into_boxed_slice();
let counts = counts.into_boxed_slice();
Self {
bits,
upper_counts,
counts,
num_ones: past_ones,
}
}
}
impl<
B: Backend<Word: Word> + AsRef<[B::Word]> + BitLength + RankHinted,
C1: AsRef<[u64]>,
C2: AsRef<[Block32Counters<$NUM_U32S, $COUNTER_WIDTH>]>,
> RankUnchecked for RankSmall<$WORD_BITS, $NUM_U32S, $COUNTER_WIDTH, B, C1, C2>
{
#[inline(always)]
unsafe fn rank_unchecked(&self, pos: usize) -> usize {
let bits_per_word = B::Word::BITS as usize;
debug_assert!(pos < self.bits.len());
unsafe {
let word_pos = pos / bits_per_word;
crate::utils::prefetch_index(self.bits.as_ref(), word_pos);
let block = word_pos / Self::WORDS_PER_BLOCK;
let offset = (word_pos % Self::WORDS_PER_BLOCK) / Self::WORDS_PER_SUBBLOCK;
let counts = self.counts.as_ref().get_unchecked(block);
let words_per_superblock = 1usize << (32 - Self::WORD_BIT_LOG2);
let upper_count = self
.upper_counts
.as_ref()
.get_unchecked(word_pos / words_per_superblock);
let hint_rank =
*upper_count as usize + counts.absolute as usize + counts.rel(offset);
if Self::WORDS_PER_SUBBLOCK == 1 {
let word = *self.bits.as_ref().get_unchecked(word_pos);
hint_rank
+ (word
& ((B::Word::ONE << (pos % bits_per_word) as u32) - B::Word::ONE))
.count_ones() as usize
} else {
const WPS: usize = {
let word_bit_log2: usize = match $WORD_BITS {
32 => 5,
64 => 6,
_ => panic!(""),
};
let words_per_block: usize = 1 << ($COUNTER_WIDTH - word_bit_log2);
match $NUM_U32S {
1 => words_per_block / 4,
2 => words_per_block / 8,
3 => words_per_block / 8,
_ => panic!(""),
}
};
#[allow(clippy::modulo_one)]
let hint_pos = word_pos
- ((word_pos % Self::WORDS_PER_BLOCK) % Self::WORDS_PER_SUBBLOCK);
RankHinted::rank_hinted::<WPS>(&self.bits, pos, hint_pos, hint_rank)
}
}
}
}
};
}
impl_rank_small!(64; 2; 9);
impl_rank_small!(64; 1; 9);
impl_rank_small!(64; 1; 10);
impl_rank_small!(64; 1; 11);
impl_rank_small!(64; 3; 13);
impl_rank_small!(32; 2; 8);
impl_rank_small!(32; 1; 8);
impl_rank_small!(32; 1; 9);
impl_rank_small!(32; 1; 10);
impl_rank_small!(32; 1; 11);
impl_rank_small!(32; 3; 13);
impl<const WORD_BITS: usize, const NUM_U32S: usize, const COUNTER_WIDTH: usize, B, C1, C2> Rank
for RankSmall<WORD_BITS, NUM_U32S, COUNTER_WIDTH, B, C1, C2>
where
Self: BitLength + NumBits + RankUnchecked,
{
}
impl<const WORD_BITS: usize, const NUM_U32S: usize, const COUNTER_WIDTH: usize, B, C1, C2> RankZero
for RankSmall<WORD_BITS, NUM_U32S, COUNTER_WIDTH, B, C1, C2>
where
Self: Rank,
{
}
impl<
const WORD_BITS: usize,
const NUM_U32S: usize,
const COUNTER_WIDTH: usize,
B: BitLength,
C1,
C2,
> RankSmall<WORD_BITS, NUM_U32S, COUNTER_WIDTH, B, C1, C2>
{
#[inline(always)]
pub fn len(&self) -> usize {
BitLength::len(self)
}
}
impl<const WORD_BITS: usize, const NUM_U32S: usize, const COUNTER_WIDTH: usize, B, C1, C2>
RankSmall<WORD_BITS, NUM_U32S, COUNTER_WIDTH, B, C1, C2>
{
pub fn into_inner(self) -> B {
self.bits
}
pub unsafe fn map<B1: BitLength>(
self,
f: impl FnOnce(B) -> B1,
) -> RankSmall<WORD_BITS, NUM_U32S, COUNTER_WIDTH, B1, C1, C2> {
RankSmall {
bits: f(self.bits),
upper_counts: self.upper_counts,
counts: self.counts,
num_ones: self.num_ones,
}
}
}
impl<
const WORD_BITS: usize,
const NUM_U32S: usize,
const COUNTER_WIDTH: usize,
B: BitLength,
C1,
C2,
> NumBits for RankSmall<WORD_BITS, NUM_U32S, COUNTER_WIDTH, B, C1, C2>
{
#[inline(always)]
fn num_ones(&self) -> usize {
self.num_ones
}
}
impl<
const WORD_BITS: usize,
const NUM_U32S: usize,
const COUNTER_WIDTH: usize,
B: BitLength,
C1,
C2,
> BitCount for RankSmall<WORD_BITS, NUM_U32S, COUNTER_WIDTH, B, C1, C2>
{
#[inline(always)]
fn count_ones(&self) -> usize {
self.num_ones
}
}
impl<
const WORD_BITS: usize,
const NUM_U32S: usize,
const COUNTER_WIDTH: usize,
B,
C1: AsRef<[u64]>,
C2: AsRef<[Block32Counters<NUM_U32S, COUNTER_WIDTH>]>,
> SmallCounters<NUM_U32S, COUNTER_WIDTH>
for RankSmall<WORD_BITS, NUM_U32S, COUNTER_WIDTH, B, C1, C2>
{
#[inline(always)]
fn upper_counts(&self) -> &[u64] {
self.upper_counts.as_ref()
}
#[inline(always)]
fn counts(&self) -> &[Block32Counters<NUM_U32S, COUNTER_WIDTH>] {
self.counts.as_ref()
}
}