diff --git a/benches/insert_no_overwrite_unchecked.rs b/benches/insert_no_overwrite_unchecked.rs new file mode 100644 index 00000000..9ad431a5 --- /dev/null +++ b/benches/insert_no_overwrite_unchecked.rs @@ -0,0 +1,29 @@ +#![feature(test)] + +extern crate test; + +use test::Bencher; + +use indexmap::IndexMap; + +#[bench] +fn insert(b: &mut Bencher) { + b.iter(|| { + let mut m = IndexMap::with_capacity(1000); + for i in 0..1000 { + m.insert(i, i); + } + m + }); +} + +#[bench] +fn insert_no_overwrite_unchecked(b: &mut Bencher) { + b.iter(|| { + let mut m = IndexMap::with_capacity(1000); + for i in 0..1000 { + m.insert_no_overwrite_unchecked(i, i); + } + m + }); +} diff --git a/src/map.rs b/src/map.rs index 3a43a79b..5cf7f18b 100644 --- a/src/map.rs +++ b/src/map.rs @@ -373,6 +373,26 @@ where self.core.insert_full(hash, key, value) } + /// Insert a key-value pair into the map without checking + /// if the key already exists in the map. + /// + /// This operation is safe if a key does not exist in the map. + /// + /// However, if a key exists in the map already, the behavior is unspecified: + /// this operation may panic, or any following operation with the map may panic + /// or return arbitrary result. + /// + /// This operation is faster than regular insert, because it does not perform + /// lookup before insertion. + /// + /// This operation is useful during initial population of the map. + /// For example, when constructing a map from another map, we know + /// that keys are unique. + pub fn insert_no_overwrite_unchecked(&mut self, key: K, value: V) { + let hash = self.hash(&key); + self.core.push(hash, key, value); + } + /// Get the given key’s corresponding entry in the map for insertion and/or /// in-place manipulation. /// @@ -1834,4 +1854,14 @@ mod tests { assert!(values.contains(&'b')); assert!(values.contains(&'c')); } + + #[test] + fn insert_no_overwrite_unchecked() { + let mut map = IndexMap::new(); + map.insert_no_overwrite_unchecked(10, 11); + map.insert_no_overwrite_unchecked(20, 21); + assert_eq!(Some(&11), map.get(&10)); + assert_eq!(Some(&21), map.get(&20)); + assert_eq!(None, map.get(&30)); + } } diff --git a/src/map/core.rs b/src/map/core.rs index c4e725c9..2858331c 100644 --- a/src/map/core.rs +++ b/src/map/core.rs @@ -209,7 +209,7 @@ impl IndexMapCore { /// Append a key-value pair, *without* checking whether it already exists, /// and return the pair's new index. - fn push(&mut self, hash: HashValue, key: K, value: V) -> usize { + pub(crate) fn push(&mut self, hash: HashValue, key: K, value: V) -> usize { let i = self.entries.len(); self.indices.insert(hash.get(), i, get_hash(&self.entries)); if i == self.entries.capacity() {