Skip to content

Commit edc19cd

Browse files
author
Roderick Bovee
committed
Add force_insert to bfield for (dangerous) post-creation updates
1 parent 7fdc0dd commit edc19cd

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

src/bfield.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,22 @@ impl<'a, T: Clone + DeserializeOwned + Serialize> BField<T> {
130130
self.members[0].params.other = Some(params);
131131
}
132132

133+
/// This allows an insert of a value into the b-field after the entire
134+
/// b-field build process has been completed.
135+
///
136+
/// It has the very bad downside of potentially knocking other keys out
137+
/// of the b-field by making them indeterminate (which will make them fall
138+
/// back to the secondaries where they don't exist and thus it'll appear
139+
/// as if they were never inserted to begin with)
140+
pub fn force_insert(&mut self, key: &[u8], value: BFieldVal) {
141+
debug_assert!(!self.read_only, "Can't insert into read_only bfields");
142+
for secondary in self.members.iter_mut() {
143+
if secondary.mask_or_insert(&key, value) {
144+
break;
145+
}
146+
}
147+
}
148+
133149
pub fn insert(&mut self, key: &[u8], value: BFieldVal, pass: usize) -> bool {
134150
debug_assert!(!self.read_only, "Can't insert into read_only bfields");
135151
debug_assert!(

src/bfield_member.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,46 @@ impl<T: Clone + DeserializeOwned + Serialize> BFieldMember<T> {
157157
}
158158
}
159159

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+
160200
#[inline]
161201
pub fn get(&self, key: &[u8]) -> BFieldLookup {
162202
let k = u32::from(self.params.n_marker_bits);
@@ -284,3 +324,27 @@ fn test_bfield_bits_set() {
284324
bfield.insert(b"test3", 300);
285325
assert!(bfield.bitvec.rank(0..128) < 24); // 23 bits set
286326
}
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

Comments
 (0)