trie_db_fun/nibble/
mod.rs1use crate::{node::NodeKey, rstd::cmp};
18
19pub use self::leftnibbleslice::LeftNibbleSlice;
20
21mod leftnibbleslice;
22mod nibbleslice;
23mod nibblevec;
24
25pub mod nibble_ops {
27 use super::*;
28
29 pub const BIT_PER_NIBBLE: usize = 4;
31 pub const NIBBLE_PER_BYTE: usize = 2;
33 pub const NIBBLE_LENGTH: usize = 16;
35 pub const PADDING_BITMASK: u8 = 0x0F;
37 pub const CONTENT_HEADER_SIZE: u8 = 1;
39
40 #[inline(always)]
42 pub fn pad_left(b: u8) -> u8 {
43 b & !PADDING_BITMASK
44 }
45
46 #[inline(always)]
48 pub fn pad_right(b: u8) -> u8 {
49 b & PADDING_BITMASK
50 }
51
52 #[inline(always)]
54 pub fn at_left(ix: u8, b: u8) -> u8 {
55 if ix == 1 {
56 b & PADDING_BITMASK
57 } else {
58 b >> BIT_PER_NIBBLE
59 }
60 }
61
62 #[inline(always)]
64 pub fn left_nibble_at(v1: &[u8], ix: usize) -> u8 {
65 at_left((ix % NIBBLE_PER_BYTE) as u8, v1[ix / NIBBLE_PER_BYTE])
66 }
67
68 #[inline(always)]
70 pub fn at(s: &NibbleSlice, i: usize) -> u8 {
71 let ix = (s.offset + i) / NIBBLE_PER_BYTE;
72 let pad = (s.offset + i) % NIBBLE_PER_BYTE;
73 at_left(pad as u8, s.data[ix])
74 }
75
76 #[inline(always)]
78 pub fn push_at_left(ix: u8, v: u8, into: u8) -> u8 {
79 into | if ix == 1 { v } else { v << BIT_PER_NIBBLE }
80 }
81
82 #[inline]
84 pub fn number_padding(i: usize) -> usize {
85 i % NIBBLE_PER_BYTE
86 }
87
88 pub const SPLIT_SHIFTS: (usize, usize) = (4, 4);
92
93 pub fn biggest_depth(v1: &[u8], v2: &[u8]) -> usize {
95 let upper_bound = cmp::min(v1.len(), v2.len());
96 for a in 0..upper_bound {
97 if v1[a] != v2[a] {
98 return a * NIBBLE_PER_BYTE + left_common(v1[a], v2[a])
99 }
100 }
101 upper_bound * NIBBLE_PER_BYTE
102 }
103
104 #[inline(always)]
106 pub fn left_common(a: u8, b: u8) -> usize {
107 if a == b {
108 2
109 } else if pad_left(a) == pad_left(b) {
110 1
111 } else {
112 0
113 }
114 }
115
116 pub fn shift_key(key: &mut NodeKey, offset: usize) -> bool {
120 let old_offset = key.0;
121 key.0 = offset;
122 if old_offset > offset {
123 let (s1, s2) = nibble_ops::SPLIT_SHIFTS;
125 let kl = key.1.len();
126 (0..kl - 1).for_each(|i| key.1[i] = key.1[i] << s2 | key.1[i + 1] >> s1);
127 key.1[kl - 1] = key.1[kl - 1] << s2;
128 true
129 } else if old_offset < offset {
130 let (s1, s2) = nibble_ops::SPLIT_SHIFTS;
132 key.1.push(0);
133 (1..key.1.len())
134 .rev()
135 .for_each(|i| key.1[i] = key.1[i - 1] << s1 | key.1[i] >> s2);
136 key.1[0] = key.1[0] >> s2;
137 true
138 } else {
139 false
140 }
141 }
142}
143
144pub(crate) type BackingByteVec = smallvec::SmallVec<[u8; 40]>;
146
147#[cfg_attr(feature = "std", derive(Debug))]
151#[derive(Clone, PartialEq, Eq)]
152pub struct NibbleVec {
153 inner: BackingByteVec,
154 len: usize,
155}
156
157#[derive(Copy, Clone)]
180pub struct NibbleSlice<'a> {
181 data: &'a [u8],
182 offset: usize,
183}
184
185pub struct NibbleSliceIterator<'a> {
187 p: &'a NibbleSlice<'a>,
188 i: usize,
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194
195 #[test]
196 fn nibble_vec_size() {
197 assert_eq!(std::mem::size_of::<NibbleVec>(), 56);
198 }
199}