From 400c3a0ddcf4441f66eb4653c7365b663f9a4ea1 Mon Sep 17 00:00:00 2001 From: Ben Foppa Date: Sun, 4 Jan 2015 14:07:32 -0500 Subject: [PATCH] [breaking change] Update entry API as part of RFC 509. --- src/libcollections/bench.rs | 12 +-- src/libcollections/btree/map.rs | 66 ++++++++++----- src/librustc/lint/builtin.rs | 4 +- src/librustc/metadata/creader.rs | 4 +- src/librustc/metadata/loader.rs | 8 +- src/librustc/middle/const_eval.rs | 4 +- src/librustc/middle/infer/freshen.rs | 4 +- .../middle/infer/region_inference/graphviz.rs | 4 +- src/librustc/middle/traits/fulfill.rs | 5 +- src/librustc/middle/ty.rs | 13 +-- src/librustc/session/config.rs | 4 +- src/librustc_resolve/lib.rs | 24 +++--- src/librustc_typeck/check/_match.rs | 4 +- src/librustdoc/html/render.rs | 20 ++--- src/librustdoc/lib.rs | 8 +- src/libstd/collections/hash/map.rs | 84 ++++++++++++------- src/libstd/collections/mod.rs | 10 +-- src/libsyntax/ext/mtwt.rs | 15 ++-- src/libsyntax/ext/tt/macro_parser.rs | 4 +- src/libtest/stats.rs | 8 +- 20 files changed, 170 insertions(+), 135 deletions(-) diff --git a/src/libcollections/bench.rs b/src/libcollections/bench.rs index c7164b8199c..cd4f8d203df 100644 --- a/src/libcollections/bench.rs +++ b/src/libcollections/bench.rs @@ -11,7 +11,7 @@ use prelude::*; use std::rand; use std::rand::Rng; -use test::Bencher; +use test::{Bencher, black_box}; pub fn insert_rand_n(n: uint, map: &mut M, @@ -33,7 +33,8 @@ pub fn insert_rand_n(n: uint, let k = rng.gen::() % n; insert(map, k); remove(map, k); - }) + }); + black_box(map); } pub fn insert_seq_n(n: uint, @@ -55,7 +56,8 @@ pub fn insert_seq_n(n: uint, insert(map, i); remove(map, i); i = (i + 2) % n; - }) + }); + black_box(map); } pub fn find_rand_n(n: uint, @@ -82,7 +84,7 @@ pub fn find_rand_n(n: uint, b.iter(|| { let t = find(map, keys[i]); i = (i + 1) % n; - t + black_box(t); }) } @@ -104,6 +106,6 @@ pub fn find_seq_n(n: uint, b.iter(|| { let x = find(map, i); i = (i + 1) % n; - x + black_box(x); }) } diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 3a722178bc0..a9e09a584d6 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -19,7 +19,7 @@ pub use self::Entry::*; use core::prelude::*; -use core::borrow::BorrowFrom; +use core::borrow::{BorrowFrom, ToOwned}; use core::cmp::Ordering; use core::default::Default; use core::fmt::Show; @@ -128,20 +128,23 @@ pub struct Values<'a, K: 'a, V: 'a> { inner: Map<(&'a K, &'a V), &'a V, Iter<'a, K, V>, fn((&'a K, &'a V)) -> &'a V> } +#[stable] /// A view into a single entry in a map, which may either be vacant or occupied. -pub enum Entry<'a, K:'a, V:'a> { +pub enum Entry<'a, Sized? Q:'a, K:'a, V:'a> { /// A vacant Entry - Vacant(VacantEntry<'a, K, V>), + Vacant(VacantEntry<'a, Q, K, V>), /// An occupied Entry Occupied(OccupiedEntry<'a, K, V>), } +#[stable] /// A vacant Entry. -pub struct VacantEntry<'a, K:'a, V:'a> { - key: K, +pub struct VacantEntry<'a, Sized? Q:'a, K:'a, V:'a> { + key: &'a Q, stack: stack::SearchStack<'a, K, V, node::handle::Edge, node::handle::Leaf>, } +#[stable] /// An occupied Entry. pub struct OccupiedEntry<'a, K:'a, V:'a> { stack: stack::SearchStack<'a, K, V, node::handle::KV, node::handle::LeafOrInternal>, @@ -1132,40 +1135,56 @@ impl<'a, K, V> DoubleEndedIterator for Values<'a, K, V> { #[stable] impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {} +impl<'a, Sized? Q, K: Ord, V> Entry<'a, Q, K, V> { + #[unstable = "matches collection reform v2 specification, waiting for dust to settle"] + /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant + pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, Q, K, V>> { + match self { + Occupied(entry) => Ok(entry.into_mut()), + Vacant(entry) => Err(entry), + } + } +} -impl<'a, K: Ord, V> VacantEntry<'a, K, V> { +impl<'a, Sized? Q: ToOwned, K: Ord, V> VacantEntry<'a, Q, K, V> { + #[stable] /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it. - pub fn set(self, value: V) -> &'a mut V { - self.stack.insert(self.key, value) + pub fn insert(self, value: V) -> &'a mut V { + self.stack.insert(self.key.to_owned(), value) } } impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { + #[stable] /// Gets a reference to the value in the entry. pub fn get(&self) -> &V { self.stack.peek() } + #[stable] /// Gets a mutable reference to the value in the entry. pub fn get_mut(&mut self) -> &mut V { self.stack.peek_mut() } + #[stable] /// Converts the entry into a mutable reference to its value. pub fn into_mut(self) -> &'a mut V { self.stack.into_top() } + #[stable] /// Sets the value of the entry with the OccupiedEntry's key, /// and returns the entry's old value. - pub fn set(&mut self, mut value: V) -> V { + pub fn insert(&mut self, mut value: V) -> V { mem::swap(self.stack.peek_mut(), &mut value); value } + #[stable] /// Takes the value of the entry out of the map, and returns it. - pub fn take(self) -> V { + pub fn remove(self) -> V { self.stack.remove() } } @@ -1352,9 +1371,9 @@ impl BTreeMap { /// /// // count the number of occurrences of letters in the vec /// for x in vec!["a","b","a","c","a","b"].iter() { - /// match count.entry(*x) { + /// match count.entry(x) { /// Entry::Vacant(view) => { - /// view.set(1); + /// view.insert(1); /// }, /// Entry::Occupied(mut view) => { /// let v = view.get_mut(); @@ -1365,12 +1384,16 @@ impl BTreeMap { /// /// assert_eq!(count["a"], 3u); /// ``` - pub fn entry<'a>(&'a mut self, mut key: K) -> Entry<'a, K, V> { + /// The key must have the same ordering before or after `.to_owned()` is called. + #[stable] + pub fn entry<'a, Sized? Q>(&'a mut self, mut key: &'a Q) -> Entry<'a, Q, K, V> + where Q: Ord + ToOwned + { // same basic logic of `swap` and `pop`, blended together let mut stack = stack::PartialSearchStack::new(self); loop { let result = stack.with(move |pusher, node| { - return match Node::search(node, &key) { + return match Node::search(node, key) { Found(handle) => { // Perfect match Finished(Occupied(OccupiedEntry { @@ -1413,6 +1436,7 @@ impl BTreeMap { #[cfg(test)] mod test { use prelude::*; + use std::borrow::{ToOwned, BorrowFrom}; use super::{BTreeMap, Occupied, Vacant}; @@ -1562,11 +1586,11 @@ mod test { let mut map: BTreeMap = xs.iter().map(|&x| x).collect(); // Existing key (insert) - match map.entry(1) { + match map.entry(&1) { Vacant(_) => unreachable!(), Occupied(mut view) => { assert_eq!(view.get(), &10); - assert_eq!(view.set(100), 10); + assert_eq!(view.insert(100), 10); } } assert_eq!(map.get(&1).unwrap(), &100); @@ -1574,7 +1598,7 @@ mod test { // Existing key (update) - match map.entry(2) { + match map.entry(&2) { Vacant(_) => unreachable!(), Occupied(mut view) => { let v = view.get_mut(); @@ -1585,10 +1609,10 @@ mod test { assert_eq!(map.len(), 6); // Existing key (take) - match map.entry(3) { + match map.entry(&3) { Vacant(_) => unreachable!(), Occupied(view) => { - assert_eq!(view.take(), 30); + assert_eq!(view.remove(), 30); } } assert_eq!(map.get(&3), None); @@ -1596,10 +1620,10 @@ mod test { // Inexistent key (insert) - match map.entry(10) { + match map.entry(&10) { Occupied(_) => unreachable!(), Vacant(view) => { - assert_eq!(*view.set(1000), 1000); + assert_eq!(*view.insert(1000), 1000); } } assert_eq!(map.get(&10).unwrap(), &1000); diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 8f03f882128..ba32dbf1e4f 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1329,8 +1329,8 @@ impl UnusedMut { let ident = path1.node; if let ast::BindByValue(ast::MutMutable) = mode { if !token::get_ident(ident).get().starts_with("_") { - match mutables.entry(ident.name.uint()) { - Vacant(entry) => { entry.set(vec![id]); }, + match mutables.entry(&ident.name.uint()) { + Vacant(entry) => { entry.insert(vec![id]); }, Occupied(mut entry) => { entry.get_mut().push(id); }, } } diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 5dac2bafaec..b0cf322b068 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -87,8 +87,8 @@ fn dump_crates(cstore: &CStore) { fn warn_if_multiple_versions(diag: &SpanHandler, cstore: &CStore) { let mut map = FnvHashMap::new(); cstore.iter_crate_data(|cnum, data| { - match map.entry(data.name()) { - Vacant(entry) => { entry.set(vec![cnum]); }, + match map.entry(&data.name()) { + Vacant(entry) => { entry.insert(vec![cnum]); }, Occupied(mut entry) => { entry.get_mut().push(cnum); }, } }); diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 5f554eb9c1e..c18bd421b3b 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -228,7 +228,6 @@ use util::fs; use std::c_str::ToCStr; use std::cmp; -use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::{HashMap, HashSet}; use std::io::fs::PathExtensions; use std::io; @@ -400,10 +399,9 @@ impl<'a> Context<'a> { }; info!("lib candidate: {}", path.display()); - let slot = match candidates.entry(hash.to_string()) { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.set((HashSet::new(), HashSet::new())), - }; + let hash_str = hash.to_string(); + let slot = candidates.entry(&hash_str).get().unwrap_or_else( + |vacant_entry| vacant_entry.insert((HashSet::new(), HashSet::new()))); let (ref mut rlibs, ref mut dylibs) = *slot; if rlib { rlibs.insert(fs::realpath(path).unwrap()); diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index a62b134c48e..6671f0f72f6 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -311,8 +311,8 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr) -> P { ast::ExprCall(ref callee, ref args) => { let def = tcx.def_map.borrow()[callee.id].clone(); - if let Vacant(entry) = tcx.def_map.borrow_mut().entry(expr.id) { - entry.set(def); + if let Vacant(entry) = tcx.def_map.borrow_mut().entry(&expr.id) { + entry.insert(def); } let path = match def { def::DefStruct(def_id) => def_to_path(tcx, def_id), diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index 0ae4a3d851e..7488a72b4e4 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -66,13 +66,13 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { None => { } } - match self.freshen_map.entry(key) { + match self.freshen_map.entry(&key) { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { let index = self.freshen_count; self.freshen_count += 1; let t = ty::mk_infer(self.infcx.tcx, freshener(index)); - entry.set(t); + entry.insert(t); t } } diff --git a/src/librustc/middle/infer/region_inference/graphviz.rs b/src/librustc/middle/infer/region_inference/graphviz.rs index 2bf32e7bdae..98c69962bc2 100644 --- a/src/librustc/middle/infer/region_inference/graphviz.rs +++ b/src/librustc/middle/infer/region_inference/graphviz.rs @@ -137,8 +137,8 @@ impl<'a, 'tcx> ConstraintGraph<'a, 'tcx> { let mut node_ids = FnvHashMap::new(); { let mut add_node = |&mut : node| { - if let Vacant(e) = node_ids.entry(node) { - e.set(i); + if let Vacant(e) = node_ids.entry(&node) { + e.insert(i); i += 1; } }; diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 8bb7012fb07..c2327adece8 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -437,8 +437,9 @@ fn register_region_obligation<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("register_region_obligation({})", region_obligation.repr(tcx)); - match region_obligations.entry(region_obligation.cause.body_id) { - Vacant(entry) => { entry.set(vec![region_obligation]); }, + let body_id = region_obligation.cause.body_id; + match region_obligations.entry(&body_id) { + Vacant(entry) => { entry.insert(vec![region_obligation]); }, Occupied(mut entry) => { entry.get_mut().push(region_obligation); }, } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index d168e84a01c..4c53c360b14 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -78,7 +78,6 @@ use std::ops; use std::rc::Rc; use collections::enum_set::{EnumSet, CLike}; use std::collections::{HashMap, HashSet}; -use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::abi; use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, LOCAL_CRATE}; use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId}; @@ -5651,10 +5650,8 @@ pub fn lookup_field_type<'tcx>(tcx: &ctxt<'tcx>, node_id_to_type(tcx, id.node) } else { let mut tcache = tcx.tcache.borrow_mut(); - let pty = match tcache.entry(id) { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.set(csearch::get_field_type(tcx, struct_id, id)), - }; + let pty = tcache.entry(&id).get().unwrap_or_else( + |vacant_entry| vacant_entry.insert(csearch::get_field_type(tcx, struct_id, id))); pty.ty }; ty.subst(tcx, substs) @@ -6841,10 +6838,8 @@ pub fn replace_late_bound_regions<'tcx, T, F>( debug!("region={}", region.repr(tcx)); match region { ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => { - * match map.entry(br) { - Vacant(entry) => entry.set(mapf(br, debruijn)), - Occupied(entry) => entry.into_mut(), - } + * map.entry(&br).get().unwrap_or_else( + |vacant_entry| vacant_entry.insert(mapf(br, debruijn))) } _ => { region diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 1480ff016b5..4c9bd1e3416 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1114,8 +1114,8 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { None => early_error("--extern value must be of the format `foo=bar`"), }; - match externs.entry(name.to_string()) { - Vacant(entry) => { entry.set(vec![location.to_string()]); }, + match externs.entry(&name.to_string()) { + Vacant(entry) => { entry.insert(vec![location.to_string()]); }, Occupied(mut entry) => { entry.get_mut().push(location.to_string()); }, } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 3be7aa294f1..6321486d459 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1688,15 +1688,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let is_public = import_directive.is_public; let mut import_resolutions = module_.import_resolutions.borrow_mut(); - let dest_import_resolution = match import_resolutions.entry(name) { - Occupied(entry) => { - entry.into_mut() - } - Vacant(entry) => { + let dest_import_resolution = import_resolutions.entry(&name).get().unwrap_or_else( + |vacant_entry| { // Create a new import resolution from this child. - entry.set(ImportResolution::new(id, is_public)) - } - }; + vacant_entry.insert(ImportResolution::new(id, is_public)) + }); debug!("(resolving glob import) writing resolution `{}` in `{}` \ to `{}`", @@ -2630,16 +2626,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { def = DefUpvar(node_id, function_id, last_proc_body_id); let mut seen = self.freevars_seen.borrow_mut(); - let seen = match seen.entry(function_id) { + let seen = match seen.entry(&function_id) { Occupied(v) => v.into_mut(), - Vacant(v) => v.set(NodeSet::new()), + Vacant(v) => v.insert(NodeSet::new()), }; if seen.contains(&node_id) { continue; } - match self.freevars.borrow_mut().entry(function_id) { + match self.freevars.borrow_mut().entry(&function_id) { Occupied(v) => v.into_mut(), - Vacant(v) => v.set(vec![]), + Vacant(v) => v.insert(vec![]), }.push(Freevar { def: prev_def, span: span }); seen.insert(node_id); } @@ -4722,7 +4718,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { "Import should only be used for `use` directives"); self.last_private.insert(node_id, lp); - match self.def_map.borrow_mut().entry(node_id) { + match self.def_map.borrow_mut().entry(&node_id) { // Resolve appears to "resolve" the same ID multiple // times, so here is a sanity check it at least comes to // the same conclusion! - nmatsakis @@ -4734,7 +4730,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { *entry.get(), def)[]); }, - Vacant(entry) => { entry.set(def); }, + Vacant(entry) => { entry.insert(def); }, } } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index d8b410abf84..56cf4acc184 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -496,7 +496,7 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // Typecheck each field. for &Spanned { node: ref field, span } in fields.iter() { - let field_type = match used_fields.entry(field.ident.name) { + let field_type = match used_fields.entry(&field.ident.name) { Occupied(occupied) => { span_err!(tcx.sess, span, E0025, "field `{}` bound multiple times in the pattern", @@ -507,7 +507,7 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, tcx.types.err } Vacant(vacant) => { - vacant.set(span); + vacant.insert(span); field_type_map.get(&field.ident.name).cloned() .unwrap_or_else(|| { span_err!(tcx.sess, span, E0026, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 338b9b3e0eb..3accbbfb1a2 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -36,7 +36,6 @@ pub use self::ExternalLocation::*; use std::cell::RefCell; use std::cmp::Ordering::{self, Less, Greater, Equal}; -use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::{HashMap, HashSet}; use std::default::Default; use std::fmt; @@ -822,10 +821,8 @@ impl DocFolder for Cache { if let clean::ImplItem(ref i) = item.inner { match i.trait_ { Some(clean::ResolvedPath{ did, .. }) => { - let v = match self.implementors.entry(did) { - Vacant(entry) => entry.set(Vec::with_capacity(1)), - Occupied(entry) => entry.into_mut(), - }; + let v = self.implementors.entry(&did).get().unwrap_or_else( + |vacant_entry| vacant_entry.insert(Vec::with_capacity(1))); v.push(Implementor { def_id: item.def_id, generics: i.generics.clone(), @@ -1014,10 +1011,8 @@ impl DocFolder for Cache { }; if let Some(did) = did { - let v = match self.impls.entry(did) { - Vacant(entry) => entry.set(Vec::with_capacity(1)), - Occupied(entry) => entry.into_mut(), - }; + let v = self.impls.entry(&did).get().unwrap_or_else( + |vacant_entry| vacant_entry.insert(Vec::with_capacity(1))); v.push(Impl { impl_: i, dox: dox, @@ -1264,10 +1259,9 @@ impl Context { None => continue, Some(ref s) => s.to_string(), }; - let v = match map.entry(short.to_string()) { - Vacant(entry) => entry.set(Vec::with_capacity(1)), - Occupied(entry) => entry.into_mut(), - }; + let short = short.to_string(); + let v = map.entry(&short).get().unwrap_or_else( + |vacant_entry| vacant_entry.insert(Vec::with_capacity(1))); v.push(myname); } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 125bc21d79d..106fe452f46 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -38,7 +38,6 @@ extern crate "serialize" as rustc_serialize; // used by deriving use std::cell::RefCell; use std::collections::HashMap; -use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::io::File; use std::io; use std::rc::Rc; @@ -321,10 +320,9 @@ fn parse_externs(matches: &getopts::Matches) -> Result { return Err("--extern value must be of the format `foo=bar`".to_string()); } }; - let locs = match externs.entry(name.to_string()) { - Vacant(entry) => entry.set(Vec::with_capacity(1)), - Occupied(entry) => entry.into_mut(), - }; + let name = name.to_string(); + let locs = externs.entry(&name).get().unwrap_or_else( + |vacant_entry| vacant_entry.insert(Vec::with_capacity(1))); locs.push(location.to_string()); } Ok(externs) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 651f31b205d..a6532707f3e 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -14,7 +14,7 @@ use self::Entry::*; use self::SearchResult::*; use self::VacantEntryState::*; -use borrow::BorrowFrom; +use borrow::{BorrowFrom, ToOwned}; use clone::Clone; use cmp::{max, Eq, PartialEq}; use default::Default; @@ -920,12 +920,16 @@ impl, V, S, H: Hasher> HashMap { } } - /// Gets the given key's corresponding entry in the map for in-place manipulation - pub fn entry<'a>(&'a mut self, key: K) -> Entry<'a, K, V> { + #[stable] + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// Regardless of whether or not `to_owned()` has been called, the key must hash the same way. + pub fn entry<'a, Sized? Q>(&'a mut self, key: &'a Q) -> Entry<'a, Q, K, V> + where Q: Eq + Hash + ToOwned + { // Gotta resize now. self.reserve(1); - let hash = self.make_hash(&key); + let hash = self.make_hash(key); search_entry_hashed(&mut self.table, hash, key) } @@ -1138,8 +1142,10 @@ impl, V, S, H: Hasher> HashMap { } } -fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable, hash: SafeHash, k: K) - -> Entry<'a, K, V> { +fn search_entry_hashed<'a, K, V, Sized? Q>(table: &'a mut RawTable, hash: SafeHash, k: &'a Q) + -> Entry<'a, Q, K, V> + where Q: Eq + ToOwned +{ // Worst case, we'll find one empty bucket among `size + 1` buckets. let size = table.size(); let mut probe = Bucket::new(table, hash); @@ -1161,7 +1167,7 @@ fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable, hash: SafeHas // hash matches? if bucket.hash() == hash { // key matches? - if k == *bucket.read().0 { + if *k == *BorrowFrom::borrow_from(bucket.read().0) { return Occupied(OccupiedEntry{ elem: bucket, }); @@ -1343,24 +1349,27 @@ pub struct Drain<'a, K: 'a, V: 'a> { > } +#[stable] /// A view into a single occupied location in a HashMap -pub struct OccupiedEntry<'a, K:'a, V:'a> { +pub struct OccupiedEntry<'a, K: 'a, V: 'a> { elem: FullBucket>, } +#[stable] /// A view into a single empty location in a HashMap -pub struct VacantEntry<'a, K:'a, V:'a> { +pub struct VacantEntry<'a, Sized? Q: 'a, K: 'a, V: 'a> { hash: SafeHash, - key: K, - elem: VacantEntryState>, + key: &'a Q, + elem: VacantEntryState>, } +#[stable] /// A view into a single location in a map, which may be vacant or occupied -pub enum Entry<'a, K:'a, V:'a> { +pub enum Entry<'a, Sized? Q: 'a, K: 'a, V: 'a> { /// An occupied Entry Occupied(OccupiedEntry<'a, K, V>), /// A vacant Entry - Vacant(VacantEntry<'a, K, V>), + Vacant(VacantEntry<'a, Q, K, V>), } /// Possible states of a VacantEntry @@ -1426,46 +1435,63 @@ impl<'a, K: 'a, V: 'a> Iterator for Drain<'a, K, V> { } } +impl<'a, Sized? Q, K, V> Entry<'a, Q, K, V> { + #[unstable = "matches collection reform v2 specification, waiting for dust to settle"] + /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant + pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, Q, K, V>> { + match self { + Occupied(entry) => Ok(entry.into_mut()), + Vacant(entry) => Err(entry), + } + } +} + impl<'a, K, V> OccupiedEntry<'a, K, V> { + #[stable] /// Gets a reference to the value in the entry pub fn get(&self) -> &V { self.elem.read().1 } + #[stable] /// Gets a mutable reference to the value in the entry pub fn get_mut(&mut self) -> &mut V { self.elem.read_mut().1 } + #[stable] /// Converts the OccupiedEntry into a mutable reference to the value in the entry /// with a lifetime bound to the map itself pub fn into_mut(self) -> &'a mut V { self.elem.into_mut_refs().1 } + #[stable] /// Sets the value of the entry, and returns the entry's old value - pub fn set(&mut self, mut value: V) -> V { + pub fn insert(&mut self, mut value: V) -> V { let old_value = self.get_mut(); mem::swap(&mut value, old_value); value } + #[stable] /// Takes the value out of the entry, and returns it - pub fn take(self) -> V { + pub fn remove(self) -> V { pop_internal(self.elem).1 } } -impl<'a, K, V> VacantEntry<'a, K, V> { +impl<'a, Sized? Q: 'a + ToOwned, K: 'a, V: 'a> VacantEntry<'a, Q, K, V> { + #[stable] /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it - pub fn set(self, value: V) -> &'a mut V { + pub fn insert(self, value: V) -> &'a mut V { match self.elem { NeqElem(bucket, ib) => { - robin_hood(bucket, ib, self.hash, self.key, value) + robin_hood(bucket, ib, self.hash, self.key.to_owned(), value) } NoElem(bucket) => { - bucket.put(self.hash, self.key, value).into_mut_refs().1 + bucket.put(self.hash, self.key.to_owned(), value).into_mut_refs().1 } } } @@ -1497,6 +1523,8 @@ mod test_map { use super::HashMap; use super::Entry::{Occupied, Vacant}; use iter::{range_inclusive, range_step_inclusive, repeat}; + use borrow::ToOwned; + use hash; use cell::RefCell; use rand::{weak_rng, Rng}; @@ -2090,11 +2118,11 @@ mod test_map { let mut map: HashMap = xs.iter().map(|&x| x).collect(); // Existing key (insert) - match map.entry(1) { + match map.entry(&1) { Vacant(_) => unreachable!(), Occupied(mut view) => { assert_eq!(view.get(), &10); - assert_eq!(view.set(100), 10); + assert_eq!(view.insert(100), 10); } } assert_eq!(map.get(&1).unwrap(), &100); @@ -2102,7 +2130,7 @@ mod test_map { // Existing key (update) - match map.entry(2) { + match map.entry(&2) { Vacant(_) => unreachable!(), Occupied(mut view) => { let v = view.get_mut(); @@ -2114,10 +2142,10 @@ mod test_map { assert_eq!(map.len(), 6); // Existing key (take) - match map.entry(3) { + match map.entry(&3) { Vacant(_) => unreachable!(), Occupied(view) => { - assert_eq!(view.take(), 30); + assert_eq!(view.remove(), 30); } } assert_eq!(map.get(&3), None); @@ -2125,10 +2153,10 @@ mod test_map { // Inexistent key (insert) - match map.entry(10) { + match map.entry(&10) { Occupied(_) => unreachable!(), Vacant(view) => { - assert_eq!(*view.set(1000), 1000); + assert_eq!(*view.insert(1000), 1000); } } assert_eq!(map.get(&10).unwrap(), &1000); @@ -2156,11 +2184,11 @@ mod test_map { for i in range(0u, 1000) { let x = rng.gen_range(-10, 10); - match m.entry(x) { + match m.entry(&x) { Vacant(_) => {}, Occupied(e) => { println!("{}: remove {}", i, x); - e.take(); + e.remove(); }, } diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 4be83bfc664..c0445fb5aea 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -226,7 +226,7 @@ //! the key has been seen or not. Normally, this would require a `find` followed by an //! `insert`, effectively duplicating the search effort on each insertion. //! -//! When a user calls `map.entry(key)`, the map will search for the key and then yield +//! When a user calls `map.entry(&key)`, the map will search for the key and then yield //! a variant of the `Entry` enum. //! //! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case the @@ -255,8 +255,8 @@ //! let message = "she sells sea shells by the sea shore"; //! //! for c in message.chars() { -//! match count.entry(c) { -//! Vacant(entry) => { entry.set(1u); }, +//! match count.entry(&c) { +//! Vacant(entry) => { entry.insert(1u); }, //! Occupied(mut entry) => *entry.get_mut() += 1, //! } //! } @@ -290,8 +290,8 @@ //! for id in orders.into_iter() { //! // If this is the first time we've seen this customer, initialize them //! // with no blood alcohol. Otherwise, just retrieve them. -//! let person = match blood_alcohol.entry(id) { -//! Vacant(entry) => entry.set(Person{id: id, blood_alcohol: 0.0}), +//! let person = match blood_alcohol.entry(&id) { +//! Vacant(entry) => entry.insert(Person{id: id, blood_alcohol: 0.0}), //! Occupied(entry) => entry.into_mut(), //! }; //! diff --git a/src/libsyntax/ext/mtwt.rs b/src/libsyntax/ext/mtwt.rs index bac82494f28..4075b208f78 100644 --- a/src/libsyntax/ext/mtwt.rs +++ b/src/libsyntax/ext/mtwt.rs @@ -21,7 +21,6 @@ use ast::{Ident, Mrk, Name, SyntaxContext}; use std::cell::RefCell; use std::collections::HashMap; -use std::collections::hash_map::Entry::{Occupied, Vacant}; /// The SCTable contains a table of SyntaxContext_'s. It /// represents a flattened tree structure, to avoid having @@ -67,10 +66,9 @@ pub fn apply_mark(m: Mrk, ctxt: SyntaxContext) -> SyntaxContext { /// Extend a syntax context with a given mark and sctable (explicit memoization) fn apply_mark_internal(m: Mrk, ctxt: SyntaxContext, table: &SCTable) -> SyntaxContext { let key = (ctxt, m); - * match table.mark_memo.borrow_mut().entry(key) { - Vacant(entry) => entry.set(idx_push(&mut *table.table.borrow_mut(), Mark(m, ctxt))), - Occupied(entry) => entry.into_mut(), - } + * table.mark_memo.borrow_mut().entry(&key).get().unwrap_or_else( + |vacant_entry| + vacant_entry.insert(idx_push(&mut *table.table.borrow_mut(), Mark(m, ctxt)))) } /// Extend a syntax context with a given rename @@ -86,10 +84,9 @@ fn apply_rename_internal(id: Ident, table: &SCTable) -> SyntaxContext { let key = (ctxt, id, to); - * match table.rename_memo.borrow_mut().entry(key) { - Vacant(entry) => entry.set(idx_push(&mut *table.table.borrow_mut(), Rename(id, to, ctxt))), - Occupied(entry) => entry.into_mut(), - } + * table.rename_memo.borrow_mut().entry(&key).get().unwrap_or_else( + |vacant_entry| + vacant_entry.insert(idx_push(&mut *table.table.borrow_mut(), Rename(id, to, ctxt)))) } /// Apply a list of renamings to a context diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 69e473055e8..1438d152554 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -219,9 +219,9 @@ pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc]) } } &TtToken(sp, MatchNt(bind_name, _, _, _)) => { - match ret_val.entry(bind_name) { + match ret_val.entry(&bind_name) { Vacant(spot) => { - spot.set(res[*idx].clone()); + spot.insert(res[*idx].clone()); *idx += 1; } Occupied(..) => { diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 35af0e763d7..7e7f36f6e83 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -438,12 +438,14 @@ pub fn write_boxplot( /// Returns a HashMap with the number of occurrences of every element in the /// sequence that the iterator exposes. -pub fn freq_count, U: Eq+Hash>(mut iter: T) -> hash_map::HashMap { +pub fn freq_count(mut iter: T) -> hash_map::HashMap + where T: Iterator, U: Eq + Clone + Hash +{ let mut map: hash_map::HashMap = hash_map::HashMap::new(); for elem in iter { - match map.entry(elem) { + match map.entry(&elem) { Occupied(mut entry) => { *entry.get_mut() += 1; }, - Vacant(entry) => { entry.set(1); }, + Vacant(entry) => { entry.insert(1); }, } } map