BitVec: remove zero words to avoid expanding when unnecessary.
This commit is contained in:
@@ -43,16 +43,34 @@ impl AdaptiveMap {
|
|||||||
fn expand(&mut self) {
|
fn expand(&mut self) {
|
||||||
match self {
|
match self {
|
||||||
&mut Self::Small {
|
&mut Self::Small {
|
||||||
len,
|
ref mut len,
|
||||||
ref keys,
|
ref mut keys,
|
||||||
ref values,
|
ref mut values,
|
||||||
} => {
|
} => {
|
||||||
|
// Note: we *may* remain as `Small` if there are any
|
||||||
|
// zero elements. Try removing them first, before we
|
||||||
|
// commit to a memory allocation.
|
||||||
|
if values.iter().any(|v| *v == 0) {
|
||||||
|
let mut out = 0;
|
||||||
|
for i in 0..(*len as usize) {
|
||||||
|
if values[i] == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if out < i {
|
||||||
|
keys[out] = keys[i];
|
||||||
|
values[out] = values[i];
|
||||||
|
}
|
||||||
|
out += 1;
|
||||||
|
}
|
||||||
|
*len = out as u32;
|
||||||
|
} else {
|
||||||
let mut map = FxHashMap::default();
|
let mut map = FxHashMap::default();
|
||||||
for i in 0..len {
|
for i in 0..(*len as usize) {
|
||||||
map.insert(keys[i as usize], values[i as usize]);
|
map.insert(keys[i], values[i]);
|
||||||
}
|
}
|
||||||
*self = Self::Large(map);
|
*self = Self::Large(map);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -256,6 +274,15 @@ impl BitVec {
|
|||||||
set_bits(bits).map(move |i| BITS_PER_WORD * word_idx + i)
|
set_bits(bits).map(move |i| BITS_PER_WORD * word_idx + i)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is the adaptive data structure in "small" mode? This is meant
|
||||||
|
/// for testing assertions only.
|
||||||
|
pub(crate) fn is_small(&self) -> bool {
|
||||||
|
match &self.elems {
|
||||||
|
&AdaptiveMap::Small { .. } => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_bits(bits: u64) -> impl Iterator<Item = usize> {
|
fn set_bits(bits: u64) -> impl Iterator<Item = usize> {
|
||||||
@@ -309,4 +336,18 @@ mod test {
|
|||||||
|
|
||||||
assert_eq!(sum, checksum);
|
assert_eq!(sum, checksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_expand_remove_zero_elems() {
|
||||||
|
let mut vec = BitVec::new();
|
||||||
|
// Set 12 different words (this is the max small-mode size).
|
||||||
|
for i in 0..12 {
|
||||||
|
vec.set(64 * i, true);
|
||||||
|
}
|
||||||
|
// Now clear a bit, and set a bit in a different word. We
|
||||||
|
// should still be in small mode.
|
||||||
|
vec.set(64 * 5, false);
|
||||||
|
vec.set(64 * 100, true);
|
||||||
|
assert!(vec.is_small());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user