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