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