Skip to content

Commit 8ed83e3

Browse files
committed
Fix BitVec::get_or_insert to scan only once.
1 parent f1a989f commit 8ed83e3

File tree

1 file changed

+25
-7
lines changed

1 file changed

+25
-7
lines changed

src/bitvec.rs

+25-7
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ impl AdaptiveMap {
3939
values: [0; SMALL_ELEMS],
4040
}
4141
}
42+
43+
/// Expand into `Large` mode if we are at capacity and have no
44+
/// zero-value pairs that can be trimmed.
4245
#[inline(never)]
4346
fn expand(&mut self) {
4447
match self {
@@ -76,13 +79,25 @@ impl AdaptiveMap {
7679
}
7780
#[inline(always)]
7881
fn get_or_insert<'a>(&'a mut self, key: u32) -> &'a mut u64 {
79-
let needs_expand = match self {
82+
// Check whether the key is present and we are in small mode;
83+
// if no to both, we need to expand first.
84+
let (needs_expand, small_mode_idx) = match self {
8085
&mut Self::Small { len, ref keys, .. } => {
81-
len == SMALL_ELEMS as u32 && !keys.iter().any(|k| *k == key)
86+
// Perform this scan but do not return right away;
87+
// doing so runs into overlapping-borrow issues
88+
// because the current non-lexical lifetimes
89+
// implementation is not able to see that the `self`
90+
// mutable borrow on return is only on the
91+
// early-return path.
92+
let small_mode_idx = keys.iter().position(|k| *k == key);
93+
let needs_expand = small_mode_idx.is_none() && len == SMALL_ELEMS as u32;
94+
(needs_expand, small_mode_idx)
8295
}
83-
_ => false,
96+
_ => (false, None),
8497
};
98+
8599
if needs_expand {
100+
assert!(small_mode_idx.is_none());
86101
self.expand();
87102
}
88103

@@ -92,11 +107,14 @@ impl AdaptiveMap {
92107
ref mut keys,
93108
ref mut values,
94109
} => {
95-
for i in 0..*len {
96-
if keys[i as usize] == key {
97-
return &mut values[i as usize];
98-
}
110+
// If we found the key already while checking whether
111+
// we need to expand above, use that index to return
112+
// early.
113+
if let Some(i) = small_mode_idx {
114+
return &mut values[i];
99115
}
116+
// Otherwise, the key must not be present; add a new
117+
// entry.
100118
assert!(*len < SMALL_ELEMS as u32);
101119
let idx = *len;
102120
*len += 1;

0 commit comments

Comments
 (0)