Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e800988

Browse files
committedNov 2, 2018
Auto merge of #54043 - fintelia:raw_entry, r=alexcrichton
Add raw_entry API to HashMap This is a continuation of #50821.
2 parents ad4c885 + daf5bd5 commit e800988

File tree

2 files changed

+673
-6
lines changed

2 files changed

+673
-6
lines changed
 

‎src/libstd/collections/hash/map.rs

Lines changed: 672 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use fmt::{self, Debug};
2020
use hash::{Hash, Hasher, BuildHasher, SipHasher13};
2121
use iter::{FromIterator, FusedIterator};
2222
use mem::{self, replace};
23-
use ops::{Deref, Index};
23+
use ops::{Deref, DerefMut, Index};
2424
use sys;
2525

2626
use super::table::{self, Bucket, EmptyBucket, Fallibility, FullBucket, FullBucketMut, RawTable,
@@ -435,12 +435,13 @@ fn search_hashed<K, V, M, F>(table: M, hash: SafeHash, is_match: F) -> InternalE
435435
return InternalEntry::TableIsEmpty;
436436
}
437437

438-
search_hashed_nonempty(table, hash, is_match)
438+
search_hashed_nonempty(table, hash, is_match, true)
439439
}
440440

441441
/// Search for a pre-hashed key when the hash map is known to be non-empty.
442442
#[inline]
443-
fn search_hashed_nonempty<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F)
443+
fn search_hashed_nonempty<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F,
444+
compare_hashes: bool)
444445
-> InternalEntry<K, V, M>
445446
where M: Deref<Target = RawTable<K, V>>,
446447
F: FnMut(&K) -> bool
@@ -476,7 +477,7 @@ fn search_hashed_nonempty<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F)
476477
}
477478

478479
// If the hash doesn't match, it can't be this one..
479-
if hash == full.hash() {
480+
if !compare_hashes || hash == full.hash() {
480481
// If the key doesn't match, it can't be this one..
481482
if is_match(full.read().0) {
482483
return InternalEntry::Occupied { elem: full };
@@ -488,6 +489,57 @@ fn search_hashed_nonempty<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F)
488489
}
489490
}
490491

492+
/// Same as `search_hashed_nonempty` but for mutable access.
493+
#[inline]
494+
fn search_hashed_nonempty_mut<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F,
495+
compare_hashes: bool)
496+
-> InternalEntry<K, V, M>
497+
where M: DerefMut<Target = RawTable<K, V>>,
498+
F: FnMut(&K) -> bool
499+
{
500+
// Do not check the capacity as an extra branch could slow the lookup.
501+
502+
let size = table.size();
503+
let mut probe = Bucket::new(table, hash);
504+
let mut displacement = 0;
505+
506+
loop {
507+
let mut full = match probe.peek() {
508+
Empty(bucket) => {
509+
// Found a hole!
510+
return InternalEntry::Vacant {
511+
hash,
512+
elem: NoElem(bucket, displacement),
513+
};
514+
}
515+
Full(bucket) => bucket,
516+
};
517+
518+
let probe_displacement = full.displacement();
519+
520+
if probe_displacement < displacement {
521+
// Found a luckier bucket than me.
522+
// We can finish the search early if we hit any bucket
523+
// with a lower distance to initial bucket than we've probed.
524+
return InternalEntry::Vacant {
525+
hash,
526+
elem: NeqElem(full, probe_displacement),
527+
};
528+
}
529+
530+
// If the hash doesn't match, it can't be this one..
531+
if hash == full.hash() || !compare_hashes {
532+
// If the key doesn't match, it can't be this one..
533+
if is_match(full.read_mut().0) {
534+
return InternalEntry::Occupied { elem: full };
535+
}
536+
}
537+
displacement += 1;
538+
probe = full.next();
539+
debug_assert!(displacement <= size);
540+
}
541+
}
542+
491543
fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>)
492544
-> (K, V, &mut RawTable<K, V>)
493545
{
@@ -593,7 +645,7 @@ impl<K, V, S> HashMap<K, V, S>
593645
}
594646

595647
let hash = self.make_hash(q);
596-
search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow()))
648+
search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow()), true)
597649
.into_occupied_bucket()
598650
}
599651

@@ -608,7 +660,7 @@ impl<K, V, S> HashMap<K, V, S>
608660
}
609661

