iddqd/id_hash_map/imp.rs
1use super::{
2 Entry, IdHashItem, IntoIter, Iter, IterMut, OccupiedEntry, RefMut,
3 VacantEntry, tables::IdHashMapTables,
4};
5use crate::{
6 DefaultHashBuilder,
7 errors::DuplicateItem,
8 internal::{ValidateCompact, ValidationError},
9 support::{
10 ItemIndex,
11 alloc::{Allocator, Global, global_alloc},
12 borrow::DormantMutRef,
13 hash_table,
14 item_set::ItemSet,
15 map_hash::MapHash,
16 },
17};
18use alloc::collections::BTreeSet;
19use core::{
20 fmt,
21 hash::{BuildHasher, Hash},
22};
23use equivalent::Equivalent;
24
25/// A hash map where the key is part of the value.
26///
27/// The storage mechanism is a list of items with an embedded free chain, with
28/// indexes to occupied slots stored in a hash table. This allows for efficient
29/// lookups by the key and prevents duplicates.
30///
31/// # Examples
32///
33/// ```
34/// # #[cfg(feature = "default-hasher")] {
35/// use iddqd::{IdHashItem, IdHashMap, id_upcast};
36///
37/// // Define a struct with a key.
38/// #[derive(Debug, PartialEq, Eq, Hash)]
39/// struct MyItem {
40/// id: String,
41/// value: u32,
42/// }
43///
44/// // Implement IdHashItem for the struct.
45/// impl IdHashItem for MyItem {
46/// // Keys can borrow from the item.
47/// type Key<'a> = &'a str;
48///
49/// fn key(&self) -> Self::Key<'_> {
50/// &self.id
51/// }
52///
53/// id_upcast!();
54/// }
55///
56/// // Create an IdHashMap and insert items.
57/// let mut map = IdHashMap::new();
58/// map.insert_unique(MyItem { id: "foo".to_string(), value: 42 }).unwrap();
59/// map.insert_unique(MyItem { id: "bar".to_string(), value: 20 }).unwrap();
60///
61/// // Look up items by their keys.
62/// assert_eq!(map.get("foo").unwrap().value, 42);
63/// assert_eq!(map.get("bar").unwrap().value, 20);
64/// assert!(map.get("baz").is_none());
65/// # }
66/// ```
67#[derive(Clone)]
68pub struct IdHashMap<T, S = DefaultHashBuilder, A: Allocator = Global> {
69 pub(super) items: ItemSet<T, A>,
70 pub(super) tables: IdHashMapTables<S, A>,
71}
72
73impl<T: IdHashItem, S: Default, A: Allocator + Default> Default
74 for IdHashMap<T, S, A>
75{
76 fn default() -> Self {
77 Self {
78 items: ItemSet::with_capacity_in(0, A::default()),
79 tables: IdHashMapTables::default(),
80 }
81 }
82}
83
84#[cfg(feature = "default-hasher")]
85impl<T: IdHashItem> IdHashMap<T> {
86 /// Creates a new, empty `IdHashMap`.
87 ///
88 /// # Examples
89 ///
90 /// ```
91 /// # #[cfg(feature = "default-hasher")] {
92 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
93 ///
94 /// #[derive(Debug, PartialEq, Eq, Hash)]
95 /// struct Item {
96 /// id: String,
97 /// value: u32,
98 /// }
99 ///
100 /// impl IdHashItem for Item {
101 /// type Key<'a> = &'a str;
102 /// fn key(&self) -> Self::Key<'_> {
103 /// &self.id
104 /// }
105 /// id_upcast!();
106 /// }
107 ///
108 /// let map: IdHashMap<Item> = IdHashMap::new();
109 /// assert!(map.is_empty());
110 /// assert_eq!(map.len(), 0);
111 /// # }
112 /// ```
113 #[inline]
114 pub fn new() -> Self {
115 Self { items: ItemSet::new(), tables: IdHashMapTables::default() }
116 }
117
118 /// Creates a new `IdHashMap` with the given capacity.
119 ///
120 /// # Examples
121 ///
122 /// ```
123 /// # #[cfg(feature = "default-hasher")] {
124 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
125 ///
126 /// #[derive(Debug, PartialEq, Eq, Hash)]
127 /// struct Item {
128 /// id: String,
129 /// value: u32,
130 /// }
131 ///
132 /// impl IdHashItem for Item {
133 /// type Key<'a> = &'a str;
134 /// fn key(&self) -> Self::Key<'_> {
135 /// &self.id
136 /// }
137 /// id_upcast!();
138 /// }
139 ///
140 /// let map: IdHashMap<Item> = IdHashMap::with_capacity(10);
141 /// assert!(map.capacity() >= 10);
142 /// assert!(map.is_empty());
143 /// # }
144 /// ```
145 pub fn with_capacity(capacity: usize) -> Self {
146 Self {
147 items: ItemSet::with_capacity_in(capacity, global_alloc()),
148 tables: IdHashMapTables::with_capacity_and_hasher_in(
149 capacity,
150 DefaultHashBuilder::default(),
151 global_alloc(),
152 ),
153 }
154 }
155}
156
157impl<T: IdHashItem, S: BuildHasher> IdHashMap<T, S> {
158 /// Creates a new, empty `IdHashMap` with the given hasher.
159 ///
160 /// # Examples
161 ///
162 /// ```
163 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
164 /// use std::collections::hash_map::RandomState;
165 ///
166 /// #[derive(Debug, PartialEq, Eq, Hash)]
167 /// struct Item {
168 /// id: String,
169 /// value: u32,
170 /// }
171 ///
172 /// impl IdHashItem for Item {
173 /// type Key<'a> = &'a str;
174 /// fn key(&self) -> Self::Key<'_> {
175 /// &self.id
176 /// }
177 /// id_upcast!();
178 /// }
179 ///
180 /// let hasher = RandomState::new();
181 /// let map: IdHashMap<Item, _> = IdHashMap::with_hasher(hasher);
182 /// assert!(map.is_empty());
183 /// ```
184 pub const fn with_hasher(hasher: S) -> Self {
185 Self {
186 items: ItemSet::new(),
187 tables: IdHashMapTables::with_hasher_in(hasher, global_alloc()),
188 }
189 }
190
191 /// Creates a new `IdHashMap` with the given capacity and hasher.
192 ///
193 /// # Examples
194 ///
195 /// ```
196 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
197 /// use std::collections::hash_map::RandomState;
198 ///
199 /// #[derive(Debug, PartialEq, Eq, Hash)]
200 /// struct Item {
201 /// id: String,
202 /// value: u32,
203 /// }
204 ///
205 /// impl IdHashItem for Item {
206 /// type Key<'a> = &'a str;
207 /// fn key(&self) -> Self::Key<'_> {
208 /// &self.id
209 /// }
210 /// id_upcast!();
211 /// }
212 ///
213 /// let hasher = RandomState::new();
214 /// let map: IdHashMap<Item, _> =
215 /// IdHashMap::with_capacity_and_hasher(10, hasher);
216 /// assert!(map.capacity() >= 10);
217 /// assert!(map.is_empty());
218 /// ```
219 pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
220 Self {
221 items: ItemSet::with_capacity_in(capacity, global_alloc()),
222 tables: IdHashMapTables::with_capacity_and_hasher_in(
223 capacity,
224 hasher,
225 global_alloc(),
226 ),
227 }
228 }
229}
230
231#[cfg(feature = "default-hasher")]
232impl<T: IdHashItem, A: Clone + Allocator> IdHashMap<T, DefaultHashBuilder, A> {
233 /// Creates a new empty `IdHashMap` using the given allocator.
234 ///
235 /// Requires the `allocator-api2` feature to be enabled.
236 ///
237 /// # Examples
238 ///
239 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
240 ///
241 /// ```
242 /// # #[cfg(all(feature = "default-hasher", feature = "allocator-api2"))] {
243 /// use iddqd::{IdHashMap, IdHashItem, id_upcast};
244 /// # use iddqd_test_utils::bumpalo;
245 ///
246 /// #[derive(Debug, PartialEq, Eq, Hash)]
247 /// struct Item {
248 /// id: String,
249 /// value: u32,
250 /// }
251 ///
252 /// impl IdHashItem for Item {
253 /// type Key<'a> = &'a str;
254 /// fn key(&self) -> Self::Key<'_> { &self.id }
255 /// id_upcast!();
256 /// }
257 ///
258 /// // Define a new allocator.
259 /// let bump = bumpalo::Bump::new();
260 /// // Create a new IdHashMap using the allocator.
261 /// let map: IdHashMap<Item, _, &bumpalo::Bump> = IdHashMap::new_in(&bump);
262 /// assert!(map.is_empty());
263 /// # }
264 /// ```
265 pub fn new_in(alloc: A) -> Self {
266 Self {
267 items: ItemSet::with_capacity_in(0, alloc.clone()),
268 tables: IdHashMapTables::with_capacity_and_hasher_in(
269 0,
270 DefaultHashBuilder::default(),
271 alloc,
272 ),
273 }
274 }
275
276 /// Creates an empty `IdHashMap` with the specified capacity using the given
277 /// allocator.
278 ///
279 /// Requires the `allocator-api2` feature to be enabled.
280 ///
281 /// # Examples
282 ///
283 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
284 ///
285 /// ```
286 /// # #[cfg(all(feature = "default-hasher", feature = "allocator-api2"))] {
287 /// use iddqd::{IdHashMap, IdHashItem, id_upcast};
288 /// # use iddqd_test_utils::bumpalo;
289 ///
290 /// #[derive(Debug, PartialEq, Eq, Hash)]
291 /// struct Item {
292 /// id: String,
293 /// value: u32,
294 /// }
295 ///
296 /// impl IdHashItem for Item {
297 /// type Key<'a> = &'a str;
298 /// fn key(&self) -> Self::Key<'_> { &self.id }
299 /// id_upcast!();
300 /// }
301 ///
302 /// // Define a new allocator.
303 /// let bump = bumpalo::Bump::new();
304 /// // Create a new IdHashMap with capacity using the allocator.
305 /// let map: IdHashMap<Item, _, &bumpalo::Bump> = IdHashMap::with_capacity_in(10, &bump);
306 /// assert!(map.capacity() >= 10);
307 /// assert!(map.is_empty());
308 /// # }
309 /// ```
310 pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
311 Self {
312 items: ItemSet::with_capacity_in(capacity, alloc.clone()),
313 tables: IdHashMapTables::with_capacity_and_hasher_in(
314 capacity,
315 DefaultHashBuilder::default(),
316 alloc,
317 ),
318 }
319 }
320}
321
322impl<T: IdHashItem, S: BuildHasher, A: Clone + Allocator> IdHashMap<T, S, A> {
323 /// Creates a new, empty `IdHashMap` with the given hasher and allocator.
324 ///
325 /// Requires the `allocator-api2` feature to be enabled.
326 ///
327 /// # Examples
328 ///
329 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
330 ///
331 /// ```
332 /// # #[cfg(feature = "allocator-api2")] {
333 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
334 /// use std::collections::hash_map::RandomState;
335 /// # use iddqd_test_utils::bumpalo;
336 ///
337 /// #[derive(Debug, PartialEq, Eq, Hash)]
338 /// struct Item {
339 /// id: String,
340 /// value: u32,
341 /// }
342 ///
343 /// impl IdHashItem for Item {
344 /// type Key<'a> = &'a str;
345 /// fn key(&self) -> Self::Key<'_> {
346 /// &self.id
347 /// }
348 /// id_upcast!();
349 /// }
350 ///
351 /// // Define a new allocator.
352 /// let bump = bumpalo::Bump::new();
353 /// let hasher = RandomState::new();
354 /// // Create a new IdHashMap with hasher using the allocator.
355 /// let map: IdHashMap<Item, _, &bumpalo::Bump> =
356 /// IdHashMap::with_hasher_in(hasher, &bump);
357 /// assert!(map.is_empty());
358 /// # }
359 /// ```
360 pub fn with_hasher_in(hasher: S, alloc: A) -> Self {
361 Self {
362 items: ItemSet::new_in(alloc.clone()),
363 tables: IdHashMapTables::with_hasher_in(hasher, alloc),
364 }
365 }
366
367 /// Creates a new, empty `IdHashMap` with the given capacity, hasher, and
368 /// allocator.
369 ///
370 /// Requires the `allocator-api2` feature to be enabled.
371 ///
372 /// # Examples
373 ///
374 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
375 ///
376 /// ```
377 /// # #[cfg(feature = "allocator-api2")] {
378 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
379 /// use std::collections::hash_map::RandomState;
380 /// # use iddqd_test_utils::bumpalo;
381 ///
382 /// #[derive(Debug, PartialEq, Eq, Hash)]
383 /// struct Item {
384 /// id: String,
385 /// value: u32,
386 /// }
387 ///
388 /// impl IdHashItem for Item {
389 /// type Key<'a> = &'a str;
390 /// fn key(&self) -> Self::Key<'_> {
391 /// &self.id
392 /// }
393 /// id_upcast!();
394 /// }
395 ///
396 /// // Define a new allocator.
397 /// let bump = bumpalo::Bump::new();
398 /// let hasher = RandomState::new();
399 /// // Create a new IdHashMap with capacity and hasher using the allocator.
400 /// let map: IdHashMap<Item, _, &bumpalo::Bump> =
401 /// IdHashMap::with_capacity_and_hasher_in(10, hasher, &bump);
402 /// assert!(map.capacity() >= 10);
403 /// assert!(map.is_empty());
404 /// # }
405 /// ```
406 pub fn with_capacity_and_hasher_in(
407 capacity: usize,
408 hasher: S,
409 alloc: A,
410 ) -> Self {
411 Self {
412 items: ItemSet::with_capacity_in(capacity, alloc.clone()),
413 tables: IdHashMapTables::with_capacity_and_hasher_in(
414 capacity, hasher, alloc,
415 ),
416 }
417 }
418}
419
420impl<T: IdHashItem, S: Default + Clone + BuildHasher, A: Allocator + Default>
421 IdHashMap<T, S, A>
422{
423 /// Creates a new `IdHashMap` from an iterator of values, rejecting
424 /// duplicates.
425 ///
426 /// To overwrite duplicates instead, use [`IdHashMap::from_iter`].
427 ///
428 /// # Examples
429 ///
430 /// ```
431 /// # #[cfg(feature = "default-hasher")] {
432 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
433 ///
434 /// #[derive(Debug, PartialEq, Eq, Hash)]
435 /// struct Item {
436 /// id: String,
437 /// value: u32,
438 /// }
439 ///
440 /// impl IdHashItem for Item {
441 /// type Key<'a> = &'a str;
442 /// fn key(&self) -> Self::Key<'_> {
443 /// &self.id
444 /// }
445 /// id_upcast!();
446 /// }
447 ///
448 /// let items = vec![
449 /// Item { id: "foo".to_string(), value: 42 },
450 /// Item { id: "bar".to_string(), value: 99 },
451 /// ];
452 ///
453 /// // Successful creation with unique keys.
454 /// let map: IdHashMap<Item> = IdHashMap::from_iter_unique(items).unwrap();
455 /// assert_eq!(map.len(), 2);
456 /// assert_eq!(map.get("foo").unwrap().value, 42);
457 ///
458 /// // Error with duplicate keys.
459 /// let duplicate_items = vec![
460 /// Item { id: "foo".to_string(), value: 42 },
461 /// Item { id: "foo".to_string(), value: 99 },
462 /// ];
463 /// assert!(IdHashMap::<Item>::from_iter_unique(duplicate_items).is_err());
464 /// # }
465 /// ```
466 pub fn from_iter_unique<I: IntoIterator<Item = T>>(
467 iter: I,
468 ) -> Result<Self, DuplicateItem<T>> {
469 let iter = iter.into_iter();
470 let mut map = Self::default();
471 map.reserve(iter.size_hint().0);
472 for value in iter {
473 // It would be nice to use insert_unique here, but that would return
474 // a `DuplicateItem<T, &T>`, which can only be converted into an
475 // owned value if T: Clone. Doing this via the Entry API means we
476 // can return a `DuplicateItem<T>` without requiring T to be Clone.
477 match map.entry(value.key()) {
478 Entry::Occupied(entry) => {
479 let duplicate = entry.remove();
480 return Err(DuplicateItem::__internal_new(
481 value,
482 vec![duplicate],
483 ));
484 }
485 Entry::Vacant(entry) => {
486 entry.insert_known_unique(value);
487 }
488 }
489 }
490
491 Ok(map)
492 }
493}
494
495impl<T: IdHashItem, S: Clone + BuildHasher, A: Allocator> IdHashMap<T, S, A> {
496 #[cfg(feature = "daft")]
497 pub(crate) fn hasher(&self) -> &S {
498 self.tables.hasher()
499 }
500
501 /// Returns the allocator.
502 ///
503 /// Requires the `allocator-api2` feature to be enabled.
504 ///
505 /// # Examples
506 ///
507 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
508 ///
509 /// ```
510 /// # #[cfg(all(feature = "default-hasher", feature = "allocator-api2"))] {
511 /// use iddqd::{IdHashMap, IdHashItem, id_upcast};
512 /// # use iddqd_test_utils::bumpalo;
513 ///
514 /// #[derive(Debug, PartialEq, Eq, Hash)]
515 /// struct Item {
516 /// id: String,
517 /// value: u32,
518 /// }
519 ///
520 /// impl IdHashItem for Item {
521 /// type Key<'a> = &'a str;
522 /// fn key(&self) -> Self::Key<'_> { &self.id }
523 /// id_upcast!();
524 /// }
525 ///
526 /// // Define a new allocator.
527 /// let bump = bumpalo::Bump::new();
528 /// // Create a new IdHashMap using the allocator.
529 /// let map: IdHashMap<Item, _, &bumpalo::Bump> = IdHashMap::new_in(&bump);
530 /// let _allocator = map.allocator();
531 /// # }
532 /// ```
533 pub fn allocator(&self) -> &A {
534 self.items.allocator()
535 }
536
537 /// Returns the currently allocated capacity of the map.
538 ///
539 /// # Examples
540 ///
541 /// ```
542 /// # #[cfg(feature = "default-hasher")] {
543 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
544 ///
545 /// #[derive(Debug, PartialEq, Eq, Hash)]
546 /// struct Item {
547 /// id: String,
548 /// value: u32,
549 /// }
550 ///
551 /// impl IdHashItem for Item {
552 /// type Key<'a> = &'a str;
553 /// fn key(&self) -> Self::Key<'_> {
554 /// &self.id
555 /// }
556 /// id_upcast!();
557 /// }
558 ///
559 /// let map: IdHashMap<Item> = IdHashMap::with_capacity(10);
560 /// assert!(map.capacity() >= 10);
561 /// # }
562 /// ```
563 pub fn capacity(&self) -> usize {
564 // items and tables.capacity might theoretically diverge: use
565 // items.capacity.
566 self.items.capacity()
567 }
568
569 /// Returns true if the map is empty.
570 ///
571 /// # Examples
572 ///
573 /// ```
574 /// # #[cfg(feature = "default-hasher")] {
575 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
576 ///
577 /// #[derive(Debug, PartialEq, Eq, Hash)]
578 /// struct Item {
579 /// id: String,
580 /// value: u32,
581 /// }
582 ///
583 /// impl IdHashItem for Item {
584 /// type Key<'a> = &'a str;
585 /// fn key(&self) -> Self::Key<'_> {
586 /// &self.id
587 /// }
588 /// id_upcast!();
589 /// }
590 ///
591 /// let mut map = IdHashMap::new();
592 /// assert!(map.is_empty());
593 ///
594 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
595 /// assert!(!map.is_empty());
596 /// # }
597 /// ```
598 #[inline]
599 pub fn is_empty(&self) -> bool {
600 self.items.is_empty()
601 }
602
603 /// Returns the number of items in the map.
604 ///
605 /// # Examples
606 ///
607 /// ```
608 /// # #[cfg(feature = "default-hasher")] {
609 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
610 ///
611 /// #[derive(Debug, PartialEq, Eq, Hash)]
612 /// struct Item {
613 /// id: String,
614 /// value: u32,
615 /// }
616 ///
617 /// impl IdHashItem for Item {
618 /// type Key<'a> = &'a str;
619 /// fn key(&self) -> Self::Key<'_> {
620 /// &self.id
621 /// }
622 /// id_upcast!();
623 /// }
624 ///
625 /// let mut map = IdHashMap::new();
626 /// assert_eq!(map.len(), 0);
627 ///
628 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
629 /// assert_eq!(map.len(), 1);
630 ///
631 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
632 /// assert_eq!(map.len(), 2);
633 /// # }
634 /// ```
635 #[inline]
636 pub fn len(&self) -> usize {
637 self.items.len()
638 }
639
640 /// Clears the map, removing all items.
641 ///
642 /// # Examples
643 ///
644 /// ```
645 /// # #[cfg(feature = "default-hasher")] {
646 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
647 ///
648 /// #[derive(Debug, PartialEq, Eq, Hash)]
649 /// struct Item {
650 /// id: String,
651 /// value: u32,
652 /// }
653 ///
654 /// impl IdHashItem for Item {
655 /// type Key<'a> = &'a str;
656 /// fn key(&self) -> Self::Key<'_> {
657 /// &self.id
658 /// }
659 /// id_upcast!();
660 /// }
661 ///
662 /// let mut map = IdHashMap::new();
663 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
664 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
665 /// assert_eq!(map.len(), 2);
666 ///
667 /// map.clear();
668 /// assert!(map.is_empty());
669 /// assert_eq!(map.len(), 0);
670 /// # }
671 /// ```
672 pub fn clear(&mut self) {
673 // Clear the internal index before dropping items. This way, if a user
674 // `Drop` panics during `self.items.clear()`, `key_to_item` cannot retain
675 // indexes pointing to removed item slots.
676 self.tables.key_to_item.clear();
677 self.items.clear();
678 }
679
680 /// Reserves capacity for at least `additional` more elements to be inserted
681 /// in the `IdHashMap`. The collection may reserve more space to
682 /// speculatively avoid frequent reallocations. After calling `reserve`,
683 /// capacity will be greater than or equal to `self.len() + additional`.
684 /// Does nothing if capacity is already sufficient.
685 ///
686 /// # Panics
687 ///
688 /// Panics if the new capacity overflows [`isize::MAX`] bytes, and
689 /// [`abort`]s the program in case of an allocation error. Use
690 /// [`try_reserve`](Self::try_reserve) instead if you want to handle memory
691 /// allocation failure.
692 ///
693 /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html
694 /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html
695 ///
696 /// # Examples
697 ///
698 /// ```
699 /// # #[cfg(feature = "default-hasher")] {
700 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
701 ///
702 /// #[derive(Debug, PartialEq, Eq, Hash)]
703 /// struct Item {
704 /// id: String,
705 /// value: u32,
706 /// }
707 ///
708 /// impl IdHashItem for Item {
709 /// type Key<'a> = &'a str;
710 /// fn key(&self) -> Self::Key<'_> {
711 /// &self.id
712 /// }
713 /// id_upcast!();
714 /// }
715 ///
716 /// let mut map: IdHashMap<Item> = IdHashMap::new();
717 /// map.reserve(100);
718 /// assert!(map.capacity() >= 100);
719 /// # }
720 /// ```
721 pub fn reserve(&mut self, additional: usize) {
722 self.items.reserve(additional);
723 self.tables.key_to_item.reserve(additional);
724 }
725
726 /// Tries to reserve capacity for at least `additional` more elements to be
727 /// inserted in the `IdHashMap`. The collection may reserve more space to
728 /// speculatively avoid frequent reallocations. After calling `try_reserve`,
729 /// capacity will be greater than or equal to `self.len() + additional` if
730 /// it returns `Ok(())`. Does nothing if capacity is already sufficient.
731 ///
732 /// # Errors
733 ///
734 /// If the capacity overflows, or the allocator reports a failure, then an
735 /// error is returned.
736 ///
737 /// # Notes
738 ///
739 /// If reservation fails partway through, some internal structures may have
740 /// already increased their capacity. The map remains in a valid state but
741 /// may have uneven capacities across its internal structures.
742 ///
743 /// # Examples
744 ///
745 /// ```
746 /// # #[cfg(feature = "default-hasher")] {
747 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
748 ///
749 /// #[derive(Debug, PartialEq, Eq, Hash)]
750 /// struct Item {
751 /// id: String,
752 /// value: u32,
753 /// }
754 ///
755 /// impl IdHashItem for Item {
756 /// type Key<'a> = &'a str;
757 /// fn key(&self) -> Self::Key<'_> {
758 /// &self.id
759 /// }
760 /// id_upcast!();
761 /// }
762 ///
763 /// let mut map: IdHashMap<Item> = IdHashMap::new();
764 /// map.try_reserve(100).expect("allocation should succeed");
765 /// assert!(map.capacity() >= 100);
766 /// # }
767 /// ```
768 pub fn try_reserve(
769 &mut self,
770 additional: usize,
771 ) -> Result<(), crate::errors::TryReserveError> {
772 self.items.try_reserve(additional)?;
773 self.tables
774 .key_to_item
775 .try_reserve(additional)
776 .map_err(crate::errors::TryReserveError::from_hashbrown)?;
777 Ok(())
778 }
779
780 /// Shrinks the capacity of the map as much as possible. It will drop
781 /// down as much as possible while maintaining the internal rules
782 /// and possibly leaving some space in accordance with the resize policy.
783 ///
784 /// # Examples
785 ///
786 /// ```
787 /// # #[cfg(feature = "default-hasher")] {
788 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
789 ///
790 /// #[derive(Debug, PartialEq, Eq, Hash)]
791 /// struct Item {
792 /// id: String,
793 /// value: u32,
794 /// }
795 ///
796 /// impl IdHashItem for Item {
797 /// type Key<'a> = &'a str;
798 /// fn key(&self) -> Self::Key<'_> {
799 /// &self.id
800 /// }
801 /// id_upcast!();
802 /// }
803 ///
804 /// let mut map: IdHashMap<Item> = IdHashMap::with_capacity(100);
805 /// map.insert_unique(Item { id: "foo".to_string(), value: 1 }).unwrap();
806 /// map.insert_unique(Item { id: "bar".to_string(), value: 2 }).unwrap();
807 /// assert!(map.capacity() >= 100);
808 /// map.shrink_to_fit();
809 /// assert!(map.capacity() >= 2);
810 /// # }
811 /// ```
812 pub fn shrink_to_fit(&mut self) {
813 // Sequence this carefully.
814 //
815 // * First, compact the item set. This does not allocate through A
816 // (it allocates a small remap buffer through the global allocator),
817 // and returns a remapper.
818 // * Then, remap the tables using the remapper.
819 // * Finally, shrink the capacities of the tables and items.
820 //
821 // An allocator panic during either capacity shrink leaves the tables
822 // and items already in sync, because remap has already been committed.
823 let remap = self.items.compact();
824 if !remap.is_identity() {
825 self.tables.key_to_item.remap_indexes(&remap);
826 }
827 self.items.shrink_capacity_to_fit();
828 self.tables.key_to_item.shrink_to_fit();
829 }
830
831 /// Shrinks the capacity of the map with a lower limit. It will drop
832 /// down no lower than the supplied limit while maintaining the internal
833 /// rules and possibly leaving some space in accordance with the resize
834 /// policy.
835 ///
836 /// If the current capacity is less than the lower limit, this is a no-op.
837 ///
838 /// # Examples
839 ///
840 /// ```
841 /// # #[cfg(feature = "default-hasher")] {
842 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
843 ///
844 /// #[derive(Debug, PartialEq, Eq, Hash)]
845 /// struct Item {
846 /// id: String,
847 /// value: u32,
848 /// }
849 ///
850 /// impl IdHashItem for Item {
851 /// type Key<'a> = &'a str;
852 /// fn key(&self) -> Self::Key<'_> {
853 /// &self.id
854 /// }
855 /// id_upcast!();
856 /// }
857 ///
858 /// let mut map: IdHashMap<Item> = IdHashMap::with_capacity(100);
859 /// map.insert_unique(Item { id: "foo".to_string(), value: 1 }).unwrap();
860 /// map.insert_unique(Item { id: "bar".to_string(), value: 2 }).unwrap();
861 /// assert!(map.capacity() >= 100);
862 /// map.shrink_to(10);
863 /// assert!(map.capacity() >= 10);
864 /// map.shrink_to(0);
865 /// assert!(map.capacity() >= 2);
866 /// # }
867 /// ```
868 pub fn shrink_to(&mut self, min_capacity: usize) {
869 // See `shrink_to_fit` for the rationale behind the sequence.
870 let remap = self.items.compact();
871 if !remap.is_identity() {
872 self.tables.key_to_item.remap_indexes(&remap);
873 }
874 self.items.shrink_capacity_to(min_capacity);
875 self.tables.key_to_item.shrink_to(min_capacity);
876 }
877
878 /// Iterates over the items in the map.
879 ///
880 /// Similar to [`HashMap`], the iteration order is arbitrary and not
881 /// guaranteed to be stable.
882 ///
883 /// # Examples
884 ///
885 /// ```
886 /// # #[cfg(feature = "default-hasher")] {
887 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
888 ///
889 /// #[derive(Debug, PartialEq, Eq, Hash)]
890 /// struct Item {
891 /// id: String,
892 /// value: u32,
893 /// }
894 ///
895 /// impl IdHashItem for Item {
896 /// type Key<'a> = &'a str;
897 /// fn key(&self) -> Self::Key<'_> {
898 /// &self.id
899 /// }
900 /// id_upcast!();
901 /// }
902 ///
903 /// let mut map = IdHashMap::new();
904 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
905 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
906 ///
907 /// let mut values: Vec<u32> = map.iter().map(|item| item.value).collect();
908 /// values.sort();
909 /// assert_eq!(values, vec![20, 42]);
910 /// # }
911 /// ```
912 ///
913 /// [`HashMap`]: std::collections::HashMap
914 #[inline]
915 pub fn iter(&self) -> Iter<'_, T> {
916 Iter::new(&self.items)
917 }
918
919 /// Iterates over the items in the map, allowing for mutation.
920 ///
921 /// Similar to [`HashMap`], the iteration order is arbitrary and not
922 /// guaranteed to be stable.
923 ///
924 /// # Examples
925 ///
926 /// ```
927 /// # #[cfg(feature = "default-hasher")] {
928 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
929 ///
930 /// #[derive(Debug, PartialEq, Eq, Hash)]
931 /// struct Item {
932 /// id: String,
933 /// value: u32,
934 /// }
935 ///
936 /// impl IdHashItem for Item {
937 /// type Key<'a> = &'a str;
938 /// fn key(&self) -> Self::Key<'_> {
939 /// &self.id
940 /// }
941 /// id_upcast!();
942 /// }
943 ///
944 /// let mut map = IdHashMap::new();
945 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
946 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
947 ///
948 /// for mut item in map.iter_mut() {
949 /// item.value *= 2;
950 /// }
951 ///
952 /// assert_eq!(map.get("foo").unwrap().value, 84);
953 /// assert_eq!(map.get("bar").unwrap().value, 40);
954 /// # }
955 /// ```
956 ///
957 /// [`HashMap`]: std::collections::HashMap
958 #[inline]
959 pub fn iter_mut(&mut self) -> IterMut<'_, T, S, A> {
960 IterMut::new(&self.tables, &mut self.items)
961 }
962
963 /// Checks general invariants of the map.
964 ///
965 /// The code below always upholds these invariants, but it's useful to have
966 /// an explicit check for tests.
967 #[doc(hidden)]
968 pub fn validate(
969 &self,
970 compactness: ValidateCompact,
971 ) -> Result<(), ValidationError>
972 where
973 T: fmt::Debug,
974 {
975 self.validate_structural(compactness)?;
976
977 // Check that the indexes are all correct.
978 //
979 // Unlike the structural checks above, this re-looks up each key through
980 // the user `Hash`, so it only holds when that `Hash` is lawful.
981 for (ix, item) in self.items.iter() {
982 let key = item.key();
983 let Some(ix1) = self.find_index(&key) else {
984 return Err(ValidationError::general(format!(
985 "item at index {ix} has no key1 index"
986 )));
987 };
988
989 if ix1 != ix {
990 return Err(ValidationError::General(format!(
991 "item at index {ix} has mismatched indexes: ix1: {ix1}",
992 )));
993 }
994 }
995
996 Ok(())
997 }
998
999 /// Checks the structural invariants of the map:
1000 ///
1001 /// * The item set is well-formed.
1002 /// * The hash table holds exactly one entry per live item, with no
1003 /// duplicate `ItemIndex`es.
1004 ///
1005 /// Unlike [`validate`](Self::validate), this does not re-look-up keys
1006 /// through the user `Hash`, so it holds regardless of whether that `Hash`
1007 /// is lawful. A buggy hasher can desync the logical key→item mapping, but
1008 /// it must never break these structural invariants! Doing so would be
1009 /// unsoundness, e.g. duplicate indexes enabling mutable aliasing.
1010 #[doc(hidden)]
1011 pub fn validate_structural(
1012 &self,
1013 compactness: ValidateCompact,
1014 ) -> Result<(), ValidationError> {
1015 self.items.validate(compactness)?;
1016 self.tables.validate(self.len(), compactness)?;
1017 Ok(())
1018 }
1019
1020 /// Inserts a value into the map, removing and returning the conflicting
1021 /// item, if any.
1022 ///
1023 /// # Examples
1024 ///
1025 /// ```
1026 /// # #[cfg(feature = "default-hasher")] {
1027 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1028 ///
1029 /// #[derive(Debug, PartialEq, Eq, Hash)]
1030 /// struct Item {
1031 /// id: String,
1032 /// value: u32,
1033 /// }
1034 ///
1035 /// impl IdHashItem for Item {
1036 /// type Key<'a> = &'a str;
1037 /// fn key(&self) -> Self::Key<'_> {
1038 /// &self.id
1039 /// }
1040 /// id_upcast!();
1041 /// }
1042 ///
1043 /// let mut map = IdHashMap::new();
1044 ///
1045 /// // First insertion returns None
1046 /// let old = map.insert_overwrite(Item { id: "foo".to_string(), value: 42 });
1047 /// assert!(old.is_none());
1048 ///
1049 /// // Second insertion with same key returns the old value
1050 /// let old = map.insert_overwrite(Item { id: "foo".to_string(), value: 100 });
1051 /// assert_eq!(old.unwrap().value, 42);
1052 /// assert_eq!(map.get("foo").unwrap().value, 100);
1053 /// # }
1054 /// ```
1055 #[doc(alias = "insert")]
1056 pub fn insert_overwrite(&mut self, value: T) -> Option<T> {
1057 // Go through the entry API so all user code is called before any table
1058 // mutation. A panic in user code therefore leaves the map in its
1059 // pre-call state.
1060 //
1061 // In the vacant case, the Entry lookup has already established that the
1062 // key is unique. Calling `vacant.insert_entry` would route back through
1063 // `insert_unique_impl` and check for duplicates again, while
1064 // `vacant.insert` would also create a `RefMut` and re-hash the key. We
1065 // use `vacant.insert_known_unique` instead, which avoids both.
1066 match self.entry(value.key()) {
1067 Entry::Occupied(mut occupied) => Some(occupied.insert(value)),
1068 Entry::Vacant(vacant) => {
1069 vacant.insert_known_unique(value);
1070 None
1071 }
1072 }
1073 }
1074
1075 /// Inserts a value into the set, returning an error if any duplicates were
1076 /// added.
1077 ///
1078 /// # Examples
1079 ///
1080 /// ```
1081 /// # #[cfg(feature = "default-hasher")] {
1082 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1083 ///
1084 /// #[derive(Debug, PartialEq, Eq, Hash)]
1085 /// struct Item {
1086 /// id: String,
1087 /// value: u32,
1088 /// }
1089 ///
1090 /// impl IdHashItem for Item {
1091 /// type Key<'a> = &'a str;
1092 /// fn key(&self) -> Self::Key<'_> {
1093 /// &self.id
1094 /// }
1095 /// id_upcast!();
1096 /// }
1097 ///
1098 /// let mut map = IdHashMap::new();
1099 ///
1100 /// // First insertion succeeds
1101 /// assert!(
1102 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).is_ok()
1103 /// );
1104 ///
1105 /// // Second insertion with different key succeeds
1106 /// assert!(
1107 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).is_ok()
1108 /// );
1109 ///
1110 /// // Third insertion with duplicate key fails
1111 /// assert!(
1112 /// map.insert_unique(Item { id: "foo".to_string(), value: 100 }).is_err()
1113 /// );
1114 /// # }
1115 /// ```
1116 pub fn insert_unique(
1117 &mut self,
1118 value: T,
1119 ) -> Result<(), DuplicateItem<T, &T>> {
1120 let _ = self.insert_unique_impl(value)?;
1121 Ok(())
1122 }
1123
1124 /// Returns true if the map contains the given key.
1125 ///
1126 /// # Examples
1127 ///
1128 /// ```
1129 /// # #[cfg(feature = "default-hasher")] {
1130 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1131 ///
1132 /// #[derive(Debug, PartialEq, Eq, Hash)]
1133 /// struct Item {
1134 /// id: String,
1135 /// value: u32,
1136 /// }
1137 ///
1138 /// impl IdHashItem for Item {
1139 /// type Key<'a> = &'a str;
1140 /// fn key(&self) -> Self::Key<'_> {
1141 /// &self.id
1142 /// }
1143 /// id_upcast!();
1144 /// }
1145 ///
1146 /// let mut map = IdHashMap::new();
1147 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1148 ///
1149 /// assert!(map.contains_key("foo"));
1150 /// assert!(!map.contains_key("bar"));
1151 /// # }
1152 /// ```
1153 pub fn contains_key<'a, Q>(&'a self, key1: &Q) -> bool
1154 where
1155 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
1156 {
1157 self.find_index(key1).is_some()
1158 }
1159
1160 /// Gets a reference to the value associated with the given key.
1161 ///
1162 /// # Examples
1163 ///
1164 /// ```
1165 /// # #[cfg(feature = "default-hasher")] {
1166 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1167 ///
1168 /// #[derive(Debug, PartialEq, Eq, Hash)]
1169 /// struct Item {
1170 /// id: String,
1171 /// value: u32,
1172 /// }
1173 ///
1174 /// impl IdHashItem for Item {
1175 /// type Key<'a> = &'a str;
1176 /// fn key(&self) -> Self::Key<'_> {
1177 /// &self.id
1178 /// }
1179 /// id_upcast!();
1180 /// }
1181 ///
1182 /// let mut map = IdHashMap::new();
1183 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1184 ///
1185 /// assert_eq!(map.get("foo").unwrap().value, 42);
1186 /// assert!(map.get("bar").is_none());
1187 /// # }
1188 /// ```
1189 pub fn get<'a, Q>(&'a self, key: &Q) -> Option<&'a T>
1190 where
1191 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
1192 {
1193 self.find_index(key).map(|ix| &self.items[ix])
1194 }
1195
1196 /// Gets a mutable reference to the value associated with the given key.
1197 ///
1198 /// # Examples
1199 ///
1200 /// ```
1201 /// # #[cfg(feature = "default-hasher")] {
1202 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1203 ///
1204 /// #[derive(Debug, PartialEq, Eq, Hash)]
1205 /// struct Item {
1206 /// id: String,
1207 /// value: u32,
1208 /// }
1209 ///
1210 /// impl IdHashItem for Item {
1211 /// type Key<'a> = &'a str;
1212 /// fn key(&self) -> Self::Key<'_> {
1213 /// &self.id
1214 /// }
1215 /// id_upcast!();
1216 /// }
1217 ///
1218 /// let mut map = IdHashMap::new();
1219 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1220 ///
1221 /// if let Some(mut item) = map.get_mut("foo") {
1222 /// item.value = 100;
1223 /// }
1224 ///
1225 /// assert_eq!(map.get("foo").unwrap().value, 100);
1226 /// assert!(map.get_mut("bar").is_none());
1227 /// # }
1228 /// ```
1229 pub fn get_mut<'a, Q>(&'a mut self, key: &Q) -> Option<RefMut<'a, T, S>>
1230 where
1231 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
1232 {
1233 let (dormant_map, index) = {
1234 let (map, dormant_map) = DormantMutRef::new(self);
1235 let index = map.find_index(key)?;
1236 (dormant_map, index)
1237 };
1238
1239 // SAFETY: `map` is not used after this point.
1240 let awakened_map = unsafe { dormant_map.awaken() };
1241 let item = &mut awakened_map.items[index];
1242 let state = awakened_map.tables.state.clone();
1243 let hashes = awakened_map.tables.make_hash(item);
1244 Some(RefMut::new(state, hashes, item))
1245 }
1246
1247 /// Removes an item from the map by its key.
1248 ///
1249 /// # Examples
1250 ///
1251 /// ```
1252 /// # #[cfg(feature = "default-hasher")] {
1253 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1254 ///
1255 /// #[derive(Debug, PartialEq, Eq, Hash)]
1256 /// struct Item {
1257 /// id: String,
1258 /// value: u32,
1259 /// }
1260 ///
1261 /// impl IdHashItem for Item {
1262 /// type Key<'a> = &'a str;
1263 /// fn key(&self) -> Self::Key<'_> {
1264 /// &self.id
1265 /// }
1266 /// id_upcast!();
1267 /// }
1268 ///
1269 /// let mut map = IdHashMap::new();
1270 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1271 ///
1272 /// let removed = map.remove("foo");
1273 /// assert_eq!(removed.unwrap().value, 42);
1274 /// assert!(map.is_empty());
1275 ///
1276 /// // Removing non-existent key returns None
1277 /// assert!(map.remove("bar").is_none());
1278 /// # }
1279 /// ```
1280 pub fn remove<'a, Q>(&'a mut self, key: &Q) -> Option<T>
1281 where
1282 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
1283 {
1284 let (dormant_map, remove_index) = {
1285 let (map, dormant_map) = DormantMutRef::new(self);
1286 let remove_index = map.find_index(key)?;
1287 (dormant_map, remove_index)
1288 };
1289 // SAFETY: `map` is not used after this point.
1290 let awakened_map = unsafe { dormant_map.awaken() };
1291 awakened_map.remove_by_index(remove_index)
1292 }
1293
1294 /// Retrieves an entry by its key.
1295 ///
1296 /// Due to borrow checker limitations, this always accepts an owned key
1297 /// rather than a borrowed form of it.
1298 ///
1299 /// # Examples
1300 ///
1301 /// ```
1302 /// # #[cfg(feature = "default-hasher")] {
1303 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1304 ///
1305 /// #[derive(Debug, PartialEq, Eq, Hash)]
1306 /// struct Item {
1307 /// id: String,
1308 /// value: u32,
1309 /// }
1310 ///
1311 /// impl IdHashItem for Item {
1312 /// type Key<'a> = &'a str;
1313 /// fn key(&self) -> Self::Key<'_> {
1314 /// &self.id
1315 /// }
1316 /// id_upcast!();
1317 /// }
1318 ///
1319 /// let mut map = IdHashMap::new();
1320 ///
1321 /// // Use entry API for conditional insertion
1322 /// map.entry("foo").or_insert(Item { id: "foo".to_string(), value: 42 });
1323 /// map.entry("bar").or_insert(Item { id: "bar".to_string(), value: 20 });
1324 ///
1325 /// assert_eq!(map.len(), 2);
1326 /// # }
1327 /// ```
1328 pub fn entry<'a>(&'a mut self, key: T::Key<'_>) -> Entry<'a, T, S, A> {
1329 // Why does this always take an owned key? Well, it would seem like we
1330 // should be able to pass in any Q that is equivalent. That results in
1331 // *this* code compiling fine, but callers have trouble using it because
1332 // the borrow checker believes the keys are borrowed for the full 'a
1333 // rather than a shorter lifetime.
1334 //
1335 // By accepting owned keys, we can use the upcast functions to convert
1336 // them to a shorter lifetime (so this function accepts T::Key<'_>
1337 // rather than T::Key<'a>).
1338 //
1339 // Really, the solution here is to allow GATs to require covariant
1340 // parameters. If that were allowed, the borrow checker should be able
1341 // to figure out that keys don't need to be borrowed for the full 'a,
1342 // just for some shorter lifetime.
1343 let (map, dormant_map) = DormantMutRef::new(self);
1344 let key = T::upcast_key(key);
1345 {
1346 // index is explicitly typed to show that it has a trivial Drop impl
1347 // that doesn't capture anything from map.
1348 let index: Option<ItemIndex> = map.tables.key_to_item.find_index(
1349 &map.tables.state,
1350 &key,
1351 |index| map.items[index].key(),
1352 );
1353 if let Some(index) = index {
1354 drop(key);
1355 return Entry::Occupied(
1356 // SAFETY: `map` is not used after this point.
1357 unsafe { OccupiedEntry::new(dormant_map, index) },
1358 );
1359 }
1360 }
1361 let hash = map.make_key_hash(&key);
1362 Entry::Vacant(
1363 // SAFETY: `map` is not used after this point.
1364 unsafe { VacantEntry::new(dormant_map, hash) },
1365 )
1366 }
1367
1368 /// Retains only the elements specified by the predicate.
1369 ///
1370 /// In other words, remove all items `T` for which `f(RefMut<T>)` returns
1371 /// false. The elements are visited in an arbitrary order.
1372 ///
1373 /// # Examples
1374 ///
1375 /// ```
1376 /// # #[cfg(feature = "default-hasher")] {
1377 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1378 ///
1379 /// #[derive(Debug, PartialEq, Eq, Hash)]
1380 /// struct Item {
1381 /// id: String,
1382 /// value: u32,
1383 /// }
1384 ///
1385 /// impl IdHashItem for Item {
1386 /// type Key<'a> = &'a str;
1387 ///
1388 /// fn key(&self) -> Self::Key<'_> {
1389 /// &self.id
1390 /// }
1391 ///
1392 /// id_upcast!();
1393 /// }
1394 ///
1395 /// let mut map = IdHashMap::new();
1396 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1397 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1398 /// map.insert_unique(Item { id: "baz".to_string(), value: 99 }).unwrap();
1399 ///
1400 /// // Retain only items where value is greater than 30
1401 /// map.retain(|item| item.value > 30);
1402 ///
1403 /// assert_eq!(map.len(), 2);
1404 /// assert_eq!(map.get("foo").unwrap().value, 42);
1405 /// assert_eq!(map.get("baz").unwrap().value, 99);
1406 /// assert!(map.get("bar").is_none());
1407 /// # }
1408 /// ```
1409 pub fn retain<'a, F>(&'a mut self, mut f: F)
1410 where
1411 F: for<'b> FnMut(RefMut<'b, T, S>) -> bool,
1412 {
1413 let hash_state = self.tables.state.clone();
1414 let (_, mut dormant_items) = DormantMutRef::new(&mut self.items);
1415 let mut removed_item = None;
1416
1417 self.tables.key_to_item.retain(|index| {
1418 // Drop the previously-removed item here, at the top of the next
1419 // iteration.
1420 //
1421 // By now, the prior `key_to_item` entry has been erased, so if
1422 // `drop` below panics, `key_to_item` and `items` remain in sync.
1423 // Dropping the item at the end of the prior iteration would
1424 // unwind before the table erased the entry, leaving `key_to_item`
1425 // pointing at a slot we already removed from `items`.
1426 drop(removed_item.take());
1427
1428 let (item, dormant_items) = {
1429 // SAFETY: All uses of `items` ended in the previous iteration.
1430 let items = unsafe { dormant_items.reborrow() };
1431 let (items, dormant_items) = DormantMutRef::new(items);
1432 let item: &'a mut T = items
1433 .get_mut(index)
1434 .expect("all indexes are present in self.items");
1435 (item, dormant_items)
1436 };
1437
1438 let (hash, dormant_item) = {
1439 let (item, dormant_item): (&'a mut T, _) =
1440 DormantMutRef::new(item);
1441 // Use T::key(item) rather than item.key() to force the key
1442 // trait function to be called for T rather than &mut T.
1443 let key = T::key(item);
1444 let hash = hash_state.hash_one(key);
1445 (MapHash::new(hash), dormant_item)
1446 };
1447
1448 let retain = {
1449 // SAFETY: The original item is no longer used after the second
1450 // block above. dormant_items, from which item is derived, is
1451 // currently dormant.
1452 let item = unsafe { dormant_item.awaken() };
1453
1454 let ref_mut = RefMut::new(hash_state.clone(), hash, item);
1455 f(ref_mut)
1456 };
1457
1458 if retain {
1459 true
1460 } else {
1461 // SAFETY: The original items is no longer used after the first
1462 // block above, and item + dormant item have been used above.
1463 let items = unsafe { dormant_items.awaken() };
1464 removed_item = Some(
1465 items
1466 .remove(index)
1467 .expect("all indexes are present in self.items"),
1468 );
1469 false
1470 }
1471 });
1472
1473 // Anything in `removed_item` is implicitly dropped now.
1474 }
1475
1476 fn find_index<'a, Q>(&'a self, k: &Q) -> Option<ItemIndex>
1477 where
1478 Q: Hash + Equivalent<T::Key<'a>> + ?Sized,
1479 {
1480 self.tables
1481 .key_to_item
1482 .find_index(&self.tables.state, k, |index| self.items[index].key())
1483 }
1484
1485 fn make_hash(&self, item: &T) -> MapHash {
1486 self.tables.make_hash(item)
1487 }
1488
1489 fn make_key_hash(&self, key: &T::Key<'_>) -> MapHash {
1490 self.tables.make_key_hash::<T>(key)
1491 }
1492
1493 pub(super) fn get_by_index(&self, index: ItemIndex) -> Option<&T> {
1494 self.items.get(index)
1495 }
1496
1497 pub(super) fn get_by_index_mut(
1498 &mut self,
1499 index: ItemIndex,
1500 ) -> Option<RefMut<'_, T, S>> {
1501 let state = self.tables.state.clone();
1502 let hashes = self.make_hash(&self.items[index]);
1503 let item = &mut self.items[index];
1504 Some(RefMut::new(state, hashes, item))
1505 }
1506
1507 pub(super) fn insert_unique_impl(
1508 &mut self,
1509 value: T,
1510 ) -> Result<ItemIndex, DuplicateItem<T, &T>> {
1511 let mut duplicates = BTreeSet::new();
1512
1513 // Check for duplicates *before* inserting the new item, because we
1514 // don't want to partially insert the new item and then have to roll
1515 // back.
1516 let key = value.key();
1517 let state = &self.tables.state;
1518
1519 let entry = match self
1520 .tables
1521 .key_to_item
1522 .entry(state, key, |index| self.items[index].key())
1523 {
1524 hash_table::Entry::Occupied(slot) => {
1525 duplicates.insert(slot.get());
1526 None
1527 }
1528 hash_table::Entry::Vacant(slot) => Some(slot),
1529 };
1530
1531 if !duplicates.is_empty() {
1532 return Err(DuplicateItem::__internal_new(
1533 value,
1534 duplicates.iter().map(|ix| &self.items[*ix]).collect(),
1535 ));
1536 }
1537
1538 let next_index = self.items.assert_can_grow().insert(value);
1539 entry.unwrap().insert(next_index);
1540
1541 Ok(next_index)
1542 }
1543
1544 pub(super) fn try_reserve_insert_overwrite_commit(
1545 &mut self,
1546 ) -> Result<(), crate::errors::TryReserveError> {
1547 self.items.try_reserve(1)?;
1548 self.tables
1549 .key_to_item
1550 .try_reserve(1)
1551 .map_err(crate::errors::TryReserveError::from_hashbrown)?;
1552 Ok(())
1553 }
1554
1555 pub(super) fn remove_by_index(
1556 &mut self,
1557 remove_index: ItemIndex,
1558 ) -> Option<T> {
1559 // For panic safety, compute the key hash and look up the table entry
1560 // while `self.items` still holds the value, then remove from the table
1561 // and items in sequence. This lookup deliberately matches by
1562 // `ItemIndex` rather than by user `Eq`: at this point we already know
1563 // which item is being removed, and user `Eq` might be pathological.
1564 //
1565 // hashbrown's `find_entry_by_hash` is panic-safe because the table is
1566 // not mutated until `OccupiedEntry::remove` is called, so a panic while
1567 // hashing leaves both items and the table unmodified. (Unlike the
1568 // IdOrdMap path, we don't need a separate two-phase commit: the
1569 // BTreeMap analog has to guard against a user-`Ord` panic during the
1570 // tree walk, but the hash walk here never invokes user code.)
1571 //
1572 // If the hash lookup misses, which can happen when `mem::forget` is
1573 // called on a `RefMut` after the ID was changed, the item's current key
1574 // now hashes to a different bucket than the one its entry sits in. In
1575 // that case, we fall back to a linear scan by `ItemIndex`. This keeps
1576 // the table and item set consistent with each other across silent key
1577 // mutations, mirroring `MapBTreeTable::remove_exact`.
1578 //
1579 // This is not expected to be the common case (why are you calling
1580 // mem::forget on a RefMut?), but guarding against it explicitly makes
1581 // our invariants easier to reason about.
1582 let item = self.items.get(remove_index)?;
1583 let state = &self.tables.state;
1584 let hash = state.hash_one(item.key());
1585 match self
1586 .tables
1587 .key_to_item
1588 .find_entry_by_hash(hash, |index| index == remove_index)
1589 {
1590 Ok(entry) => entry.remove(),
1591 Err(()) => self.tables.key_to_item.remove_by_index(remove_index),
1592 }
1593 Some(
1594 self.items
1595 .remove(remove_index)
1596 .expect("items[remove_index] was Occupied above"),
1597 )
1598 }
1599
1600 pub(super) fn replace_at_index(&mut self, index: ItemIndex, value: T) -> T {
1601 // We check the key before removing it, to avoid leaving the map in an
1602 // inconsistent state.
1603 let old_key =
1604 self.get_by_index(index).expect("index is known to be valid").key();
1605 if T::upcast_key(old_key) != value.key() {
1606 panic!(
1607 "must insert a value with \
1608 the same key used to create the entry"
1609 );
1610 }
1611
1612 // Now that we know the key is the same, we can replace the value
1613 // directly without needing to tweak any tables.
1614 self.items.replace(index, value)
1615 }
1616}
1617
1618impl<'a, T, S: Clone + BuildHasher, A: Allocator> fmt::Debug
1619 for IdHashMap<T, S, A>
1620where
1621 T: IdHashItem + fmt::Debug,
1622 T::Key<'a>: fmt::Debug,
1623 T: 'a,
1624{
1625 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1626 let mut map = f.debug_map();
1627
1628 for item in self.iter() {
1629 let key = item.key();
1630
1631 // SAFETY:
1632 //
1633 // * Lifetime extension: for a type T and two lifetime params 'a and
1634 // 'b, T<'a> and T<'b> aren't guaranteed to have the same layout,
1635 // but (a) that is true today and (b) it would be shocking and
1636 // break half the Rust ecosystem if that were to change in the
1637 // future.
1638 // * We only use key within the scope of this block before immediately
1639 // dropping it. In particular, map.entry calls key.fmt() without
1640 // holding a reference to it.
1641 let key: T::Key<'a> =
1642 unsafe { core::mem::transmute::<T::Key<'_>, T::Key<'a>>(key) };
1643
1644 map.entry(&key, item);
1645 }
1646 map.finish()
1647 }
1648}
1649
1650impl<T: IdHashItem + PartialEq, S: Clone + BuildHasher, A: Allocator> PartialEq
1651 for IdHashMap<T, S, A>
1652{
1653 fn eq(&self, other: &Self) -> bool {
1654 // Implementing PartialEq for IdHashMap is tricky because IdHashMap is
1655 // not semantically like an IndexMap: two maps are equivalent even if
1656 // their items are in a different order. In other words, any permutation
1657 // of items is equivalent.
1658 //
1659 // We also can't sort the items because they're not necessarily Ord.
1660 //
1661 // So we write a custom equality check that checks that each key in one
1662 // map points to the same item as in the other map.
1663
1664 if self.items.len() != other.items.len() {
1665 return false;
1666 }
1667
1668 // Walk over all the items in the first map and check that they point to
1669 // the same item in the second map.
1670 for item in self.items.values() {
1671 let k1 = item.key();
1672
1673 // Check that the indexes are the same in the other map.
1674 let Some(other_ix) = other.find_index(&k1) else {
1675 return false;
1676 };
1677
1678 // Check that the other map's item is the same as this map's
1679 // item. (This is what we use the `PartialEq` bound on T for.)
1680 //
1681 // Because we've checked that other_ix is Some, we know that it is
1682 // valid and points to the expected item.
1683 let other_item = &other.items[other_ix];
1684 if item != other_item {
1685 return false;
1686 }
1687 }
1688
1689 true
1690 }
1691}
1692
1693// The Eq bound on T ensures that the TriHashMap forms an equivalence class.
1694impl<T: IdHashItem + Eq, S: Clone + BuildHasher, A: Allocator> Eq
1695 for IdHashMap<T, S, A>
1696{
1697}
1698
1699/// The `Extend` implementation overwrites duplicates. In the future, there will
1700/// also be an `extend_unique` method that will return an error.
1701///
1702/// # Examples
1703///
1704/// ```
1705/// # #[cfg(feature = "default-hasher")] {
1706/// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1707///
1708/// #[derive(Debug, PartialEq, Eq, Hash)]
1709/// struct Item {
1710/// id: String,
1711/// value: u32,
1712/// }
1713///
1714/// impl IdHashItem for Item {
1715/// type Key<'a> = &'a str;
1716/// fn key(&self) -> Self::Key<'_> {
1717/// &self.id
1718/// }
1719/// id_upcast!();
1720/// }
1721///
1722/// let mut map = IdHashMap::new();
1723/// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1724///
1725/// let new_items = vec![
1726/// Item { id: "foo".to_string(), value: 100 }, // overwrites existing
1727/// Item { id: "bar".to_string(), value: 20 }, // new item
1728/// ];
1729///
1730/// map.extend(new_items);
1731/// assert_eq!(map.len(), 2);
1732/// assert_eq!(map.get("foo").unwrap().value, 100); // overwritten
1733/// assert_eq!(map.get("bar").unwrap().value, 20); // new
1734///
1735/// # }
1736/// ```
1737impl<T: IdHashItem, S: Clone + BuildHasher, A: Allocator> Extend<T>
1738 for IdHashMap<T, S, A>
1739{
1740 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
1741 // Keys may already be present in the map, or multiple times in the
1742 // iterator. Reserve the entire hint lower bound if the map is empty.
1743 // Otherwise reserve half the hint (rounded up), so the map will only
1744 // resize twice in the worst case.
1745 let iter = iter.into_iter();
1746 let reserve = if self.is_empty() {
1747 iter.size_hint().0
1748 } else {
1749 iter.size_hint().0.div_ceil(2)
1750 };
1751 self.reserve(reserve);
1752 for item in iter {
1753 self.insert_overwrite(item);
1754 }
1755 }
1756}
1757
1758impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
1759 for &'a IdHashMap<T, S, A>
1760{
1761 type Item = &'a T;
1762 type IntoIter = Iter<'a, T>;
1763
1764 /// Creates an iterator over references to the items in the map.
1765 ///
1766 /// # Examples
1767 ///
1768 /// ```
1769 /// # #[cfg(feature = "default-hasher")] {
1770 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1771 ///
1772 /// #[derive(Debug, PartialEq, Eq, Hash)]
1773 /// struct Item {
1774 /// id: String,
1775 /// value: u32,
1776 /// }
1777 ///
1778 /// impl IdHashItem for Item {
1779 /// type Key<'a> = &'a str;
1780 /// fn key(&self) -> Self::Key<'_> {
1781 /// &self.id
1782 /// }
1783 /// id_upcast!();
1784 /// }
1785 ///
1786 /// let mut map = IdHashMap::new();
1787 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1788 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1789 ///
1790 /// let mut values: Vec<u32> =
1791 /// (&map).into_iter().map(|item| item.value).collect();
1792 /// values.sort();
1793 /// assert_eq!(values, vec![20, 42]);
1794 /// # }
1795 /// ```
1796 #[inline]
1797 fn into_iter(self) -> Self::IntoIter {
1798 self.iter()
1799 }
1800}
1801
1802impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
1803 for &'a mut IdHashMap<T, S, A>
1804{
1805 type Item = RefMut<'a, T, S>;
1806 type IntoIter = IterMut<'a, T, S, A>;
1807
1808 /// Creates an iterator over mutable references to the items in the map.
1809 ///
1810 /// # Examples
1811 ///
1812 /// ```
1813 /// # #[cfg(feature = "default-hasher")] {
1814 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1815 ///
1816 /// #[derive(Debug, PartialEq, Eq, Hash)]
1817 /// struct Item {
1818 /// id: String,
1819 /// value: u32,
1820 /// }
1821 ///
1822 /// impl IdHashItem for Item {
1823 /// type Key<'a> = &'a str;
1824 /// fn key(&self) -> Self::Key<'_> {
1825 /// &self.id
1826 /// }
1827 /// id_upcast!();
1828 /// }
1829 ///
1830 /// let mut map = IdHashMap::new();
1831 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1832 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1833 ///
1834 /// for mut item in &mut map {
1835 /// item.value *= 2;
1836 /// }
1837 ///
1838 /// assert_eq!(map.get("foo").unwrap().value, 84);
1839 /// assert_eq!(map.get("bar").unwrap().value, 40);
1840 /// # }
1841 /// ```
1842 #[inline]
1843 fn into_iter(self) -> Self::IntoIter {
1844 self.iter_mut()
1845 }
1846}
1847
1848impl<T: IdHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
1849 for IdHashMap<T, S, A>
1850{
1851 type Item = T;
1852 type IntoIter = IntoIter<T, A>;
1853
1854 /// Consumes the map and creates an iterator over the owned items.
1855 ///
1856 /// # Examples
1857 ///
1858 /// ```
1859 /// # #[cfg(feature = "default-hasher")] {
1860 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1861 ///
1862 /// #[derive(Debug, PartialEq, Eq, Hash)]
1863 /// struct Item {
1864 /// id: String,
1865 /// value: u32,
1866 /// }
1867 ///
1868 /// impl IdHashItem for Item {
1869 /// type Key<'a> = &'a str;
1870 /// fn key(&self) -> Self::Key<'_> {
1871 /// &self.id
1872 /// }
1873 /// id_upcast!();
1874 /// }
1875 ///
1876 /// let mut map = IdHashMap::new();
1877 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1878 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1879 ///
1880 /// let mut values: Vec<u32> = map.into_iter().map(|item| item.value).collect();
1881 /// values.sort();
1882 /// assert_eq!(values, vec![20, 42]);
1883 /// # }
1884 /// ```
1885 #[inline]
1886 fn into_iter(self) -> Self::IntoIter {
1887 IntoIter::new(self.items)
1888 }
1889}
1890
1891/// The `FromIterator` implementation for `IdHashMap` overwrites duplicate
1892/// items.
1893///
1894/// To reject duplicates, use [`IdHashMap::from_iter_unique`].
1895///
1896/// # Examples
1897///
1898/// ```
1899/// # #[cfg(feature = "default-hasher")] {
1900/// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1901///
1902/// #[derive(Debug, PartialEq, Eq, Hash)]
1903/// struct Item {
1904/// id: String,
1905/// value: u32,
1906/// }
1907///
1908/// impl IdHashItem for Item {
1909/// type Key<'a> = &'a str;
1910/// fn key(&self) -> Self::Key<'_> {
1911/// &self.id
1912/// }
1913/// id_upcast!();
1914/// }
1915///
1916/// let items = vec![
1917/// Item { id: "foo".to_string(), value: 42 },
1918/// Item { id: "bar".to_string(), value: 20 },
1919/// Item { id: "foo".to_string(), value: 100 }, // duplicate key, overwrites
1920/// ];
1921///
1922/// let map: IdHashMap<Item> = items.into_iter().collect();
1923/// assert_eq!(map.len(), 2);
1924/// assert_eq!(map.get("foo").unwrap().value, 100); // last value wins
1925/// assert_eq!(map.get("bar").unwrap().value, 20);
1926/// # }
1927/// ```
1928impl<T: IdHashItem, S: Default + Clone + BuildHasher, A: Allocator + Default>
1929 FromIterator<T> for IdHashMap<T, S, A>
1930{
1931 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1932 let mut map = IdHashMap::default();
1933 map.extend(iter);
1934 map
1935 }
1936}
1937
1938#[cfg(all(test, feature = "std"))]
1939mod tests {
1940 use super::*;
1941 use core::{cell::Cell, hash::Hasher};
1942
1943 std::thread_local! {
1944 static USER_HASH_CALLS: Cell<u32> = const { Cell::new(0) };
1945 }
1946
1947 #[derive(Debug)]
1948 struct CountedKey(u32);
1949
1950 impl Hash for CountedKey {
1951 fn hash<H: Hasher>(&self, state: &mut H) {
1952 USER_HASH_CALLS.with(|c| c.set(c.get() + 1));
1953 self.0.hash(state);
1954 }
1955 }
1956
1957 impl PartialEq for CountedKey {
1958 fn eq(&self, other: &Self) -> bool {
1959 self.0 == other.0
1960 }
1961 }
1962 impl Eq for CountedKey {}
1963
1964 #[derive(Debug)]
1965 struct CountedItem {
1966 id: u32,
1967 }
1968
1969 impl IdHashItem for CountedItem {
1970 type Key<'a> = CountedKey;
1971 fn key(&self) -> Self::Key<'_> {
1972 CountedKey(self.id)
1973 }
1974 id_upcast!();
1975 }
1976
1977 // This is a unit test and not an integration test to ensure rehashing
1978 // actually happens. (Rehashing is not externally observable in integration
1979 // tests.)
1980 #[test]
1981 fn reserve_rehash_uses_cached_hash() {
1982 let mut map = IdHashMap::<CountedItem, _>::with_hasher(
1983 foldhash::fast::FixedState::with_seed(0),
1984 );
1985 // Insert items (legitimately calls user Hash).
1986 for id in [
1987 0u32, 17, 1, 12, 5, 21, 8, 10, 18, 4, 16, 22, 9, 24, 23, 13, 7, 25,
1988 26, 20, 31, 11, 14, 2, 6,
1989 ] {
1990 let _ = map.insert_overwrite(CountedItem { id });
1991 }
1992 // Drop most entries, leaving the table heavy with tombstones so the
1993 // next reserve favors `rehash_in_place` over a fresh-allocation grow.
1994 map.retain(|item| item.id % 2 == 1 && item.id % 3 != 0);
1995
1996 USER_HASH_CALLS.with(|c| c.set(0));
1997 let rehash_calls = map.tables.key_to_item.reserve_counting_rehash(10);
1998 let user_calls = USER_HASH_CALLS.with(Cell::get);
1999
2000 assert!(
2001 rehash_calls > 0,
2002 "expected reserve to invoke the rehash callback at least once \
2003 (setup did not actually trigger a rehash; if hashbrown's \
2004 growth/rehash heuristic changed, retune the constants)",
2005 );
2006 assert_eq!(
2007 user_calls, 0,
2008 "reserve must not invoke user `Hash` during rehash; got \
2009 {user_calls} call(s) for {rehash_calls} rehash-callback \
2010 invocation(s)",
2011 );
2012
2013 map.validate(ValidateCompact::NonCompact)
2014 .expect("map remains valid after reserve");
2015 }
2016}