use std::io;
use binout::{Serializer, VByte};
use seedable_hash::map64_to_64;
use crate::seeds::SeedSize;
use super::SeedChooser;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct Conf {
pub(crate) buckets_num: usize, pub(crate) slice_len_minus_one: u16, pub(crate) num_of_slices: usize, }
#[inline(always)]
pub(crate) fn mult_hi(a: u64, b: u64) -> u64 {
let r = (a as u128) * (b as u128);
(r >> 64) as u64
}
#[inline(always)]
pub(crate) fn mix_key_seed(key: u64, seed: u16) -> u16 {
mult_hi((seed as u64).wrapping_mul(0x51_7c_c1_b7_27_22_0a_95 ), key) as u16
}
#[inline(always)]
pub(crate) fn mix(a: u64, b: u64) -> u64 {
let r = (a as u128) * (b as u128);
((r >> 64) ^ r) as u64
}
#[inline]
pub const fn bits_per_seed_to_100_bucket_size(bits_per_seed: u8) -> u16 {
match bits_per_seed {
0..=4 => 250,
5 => 290,
6 => 320,
7 => 370,
8 => 450,
9 => 530,
10 => 590,
11 => 650,
12 => 720,
13 => 770,
_ => 830
}
}
impl Conf {
pub(crate) fn new(output_range: usize, input_size: usize, bucket_size_100: u16, slice_len: u16, max_shift: u16) -> Self {
let bucket_size_100 = bucket_size_100 as usize;
Self {
buckets_num: 1.max((input_size * 100 + bucket_size_100/2) / bucket_size_100),
slice_len_minus_one: slice_len - 1,
num_of_slices: output_range + 1 - slice_len as usize - max_shift as usize,
}
}
#[inline] pub fn output_range<SC: SeedChooser>(&self, seed_chooser: SC, bits_per_seed: u8) -> usize {
self.num_of_slices + self.slice_len_minus_one as usize + seed_chooser.extra_shift(bits_per_seed) as usize
}
#[inline(always)]
pub fn bucket_for(&self, key: u64) -> usize {
map64_to_64(key, self.buckets_num as u64) as usize
}
#[inline(always)]
pub fn slice_begin(&self, key: u64) -> usize {
map64_to_64(key, self.num_of_slices as u64) as usize
}
#[inline(always)]
pub fn in_slice(&self, key: u64, seed: u16) -> usize {
(mult_hi((seed as u64).wrapping_mul(0x51_7c_c1_b7_27_22_0a_95 ), key) as u16 & self.slice_len_minus_one) as usize
}
#[inline(always)]
pub(crate) fn in_slice_nobump(&self, key: u64, seed: u16) -> usize {
(mix(mix(seed as u64 ^ 0xa076_1d64_78bd_642f, 0x1d8e_4e27_c47d_124f), key) as u16 & self.slice_len_minus_one) as usize
}
#[inline(always)]
pub(crate) fn in_slice_noseed(&self, key: u64) -> usize {
(key as u16 & self.slice_len_minus_one) as usize
}
#[inline(always)]
pub fn f(&self, key: u64, seed: u16) -> usize {
self.slice_begin(key) + self.in_slice(key, seed)
}
#[inline(always)]
pub(crate) fn f_shift0(&self, key: u64) -> usize {
self.slice_begin(key) + self.in_slice_noseed(key)
}
#[inline(always)]
pub(crate) fn f_nobump(&self, key: u64, seed: u16) -> usize {
self.slice_begin(key) + self.in_slice_nobump(key, seed)
}
#[inline] pub fn slice_len(&self) -> u16 {
self.slice_len_minus_one + 1
}
#[inline] pub(crate) fn new_seeds_vec<SS: SeedSize>(&self, seed_size: SS) -> Box<[SS::VecElement]> {
seed_size.new_zeroed_seed_vec(self.buckets_num)
}
pub fn write(&self, output: &mut dyn io::Write) -> io::Result<()> {
VByte::write(output, self.buckets_num)?;
VByte::write(output, self.slice_len_minus_one)?;
VByte::write(output, self.num_of_slices)
}
pub fn write_bytes(&self) -> usize {
VByte::size(self.buckets_num)
+ VByte::size(self.slice_len_minus_one)
+ VByte::size(self.num_of_slices)
}
pub fn read(input: &mut dyn io::Read) -> io::Result<Self>
{
let buckets_num = VByte::read(input)?;
let slice_len_minus_one = VByte::read(input)?;
let num_of_slices = VByte::read(input)?;
Ok(Self {
buckets_num,
slice_len_minus_one,
num_of_slices,
})
}
}
#[derive(Clone, Copy)]
pub struct Params<SS> {
pub seed_size: SS,
pub bucket_size100: u16,
pub preferred_slice_len: u16
}
impl<SS> Params<SS> {
#[inline]
pub fn new(seed_size: SS, bucket_size100: u16) -> Self {
Self { seed_size, bucket_size100, preferred_slice_len: 0 }
}
#[inline]
pub fn new_psl(seed_size: SS, bucket_size100: u16, preferred_slice_len: u16) -> Self {
Self { seed_size, bucket_size100, preferred_slice_len }
}
}
impl<SS: Copy+Into<u8>> Params<SS> {
#[inline(always)]
pub fn bits_per_seed(&self) -> u8 { self.seed_size.into() }
}