NibbleSlice struct.
This commit is contained in:
parent
f1315cff71
commit
930865fefb
138
src/nibbleslice.rs
Normal file
138
src/nibbleslice.rs
Normal file
@ -0,0 +1,138 @@
|
||||
use std::cmp::*;
|
||||
|
||||
/// Nibble-orientated view onto byte-slice, allowing nibble-precision offsets.
|
||||
///
|
||||
/// This is an immutable struct. No operations actually change it.
|
||||
#[derive(Debug, Copy, Clone, Eq, Ord)]
|
||||
pub struct NibbleSlice<'a> {
|
||||
data: &'a [u8],
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl<'a> NibbleSlice<'a> {
|
||||
/// Create a new nibble slice with the given byte-slice.
|
||||
pub fn new(data: &[u8]) -> NibbleSlice { NibbleSlice::new_offset(data, 0) }
|
||||
|
||||
/// Create a new nibble slice with the given byte-slice with a nibble offset.
|
||||
pub fn new_offset(data: &'a [u8], offset: usize) -> NibbleSlice { NibbleSlice{data: data, offset: offset} }
|
||||
|
||||
/// Is this an empty slice?
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
|
||||
/// Get the length (in nibbles, naturally) of this slice.
|
||||
pub fn len(&self) -> usize { self.data.len() * 2 - self.offset }
|
||||
|
||||
/// Get the nibble at position `i`.
|
||||
pub fn at(&self, i: usize) -> u8 {
|
||||
if (self.offset + i) & 1 == 1 {
|
||||
self.data[(self.offset + i) / 2] & 15u8
|
||||
}
|
||||
else {
|
||||
self.data[(self.offset + i) / 2] >> 4
|
||||
}
|
||||
}
|
||||
|
||||
/// Return object which represents a view on to this slice (further) offset by `i` nibbles.
|
||||
pub fn mid(&self, i: usize) -> Self { NibbleSlice{ data: self.data, offset: self.offset + i} }
|
||||
|
||||
/// Do we start with the same nibbles as the whole of `them`?
|
||||
pub fn starts_with(&self, them: &Self) -> bool { self.common_prefix(them) == them.len() }
|
||||
|
||||
/// How many of the same nibbles at the beginning do we match with `them`?
|
||||
pub fn common_prefix(&self, them: &Self) -> usize {
|
||||
let s = min(self.len(), them.len());
|
||||
let mut i = 0usize;
|
||||
while i < s {
|
||||
if self.at(i) != them.at(i) { break; }
|
||||
i += 1;
|
||||
}
|
||||
i
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq for NibbleSlice<'a> {
|
||||
fn eq(&self, them: &Self) -> bool {
|
||||
self.len() == them.len() && self.starts_with(them)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialOrd for NibbleSlice<'a> {
|
||||
fn partial_cmp(&self, them: &Self) -> Option<Ordering> {
|
||||
let s = min(self.len(), them.len());
|
||||
let mut i = 0usize;
|
||||
while i < s {
|
||||
match self.at(i).partial_cmp(&them.at(i)).unwrap() {
|
||||
Ordering::Less => return Some(Ordering::Less),
|
||||
Ordering::Greater => return Some(Ordering::Greater),
|
||||
_ => i += 1,
|
||||
}
|
||||
}
|
||||
self.len().partial_cmp(&them.len())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::NibbleSlice;
|
||||
static D: &'static [u8;3] = &[0x01u8, 0x23, 0x45];
|
||||
|
||||
#[test]
|
||||
fn basics() {
|
||||
let n = NibbleSlice::new(D);
|
||||
assert_eq!(n.len(), 6);
|
||||
assert!(!n.is_empty());
|
||||
|
||||
let n = NibbleSlice::new_offset(D, 6);
|
||||
assert!(n.is_empty());
|
||||
|
||||
let n = NibbleSlice::new_offset(D, 3);
|
||||
assert_eq!(n.len(), 3);
|
||||
for i in 0..3 {
|
||||
assert_eq!(n.at(i), i as u8 + 3);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mid() {
|
||||
let n = NibbleSlice::new(D);
|
||||
let m = n.mid(2);
|
||||
for i in 0..4 {
|
||||
assert_eq!(m.at(i), i as u8 + 2);
|
||||
}
|
||||
let m = n.mid(3);
|
||||
for i in 0..3 {
|
||||
assert_eq!(m.at(i), i as u8 + 3);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shared() {
|
||||
let n = NibbleSlice::new(D);
|
||||
|
||||
let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45, 0x67];
|
||||
let m = NibbleSlice::new(other);
|
||||
|
||||
assert_eq!(n.common_prefix(&m), 4);
|
||||
assert_eq!(m.common_prefix(&n), 4);
|
||||
assert_eq!(n.mid(1).common_prefix(&m.mid(1)), 3);
|
||||
assert_eq!(n.mid(1).common_prefix(&m.mid(2)), 0);
|
||||
assert_eq!(n.common_prefix(&m.mid(4)), 6);
|
||||
assert!(!n.starts_with(&m.mid(4)));
|
||||
assert!(m.mid(4).starts_with(&n));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare() {
|
||||
let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45];
|
||||
let n = NibbleSlice::new(D);
|
||||
let m = NibbleSlice::new(other);
|
||||
|
||||
assert!(n != m);
|
||||
assert!(n > m);
|
||||
assert!(m < n);
|
||||
|
||||
assert!(n == m.mid(4));
|
||||
assert!(n >= m.mid(4));
|
||||
assert!(n <= m.mid(4));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user