]> git.lizzy.rs Git - rust.git/commitdiff
Smarter HashMap/HashSet extend
authorarthurprs <arthurprs@gmail.com>
Sat, 26 Nov 2016 16:30:29 +0000 (17:30 +0100)
committerarthurprs <arthurprs@gmail.com>
Tue, 6 Dec 2016 09:14:59 +0000 (10:14 +0100)
src/libstd/collections/hash/map.rs
src/libstd/collections/hash/set.rs

index ece51d6d82616753a762bc1c7c36705efe872d4f..9f9d0429fcadd5a4d52fe066b5983f411af9067f 100644 (file)
@@ -1971,10 +1971,8 @@ impl<K, V, S> FromIterator<(K, V)> for HashMap<K, V, S>
           S: BuildHasher + Default
 {
     fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> HashMap<K, V, S> {
-        let iterator = iter.into_iter();
-        let lower = iterator.size_hint().0;
-        let mut map = HashMap::with_capacity_and_hasher(lower, Default::default());
-        map.extend(iterator);
+        let mut map = HashMap::with_hasher(Default::default());
+        map.extend(iter);
         map
     }
 }
@@ -1985,6 +1983,17 @@ impl<K, V, S> Extend<(K, V)> for HashMap<K, V, S>
           S: BuildHasher
 {
     fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
+        // Keys may be already present or show multiple times in the iterator.
+        // Reserve the entire hint lower bound if the map is empty.
+        // Otherwise reserve half the hint (rounded up), so the map
+        // will only resize twice in the worst case.
+        let iter = iter.into_iter();
+        let reserve = if self.is_empty() {
+            iter.size_hint().0
+        } else {
+            (iter.size_hint().0 + 1) / 2
+        };
+        self.reserve(reserve);
         for (k, v) in iter {
             self.insert(k, v);
         }
index 1ec7a4a7b639b51916e9cd10c81ac6ca83a6cdd5..72af612f5696f51c8676bb2b91da6a6864d57859 100644 (file)
@@ -663,10 +663,8 @@ impl<T, S> FromIterator<T> for HashSet<T, S>
           S: BuildHasher + Default
 {
     fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> HashSet<T, S> {
-        let iterator = iter.into_iter();
-        let lower = iterator.size_hint().0;
-        let mut set = HashSet::with_capacity_and_hasher(lower, Default::default());
-        set.extend(iterator);
+        let mut set = HashSet::with_hasher(Default::default());
+        set.extend(iter);
         set
     }
 }
@@ -677,9 +675,7 @@ impl<T, S> Extend<T> for HashSet<T, S>
           S: BuildHasher
 {
     fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
-        for k in iter {
-            self.insert(k);
-        }
+        self.map.extend(iter.into_iter().map(|k| (k, ())));
     }
 }