Skip to content

Commit fda97aa

Browse files
committed
Providing default implementation for ZipperMoving::to_prev_sibling_byte, which fixes the remaining WriteZipper ZipperMoving test
1 parent 531c649 commit fda97aa

3 files changed

Lines changed: 110 additions & 23 deletions

File tree

src/utils.rs

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub struct ByteMask(pub [u64; 4]);
88

99
impl ByteMask {
1010
pub const EMPTY: ByteMask = Self(empty_mask());
11+
pub const FULL: ByteMask = Self([!0u64; 4]);
1112

1213
/// Create a new empty ByteMask
1314
#[inline]
@@ -90,7 +91,7 @@ impl ByteMask {
9091
}
9192

9293
/// Returns the bit in the mask corresponding to the next highest bit above `byte`, or `None`
93-
/// if `byte` was the highest set bit in the mask
94+
/// if `byte` was at or above the highest set bit in the mask
9495
pub fn next_bit(&self, byte: u8) -> Option<u8> {
9596
if byte == 255 {
9697
return None
@@ -130,6 +131,48 @@ impl ByteMask {
130131
}
131132
None
132133
}
134+
135+
/// Returns the bit in the mask corresponding to the previous bit below `byte`, or `None`
136+
/// if `byte` was at or below the lowest set bit in the mask
137+
pub fn prev_bit(&self, byte: u8) -> Option<u8> {
138+
if byte == 0 {
139+
return None
140+
}
141+
let byte = byte - 1;
142+
let word_idx = byte >> 6;
143+
let mod_idx = byte & 0x3F;
144+
let mut mask = !0u64 >> (63 - mod_idx);
145+
if word_idx == 3 {
146+
let cnt = (self.0[3] & mask).leading_zeros() as u8;
147+
if cnt < 64 {
148+
return Some(255 - cnt)
149+
}
150+
mask = !0u64;
151+
}
152+
if word_idx > 1 {
153+
let cnt = (self.0[2] & mask).leading_zeros() as u8;
154+
if cnt < 64 {
155+
return Some(191 - cnt)
156+
}
157+
if word_idx == 2 {
158+
mask = !0u64;
159+
}
160+
}
161+
if word_idx > 0 {
162+
let cnt = (self.0[1] & mask).leading_zeros() as u8;
163+
if cnt < 64 {
164+
return Some(127 - cnt)
165+
}
166+
if word_idx == 1 {
167+
mask = !0u64;
168+
}
169+
}
170+
let cnt = (self.0[0] & mask).leading_zeros() as u8;
171+
if cnt < 64 {
172+
return Some(63 - cnt)
173+
}
174+
None
175+
}
133176
}
134177

135178
impl core::fmt::Debug for ByteMask {
@@ -548,22 +591,41 @@ fn bit_utils_test() {
548591

549592
#[test]
550593
fn next_bit_test() {
551-
let test_mask = ByteMask::from([
552-
0b1010010010010010010010000000000000000000000000000000000000010101u64,
553-
0b0000000000000000000000000000000000000000100000000000000000000000u64,
554-
0b0000000000000000000000000000000000000000000000000000000000000000u64,
555-
0b1000000000000000000000000000010000000000000000000000000000000001u64,
556-
]);
557-
let set_bits: Vec<u8> = (0..=255).into_iter().filter(|i| test_mask.test_bit(*i)).collect();
558-
559-
let mut i = 0;
560-
let mut cnt = test_mask.test_bit(0) as usize;
561-
while let Some(next_bit) = test_mask.next_bit(i) {
562-
assert!(test_mask.test_bit(next_bit));
563-
i = next_bit;
564-
cnt += 1;
565-
}
566-
assert_eq!(cnt, set_bits.len());
594+
fn do_test(test_mask: ByteMask) {
595+
let set_bits: Vec<u8> = (0..=255).into_iter().filter(|i| test_mask.test_bit(*i)).collect();
596+
597+
let mut i = 0;
598+
let mut cnt = test_mask.test_bit(0) as usize;
599+
while let Some(next_bit) = test_mask.next_bit(i) {
600+
assert!(test_mask.test_bit(next_bit));
601+
i = next_bit;
602+
cnt += 1;
603+
}
604+
assert_eq!(cnt, set_bits.len());
605+
606+
let mut i = 255;
607+
let mut cnt = test_mask.test_bit(255) as usize;
608+
while let Some(prev_bit) = test_mask.prev_bit(i) {
609+
assert!(test_mask.test_bit(prev_bit));
610+
i = prev_bit;
611+
cnt += 1;
612+
}
613+
assert_eq!(cnt, set_bits.len());
614+
}
615+
616+
// do_test(ByteMask::from([
617+
// 0b1010010010010010010010000000000000000000000000000000000000010101u64,
618+
// 0b0000000000000000000000000000000000000000100000000000000000000000u64,
619+
// 0b0000000000000000000000000000000000000000000000000000000000000000u64,
620+
// 0b1001000000000000000000000000000000000000000000000000000000000001u64,
621+
// ]));
622+
// do_test(ByteMask::from([
623+
// 0b0000000000000000000000000000000000000000000000000000000000000000u64,
624+
// 0b0000000000000000000000000000000000000000100000000000000000000000u64,
625+
// 0b0000000000000000000000000000000000000000000000000000000000000000u64,
626+
// 0b1001000000000000000000000000000000000000000000000000000000000001u64,
627+
// ]));
628+
do_test(ByteMask::from(ByteMask::FULL));
567629
}
568630

569631
#[test]

src/write_zipper.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -813,10 +813,6 @@ impl<V: Clone + Send + Sync + Unpin> ZipperMoving for WriteZipperCore<'_, '_, V>
813813
}
814814
}
815815

816-
fn to_prev_sibling_byte(&mut self) -> bool {
817-
unimplemented!()
818-
}
819-
820816
fn ascend(&mut self, mut steps: usize) -> bool {
821817
loop {
822818
if self.key.node_key().len() == 0 {

src/zipper.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,11 @@ pub trait ZipperMoving: Zipper + ZipperMovingPriv {
120120
}
121121

122122
/// Resets the zipper's focus back to its root
123-
fn reset(&mut self);
123+
fn reset(&mut self) {
124+
while !self.at_root() {
125+
self.ascend_byte();
126+
}
127+
}
124128

125129
/// Returns the path from the zipper's root to the current focus
126130
fn path(&self) -> &[u8];
@@ -259,11 +263,15 @@ pub trait ZipperMoving: Zipper + ZipperMovingPriv {
259263

260264
/// Ascends the zipper to the nearest upstream branch point or value. Returns `true` if the zipper
261265
/// focus moved upwards, otherwise returns `false` if the zipper was already at the root
266+
///
267+
/// NOTE: A default implementation could be provided, but all current zippers have more optimal native implementations.
262268
fn ascend_until(&mut self) -> bool;
263269

264270
/// Ascends the zipper to the nearest upstream branch point, skipping over values along the way. Returns
265271
/// `true` if the zipper focus moved upwards, otherwise returns `false` if the zipper was already at the
266272
/// root
273+
///
274+
/// NOTE: A default implementation could be provided, but all current zippers have more optimal native implementations.
267275
fn ascend_until_branch(&mut self) -> bool;
268276

269277
//GOAT, I think this method ought to behave like the other two, and ascend above the current value, instead
@@ -337,7 +345,28 @@ pub trait ZipperMoving: Zipper + ZipperMovingPriv {
337345
///
338346
/// This method is equivalent to calling [Self::ascend] with `1`, followed by [Self::descend_indexed_branch]
339347
/// where the index passed is 1 less than the index of the current focus position.
340-
fn to_prev_sibling_byte(&mut self) -> bool;
348+
fn to_prev_sibling_byte(&mut self) -> bool {
349+
let cur_byte = match self.path().last() {
350+
Some(byte) => *byte,
351+
None => return false
352+
};
353+
if !self.ascend_byte() {
354+
return false
355+
}
356+
let mask = self.child_mask();
357+
match mask.prev_bit(cur_byte) {
358+
Some(byte) => {
359+
let descended = self.descend_to_byte(byte);
360+
debug_assert!(descended);
361+
true
362+
},
363+
None => {
364+
let descended = self.descend_to_byte(cur_byte);
365+
debug_assert!(descended);
366+
false
367+
}
368+
}
369+
}
341370

342371
/// Advances the zipper to visit every existing path within the trie in a depth-first order
343372
///

0 commit comments

Comments
 (0)