use crate::{node::NodeKey, rstd::cmp};
pub use self::leftnibbleslice::LeftNibbleSlice;
mod leftnibbleslice;
mod nibbleslice;
mod nibblevec;
pub mod nibble_ops {
use super::*;
pub const BIT_PER_NIBBLE: usize = 4;
pub const NIBBLE_PER_BYTE: usize = 2;
pub const NIBBLE_LENGTH: usize = 16;
pub const PADDING_BITMASK: u8 = 0x0F;
pub const CONTENT_HEADER_SIZE: u8 = 1;
#[inline(always)]
pub fn pad_left(b: u8) -> u8 {
b & !PADDING_BITMASK
}
#[inline(always)]
pub fn pad_right(b: u8) -> u8 {
b & PADDING_BITMASK
}
#[inline(always)]
pub fn at_left(ix: u8, b: u8) -> u8 {
if ix == 1 {
b & PADDING_BITMASK
} else {
b >> BIT_PER_NIBBLE
}
}
#[inline(always)]
pub fn left_nibble_at(v1: &[u8], ix: usize) -> u8 {
at_left((ix % NIBBLE_PER_BYTE) as u8, v1[ix / NIBBLE_PER_BYTE])
}
#[inline(always)]
pub fn at(s: &NibbleSlice, i: usize) -> u8 {
let ix = (s.offset + i) / NIBBLE_PER_BYTE;
let pad = (s.offset + i) % NIBBLE_PER_BYTE;
at_left(pad as u8, s.data[ix])
}
#[inline(always)]
pub fn push_at_left(ix: u8, v: u8, into: u8) -> u8 {
into | if ix == 1 { v } else { v << BIT_PER_NIBBLE }
}
#[inline]
pub fn number_padding(i: usize) -> usize {
i % NIBBLE_PER_BYTE
}
pub const SPLIT_SHIFTS: (usize, usize) = (4, 4);
pub fn biggest_depth(v1: &[u8], v2: &[u8]) -> usize {
let upper_bound = cmp::min(v1.len(), v2.len());
for a in 0..upper_bound {
if v1[a] != v2[a] {
return a * NIBBLE_PER_BYTE + left_common(v1[a], v2[a])
}
}
upper_bound * NIBBLE_PER_BYTE
}
#[inline(always)]
pub fn left_common(a: u8, b: u8) -> usize {
if a == b {
2
} else if pad_left(a) == pad_left(b) {
1
} else {
0
}
}
pub fn shift_key(key: &mut NodeKey, offset: usize) -> bool {
let old_offset = key.0;
key.0 = offset;
if old_offset > offset {
let (s1, s2) = nibble_ops::SPLIT_SHIFTS;
let kl = key.1.len();
(0..kl - 1).for_each(|i| key.1[i] = key.1[i] << s2 | key.1[i + 1] >> s1);
key.1[kl - 1] = key.1[kl - 1] << s2;
true
} else if old_offset < offset {
let (s1, s2) = nibble_ops::SPLIT_SHIFTS;
key.1.push(0);
(1..key.1.len())
.rev()
.for_each(|i| key.1[i] = key.1[i - 1] << s1 | key.1[i] >> s2);
key.1[0] = key.1[0] >> s2;
true
} else {
false
}
}
}
pub(crate) type BackingByteVec = smallvec::SmallVec<[u8; 40]>;
#[cfg_attr(feature = "std", derive(Debug))]
#[derive(Clone, PartialEq, Eq)]
pub struct NibbleVec {
inner: BackingByteVec,
len: usize,
}
#[derive(Copy, Clone)]
pub struct NibbleSlice<'a> {
data: &'a [u8],
offset: usize,
}
pub struct NibbleSliceIterator<'a> {
p: &'a NibbleSlice<'a>,
i: usize,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn nibble_vec_size() {
assert_eq!(std::mem::size_of::<NibbleVec>(), 56);
}
}