@@ -157,6 +157,46 @@ impl<T: Clone + DeserializeOwned + Serialize> BFieldMember<T> {
157
157
}
158
158
}
159
159
160
+ /// "Removes" a key from the b-field by flipping an extra bit to make it
161
+ /// indeterminate. Use this with caution because it can make other keys
162
+ /// indeterminate by saturating the b-field with ones.
163
+ ///
164
+ /// Returns `true` if the value was inserted or was already present with
165
+ /// the correct value; `false` if masking occured or if it was already
166
+ /// indeterminate.
167
+ pub fn mask_or_insert ( & mut self , key : & [ u8 ] , value : BFieldVal ) -> bool {
168
+ let correct_marker = to_marker ( value, self . params . n_marker_bits ) ;
169
+ let k = u32:: from ( self . params . n_marker_bits ) ;
170
+ let existing_marker = self . get_raw ( key, k) ;
171
+
172
+ match existing_marker. count_ones ( ) . cmp ( & k) {
173
+ Ordering :: Greater => false , // already indeterminate
174
+ Ordering :: Equal => {
175
+ // value already in b-field, but is it correct?
176
+ if existing_marker == correct_marker {
177
+ return true ;
178
+ }
179
+ // try to find a new, invalid marker that has an extra
180
+ // bit over the existing marker so that it'll become
181
+ // indeterminate once we overwrite it
182
+ let mut pos = 0 ;
183
+ let mut new_marker = existing_marker;
184
+ while new_marker. count_ones ( ) == k {
185
+ new_marker = existing_marker | ( 1 << pos) ;
186
+ pos += 1 ;
187
+ }
188
+ // mask out the existing!
189
+ self . insert_raw ( key, new_marker) ;
190
+ false
191
+ } ,
192
+ Ordering :: Less => {
193
+ // nothing present; insert the value
194
+ self . insert_raw ( key, correct_marker) ;
195
+ true
196
+ } ,
197
+ }
198
+ }
199
+
160
200
#[ inline]
161
201
pub fn get ( & self , key : & [ u8 ] ) -> BFieldLookup {
162
202
let k = u32:: from ( self . params . n_marker_bits ) ;
@@ -284,3 +324,27 @@ fn test_bfield_bits_set() {
284
324
bfield. insert ( b"test3" , 300 ) ;
285
325
assert ! ( bfield. bitvec. rank( 0 ..128 ) < 24 ) ; // 23 bits set
286
326
}
327
+
328
+ #[ test]
329
+ fn test_bfield_mask_or_insert ( ) {
330
+ let mut bfield: BFieldMember < usize > = BFieldMember :: in_memory ( 1024 , 2 , 16 , 4 ) . unwrap ( ) ;
331
+
332
+ bfield. insert ( b"test" , 2 ) ;
333
+ assert_eq ! ( bfield. get( b"test" ) , BFieldLookup :: Some ( 2 ) ) ;
334
+
335
+ // `mask_or_insert`ing the same value doesn't change anything
336
+ assert_eq ! ( bfield. mask_or_insert( b"test" , 2 ) , true ) ;
337
+ assert_eq ! ( bfield. get( b"test" ) , BFieldLookup :: Some ( 2 ) ) ;
338
+
339
+ // `mask_or_insert`ing a new value results in an indeterminate
340
+ assert_eq ! ( bfield. mask_or_insert( b"test" , 3 ) , false ) ;
341
+ assert_eq ! ( bfield. get( b"test" ) , BFieldLookup :: Indeterminate ) ;
342
+
343
+ // `mask_or_insert`ing an indeterminate value is still indeterminate
344
+ assert_eq ! ( bfield. mask_or_insert( b"test" , 3 ) , false ) ;
345
+ assert_eq ! ( bfield. get( b"test" ) , BFieldLookup :: Indeterminate ) ;
346
+
347
+ // `mask_or_insert`ing a new key just sets that key
348
+ assert_eq ! ( bfield. mask_or_insert( b"test2" , 2 ) , true ) ;
349
+ assert_eq ! ( bfield. get( b"test2" ) , BFieldLookup :: Some ( 2 ) ) ;
350
+ }
0 commit comments