tetsy_trie_db/nibble/
nibbleslice.rs

1// Copyright 2017, 2018 Parity Technologies
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Nibble-orientated view onto byte-slice, allowing nibble-precision offsets.
16
17use crate::rstd::{cmp::*, fmt};
18use super::{nibble_ops, NibbleSlice, NibbleSliceIterator, BackingByteVec};
19use crate::node::NodeKey;
20use crate::node_codec::Partial;
21use tetsy_hash_db::Prefix;
22
23impl<'a> Iterator for NibbleSliceIterator<'a> {
24	type Item = u8;
25	fn next(&mut self) -> Option<u8> {
26		self.i += 1;
27		match self.i <= self.p.len() {
28			true => Some(self.p.at(self.i - 1)),
29			false => None,
30		}
31	}
32}
33
34impl<'a> NibbleSlice<'a> {
35	/// Create a new nibble slice with the given byte-slice.
36	pub fn new(data: &'a [u8]) -> Self { NibbleSlice::new_slice(data, 0) }
37
38	/// Create a new nibble slice with the given byte-slice with a nibble offset.
39	pub fn new_offset(data: &'a [u8], offset: usize) -> Self {
40		Self::new_slice(data, offset)
41	}
42
43	fn new_slice(data: &'a [u8], offset: usize) -> Self {
44		NibbleSlice {
45			data,
46			offset,
47		}
48	}
49
50	/// Get an iterator for the series of nibbles.
51	pub fn iter(&'a self) -> NibbleSliceIterator<'a> {
52		NibbleSliceIterator { p: self, i: 0 }
53	}
54
55	/// Get nibble slice from a `NodeKey`.
56	pub fn from_stored(i: &NodeKey) -> NibbleSlice {
57		NibbleSlice::new_offset(&i.1[..], i.0)
58	}
59
60	/// Helper function to create a owned `NodeKey` from this `NibbleSlice`.
61	pub fn to_stored(&self) -> NodeKey {
62		let split = self.offset / nibble_ops::NIBBLE_PER_BYTE;
63		let offset = self.offset % nibble_ops::NIBBLE_PER_BYTE;
64		(offset, self.data[split..].into())
65	}
66
67	/// Helper function to create a owned `NodeKey` from this `NibbleSlice`,
68	/// and for a given number of nibble.
69	/// Warning this method can be slow (number of nibble does not align the
70	/// original padding).
71	pub fn to_stored_range(&self, nb: usize) -> NodeKey {
72		if nb >= self.len() { return self.to_stored() }
73		if (self.offset + nb) % nibble_ops::NIBBLE_PER_BYTE == 0 {
74			// aligned
75			let start = self.offset / nibble_ops::NIBBLE_PER_BYTE;
76			let end = (self.offset + nb) / nibble_ops::NIBBLE_PER_BYTE;
77			(
78				self.offset % nibble_ops::NIBBLE_PER_BYTE,
79				BackingByteVec::from_slice(&self.data[start..end]),
80			)
81		} else {
82			// unaligned
83			let start = self.offset / nibble_ops::NIBBLE_PER_BYTE;
84			let end = (self.offset + nb) / nibble_ops::NIBBLE_PER_BYTE;
85			let ea = BackingByteVec::from_slice(&self.data[start..=end]);
86			let ea_offset = self.offset % nibble_ops::NIBBLE_PER_BYTE;
87			let n_offset = nibble_ops::number_padding(nb);
88			let mut result = (ea_offset, ea);
89			nibble_ops::shift_key(&mut result, n_offset);
90			result.1.pop();
91			result
92		}
93	}
94
95	/// Return true if the slice contains no nibbles.
96	pub fn is_empty(&self) -> bool { self.len() == 0 }
97
98	/// Get the length (in nibbles, naturally) of this slice.
99	#[inline]
100	pub fn len(&self) -> usize { self.data.len() * nibble_ops::NIBBLE_PER_BYTE - self.offset }
101
102	/// Get the nibble at position `i`.
103	#[inline(always)]
104	pub fn at(&self, i: usize) -> u8 {
105		nibble_ops::at(&self, i)
106	}
107
108	/// Return object which represents a view on to this slice (further) offset by `i` nibbles.
109	pub fn mid(&self, i: usize) -> NibbleSlice<'a> {
110		NibbleSlice {
111			data: self.data,
112			offset: self.offset + i,
113		}
114	}
115
116	/// Advance the view on the slice by `i` nibbles.
117	pub fn advance(&mut self, i: usize) {
118		debug_assert!(self.len() >= i);
119		self.offset += i;
120	}
121
122	/// Move back to a previously valid fix offset position.
123	pub fn back(&self, i: usize) -> NibbleSlice<'a> {
124		NibbleSlice {
125			data: self.data,
126			offset: i,
127		}
128	}
129
130	/// Do we start with the same nibbles as the whole of `them`?
131	pub fn starts_with(&self, them: &Self) -> bool { self.common_prefix(them) == them.len() }
132
133	/// How many of the same nibbles at the beginning do we match with `them`?
134	pub fn common_prefix(&self, them: &Self) -> usize {
135		let s = min(self.len(), them.len());
136		let mut i = 0usize;
137		while i < s {
138			if self.at(i) != them.at(i) { break; }
139			i += 1;
140		}
141		i
142	}
143
144	/// Return `Partial` representation of this slice:
145	/// first encoded byte and following slice.
146	pub fn right(&'a self) -> Partial {
147		let split = self.offset / nibble_ops::NIBBLE_PER_BYTE;
148		let nb = (self.len() % nibble_ops::NIBBLE_PER_BYTE) as u8;
149		if nb > 0 {
150			((nb, nibble_ops::pad_right(self.data[split])), &self.data[split + 1 ..])
151		} else {
152			((0, 0), &self.data[split..])
153		}
154	}
155
156	/// Return an iterator over `Partial` bytes representation.
157	pub fn right_iter(&'a self) -> impl Iterator<Item = u8> + 'a {
158		let (mut first, sl) = self.right();
159		let mut ix = 0;
160		crate::rstd::iter::from_fn(move || {
161			if first.0 > 0 {
162				first.0 = 0;
163				Some(nibble_ops::pad_right(first.1))
164			} else if ix < sl.len() {
165				ix += 1;
166				Some(sl[ix - 1])
167			} else {
168				None
169			}
170		})
171	}
172
173	/// Return `Partial` bytes iterator over a range of byte..
174	/// Warning can be slow when unaligned (similar to `to_stored_range`).
175	pub fn right_range_iter(&'a self, to: usize) -> impl Iterator<Item = u8> + 'a {
176		let mut nib_res = to % nibble_ops::NIBBLE_PER_BYTE;
177		let aligned_i = (self.offset + to) % nibble_ops::NIBBLE_PER_BYTE;
178		let aligned = aligned_i == 0;
179		let mut ix = self.offset / nibble_ops::NIBBLE_PER_BYTE;
180		let ix_lim = (self.offset + to) / nibble_ops::NIBBLE_PER_BYTE;
181		crate::rstd::iter::from_fn( move || {
182			if aligned {
183				if nib_res > 0 {
184					let v = nibble_ops::pad_right(self.data[ix]);
185					nib_res = 0;
186					ix += 1;
187					Some(v)
188				} else if ix < ix_lim {
189					ix += 1;
190					Some(self.data[ix - 1])
191				} else {
192					None
193				}
194			} else {
195				let (s1, s2) = nibble_ops::SPLIT_SHIFTS;
196				// unaligned
197				if nib_res > 0 {
198					let v = self.data[ix] >> s1;
199					let v = nibble_ops::pad_right(v);
200					nib_res = 0;
201					Some(v)
202				} else if ix < ix_lim {
203					ix += 1;
204					let b1 = self.data[ix - 1] << s2;
205					let b2 = self.data[ix] >> s1;
206					Some(b1 | b2)
207				} else {
208					None
209				}
210			}
211		})
212	}
213
214	/// Return left portion of `NibbleSlice`, if the slice
215	/// originates from a full key it will be the `Prefix of
216	/// the node`.
217	pub fn left(&'a self) -> Prefix {
218		let split = self.offset / nibble_ops::NIBBLE_PER_BYTE;
219		let ix = (self.offset % nibble_ops::NIBBLE_PER_BYTE) as u8;
220		if ix == 0 {
221			(&self.data[..split], None)
222		} else {
223			(&self.data[..split], Some(nibble_ops::pad_left(self.data[split])))
224		}
225	}
226
227	/// Owned version of a `Prefix` from a `left` method call.
228	pub fn left_owned(&'a self) -> (BackingByteVec, Option<u8>) {
229		let (a, b) = self.left();
230		(a.into(), b)
231	}
232}
233
234impl<'a> Into<NodeKey> for NibbleSlice<'a> {
235	fn into(self) -> NodeKey {
236		(self.offset, self.data.into())
237	}
238}
239
240impl<'a> PartialEq for NibbleSlice<'a> {
241	fn eq(&self, them: &Self) -> bool {
242		self.len() == them.len() && self.starts_with(them)
243	}
244}
245
246impl<'a> Eq for NibbleSlice<'a> { }
247
248impl<'a> PartialOrd for NibbleSlice<'a> {
249	fn partial_cmp(&self, them: &Self) -> Option<Ordering> {
250		Some(self.cmp(them))
251	}
252}
253
254impl<'a> Ord for NibbleSlice<'a> {
255	fn cmp(&self, them: &Self) -> Ordering {
256		let s = min(self.len(), them.len());
257		let mut i = 0usize;
258		while i < s {
259			match self.at(i).partial_cmp(&them.at(i)).unwrap() {
260				Ordering::Less => return Ordering::Less,
261				Ordering::Greater => return Ordering::Greater,
262				_ => i += 1,
263			}
264		}
265		self.len().cmp(&them.len())
266	}
267}
268
269#[cfg(feature = "std")]
270impl<'a> fmt::Debug for NibbleSlice<'a> {
271	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
272		for i in 0..self.len() {
273			match i {
274				0 => write!(f, "{:01x}", self.at(i))?,
275				_ => write!(f, "'{:01x}", self.at(i))?,
276			}
277		}
278		Ok(())
279	}
280}
281
282#[cfg(test)]
283mod tests {
284	use crate::nibble::{NibbleSlice, BackingByteVec};
285	static D: &'static [u8;3] = &[0x01u8, 0x23, 0x45];
286
287	#[test]
288	fn basics() {
289		let n = NibbleSlice::new(D);
290		assert_eq!(n.len(), 6);
291		assert!(!n.is_empty());
292
293		let n = NibbleSlice::new_offset(D, 6);
294		assert!(n.is_empty());
295
296		let n = NibbleSlice::new_offset(D, 3);
297		assert_eq!(n.len(), 3);
298		for i in 0..3 {
299			assert_eq!(n.at(i), i as u8 + 3);
300		}
301	}
302
303	#[test]
304	fn iterator() {
305		let n = NibbleSlice::new(D);
306		let mut nibbles: Vec<u8> = vec![];
307		nibbles.extend(n.iter());
308		assert_eq!(nibbles, (0u8..6).collect::<Vec<_>>())
309	}
310
311	#[test]
312	fn mid() {
313		let n = NibbleSlice::new(D);
314		let m = n.mid(2);
315		for i in 0..4 {
316			assert_eq!(m.at(i), i as u8 + 2);
317		}
318		let m = n.mid(3);
319		for i in 0..3 {
320			assert_eq!(m.at(i), i as u8 + 3);
321		}
322	}
323
324	#[test]
325	fn encoded_pre() {
326		let n = NibbleSlice::new(D);
327		assert_eq!(n.to_stored(), (0, BackingByteVec::from_slice(&[0x01, 0x23, 0x45])));
328		assert_eq!(n.mid(1).to_stored(), (1, BackingByteVec::from_slice(&[0x01, 0x23, 0x45])));
329		assert_eq!(n.mid(2).to_stored(), (0, BackingByteVec::from_slice(&[0x23, 0x45])));
330		assert_eq!(n.mid(3).to_stored(), (1, BackingByteVec::from_slice(&[0x23, 0x45])));
331	}
332
333	#[test]
334	fn from_encoded_pre() {
335		let n = NibbleSlice::new(D);
336		let stored: BackingByteVec = [0x01, 0x23, 0x45][..].into();
337		assert_eq!(n, NibbleSlice::from_stored(&(0, stored.clone())));
338		assert_eq!(n.mid(1), NibbleSlice::from_stored(&(1, stored)));
339	}
340
341	#[test]
342	fn range_iter() {
343		let n = NibbleSlice::new(D);
344		for i in [
345			vec![],
346			vec![0x00],
347			vec![0x01],
348			vec![0x00, 0x12],
349			vec![0x01, 0x23],
350			vec![0x00, 0x12, 0x34],
351			vec![0x01, 0x23, 0x45],
352		].iter().enumerate() {
353			range_iter_test(n, i.0, None, &i.1[..]);
354		}
355		for i in [
356			vec![],
357			vec![0x01],
358			vec![0x12],
359			vec![0x01, 0x23],
360			vec![0x12, 0x34],
361			vec![0x01, 0x23, 0x45],
362		].iter().enumerate() {
363			range_iter_test(n, i.0, Some(1), &i.1[..]);
364		}
365		for i in [
366			vec![],
367			vec![0x02],
368			vec![0x23],
369			vec![0x02, 0x34],
370			vec![0x23, 0x45],
371		].iter().enumerate() {
372			range_iter_test(n, i.0, Some(2), &i.1[..]);
373		}
374		for i in [
375			vec![],
376			vec![0x03],
377			vec![0x34],
378			vec![0x03, 0x45],
379		].iter().enumerate() {
380			range_iter_test(n, i.0, Some(3), &i.1[..]);
381		}
382	}
383
384	fn range_iter_test(n: NibbleSlice, nb: usize, mid: Option<usize>, res: &[u8]) {
385		let n = if let Some(i) = mid {
386			n.mid(i)
387		} else { n };
388		assert_eq!(&n.right_range_iter(nb).collect::<Vec<_>>()[..], res);
389	}
390
391	#[test]
392	fn shared() {
393		let n = NibbleSlice::new(D);
394
395		let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45, 0x67];
396		let m = NibbleSlice::new(other);
397
398		assert_eq!(n.common_prefix(&m), 4);
399		assert_eq!(m.common_prefix(&n), 4);
400		assert_eq!(n.mid(1).common_prefix(&m.mid(1)), 3);
401		assert_eq!(n.mid(1).common_prefix(&m.mid(2)), 0);
402		assert_eq!(n.common_prefix(&m.mid(4)), 6);
403		assert!(!n.starts_with(&m.mid(4)));
404		assert!(m.mid(4).starts_with(&n));
405	}
406
407	#[test]
408	fn compare() {
409		let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45];
410		let n = NibbleSlice::new(D);
411		let m = NibbleSlice::new(other);
412
413		assert!(n != m);
414		assert!(n > m);
415		assert!(m < n);
416
417		assert!(n == m.mid(4));
418		assert!(n >= m.mid(4));
419		assert!(n <= m.mid(4));
420	}
421}