610662
let hash = self.make_hash(q);
611-
search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow()))
663+
search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow()), true)
612664
.into_occupied_bucket()
613665
}
614666

@@ -1484,6 +1536,68 @@ impl<K, V, S> HashMap<K, V, S>
14841536
}
14851537
}
14861538

1539+
impl<K, V, S> HashMap<K, V, S>
1540+
where K: Eq + Hash,
1541+
S: BuildHasher
1542+
{
1543+
/// Creates a raw entry builder for the HashMap.
1544+
///
1545+
/// Raw entries provide the lowest level of control for searching and
1546+
/// manipulating a map. They must be manually initialized with a hash and
1547+
/// then manually searched. After this, insertions into a vacant entry
1548+
/// still require an owned key to be provided.
1549+
///
1550+
/// Raw entries are useful for such exotic situations as:
1551+
///
1552+
/// * Hash memoization
1553+
/// * Deferring the creation of an owned key until it is known to be required
1554+
/// * Using a search key that doesn't work with the Borrow trait
1555+
/// * Using custom comparison logic without newtype wrappers
1556+
///
1557+
/// Because raw entries provide much more low-level control, it's much easier
1558+
/// to put the HashMap into an inconsistent state which, while memory-safe,
1559+
/// will cause the map to produce seemingly random results. Higher-level and
1560+
/// more foolproof APIs like `entry` should be preferred when possible.
1561+
///
1562+
/// In particular, the hash used to initialized the raw entry must still be
1563+
/// consistent with the hash of the key that is ultimately stored in the entry.
1564+
/// This is because implementations of HashMap may need to recompute hashes
1565+
/// when resizing, at which point only the keys are available.
1566+
///
1567+
/// Raw entries give mutable access to the keys. This must not be used
1568+
/// to modify how the key would compare or hash, as the map will not re-evaluate
1569+
/// where the key should go, meaning the keys may become "lost" if their
1570+
/// location does not reflect their state. For instance, if you change a key
1571+
/// so that the map now contains keys which compare equal, search may start
1572+
/// acting eratically, with two keys randomly masking eachother. Implementations
1573+
/// are free to assume this doesn't happen (within the limits of memory-safety).
1574+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
1575+
pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<K, V, S> {
1576+
self.reserve(1);
1577+
RawEntryBuilderMut { map: self }
1578+
}
1579+
1580+
/// Creates a raw immutable entry builder for the HashMap.
1581+
///
1582+
/// Raw entries provide the lowest level of control for searching and
1583+
/// manipulating a map. They must be manually initialized with a hash and
1584+
/// then manually searched.
1585+
///
1586+
/// This is useful for
1587+
/// * Hash memoization
1588+
/// * Using a search key that doesn't work with the Borrow trait
1589+
/// * Using custom comparison logic without newtype wrappers
1590+
///
1591+
/// Unless you are in such a situation, higher-level and more foolproof APIs like
1592+
/// `get` should be preferred.
1593+
///
1594+
/// Immutable raw entries have very limited use; you might instead want `raw_entry_mut`.
1595+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
1596+
pub fn raw_entry(&self) -> RawEntryBuilder<K, V, S> {
1597+
RawEntryBuilder { map: self }
1598+
}
1599+
}
1600+
14871601
#[stable(feature = "rust1", since = "1.0.0")]
14881602
impl<K, V, S> PartialEq for HashMap<K, V, S>
14891603
where K: Eq + Hash,
@@ -1724,6 +1838,456 @@ impl<'a, K, V> InternalEntry<K, V, &'a mut RawTable<K, V>> {
17241838
}
17251839
}
17261840

