From 4eb069c9811bc25d6ef9413de6058e5f14707816 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 26 Sep 2016 13:05:54 +1000 Subject: [PATCH] Don't allocate during default HashSet creation. The following `HashMap` creation functions don't allocate heap storage for elements. ``` HashMap::new() HashMap::default() HashMap::with_hasher() ``` This is good, because it's surprisingly common to create a HashMap and never use it. So that case should be cheap. However, `HashSet` does not have the same behaviour. The corresponding creation functions *do* allocate heap storage for the default number of non-zero elements (which is 32 slots for 29 elements). ``` HashMap::new() HashMap::default() HashMap::with_hasher() ``` This commit gives `HashSet` the same behaviour as `HashMap`, by simply calling the corresponding `HashMap` functions (something `HashSet` already does for `with_capacity` and `with_capacity_and_hasher`). It also reformats one existing `HashSet` construction to use a consistent single-line format. This speeds up rustc itself by 1.01--1.04x on most of the non-tiny rustc-benchmarks. --- src/libstd/collections/hash/map.rs | 15 +++++++++++++++ src/libstd/collections/hash/set.rs | 27 +++++++++++++++++++-------- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index eb1653f18cba1..29a79631535b2 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2087,9 +2087,24 @@ fn assert_covariance() { mod test_map { use super::HashMap; use super::Entry::{Occupied, Vacant}; + use super::RandomState; use cell::RefCell; use rand::{thread_rng, Rng}; + #[test] + fn test_create_capacities() { + type HM = HashMap; + + let m = HM::new(); + assert_eq!(m.capacity(), 0); + + let m = HM::default(); + assert_eq!(m.capacity(), 0); + + let m = HM::with_hasher(RandomState::new()); + assert_eq!(m.capacity(), 0); + } + #[test] fn test_create_capacity_zero() { let mut m = HashMap::with_capacity(0); diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index ff56747fee6af..a508954398052 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -17,8 +17,6 @@ use ops::{BitOr, BitAnd, BitXor, Sub}; use super::Recover; use super::map::{self, HashMap, Keys, RandomState}; -const INITIAL_CAPACITY: usize = 32; - // Future Optimization (FIXME!) // ============================= // @@ -118,7 +116,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> HashSet { - HashSet::with_capacity(INITIAL_CAPACITY) + HashSet { map: HashMap::new() } } /// Creates an empty HashSet with space for at least `n` elements in @@ -163,7 +161,7 @@ impl HashSet #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_hasher(hasher: S) -> HashSet { - HashSet::with_capacity_and_hasher(INITIAL_CAPACITY, hasher) + HashSet { map: HashMap::with_hasher(hasher) } } /// Creates an empty HashSet with space for at least `capacity` @@ -188,9 +186,7 @@ impl HashSet #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { - HashSet { - map: HashMap::with_capacity_and_hasher(capacity, hasher), - } + HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) } } /// Returns a reference to the set's hasher. @@ -667,7 +663,7 @@ impl Default for HashSet { /// Creates an empty `HashSet` with the `Default` value for the hasher. fn default() -> HashSet { - HashSet::with_hasher(Default::default()) + HashSet { map: HashMap::default() } } } @@ -1069,6 +1065,21 @@ fn assert_covariance() { #[cfg(test)] mod test_set { use super::HashSet; + use super::super::map::RandomState; + + #[test] + fn test_create_capacities() { + type HS = HashSet; + + let s = HS::new(); + assert_eq!(s.capacity(), 0); + + let s = HS::default(); + assert_eq!(s.capacity(), 0); + + let s = HS::with_hasher(RandomState::new()); + assert_eq!(s.capacity(), 0); + } #[test] fn test_disjoint() {