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