hashbrown/
rustc_entry.rs

1use self::RustcEntry::*;
2use crate::map::{make_hash, Drain, HashMap, IntoIter, Iter, IterMut};
3use crate::raw::{Allocator, Bucket, Global, RawTable};
4use core::fmt::{self, Debug};
5use core::hash::{BuildHasher, Hash};
6use core::mem;
7
8impl<K, V, S, A> HashMap<K, V, S, A>
9where
10    K: Eq + Hash,
11    S: BuildHasher,
12    A: Allocator,
13{
14    /// Gets the given key's corresponding entry in the map for in-place manipulation.
15    ///
16    /// # Examples
17    ///
18    /// ```
19    /// use hashbrown::HashMap;
20    ///
21    /// let mut letters = HashMap::new();
22    ///
23    /// for ch in "a short treatise on fungi".chars() {
24    ///     let counter = letters.rustc_entry(ch).or_insert(0);
25    ///     *counter += 1;
26    /// }
27    ///
28    /// assert_eq!(letters[&'s'], 2);
29    /// assert_eq!(letters[&'t'], 3);
30    /// assert_eq!(letters[&'u'], 1);
31    /// assert_eq!(letters.get(&'y'), None);
32    /// ```
33    #[cfg_attr(feature = "inline-more", inline)]
34    pub fn rustc_entry(&mut self, key: K) -> RustcEntry<'_, K, V, A> {
35        let hash = make_hash(&self.hash_builder, &key);
36        if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) {
37            RustcEntry::Occupied(RustcOccupiedEntry {
38                elem,
39                table: &mut self.table,
40            })
41        } else {
42            // Ideally we would put this in VacantEntry::insert, but Entry is not
43            // generic over the BuildHasher and adding a generic parameter would be
44            // a breaking change.
45            self.reserve(1);
46
47            RustcEntry::Vacant(RustcVacantEntry {
48                hash,
49                key,
50                table: &mut self.table,
51            })
52        }
53    }
54}
55
56/// A view into a single entry in a map, which may either be vacant or occupied.
57///
58/// This `enum` is constructed from the [`rustc_entry`] method on [`HashMap`].
59///
60/// [`HashMap`]: struct.HashMap.html
61/// [`rustc_entry`]: struct.HashMap.html#method.rustc_entry
62pub enum RustcEntry<'a, K, V, A = Global>
63where
64    A: Allocator,
65{
66    /// An occupied entry.
67    Occupied(RustcOccupiedEntry<'a, K, V, A>),
68
69    /// A vacant entry.
70    Vacant(RustcVacantEntry<'a, K, V, A>),
71}
72
73impl<K: Debug, V: Debug, A: Allocator> Debug for RustcEntry<'_, K, V, A> {
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        match *self {
76            Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(),
77            Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(),
78        }
79    }
80}
81
82/// A view into an occupied entry in a `HashMap`.
83/// It is part of the [`RustcEntry`] enum.
84///
85/// [`RustcEntry`]: enum.RustcEntry.html
86pub struct RustcOccupiedEntry<'a, K, V, A = Global>
87where
88    A: Allocator,
89{
90    elem: Bucket<(K, V)>,
91    table: &'a mut RawTable<(K, V), A>,
92}
93
94unsafe impl<K, V, A> Send for RustcOccupiedEntry<'_, K, V, A>
95where
96    K: Send,
97    V: Send,
98    A: Allocator + Send,
99{
100}
101unsafe impl<K, V, A> Sync for RustcOccupiedEntry<'_, K, V, A>
102where
103    K: Sync,
104    V: Sync,
105    A: Allocator + Sync,
106{
107}
108
109impl<K: Debug, V: Debug, A: Allocator> Debug for RustcOccupiedEntry<'_, K, V, A> {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        f.debug_struct("OccupiedEntry")
112            .field("key", self.key())
113            .field("value", self.get())
114            .finish()
115    }
116}
117
118/// A view into a vacant entry in a `HashMap`.
119/// It is part of the [`RustcEntry`] enum.
120///
121/// [`RustcEntry`]: enum.RustcEntry.html
122pub struct RustcVacantEntry<'a, K, V, A = Global>
123where
124    A: Allocator,
125{
126    hash: u64,
127    key: K,
128    table: &'a mut RawTable<(K, V), A>,
129}
130
131impl<K: Debug, V, A: Allocator> Debug for RustcVacantEntry<'_, K, V, A> {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        f.debug_tuple("VacantEntry").field(self.key()).finish()
134    }
135}
136
137impl<'a, K, V, A: Allocator> RustcEntry<'a, K, V, A> {
138    /// Sets the value of the entry, and returns a RustcOccupiedEntry.
139    ///
140    /// # Examples
141    ///
142    /// ```
143    /// use hashbrown::HashMap;
144    ///
145    /// let mut map: HashMap<&str, u32> = HashMap::new();
146    /// let entry = map.rustc_entry("horseyland").insert(37);
147    ///
148    /// assert_eq!(entry.key(), &"horseyland");
149    /// ```
150    pub fn insert(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> {
151        match self {
152            Vacant(entry) => entry.insert_entry(value),
153            Occupied(mut entry) => {
154                entry.insert(value);
155                entry
156            }
157        }
158    }
159
160    /// Ensures a value is in the entry by inserting the default if empty, and returns
161    /// a mutable reference to the value in the entry.
162    ///
163    /// # Examples
164    ///
165    /// ```
166    /// use hashbrown::HashMap;
167    ///
168    /// let mut map: HashMap<&str, u32> = HashMap::new();
169    ///
170    /// map.rustc_entry("poneyland").or_insert(3);
171    /// assert_eq!(map["poneyland"], 3);
172    ///
173    /// *map.rustc_entry("poneyland").or_insert(10) *= 2;
174    /// assert_eq!(map["poneyland"], 6);
175    /// ```
176    #[cfg_attr(feature = "inline-more", inline)]
177    pub fn or_insert(self, default: V) -> &'a mut V
178    where
179        K: Hash,
180    {
181        match self {
182            Occupied(entry) => entry.into_mut(),
183            Vacant(entry) => entry.insert(default),
184        }
185    }
186
187    /// Ensures a value is in the entry by inserting the result of the default function if empty,
188    /// and returns a mutable reference to the value in the entry.
189    ///
190    /// # Examples
191    ///
192    /// ```
193    /// use hashbrown::HashMap;
194    ///
195    /// let mut map: HashMap<&str, String> = HashMap::new();
196    /// let s = "hoho".to_string();
197    ///
198    /// map.rustc_entry("poneyland").or_insert_with(|| s);
199    ///
200    /// assert_eq!(map["poneyland"], "hoho".to_string());
201    /// ```
202    #[cfg_attr(feature = "inline-more", inline)]
203    pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V
204    where
205        K: Hash,
206    {
207        match self {
208            Occupied(entry) => entry.into_mut(),
209            Vacant(entry) => entry.insert(default()),
210        }
211    }
212
213    /// Returns a reference to this entry's key.
214    ///
215    /// # Examples
216    ///
217    /// ```
218    /// use hashbrown::HashMap;
219    ///
220    /// let mut map: HashMap<&str, u32> = HashMap::new();
221    /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland");
222    /// ```
223    #[cfg_attr(feature = "inline-more", inline)]
224    pub fn key(&self) -> &K {
225        match *self {
226            Occupied(ref entry) => entry.key(),
227            Vacant(ref entry) => entry.key(),
228        }
229    }
230
231    /// Provides in-place mutable access to an occupied entry before any
232    /// potential inserts into the map.
233    ///
234    /// # Examples
235    ///
236    /// ```
237    /// use hashbrown::HashMap;
238    ///
239    /// let mut map: HashMap<&str, u32> = HashMap::new();
240    ///
241    /// map.rustc_entry("poneyland")
242    ///    .and_modify(|e| { *e += 1 })
243    ///    .or_insert(42);
244    /// assert_eq!(map["poneyland"], 42);
245    ///
246    /// map.rustc_entry("poneyland")
247    ///    .and_modify(|e| { *e += 1 })
248    ///    .or_insert(42);
249    /// assert_eq!(map["poneyland"], 43);
250    /// ```
251    #[cfg_attr(feature = "inline-more", inline)]
252    pub fn and_modify<F>(self, f: F) -> Self
253    where
254        F: FnOnce(&mut V),
255    {
256        match self {
257            Occupied(mut entry) => {
258                f(entry.get_mut());
259                Occupied(entry)
260            }
261            Vacant(entry) => Vacant(entry),
262        }
263    }
264}
265
266impl<'a, K, V: Default, A: Allocator> RustcEntry<'a, K, V, A> {
267    /// Ensures a value is in the entry by inserting the default value if empty,
268    /// and returns a mutable reference to the value in the entry.
269    ///
270    /// # Examples
271    ///
272    /// ```
273    /// # fn main() {
274    /// use hashbrown::HashMap;
275    ///
276    /// let mut map: HashMap<&str, Option<u32>> = HashMap::new();
277    /// map.rustc_entry("poneyland").or_default();
278    ///
279    /// assert_eq!(map["poneyland"], None);
280    /// # }
281    /// ```
282    #[cfg_attr(feature = "inline-more", inline)]
283    pub fn or_default(self) -> &'a mut V
284    where
285        K: Hash,
286    {
287        match self {
288            Occupied(entry) => entry.into_mut(),
289            Vacant(entry) => entry.insert(Default::default()),
290        }
291    }
292}
293
294impl<'a, K, V, A: Allocator> RustcOccupiedEntry<'a, K, V, A> {
295    /// Gets a reference to the key in the entry.
296    ///
297    /// # Examples
298    ///
299    /// ```
300    /// use hashbrown::HashMap;
301    ///
302    /// let mut map: HashMap<&str, u32> = HashMap::new();
303    /// map.rustc_entry("poneyland").or_insert(12);
304    /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland");
305    /// ```
306    #[cfg_attr(feature = "inline-more", inline)]
307    pub fn key(&self) -> &K {
308        unsafe { &self.elem.as_ref().0 }
309    }
310
311    /// Take the ownership of the key and value from the map.
312    ///
313    /// # Examples
314    ///
315    /// ```
316    /// use hashbrown::HashMap;
317    /// use hashbrown::hash_map::RustcEntry;
318    ///
319    /// let mut map: HashMap<&str, u32> = HashMap::new();
320    /// map.rustc_entry("poneyland").or_insert(12);
321    ///
322    /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") {
323    ///     // We delete the entry from the map.
324    ///     o.remove_entry();
325    /// }
326    ///
327    /// assert_eq!(map.contains_key("poneyland"), false);
328    /// ```
329    #[cfg_attr(feature = "inline-more", inline)]
330    pub fn remove_entry(self) -> (K, V) {
331        unsafe { self.table.remove(self.elem).0 }
332    }
333
334    /// Gets a reference to the value in the entry.
335    ///
336    /// # Examples
337    ///
338    /// ```
339    /// use hashbrown::HashMap;
340    /// use hashbrown::hash_map::RustcEntry;
341    ///
342    /// let mut map: HashMap<&str, u32> = HashMap::new();
343    /// map.rustc_entry("poneyland").or_insert(12);
344    ///
345    /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") {
346    ///     assert_eq!(o.get(), &12);
347    /// }
348    /// ```
349    #[cfg_attr(feature = "inline-more", inline)]
350    pub fn get(&self) -> &V {
351        unsafe { &self.elem.as_ref().1 }
352    }
353
354    /// Gets a mutable reference to the value in the entry.
355    ///
356    /// If you need a reference to the `RustcOccupiedEntry` which may outlive the
357    /// destruction of the `RustcEntry` value, see [`into_mut`].
358    ///
359    /// [`into_mut`]: #method.into_mut
360    ///
361    /// # Examples
362    ///
363    /// ```
364    /// use hashbrown::HashMap;
365    /// use hashbrown::hash_map::RustcEntry;
366    ///
367    /// let mut map: HashMap<&str, u32> = HashMap::new();
368    /// map.rustc_entry("poneyland").or_insert(12);
369    ///
370    /// assert_eq!(map["poneyland"], 12);
371    /// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") {
372    ///     *o.get_mut() += 10;
373    ///     assert_eq!(*o.get(), 22);
374    ///
375    ///     // We can use the same RustcEntry multiple times.
376    ///     *o.get_mut() += 2;
377    /// }
378    ///
379    /// assert_eq!(map["poneyland"], 24);
380    /// ```
381    #[cfg_attr(feature = "inline-more", inline)]
382    pub fn get_mut(&mut self) -> &mut V {
383        unsafe { &mut self.elem.as_mut().1 }
384    }
385
386    /// Converts the RustcOccupiedEntry into a mutable reference to the value in the entry
387    /// with a lifetime bound to the map itself.
388    ///
389    /// If you need multiple references to the `RustcOccupiedEntry`, see [`get_mut`].
390    ///
391    /// [`get_mut`]: #method.get_mut
392    ///
393    /// # Examples
394    ///
395    /// ```
396    /// use hashbrown::HashMap;
397    /// use hashbrown::hash_map::RustcEntry;
398    ///
399    /// let mut map: HashMap<&str, u32> = HashMap::new();
400    /// map.rustc_entry("poneyland").or_insert(12);
401    ///
402    /// assert_eq!(map["poneyland"], 12);
403    /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") {
404    ///     *o.into_mut() += 10;
405    /// }
406    ///
407    /// assert_eq!(map["poneyland"], 22);
408    /// ```
409    #[cfg_attr(feature = "inline-more", inline)]
410    pub fn into_mut(self) -> &'a mut V {
411        unsafe { &mut self.elem.as_mut().1 }
412    }
413
414    /// Sets the value of the entry, and returns the entry's old value.
415    ///
416    /// # Examples
417    ///
418    /// ```
419    /// use hashbrown::HashMap;
420    /// use hashbrown::hash_map::RustcEntry;
421    ///
422    /// let mut map: HashMap<&str, u32> = HashMap::new();
423    /// map.rustc_entry("poneyland").or_insert(12);
424    ///
425    /// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") {
426    ///     assert_eq!(o.insert(15), 12);
427    /// }
428    ///
429    /// assert_eq!(map["poneyland"], 15);
430    /// ```
431    #[cfg_attr(feature = "inline-more", inline)]
432    pub fn insert(&mut self, value: V) -> V {
433        mem::replace(self.get_mut(), value)
434    }
435
436    /// Takes the value out of the entry, and returns it.
437    ///
438    /// # Examples
439    ///
440    /// ```
441    /// use hashbrown::HashMap;
442    /// use hashbrown::hash_map::RustcEntry;
443    ///
444    /// let mut map: HashMap<&str, u32> = HashMap::new();
445    /// map.rustc_entry("poneyland").or_insert(12);
446    ///
447    /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") {
448    ///     assert_eq!(o.remove(), 12);
449    /// }
450    ///
451    /// assert_eq!(map.contains_key("poneyland"), false);
452    /// ```
453    #[cfg_attr(feature = "inline-more", inline)]
454    pub fn remove(self) -> V {
455        self.remove_entry().1
456    }
457}
458
459impl<'a, K, V, A: Allocator> RustcVacantEntry<'a, K, V, A> {
460    /// Gets a reference to the key that would be used when inserting a value
461    /// through the `RustcVacantEntry`.
462    ///
463    /// # Examples
464    ///
465    /// ```
466    /// use hashbrown::HashMap;
467    ///
468    /// let mut map: HashMap<&str, u32> = HashMap::new();
469    /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland");
470    /// ```
471    #[cfg_attr(feature = "inline-more", inline)]
472    pub fn key(&self) -> &K {
473        &self.key
474    }
475
476    /// Take ownership of the key.
477    ///
478    /// # Examples
479    ///
480    /// ```
481    /// use hashbrown::HashMap;
482    /// use hashbrown::hash_map::RustcEntry;
483    ///
484    /// let mut map: HashMap<&str, u32> = HashMap::new();
485    ///
486    /// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") {
487    ///     v.into_key();
488    /// }
489    /// ```
490    #[cfg_attr(feature = "inline-more", inline)]
491    pub fn into_key(self) -> K {
492        self.key
493    }
494
495    /// Sets the value of the entry with the RustcVacantEntry's key,
496    /// and returns a mutable reference to it.
497    ///
498    /// # Examples
499    ///
500    /// ```
501    /// use hashbrown::HashMap;
502    /// use hashbrown::hash_map::RustcEntry;
503    ///
504    /// let mut map: HashMap<&str, u32> = HashMap::new();
505    ///
506    /// if let RustcEntry::Vacant(o) = map.rustc_entry("poneyland") {
507    ///     o.insert(37);
508    /// }
509    /// assert_eq!(map["poneyland"], 37);
510    /// ```
511    #[cfg_attr(feature = "inline-more", inline)]
512    pub fn insert(self, value: V) -> &'a mut V {
513        unsafe {
514            let bucket = self.table.insert_no_grow(self.hash, (self.key, value));
515            &mut bucket.as_mut().1
516        }
517    }
518
519    /// Sets the value of the entry with the RustcVacantEntry's key,
520    /// and returns a RustcOccupiedEntry.
521    ///
522    /// # Examples
523    ///
524    /// ```
525    /// use hashbrown::HashMap;
526    /// use hashbrown::hash_map::RustcEntry;
527    ///
528    /// let mut map: HashMap<&str, u32> = HashMap::new();
529    ///
530    /// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") {
531    ///     let o = v.insert_entry(37);
532    ///     assert_eq!(o.get(), &37);
533    /// }
534    /// ```
535    #[cfg_attr(feature = "inline-more", inline)]
536    pub fn insert_entry(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> {
537        let bucket = unsafe { self.table.insert_no_grow(self.hash, (self.key, value)) };
538        RustcOccupiedEntry {
539            elem: bucket,
540            table: self.table,
541        }
542    }
543}
544
545impl<K, V> IterMut<'_, K, V> {
546    /// Returns a iterator of references over the remaining items.
547    #[cfg_attr(feature = "inline-more", inline)]
548    pub fn rustc_iter(&self) -> Iter<'_, K, V> {
549        self.iter()
550    }
551}
552
553impl<K, V> IntoIter<K, V> {
554    /// Returns a iterator of references over the remaining items.
555    #[cfg_attr(feature = "inline-more", inline)]
556    pub fn rustc_iter(&self) -> Iter<'_, K, V> {
557        self.iter()
558    }
559}
560
561impl<K, V> Drain<'_, K, V> {
562    /// Returns a iterator of references over the remaining items.
563    #[cfg_attr(feature = "inline-more", inline)]
564    pub fn rustc_iter(&self) -> Iter<'_, K, V> {
565        self.iter()
566    }
567}