pub mod builder;
pub mod decoder;
mod intvec;
pub mod iter;
pub mod locator;
pub mod predictive_iter;
mod utils;
use std::cmp::Ordering;
use std::io;
use anyhow::{anyhow, Result};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use builder::Builder;
use decoder::Decoder;
use intvec::IntVector;
use iter::Iter;
use locator::Locator;
use predictive_iter::PredictiveIter;
pub const END_MARKER: u8 = 0;
pub const DEFAULT_BUCKET_SIZE: usize = 8;
const SERIAL_COOKIE: u32 = 114514;
#[derive(Clone)]
pub struct Set {
pointers: IntVector,
serialized: Vec<u8>,
len: usize,
bucket_bits: usize,
bucket_mask: usize,
max_length: usize,
}
impl Set {
pub fn new<I, P>(keys: I) -> Result<Self>
where
I: IntoIterator<Item = P>,
P: AsRef<[u8]>,
{
Self::with_bucket_size(keys, DEFAULT_BUCKET_SIZE)
}
pub fn with_bucket_size<I, P>(keys: I, bucket_size: usize) -> Result<Self>
where
I: IntoIterator<Item = P>,
P: AsRef<[u8]>,
{
let mut builder = Builder::new(bucket_size)?;
for key in keys {
builder.add(key.as_ref())?;
}
Ok(builder.finish())
}
pub fn size_in_bytes(&self) -> usize {
let mut bytes = 0;
bytes += 4; bytes += self.pointers.size_in_bytes(); bytes += 8 + self.serialized.len(); bytes + 8 * 4
}
pub fn serialize_into<W>(&self, mut writer: W) -> Result<()>
where
W: io::Write,
{
writer.write_u32::<LittleEndian>(SERIAL_COOKIE)?;
self.pointers.serialize_into(&mut writer)?;
writer.write_u64::<LittleEndian>(self.serialized.len() as u64)?;
for &x in &self.serialized {
writer.write_u8(x)?;
}
writer.write_u64::<LittleEndian>(self.len as u64)?;
writer.write_u64::<LittleEndian>(self.bucket_bits as u64)?;
writer.write_u64::<LittleEndian>(self.bucket_mask as u64)?;
writer.write_u64::<LittleEndian>(self.max_length as u64)?;
Ok(())
}
pub fn deserialize_from<R>(mut reader: R) -> Result<Self>
where
R: io::Read,
{
let cookie = reader.read_u32::<LittleEndian>()?;
if cookie != SERIAL_COOKIE {
return Err(anyhow!("unknown cookie value"));
}
let pointers = IntVector::deserialize_from(&mut reader)?;
let serialized = {
let len = reader.read_u64::<LittleEndian>()? as usize;
let mut serialized = vec![0; len];
for x in serialized.iter_mut() {
*x = reader.read_u8()?;
}
serialized
};
let len = reader.read_u64::<LittleEndian>()? as usize;
let bucket_bits = reader.read_u64::<LittleEndian>()? as usize;
let bucket_mask = reader.read_u64::<LittleEndian>()? as usize;
let max_length = reader.read_u64::<LittleEndian>()? as usize;
Ok(Self {
pointers,
serialized,
len,
bucket_bits,
bucket_mask,
max_length,
})
}
pub fn locator(&self) -> Locator {
Locator::new(self)
}
pub fn decoder(&self) -> Decoder {
Decoder::new(self)
}
pub fn iter(&self) -> Iter {
Iter::new(self)
}
pub fn predictive_iter<P>(&self, prefix: P) -> PredictiveIter
where
P: AsRef<[u8]>,
{
PredictiveIter::new(self, prefix)
}
#[inline(always)]
pub const fn len(&self) -> usize {
self.len
}
#[inline(always)]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
#[inline(always)]
pub const fn num_buckets(&self) -> usize {
self.pointers.len()
}
#[inline(always)]
pub const fn bucket_size(&self) -> usize {
self.bucket_mask + 1
}
#[inline(always)]
const fn max_length(&self) -> usize {
self.max_length
}
#[inline(always)]
const fn bucket_id(&self, id: usize) -> usize {
id >> self.bucket_bits
}
#[inline(always)]
const fn pos_in_bucket(&self, id: usize) -> usize {
id & self.bucket_mask
}
#[inline(always)]
fn get_header(&self, bi: usize) -> &[u8] {
let header = &self.serialized[self.pointers.get(bi) as usize..];
&header[..utils::get_strlen(header)]
}
#[inline(always)]
fn decode_header(&self, bi: usize, dec: &mut Vec<u8>) -> usize {
dec.clear();
let mut pos = self.pointers.get(bi) as usize;
while self.serialized[pos] != END_MARKER {
dec.push(self.serialized[pos]);
pos += 1;
}
pos + 1
}
#[inline(always)]
fn decode_lcp(&self, pos: usize) -> (usize, usize) {
let (lcp, num) = utils::vbyte::decode(&self.serialized[pos..]);
(lcp, pos + num)
}
#[inline(always)]
fn decode_next(&self, mut pos: usize, dec: &mut Vec<u8>) -> usize {
while self.serialized[pos] != END_MARKER {
dec.push(self.serialized[pos]);
pos += 1;
}
pos + 1
}
fn search_bucket(&self, key: &[u8]) -> (usize, bool) {
let mut cmp = 0;
let (mut lo, mut hi, mut mi) = (0, self.num_buckets(), 0);
while lo < hi {
mi = (lo + hi) / 2;
cmp = utils::get_lcp(key, self.get_header(mi)).1;
match cmp.cmp(&0) {
Ordering::Less => lo = mi + 1,
Ordering::Greater => hi = mi,
Ordering::Equal => return (mi, true),
}
}
if cmp < 0 || mi == 0 {
(mi, false)
} else {
(mi - 1, false)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaChaRng;
fn gen_random_keys(num: usize, max_len: usize, seed: u64) -> Vec<Vec<u8>> {
let mut rng = ChaChaRng::seed_from_u64(seed);
let mut keys = Vec::with_capacity(num);
for _ in 0..num {
let len = (rng.gen::<usize>() % (max_len - 1)) + 1;
keys.push((0..len).map(|_| (rng.gen::<u8>() % 4) + 1).collect());
}
keys.sort();
keys.dedup();
keys
}
#[test]
fn test_toy() {
let keys = [
"deal",
"idea",
"ideal",
"ideas",
"ideology",
"tea",
"techie",
"technology",
"tie",
"trie",
];
assert!(Builder::new(0).is_err());
assert!(Builder::new(3).is_err());
let mut builder = Builder::new(4).unwrap();
for &key in &keys {
builder.add(key.as_bytes()).unwrap();
}
assert!(builder.add("tri".as_bytes()).is_err());
assert!(builder.add(&[0xFF, 0x00]).is_err());
let set = builder.finish();
let mut locator = set.locator();
for i in 0..keys.len() {
let id = locator.run(keys[i].as_bytes()).unwrap();
assert_eq!(i, id);
}
assert!(locator.run("aaa".as_bytes()).is_none());
assert!(locator.run("tell".as_bytes()).is_none());
assert!(locator.run("techno".as_bytes()).is_none());
assert!(locator.run("zzz".as_bytes()).is_none());
let mut decoder = set.decoder();
for i in 0..keys.len() {
assert_eq!(keys[i].as_bytes(), &decoder.run(i));
}
let mut iterator = set.iter();
for i in 0..keys.len() {
let (id, dec) = iterator.next().unwrap();
assert_eq!(i, id);
assert_eq!(keys[i].as_bytes(), &dec);
}
assert!(iterator.next().is_none());
let mut iterator = set.predictive_iter("idea".as_bytes());
{
let (id, dec) = iterator.next().unwrap();
assert_eq!(1, id);
assert_eq!(keys[1].as_bytes(), &dec);
}
{
let (id, dec) = iterator.next().unwrap();
assert_eq!(2, id);
assert_eq!(keys[2].as_bytes(), &dec);
}
{
let (id, dec) = iterator.next().unwrap();
assert_eq!(3, id);
assert_eq!(keys[3].as_bytes(), &dec);
}
assert!(iterator.next().is_none());
let mut buffer = vec![];
set.serialize_into(&mut buffer).unwrap();
assert_eq!(buffer.len(), set.size_in_bytes());
let other = Set::deserialize_from(&buffer[..]).unwrap();
let mut iterator = other.iter();
for i in 0..keys.len() {
let (id, dec) = iterator.next().unwrap();
assert_eq!(i, id);
assert_eq!(keys[i].as_bytes(), &dec);
}
assert!(iterator.next().is_none());
}
#[test]
fn test_random() {
let keys = gen_random_keys(10000, 8, 11);
let mut builder = Builder::new(8).unwrap();
for key in &keys {
builder.add(key).unwrap();
}
let set = builder.finish();
let mut locator = set.locator();
for i in 0..keys.len() {
let id = locator.run(&keys[i]).unwrap();
assert_eq!(i, id);
}
let mut decoder = set.decoder();
for i in 0..keys.len() {
let dec = decoder.run(i);
assert_eq!(&keys[i], &dec);
}
let mut iterator = set.iter();
for i in 0..keys.len() {
let (id, dec) = iterator.next().unwrap();
assert_eq!(i, id);
assert_eq!(&keys[i], &dec);
}
assert!(iterator.next().is_none());
let mut buffer = vec![];
set.serialize_into(&mut buffer).unwrap();
assert_eq!(buffer.len(), set.size_in_bytes());
let other = Set::deserialize_from(&buffer[..]).unwrap();
let mut iterator = other.iter();
for i in 0..keys.len() {
let (id, dec) = iterator.next().unwrap();
assert_eq!(i, id);
assert_eq!(&keys[i], &dec);
}
assert!(iterator.next().is_none());
}
}