1841+
/// A builder for computing where in a HashMap a key-value pair would be stored.
1842+
///
1843+
/// See the [`HashMap::raw_entry_mut`] docs for usage examples.
1844+
///
1845+
/// [`HashMap::raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut
1846+
1847+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
1848+
pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> {
1849+
map: &'a mut HashMap<K, V, S>,
1850+
}
1851+
1852+
/// A view into a single entry in a map, which may either be vacant or occupied.
1853+
///
1854+
/// This is a lower-level version of [`Entry`].
1855+
///
1856+
/// This `enum` is constructed from the [`raw_entry`] method on [`HashMap`].
1857+
///
1858+
/// [`HashMap`]: struct.HashMap.html
1859+
/// [`Entry`]: enum.Entry.html
1860+
/// [`raw_entry`]: struct.HashMap.html#method.raw_entry
1861+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
1862+
pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> {
1863+
/// An occupied entry.
1864+
Occupied(RawOccupiedEntryMut<'a, K, V>),
1865+
/// A vacant entry.
1866+
Vacant(RawVacantEntryMut<'a, K, V, S>),
1867+
}
1868+
1869+
/// A view into an occupied entry in a `HashMap`.
1870+
/// It is part of the [`RawEntryMut`] enum.
1871+
///
1872+
/// [`RawEntryMut`]: enum.RawEntryMut.html
1873+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
1874+
pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a> {
1875+
elem: FullBucket<K, V, &'a mut RawTable<K, V>>,
1876+
}
1877+
1878+
/// A view into a vacant entry in a `HashMap`.
1879+
/// It is part of the [`RawEntryMut`] enum.
1880+
///
1881+
/// [`RawEntryMut`]: enum.RawEntryMut.html
1882+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
1883+
pub struct RawVacantEntryMut<'a, K: 'a, V: 'a, S: 'a> {
1884+
elem: VacantEntryState<K, V, &'a mut RawTable<K, V>>,
1885+
hash_builder: &'a S,
1886+
}
1887+
1888+
/// A builder for computing where in a HashMap a key-value pair would be stored.
1889+
///
1890+
/// See the [`HashMap::raw_entry`] docs for usage examples.
1891+
///
1892+
/// [`HashMap::raw_entry`]: struct.HashMap.html#method.raw_entry
1893+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
1894+
pub struct RawEntryBuilder<'a, K: 'a, V: 'a, S: 'a> {
1895+
map: &'a HashMap<K, V, S>,
1896+
}
1897+
1898+
impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S>
1899+
where S: BuildHasher,
1900+
K: Eq + Hash,
1901+
{
1902+
/// Create a `RawEntryMut` from the given key.
1903+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
1904+
pub fn from_key<Q: ?Sized>(self, k: &Q) -> RawEntryMut<'a, K, V, S>
1905+
where K: Borrow<Q>,
1906+
Q: Hash + Eq
1907+
{
1908+
let mut hasher = self.map.hash_builder.build_hasher();
1909+
k.hash(&mut hasher);
1910+
self.from_key_hashed_nocheck(hasher.finish(), k)
1911+
}
1912+
1913+
/// Create a `RawEntryMut` from the given key and its hash.
1914+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
1915+
pub fn from_key_hashed_nocheck<Q: ?Sized>(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S>
1916+
where K: Borrow<Q>,
1917+
Q: Eq
1918+
{
1919+
self.from_hash(hash, |q| q.borrow().eq(k))
1920+
}
1921+
1922+
fn search<F>(self, hash: u64, is_match: F, compare_hashes: bool) -> RawEntryMut<'a, K, V, S>
1923+
where for<'b> F: FnMut(&'b K) -> bool,
1924+
{
1925+
match search_hashed_nonempty_mut(&mut self.map.table,
1926+
SafeHash::new(hash),
1927+
is_match,
1928+
compare_hashes) {
1929+
InternalEntry::Occupied { elem } => {
1930+
RawEntryMut::Occupied(RawOccupiedEntryMut { elem })
1931+
}
1932+
InternalEntry::Vacant { elem, .. } => {
1933+
RawEntryMut::Vacant(RawVacantEntryMut {
1934+
elem,
1935+
hash_builder: &self.map.hash_builder,
1936+
})
1937+
}
1938+
InternalEntry::TableIsEmpty => {
1939+
unreachable!()
1940+
}
1941+
}
1942+
}
1943+
/// Create a `RawEntryMut` from the given hash.
1944+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
1945+
pub fn from_hash<F>(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S>
1946+
where for<'b> F: FnMut(&'b K) -> bool,
1947+
{
1948+
self.search(hash, is_match, true)
1949+
}
1950+
1951+
/// Search possible locations for an element with hash `hash` until `is_match` returns true for
1952+
/// one of them. There is no guarantee that all keys passed to `is_match` will have the provided
1953+
/// hash.
1954+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
1955+
pub fn search_bucket<F>(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S>
1956+
where for<'b> F: FnMut(&'b K) -> bool,
1957+
{
1958+
self.search(hash, is_match, false)
1959+
}
1960+
}
1961+
1962+
impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S>
1963+
where S: BuildHasher,
1964+
{
1965+
/// Access an entry by key.
1966+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
1967+
pub fn from_key<Q: ?Sized>(self, k: &Q) -> Option<(&'a K, &'a V)>
1968+
where K: Borrow<Q>,
1969+
Q: Hash + Eq
1970+
{
1971+
let mut hasher = self.map.hash_builder.build_hasher();
1972+
k.hash(&mut hasher);
1973+
self.from_key_hashed_nocheck(hasher.finish(), k)
1974+
}
1975+
1976+
/// Access an entry by a key and its hash.
1977+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
1978+
pub fn from_key_hashed_nocheck<Q: ?Sized>(self, hash: u64, k: &Q) -> Option<(&'a K, &'a V)>
1979+
where K: Borrow<Q>,
1980+
Q: Hash + Eq
1981+
1982+
{
1983+
self.from_hash(hash, |q| q.borrow().eq(k))
1984+
}
1985+
1986+
fn search<F>(self, hash: u64, is_match: F, compare_hashes: bool) -> Option<(&'a K, &'a V)>
1987+
where F: FnMut(&K) -> bool
1988+
{
1989+
match search_hashed_nonempty(&self.map.table,
1990+
SafeHash::new(hash),
1991+
is_match,
1992+
compare_hashes) {
1993+
InternalEntry::Occupied { elem } => Some(elem.into_refs()),
1994+
InternalEntry::Vacant { .. } => None,
1995+
InternalEntry::TableIsEmpty => unreachable!(),
1996+
}
1997+
}
1998+
1999+
/// Access an entry by hash.
2000+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2001+
pub fn from_hash<F>(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)>
2002+
where F: FnMut(&K) -> bool
2003+
{
2004+
self.search(hash, is_match, true)
2005+
}
2006+
2007+
/// Search possible locations for an element with hash `hash` until `is_match` returns true for
2008+
/// one of them. There is no guarantee that all keys passed to `is_match` will have the provided
2009+
/// hash.
2010+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2011+
pub fn search_bucket<F>(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)>
2012+
where F: FnMut(&K) -> bool
2013+
{
2014+
self.search(hash, is_match, false)
2015+
}
2016+
}
2017+
2018+
impl<'a, K, V, S> RawEntryMut<'a, K, V, S> {
2019+
/// Ensures a value is in the entry by inserting the default if empty, and returns
2020+
/// mutable references to the key and value in the entry.
2021+
///
2022+
/// # Examples
2023+
///
2024+
/// ```
2025+
/// #![feature(hash_raw_entry)]
2026+
/// use std::collections::HashMap;
2027+
///
2028+
/// let mut map: HashMap<&str, u32> = HashMap::new();
2029+
/// map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 12);
2030+
///
2031+
/// assert_eq!(map["poneyland"], 12);
2032+
///
2033+
/// *map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 12).1 += 10;
2034+
/// assert_eq!(map["poneyland"], 22);
2035+
/// ```
2036+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2037+
pub fn or_insert(self, default_key: K, default_val: V) -> (&'a mut K, &'a mut V)
2038+
where K: Hash,
2039+
S: BuildHasher,
2040+
{
2041+
match self {
2042+
RawEntryMut::Occupied(entry) => entry.into_key_value(),
2043+
RawEntryMut::Vacant(entry) => entry.insert(default_key, default_val),
2044+
}
2045+
}
2046+
2047+
/// Ensures a value is in the entry by inserting the result of the default function if empty,
2048+
/// and returns mutable references to the key and value in the entry.
2049+
///
2050+
/// # Examples
2051+
///
2052+
/// ```
2053+
/// #![feature(hash_raw_entry)]
2054+
/// use std::collections::HashMap;
2055+
///
2056+
/// let mut map: HashMap<&str, String> = HashMap::new();
2057+
///
2058+
/// map.raw_entry_mut().from_key("poneyland").or_insert_with(|| {
2059+
/// ("poneyland", "hoho".to_string())
2060+
/// });
2061+
///
2062+
/// assert_eq!(map["poneyland"], "hoho".to_string());
2063+
/// ```
2064+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2065+
pub fn or_insert_with<F>(self, default: F) -> (&'a mut K, &'a mut V)
2066+
where F: FnOnce() -> (K, V),
2067+
K: Hash,
2068+
S: BuildHasher,
2069+
{
2070+
match self {
2071+
RawEntryMut::Occupied(entry) => entry.into_key_value(),
2072+
RawEntryMut::Vacant(entry) => {
2073+
let (k, v) = default();
2074+
entry.insert(k, v)
2075+
}
2076+
}
2077+
}
2078+
2079+
/// Provides in-place mutable access to an occupied entry before any
2080+
/// potential inserts into the map.
2081+
///
2082+
/// # Examples
2083+
///
2084+
/// ```
2085+
/// #![feature(hash_raw_entry)]
2086+
/// use std::collections::HashMap;
2087+
///
2088+
/// let mut map: HashMap<&str, u32> = HashMap::new();
2089+
///
2090+
/// map.raw_entry_mut()
2091+
/// .from_key("poneyland")
2092+
/// .and_modify(|_k, v| { *v += 1 })
2093+
/// .or_insert("poneyland", 42);
2094+
/// assert_eq!(map["poneyland"], 42);
2095+
///
2096+
/// map.raw_entry_mut()
2097+
/// .from_key("poneyland")
2098+
/// .and_modify(|_k, v| { *v += 1 })
2099+
/// .or_insert("poneyland", 0);
2100+
/// assert_eq!(map["poneyland"], 43);
2101+
/// ```
2102+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2103+
pub fn and_modify<F>(self, f: F) -> Self
2104+
where F: FnOnce(&mut K, &mut V)
2105+
{
2106+
match self {
2107+
RawEntryMut::Occupied(mut entry) => {
2108+
{
2109+
let (k, v) = entry.get_key_value_mut();
2110+
f(k, v);
2111+
}
2112+
RawEntryMut::Occupied(entry)
2113+
},
2114+
RawEntryMut::Vacant(entry) => RawEntryMut::Vacant(entry),
2115+
}
2116+
}
2117+
}
2118+
2119+
impl<'a, K, V> RawOccupiedEntryMut<'a, K, V> {
2120+
/// Gets a reference to the key in the entry.
2121+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2122+
pub fn key(&self) -> &K {
2123+
self.elem.read().0
2124+
}
2125+
2126+
/// Gets a mutable reference to the key in the entry.
2127+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2128+
pub fn key_mut(&mut self) -> &mut K {
2129+
self.elem.read_mut().0
2130+
}
2131+
2132+
/// Converts the entry into a mutable reference to the key in the entry
2133+
/// with a lifetime bound to the map itself.
2134+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2135+
pub fn into_key(self) -> &'a mut K {
2136+
self.elem.into_mut_refs().0
2137+
}
2138+
2139+
/// Gets a reference to the value in the entry.
2140+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2141+
pub fn get(&self) -> &V {
2142+
self.elem.read().1
2143+
}
2144+
2145+
/// Converts the OccupiedEntry into a mutable reference to the value in the entry
2146+
/// with a lifetime bound to the map itself.
2147+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2148+
pub fn into_mut(self) -> &'a mut V {
2149+
self.elem.into_mut_refs().1
2150+
}
2151+
2152+
/// Gets a mutable reference to the value in the entry.
2153+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2154+
pub fn get_mut(&mut self) -> &mut V {
2155+
self.elem.read_mut().1
2156+
}
2157+
2158+
/// Gets a reference to the key and value in the entry.
2159+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2160+
pub fn get_key_value(&mut self) -> (&K, &V) {
2161+
self.elem.read()
2162+
}
2163+
2164+
/// Gets a mutable reference to the key and value in the entry.
2165+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2166+
pub fn get_key_value_mut(&mut self) -> (&mut K, &mut V) {
2167+
self.elem.read_mut()
2168+
}
2169+
2170+
/// Converts the OccupiedEntry into a mutable reference to the key and value in the entry
2171+
/// with a lifetime bound to the map itself.
2172+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2173+
pub fn into_key_value(self) -> (&'a mut K, &'a mut V) {
2174+
self.elem.into_mut_refs()
2175+
}
2176+
2177+
/// Sets the value of the entry, and returns the entry's old value.
2178+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2179+
pub fn insert(&mut self, value: V) -> V {
2180+
mem::replace(self.get_mut(), value)
2181+
}
2182+
2183+
/// Sets the value of the entry, and returns the entry's old value.
2184+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2185+
pub fn insert_key(&mut self, key: K) -> K {
2186+
mem::replace(self.key_mut(), key)
2187+
}
2188+
2189+
/// Takes the value out of the entry, and returns it.
2190+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2191+
pub fn remove(self) -> V {
2192+
pop_internal(self.elem).1
2193+
}
2194+
2195+
/// Take the ownership of the key and value from the map.
2196+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2197+
pub fn remove_entry(self) -> (K, V) {
2198+
let (k, v, _) = pop_internal(self.elem);
2199+
(k, v)
2200+
}
2201+
}
2202+
2203+
impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
2204+
/// Sets the value of the entry with the VacantEntry's key,
2205+
/// and returns a mutable reference to it.
2206+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2207+
pub fn insert(self, key: K, value: V) -> (&'a mut K, &'a mut V)
2208+
where K: Hash,
2209+
S: BuildHasher,
2210+
{
2211+
let mut hasher = self.hash_builder.build_hasher();
2212+
key.hash(&mut hasher);
2213+
self.insert_hashed_nocheck(hasher.finish(), key, value)
2214+
}
2215+
2216+
/// Sets the value of the entry with the VacantEntry's key,
2217+
/// and returns a mutable reference to it.
2218+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2219+
pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) {
2220+
let hash = SafeHash::new(hash);
2221+
let b = match self.elem {
2222+
NeqElem(mut bucket, disp) => {
2223+
if disp >= DISPLACEMENT_THRESHOLD {
2224+
bucket.table_mut().set_tag(true);
2225+
}
2226+
robin_hood(bucket, disp, hash, key, value)
2227+
},
2228+
NoElem(mut bucket, disp) => {
2229+
if disp >= DISPLACEMENT_THRESHOLD {
2230+
bucket.table_mut().set_tag(true);
2231+
}
2232+
bucket.put(hash, key, value)
2233+
},
2234+
};
2235+
b.into_mut_refs()
2236+
}
2237+
}
2238+
2239+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2240+
impl<'a, K, V, S> Debug for RawEntryBuilderMut<'a, K, V, S> {
2241+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2242+
f.debug_struct("RawEntryBuilder")
2243+
.finish()
2244+
}
2245+
}
2246+
2247+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2248+
impl<'a, K: Debug, V: Debug, S> Debug for RawEntryMut<'a, K, V, S> {
2249+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2250+
match *self {
2251+
RawEntryMut::Vacant(ref v) => {
2252+
f.debug_tuple("RawEntry")
2253+
.field(v)
2254+
.finish()
2255+
}
2256+
RawEntryMut::Occupied(ref o) => {
2257+
f.debug_tuple("RawEntry")
2258+
.field(o)
2259+
.finish()
2260+
}
2261+
}
2262+
}
2263+
}
2264+
2265+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2266+
impl<'a, K: Debug, V: Debug> Debug for RawOccupiedEntryMut<'a, K, V> {
2267+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2268+
f.debug_struct("RawOccupiedEntryMut")
2269+
.field("key", self.key())
2270+
.field("value", self.get())
2271+
.finish()
2272+
}
2273+
}
2274+
2275+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2276+
impl<'a, K, V, S> Debug for RawVacantEntryMut<'a, K, V, S> {
2277+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2278+
f.debug_struct("RawVacantEntryMut")
2279+
.finish()
2280+
}
2281+
}
2282+
2283+
#[unstable(feature = "hash_raw_entry", issue = "54043")]
2284+
impl<'a, K, V, S> Debug for RawEntryBuilder<'a, K, V, S> {
2285+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2286+
f.debug_struct("RawEntryBuilder")
2287+
.finish()
2288+
}
2289+
}
2290+
17272291
/// A view into a single entry in a map, which may either be vacant or occupied.
17282292
///
17292293
/// This `enum` is constructed from the [`entry`] method on [`HashMap`].
@@ -3681,4 +4245,106 @@ mod test_map {
36814245
}
36824246
}
36834247

