Skip to content

Commit 9b03b59

Browse files
MarcusGrassjaparic
authored andcommitted
Drive-by fix insert on full map
1 parent b6b3438 commit 9b03b59

File tree

1 file changed

+40
-18
lines changed

1 file changed

+40
-18
lines changed

src/indexmap.rs

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,11 @@ impl Pos {
9898
}
9999
}
100100

101-
struct Insert<V> {
101+
enum Insert<K, V> {
102+
Success(Inserted<V>),
103+
Full((K, V)),
104+
}
105+
struct Inserted<V> {
102106
index: usize,
103107
old_value: Option<V>,
104108
}
@@ -175,7 +179,7 @@ where
175179
});
176180
}
177181

178-
fn insert(&mut self, hash: HashValue, key: K, value: V) -> Insert<V> {
182+
fn insert(&mut self, hash: HashValue, key: K, value: V) -> Insert<K, V> {
179183
let mut probe = hash.desired_pos(Self::mask());
180184
let mut dist = 0;
181185

@@ -191,32 +195,38 @@ where
191195
let their_dist = entry_hash.probe_distance(Self::mask(), probe);
192196

193197
if their_dist < dist {
198+
if self.entries.is_full() {
199+
return Insert::Full((key, value));
200+
}
194201
// robin hood: steal the spot if it's better for us
195202
let index = self.entries.len();
196203
unsafe { self.entries.push_unchecked(Bucket { hash, key, value }) };
197-
return Insert {
204+
return Insert::Success(Inserted {
198205
index: self.insert_phase_2(probe, Pos::new(index, hash)),
199206
old_value: None
200-
}
207+
});
201208
} else if entry_hash == hash && unsafe { self.entries.get_unchecked(i).key == key }
202209
{
203-
return Insert {
210+
return Insert::Success(Inserted {
204211
index: i,
205212
old_value: Some(mem::replace(
206213
unsafe { &mut self.entries.get_unchecked_mut(i).value },
207214
value,
208215
)),
209-
};
216+
});
210217
}
211218
} else {
219+
if self.entries.is_full() {
220+
return Insert::Full((key, value))
221+
}
212222
// empty bucket, insert here
213223
let index = self.entries.len();
214224
*pos = Some(Pos::new(index, hash));
215225
unsafe { self.entries.push_unchecked(Bucket { hash, key, value }) };
216-
return Insert {
226+
return Insert::Success(Inserted {
217227
index,
218228
old_value: None,
219-
}
229+
});
220230
}
221231
dist += 1;
222232
});
@@ -394,11 +404,15 @@ impl<'a, K, V, const N: usize> VacantEntry<'a, K, V, N> where K: Eq + Hash {
394404
if self.core.entries.is_full() {
395405
Err(value)
396406
} else {
397-
let index = self.core.insert(self.hash_val, self.key, value).index;
398-
unsafe {
399-
// SAFETY: Already checked existence at instantiation and the only mutable reference
400-
// to the map is internally held.
401-
Ok(&mut self.core.entries.get_unchecked_mut(index).value)
407+
match self.core.insert(self.hash_val, self.key, value) {
408+
Insert::Success(inserted) => {
409+
unsafe {
410+
// SAFETY: Already checked existence at instantiation and the only mutable reference
411+
// to the map is internally held.
412+
Ok(&mut self.core.entries.get_unchecked_mut(inserted.index).value)
413+
}
414+
}
415+
Insert::Full((_, v)) => Err(v),
402416
}
403417
}
404418
}
@@ -777,11 +791,10 @@ where
777791
/// assert_eq!(map[&37], "c");
778792
/// ```
779793
pub fn insert(&mut self, key: K, value: V) -> Result<Option<V>, (K, V)> {
780-
if self.core.entries.is_full() {
781-
Err((key, value))
782-
} else {
783-
let hash = hash_with(&key, &self.build_hasher);
784-
Ok(self.core.insert(hash, key, value).old_value)
794+
let hash = hash_with(&key, &self.build_hasher);
795+
match self.core.insert(hash, key, value) {
796+
Insert::Success(inserted) => Ok(inserted.old_value),
797+
Insert::Full((k, v)) => Err((k, v))
785798
}
786799
}
787800

@@ -1129,6 +1142,15 @@ mod tests {
11291142
}
11301143
}
11311144

1145+
#[test]
1146+
fn insert_replaces_on_full_map() {
1147+
let mut a: FnvIndexMap<_, _, 2> = FnvIndexMap::new();
1148+
a.insert("k1", "v1").unwrap();
1149+
a.insert("k2", "v2").unwrap();
1150+
a.insert("k1", "v2").unwrap();
1151+
assert_eq!(a.get("k1"), a.get("k2"));
1152+
}
1153+
11321154
const MAP_SLOTS: usize = 4096;
11331155
fn almost_filled_map() -> FnvIndexMap<usize, usize, MAP_SLOTS> {
11341156
let mut almost_filled = FnvIndexMap::new();

0 commit comments

Comments
 (0)