use std::collections::Bitv;
use std::intrinsics::ctpop8;
fn ctpop(v: u8) -> u8 {
let p: u8;
unsafe { p = ctpop8(v); }
p
}
pub struct RankSelect {
n: usize,
bits: Vec<u8>,
superblocks: Vec<u32>,
s: usize,
}
impl RankSelect {
pub fn new(bits: Bitv, k: usize) -> RankSelect {
let n = bits.len();
let raw = bits.to_bytes();
let s = k * 32;
RankSelect { n: n, s: s, superblocks: superblocks(n, s, &raw), bits: raw }
}
pub fn rank(&self, i: usize) -> Option<u32> {
if i >= self.n {
None
}
else {
let s = i / self.s; let b = i / 8; let mut rank = self.superblocks[s];
rank += ctpop(self.bits[b] >> 7 - i % 8) as u32;
rank += self.bits[s * 32 / 8..b].iter()
.map(|&a| ctpop(a) as u32)
.fold(0, |a, b| a + b);
Some(rank)
}
}
pub fn select(&self, j: u32) -> Option<usize> {
let mut superblock = match self.superblocks.binary_search(&j) {
Ok(i) => i, Err(i) => i
};
if superblock > 0 {
superblock -= 1;
}
let mut rank = self.superblocks[superblock];
let first_block = superblock * self.s / 8;
for (block, &b) in self.bits[first_block..].iter().enumerate() {
let p = ctpop(b) as u32;
if rank + p >= j {
let mut bit = 0b10000000;
for i in 0us..8us {
rank += (b & bit > 0) as u32;
if rank == j {
return Some((first_block + block) * 8 + i);
}
bit >>= 1;
}
}
rank += p;
}
None
}
}
fn superblocks(n: usize, s: usize, raw_bits: &Vec<u8>) -> Vec<u32> {
let mut superblocks = Vec::with_capacity(n / s + 1);
let mut rank: u32 = 0;
let mut i = 0;
for &b in raw_bits.iter() {
if i % s == 0 {
superblocks.push(rank);
}
rank += ctpop(b) as u32;
i += 8;
}
superblocks
}