4248+
#[test]
4249+
fn test_raw_entry() {
4250+
use super::RawEntryMut::{Occupied, Vacant};
4251+
4252+
let xs = [(1i32, 10i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
4253+
4254+
let mut map: HashMap<_, _> = xs.iter().cloned().collect();
4255+
4256+
let compute_hash = |map: &HashMap<i32, i32>, k: i32| -> u64 {
4257+
use core::hash::{BuildHasher, Hash, Hasher};
4258+
4259+
let mut hasher = map.hasher().build_hasher();
4260+
k.hash(&mut hasher);
4261+
hasher.finish()
4262+
};
4263+
4264+
// Existing key (insert)
4265+
match map.raw_entry_mut().from_key(&1) {
4266+
Vacant(_) => unreachable!(),
4267+
Occupied(mut view) => {
4268+
assert_eq!(view.get(), &10);
4269+
assert_eq!(view.insert(100), 10);
4270+
}
4271+
}
4272+
let hash1 = compute_hash(&map, 1);
4273+
assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100));
4274+
assert_eq!(map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), (&1, &100));
4275+
assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), (&1, &100));
4276+
assert_eq!(map.raw_entry().search_bucket(hash1, |k| *k == 1).unwrap(), (&1, &100));
4277+
assert_eq!(map.len(), 6);
4278+
4279+
// Existing key (update)
4280+
match map.raw_entry_mut().from_key(&2) {
4281+
Vacant(_) => unreachable!(),
4282+
Occupied(mut view) => {
4283+
let v = view.get_mut();
4284+
let new_v = (*v) * 10;
4285+
*v = new_v;
4286+
}
4287+
}
4288+
let hash2 = compute_hash(&map, 2);
4289+
assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200));
4290+
assert_eq!(map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), (&2, &200));
4291+
assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), (&2, &200));
4292+
assert_eq!(map.raw_entry().search_bucket(hash2, |k| *k == 2).unwrap(), (&2, &200));
4293+
assert_eq!(map.len(), 6);
4294+
4295+
// Existing key (take)
4296+
let hash3 = compute_hash(&map, 3);
4297+
match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) {
4298+
Vacant(_) => unreachable!(),
4299+
Occupied(view) => {
4300+
assert_eq!(view.remove_entry(), (3, 30));
4301+
}
4302+
}
4303+
assert_eq!(map.raw_entry().from_key(&3), None);
4304+
assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None);
4305+
assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None);
4306+
assert_eq!(map.raw_entry().search_bucket(hash3, |k| *k == 3), None);
4307+
assert_eq!(map.len(), 5);
4308+
4309+
4310+
// Nonexistent key (insert)
4311+
match map.raw_entry_mut().from_key(&10) {
4312+
Occupied(_) => unreachable!(),
4313+
Vacant(view) => {
4314+
assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000));
4315+
}
4316+
}
4317+
assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000));
4318+
assert_eq!(map.len(), 6);
4319+
4320+
// Ensure all lookup methods produce equivalent results.
4321+
for k in 0..12 {
4322+
let hash = compute_hash(&map, k);
4323+
let v = map.get(&k).cloned();
4324+
let kv = v.as_ref().map(|v| (&k, v));
4325+
4326+
assert_eq!(map.raw_entry().from_key(&k), kv);
4327+
assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv);
4328+
assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv);
4329+
assert_eq!(map.raw_entry().search_bucket(hash, |q| *q == k), kv);
4330+
4331+
match map.raw_entry_mut().from_key(&k) {
4332+
Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
4333+
Vacant(_) => assert_eq!(v, None),
4334+
}
4335+
match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) {
4336+
Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
4337+
Vacant(_) => assert_eq!(v, None),
4338+
}
4339+
match map.raw_entry_mut().from_hash(hash, |q| *q == k) {
4340+
Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
4341+
Vacant(_) => assert_eq!(v, None),
4342+
}
4343+
match map.raw_entry_mut().search_bucket(hash, |q| *q == k) {
4344+
Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
4345+
Vacant(_) => assert_eq!(v, None),
4346+
}
4347+
}
4348+
}
4349+
36844350
}

‎src/libstd/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@
283283
#![feature(prelude_import)]
284284
#![feature(ptr_internals)]
285285
#![feature(raw)]
286+
#![feature(hash_raw_entry)]
286287
#![feature(rustc_attrs)]
287288
#![feature(rustc_const_unstable)]
288289
#![feature(std_internals)]

0 commit comments

Comments
 (0)
Please sign in to comment.