diff --git a/CHANGELOG.md b/CHANGELOG.md index 11a3eba9cb..e972b3dcec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Fixed `IndexMap::truncate` leading to an inconsistent state. - Added `resize_with` to `Vec` - Added `retain_back` (aka `truncate_front`) to `Deque` - Fixed unsoundness in `Vec::IntoIter::drop` and `HistoryBuf::write`in the context of panicking drop implementations. diff --git a/src/index_map.rs b/src/index_map.rs index e8df5d45eb..c33b8f0d55 100644 --- a/src/index_map.rs +++ b/src/index_map.rs @@ -311,11 +311,14 @@ where where F: FnMut(&mut K, &mut V) -> bool, { - const INIT: Option = None; - self.entries .retain_mut(|entry| keep(&mut entry.key, &mut entry.value)); + self.reinsert_all(); + } + + fn reinsert_all(&mut self) { + const INIT: Option = None; if self.entries.len() < self.indices.len() { for index in self.indices.iter_mut() { *index = INIT; @@ -1299,6 +1302,7 @@ where } } } + self.core.reinsert_all(); } /* Private API */ @@ -2106,4 +2110,20 @@ mod tests { history_buf.clear(); assert_eq!(Dropper::count(), 0); } + + /// See + #[test] + fn truncate_invalid() { + let mut map: FnvIndexMap = FnvIndexMap::new(); + map.insert(4, 444).unwrap(); + map.insert(2, 222).unwrap(); + map.insert(0, 0).unwrap(); + map.insert(7, 7).unwrap(); + + assert_eq!(map.get(&2), Some(&222)); // ok before map.truncate(2); + map.truncate(2); + assert_eq!(map.iter().collect::>(), vec![(&4, &444), (&2, &222)]); // ok + assert_eq!(map.get(&4), Some(&444)); // ok + assert_eq!(map.get(&2), Some(&222)); // <-- key present in iter() but unreachable + } }