1
+ use bumpalo:: Bump ;
2
+
1
3
#[ repr( u8 ) ]
2
4
#[ derive( PartialEq , Eq , Clone , Debug , Copy , Hash ) ]
3
5
pub enum ChildPos {
@@ -9,33 +11,42 @@ pub enum ChildPos {
9
11
/// are laid out in big-endian order, where the left-most byte is index 0. The
10
12
/// path is built from left to right, since it's parsed right to left when
11
13
/// followed).
12
- #[ derive( Clone , Debug , PartialEq ) ]
13
- pub struct PathBuilder {
14
- // TODO: It might make sense to implement small object optimization here.
15
- // The vast majority of paths are just a single byte, statically allocate 8
16
- // would seem reasonable
17
- store : Vec < u8 > ,
14
+ #[ derive( Debug , PartialEq ) ]
15
+ pub struct PathBuilder < ' a > {
16
+ store : & ' a mut [ u8 ] ,
17
+ in_use : u32 ,
18
18
/// the bit the next write will happen to (counts down)
19
19
bit_pos : u8 ,
20
20
}
21
21
22
- impl Default for PathBuilder {
22
+ impl Default for PathBuilder < ' _ > {
23
23
fn default ( ) -> Self {
24
24
Self {
25
- store : Vec :: with_capacity ( 16 ) ,
25
+ store : & mut [ ] ,
26
+ in_use : 0 ,
26
27
bit_pos : 7 ,
27
28
}
28
29
}
29
30
}
30
31
31
- impl PathBuilder {
32
- pub fn push ( & mut self , dir : ChildPos ) {
32
+ impl < ' a > PathBuilder < ' a > {
33
+ pub fn push ( & mut self , a : & ' a Bump , dir : ChildPos ) {
33
34
if self . bit_pos == 7 {
34
- self . store . push ( 0 ) ;
35
+ if self . in_use as usize == self . store . len ( ) {
36
+ let old_size = self . store . len ( ) ;
37
+ let new_size = std:: cmp:: max ( old_size * 2 , 16 ) ;
38
+ let new_store = a. alloc_slice_fill_default :: < u8 > ( new_size) ;
39
+ new_store[ 0 ..old_size] . copy_from_slice ( self . store ) ;
40
+ self . store = new_store;
41
+ }
42
+ self . in_use += 1 ;
35
43
}
36
44
45
+ assert ! ( self . in_use > 0 ) ;
46
+ assert ! ( self . store. len( ) >= self . in_use as usize ) ;
47
+
37
48
if dir == ChildPos :: Right {
38
- * self . store . last_mut ( ) . unwrap ( ) |= 1 << self . bit_pos ;
49
+ self . store [ self . in_use as usize - 1 ] |= 1 << self . bit_pos ;
39
50
}
40
51
if self . bit_pos == 0 {
41
52
self . bit_pos = 7 ;
@@ -44,20 +55,28 @@ impl PathBuilder {
44
55
}
45
56
}
46
57
47
- pub fn done ( mut self ) -> Vec < u8 > {
58
+ pub fn clone ( & self , a : & ' a Bump ) -> Self {
59
+ Self {
60
+ store : a. alloc_slice_copy ( self . store ) ,
61
+ in_use : self . in_use ,
62
+ bit_pos : self . bit_pos ,
63
+ }
64
+ }
65
+
66
+ pub fn done ( self ) -> Vec < u8 > {
48
67
if self . bit_pos < 7 {
49
68
let right_shift = self . bit_pos + 1 ;
50
69
let left_shift = 7 - self . bit_pos ;
51
70
// we need to shift all bits to the right, to right-align the path
52
71
let mask = 0xff << left_shift;
53
- for idx in ( 1 ..self . store . len ( ) ) . rev ( ) {
72
+ for idx in ( 1 ..self . in_use as usize ) . rev ( ) {
54
73
self . store [ idx] >>= right_shift;
55
74
let from_next = self . store [ idx - 1 ] << left_shift;
56
75
self . store [ idx] |= from_next & mask;
57
76
}
58
77
self . store [ 0 ] >>= right_shift;
59
78
}
60
- self . store
79
+ self . store [ 0 .. self . in_use as usize ] . to_vec ( )
61
80
}
62
81
63
82
pub fn is_empty ( & self ) -> bool {
@@ -66,17 +85,17 @@ impl PathBuilder {
66
85
67
86
pub fn len ( & self ) -> u32 {
68
87
if self . bit_pos == 7 {
69
- ( self . store . len ( ) as u32 ) * u8:: BITS
88
+ self . in_use * u8:: BITS
70
89
} else {
71
- ( self . store . len ( ) as u32 ) * u8:: BITS - self . bit_pos as u32 - 1
90
+ self . in_use * u8:: BITS - self . bit_pos as u32 - 1
72
91
}
73
92
}
74
93
75
94
/// returns the number of bytes this atom would need to serialize If this,
76
95
/// plus 1 (for the 0xfe introduction) is larger or equal to the one we're
77
96
/// deduplicating, we should leave it.
78
97
pub fn serialized_length ( & self ) -> u32 {
79
- let len = self . store . len ( ) as u32 ;
98
+ let len = self . in_use ;
80
99
match len {
81
100
0 => 1 ,
82
101
// if we have one byte, the top bit determines whether we can
@@ -108,7 +127,7 @@ impl PathBuilder {
108
127
match lhs_len. cmp ( & rhs_len) {
109
128
Ordering :: Less => true ,
110
129
Ordering :: Greater => false ,
111
- Ordering :: Equal => self . store <= rhs . store ,
130
+ Ordering :: Equal => rhs . store . cmp ( & self . store ) != Ordering :: Less ,
112
131
}
113
132
}
114
133
}
@@ -120,17 +139,20 @@ mod tests {
120
139
use hex;
121
140
use rstest:: rstest;
122
141
123
- fn build_path ( input : & [ u8 ] ) -> PathBuilder {
142
+ fn build_path < ' a > ( a : & ' a Bump , input : & [ u8 ] ) -> PathBuilder < ' a > {
124
143
let mut path = PathBuilder :: default ( ) ;
125
144
// keep in mind that paths are built in reverse order (starting from the
126
145
// target).
127
146
for ( idx, b) in input. iter ( ) . enumerate ( ) {
128
147
assert_eq ! ( path. len( ) , idx as u32 ) ;
129
- path. push ( if * b == 0 {
130
- ChildPos :: Left
131
- } else {
132
- ChildPos :: Right
133
- } ) ;
148
+ path. push (
149
+ a,
150
+ if * b == 0 {
151
+ ChildPos :: Left
152
+ } else {
153
+ ChildPos :: Right
154
+ } ,
155
+ ) ;
134
156
}
135
157
path
136
158
}
@@ -155,7 +177,8 @@ mod tests {
155
177
#[ case( & [ 1 , 1 , 1 , 0 , 0 ] , "1c" ) ]
156
178
#[ case( & [ 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 0 ] , "0148" ) ]
157
179
fn test_build ( #[ case] input : & [ u8 ] , #[ case] expect : & str ) {
158
- let path = build_path ( input) ;
180
+ let a = Bump :: new ( ) ;
181
+ let path = build_path ( & a, input) ;
159
182
let ret = path. done ( ) ;
160
183
assert_eq ! ( hex:: encode( ret) , expect) ;
161
184
}
@@ -187,8 +210,9 @@ mod tests {
187
210
#[ case( & [ 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] , & [ 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] , false ) ]
188
211
#[ case( & [ 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ] , & [ 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] , false ) ]
189
212
fn test_better_than ( #[ case] lhs : & [ u8 ] , #[ case] rhs : & [ u8 ] , #[ case] expect : bool ) {
190
- let lhs = build_path ( lhs) ;
191
- let rhs = build_path ( rhs) ;
213
+ let a = Bump :: new ( ) ;
214
+ let lhs = build_path ( & a, lhs) ;
215
+ let rhs = build_path ( & a, rhs) ;
192
216
assert_eq ! ( lhs. better_than( & rhs) , expect) ;
193
217
}
194
218
@@ -209,9 +233,10 @@ mod tests {
209
233
#[ case( 513 ) ]
210
234
#[ case( 0xfff9 ) ]
211
235
fn test_serialized_length ( #[ case] num_bits : u32 ) {
236
+ let a = Bump :: new ( ) ;
212
237
let mut path = PathBuilder :: default ( ) ;
213
238
for _ in 0 ..num_bits {
214
- path. push ( ChildPos :: Right ) ;
239
+ path. push ( & a , ChildPos :: Right ) ;
215
240
}
216
241
let ser_len = path. serialized_length ( ) ;
217
242
let vec = path. done ( ) ;
0 commit comments