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.items.validate(compactness)?;
901 self.tables.validate(self.len(), compactness)?;
902
903 // Check that the indexes are all correct.
904 for (ix, item) in self.items.iter() {
905 let key = item.key();
906 let Some(ix1) = self.find_index(&key) else {
907 return Err(ValidationError::general(format!(
908 "item at index {ix} has no key1 index"
909 )));
910 };
911
912 if ix1 != ix {
913 return Err(ValidationError::General(format!(
914 "item at index {ix} has mismatched indexes: ix1: {ix1}",
915 )));
916 }
917 }
918
919 Ok(())
920 }
921
922 /// Inserts a value into the map, removing and returning the conflicting
923 /// item, if any.
924 ///
925 /// # Examples
926 ///
927 /// ```
928 /// # #[cfg(feature = "default-hasher")] {
929 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
930 ///
931 /// #[derive(Debug, PartialEq, Eq, Hash)]
932 /// struct Item {
933 /// id: String,
934 /// value: u32,
935 /// }
936 ///
937 /// impl IdHashItem for Item {
938 /// type Key<'a> = &'a str;
939 /// fn key(&self) -> Self::Key<'_> {
940 /// &self.id
941 /// }
942 /// id_upcast!();
943 /// }
944 ///
945 /// let mut map = IdHashMap::new();
946 ///
947 /// // First insertion returns None
948 /// let old = map.insert_overwrite(Item { id: "foo".to_string(), value: 42 });
949 /// assert!(old.is_none());
950 ///
951 /// // Second insertion with same key returns the old value
952 /// let old = map.insert_overwrite(Item { id: "foo".to_string(), value: 100 });
953 /// assert_eq!(old.unwrap().value, 42);
954 /// assert_eq!(map.get("foo").unwrap().value, 100);
955 /// # }
956 /// ```
957 #[doc(alias = "insert")]
958 pub fn insert_overwrite(&mut self, value: T) -> Option<T> {
959 // Go through the entry API so all user code is called before any table
960 // mutation. A panic in user code therefore leaves the map in its
961 // pre-call state.
962 //
963 // We use `vacant.insert_entry` rather than `vacant.insert` to avoid
964 // creating a `RefMut`, which would (unnecessarily) re-hash the key
965 // after the mutation when that `RefMut` is created.
966 match self.entry(value.key()) {
967 Entry::Occupied(mut occupied) => Some(occupied.insert(value)),
968 Entry::Vacant(vacant) => {
969 vacant.insert_entry(value);
970 None
971 }
972 }
973 }
974
975 /// Inserts a value into the set, returning an error if any duplicates were
976 /// added.
977 ///
978 /// # Examples
979 ///
980 /// ```
981 /// # #[cfg(feature = "default-hasher")] {
982 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
983 ///
984 /// #[derive(Debug, PartialEq, Eq, Hash)]
985 /// struct Item {
986 /// id: String,
987 /// value: u32,
988 /// }
989 ///
990 /// impl IdHashItem for Item {
991 /// type Key<'a> = &'a str;
992 /// fn key(&self) -> Self::Key<'_> {
993 /// &self.id
994 /// }
995 /// id_upcast!();
996 /// }
997 ///
998 /// let mut map = IdHashMap::new();
999 ///
1000 /// // First insertion succeeds
1001 /// assert!(
1002 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).is_ok()
1003 /// );
1004 ///
1005 /// // Second insertion with different key succeeds
1006 /// assert!(
1007 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).is_ok()
1008 /// );
1009 ///
1010 /// // Third insertion with duplicate key fails
1011 /// assert!(
1012 /// map.insert_unique(Item { id: "foo".to_string(), value: 100 }).is_err()
1013 /// );
1014 /// # }
1015 /// ```
1016 pub fn insert_unique(
1017 &mut self,
1018 value: T,
1019 ) -> Result<(), DuplicateItem<T, &T>> {
1020 let _ = self.insert_unique_impl(value)?;
1021 Ok(())
1022 }
1023
1024 /// Returns true if the map contains the given key.
1025 ///
1026 /// # Examples
1027 ///
1028 /// ```
1029 /// # #[cfg(feature = "default-hasher")] {
1030 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1031 ///
1032 /// #[derive(Debug, PartialEq, Eq, Hash)]
1033 /// struct Item {
1034 /// id: String,
1035 /// value: u32,
1036 /// }
1037 ///
1038 /// impl IdHashItem for Item {
1039 /// type Key<'a> = &'a str;
1040 /// fn key(&self) -> Self::Key<'_> {
1041 /// &self.id
1042 /// }
1043 /// id_upcast!();
1044 /// }
1045 ///
1046 /// let mut map = IdHashMap::new();
1047 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1048 ///
1049 /// assert!(map.contains_key("foo"));
1050 /// assert!(!map.contains_key("bar"));
1051 /// # }
1052 /// ```
1053 pub fn contains_key<'a, Q>(&'a self, key1: &Q) -> bool
1054 where
1055 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
1056 {
1057 self.find_index(key1).is_some()
1058 }
1059
1060 /// Gets a reference to the value associated with the given key.
1061 ///
1062 /// # Examples
1063 ///
1064 /// ```
1065 /// # #[cfg(feature = "default-hasher")] {
1066 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1067 ///
1068 /// #[derive(Debug, PartialEq, Eq, Hash)]
1069 /// struct Item {
1070 /// id: String,
1071 /// value: u32,
1072 /// }
1073 ///
1074 /// impl IdHashItem for Item {
1075 /// type Key<'a> = &'a str;
1076 /// fn key(&self) -> Self::Key<'_> {
1077 /// &self.id
1078 /// }
1079 /// id_upcast!();
1080 /// }
1081 ///
1082 /// let mut map = IdHashMap::new();
1083 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1084 ///
1085 /// assert_eq!(map.get("foo").unwrap().value, 42);
1086 /// assert!(map.get("bar").is_none());
1087 /// # }
1088 /// ```
1089 pub fn get<'a, Q>(&'a self, key: &Q) -> Option<&'a T>
1090 where
1091 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
1092 {
1093 self.find_index(key).map(|ix| &self.items[ix])
1094 }
1095
1096 /// Gets a mutable reference to the value associated with the given key.
1097 ///
1098 /// # Examples
1099 ///
1100 /// ```
1101 /// # #[cfg(feature = "default-hasher")] {
1102 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1103 ///
1104 /// #[derive(Debug, PartialEq, Eq, Hash)]
1105 /// struct Item {
1106 /// id: String,
1107 /// value: u32,
1108 /// }
1109 ///
1110 /// impl IdHashItem for Item {
1111 /// type Key<'a> = &'a str;
1112 /// fn key(&self) -> Self::Key<'_> {
1113 /// &self.id
1114 /// }
1115 /// id_upcast!();
1116 /// }
1117 ///
1118 /// let mut map = IdHashMap::new();
1119 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1120 ///
1121 /// if let Some(mut item) = map.get_mut("foo") {
1122 /// item.value = 100;
1123 /// }
1124 ///
1125 /// assert_eq!(map.get("foo").unwrap().value, 100);
1126 /// assert!(map.get_mut("bar").is_none());
1127 /// # }
1128 /// ```
1129 pub fn get_mut<'a, Q>(&'a mut self, key: &Q) -> Option<RefMut<'a, T, S>>
1130 where
1131 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
1132 {
1133 let (dormant_map, index) = {
1134 let (map, dormant_map) = DormantMutRef::new(self);
1135 let index = map.find_index(key)?;
1136 (dormant_map, index)
1137 };
1138
1139 // SAFETY: `map` is not used after this point.
1140 let awakened_map = unsafe { dormant_map.awaken() };
1141 let item = &mut awakened_map.items[index];
1142 let state = awakened_map.tables.state.clone();
1143 let hashes = awakened_map.tables.make_hash(item);
1144 Some(RefMut::new(state, hashes, item))
1145 }
1146
1147 /// Removes an item from the map by its key.
1148 ///
1149 /// # Examples
1150 ///
1151 /// ```
1152 /// # #[cfg(feature = "default-hasher")] {
1153 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1154 ///
1155 /// #[derive(Debug, PartialEq, Eq, Hash)]
1156 /// struct Item {
1157 /// id: String,
1158 /// value: u32,
1159 /// }
1160 ///
1161 /// impl IdHashItem for Item {
1162 /// type Key<'a> = &'a str;
1163 /// fn key(&self) -> Self::Key<'_> {
1164 /// &self.id
1165 /// }
1166 /// id_upcast!();
1167 /// }
1168 ///
1169 /// let mut map = IdHashMap::new();
1170 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1171 ///
1172 /// let removed = map.remove("foo");
1173 /// assert_eq!(removed.unwrap().value, 42);
1174 /// assert!(map.is_empty());
1175 ///
1176 /// // Removing non-existent key returns None
1177 /// assert!(map.remove("bar").is_none());
1178 /// # }
1179 /// ```
1180 pub fn remove<'a, Q>(&'a mut self, key: &Q) -> Option<T>
1181 where
1182 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
1183 {
1184 let (dormant_map, remove_index) = {
1185 let (map, dormant_map) = DormantMutRef::new(self);
1186 let remove_index = map.find_index(key)?;
1187 (dormant_map, remove_index)
1188 };
1189 // SAFETY: `map` is not used after this point.
1190 let awakened_map = unsafe { dormant_map.awaken() };
1191 awakened_map.remove_by_index(remove_index)
1192 }
1193
1194 /// Retrieves an entry by its key.
1195 ///
1196 /// Due to borrow checker limitations, this always accepts an owned key
1197 /// rather than a borrowed form of it.
1198 ///
1199 /// # Examples
1200 ///
1201 /// ```
1202 /// # #[cfg(feature = "default-hasher")] {
1203 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1204 ///
1205 /// #[derive(Debug, PartialEq, Eq, Hash)]
1206 /// struct Item {
1207 /// id: String,
1208 /// value: u32,
1209 /// }
1210 ///
1211 /// impl IdHashItem for Item {
1212 /// type Key<'a> = &'a str;
1213 /// fn key(&self) -> Self::Key<'_> {
1214 /// &self.id
1215 /// }
1216 /// id_upcast!();
1217 /// }
1218 ///
1219 /// let mut map = IdHashMap::new();
1220 ///
1221 /// // Use entry API for conditional insertion
1222 /// map.entry("foo").or_insert(Item { id: "foo".to_string(), value: 42 });
1223 /// map.entry("bar").or_insert(Item { id: "bar".to_string(), value: 20 });
1224 ///
1225 /// assert_eq!(map.len(), 2);
1226 /// # }
1227 /// ```
1228 pub fn entry<'a>(&'a mut self, key: T::Key<'_>) -> Entry<'a, T, S, A> {
1229 // Why does this always take an owned key? Well, it would seem like we
1230 // should be able to pass in any Q that is equivalent. That results in
1231 // *this* code compiling fine, but callers have trouble using it because
1232 // the borrow checker believes the keys are borrowed for the full 'a
1233 // rather than a shorter lifetime.
1234 //
1235 // By accepting owned keys, we can use the upcast functions to convert
1236 // them to a shorter lifetime (so this function accepts T::Key<'_>
1237 // rather than T::Key<'a>).
1238 //
1239 // Really, the solution here is to allow GATs to require covariant
1240 // parameters. If that were allowed, the borrow checker should be able
1241 // to figure out that keys don't need to be borrowed for the full 'a,
1242 // just for some shorter lifetime.
1243 let (map, dormant_map) = DormantMutRef::new(self);
1244 let key = T::upcast_key(key);
1245 {
1246 // index is explicitly typed to show that it has a trivial Drop impl
1247 // that doesn't capture anything from map.
1248 let index: Option<ItemIndex> = map.tables.key_to_item.find_index(
1249 &map.tables.state,
1250 &key,
1251 |index| map.items[index].key(),
1252 );
1253 if let Some(index) = index {
1254 drop(key);
1255 return Entry::Occupied(
1256 // SAFETY: `map` is not used after this point.
1257 unsafe { OccupiedEntry::new(dormant_map, index) },
1258 );
1259 }
1260 }
1261 let hash = map.make_key_hash(&key);
1262 Entry::Vacant(
1263 // SAFETY: `map` is not used after this point.
1264 unsafe { VacantEntry::new(dormant_map, hash) },
1265 )
1266 }
1267
1268 /// Retains only the elements specified by the predicate.
1269 ///
1270 /// In other words, remove all items `T` for which `f(RefMut<T>)` returns
1271 /// false. The elements are visited in an arbitrary order.
1272 ///
1273 /// # Examples
1274 ///
1275 /// ```
1276 /// # #[cfg(feature = "default-hasher")] {
1277 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1278 ///
1279 /// #[derive(Debug, PartialEq, Eq, Hash)]
1280 /// struct Item {
1281 /// id: String,
1282 /// value: u32,
1283 /// }
1284 ///
1285 /// impl IdHashItem for Item {
1286 /// type Key<'a> = &'a str;
1287 ///
1288 /// fn key(&self) -> Self::Key<'_> {
1289 /// &self.id
1290 /// }
1291 ///
1292 /// id_upcast!();
1293 /// }
1294 ///
1295 /// let mut map = IdHashMap::new();
1296 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1297 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1298 /// map.insert_unique(Item { id: "baz".to_string(), value: 99 }).unwrap();
1299 ///
1300 /// // Retain only items where value is greater than 30
1301 /// map.retain(|item| item.value > 30);
1302 ///
1303 /// assert_eq!(map.len(), 2);
1304 /// assert_eq!(map.get("foo").unwrap().value, 42);
1305 /// assert_eq!(map.get("baz").unwrap().value, 99);
1306 /// assert!(map.get("bar").is_none());
1307 /// # }
1308 /// ```
1309 pub fn retain<'a, F>(&'a mut self, mut f: F)
1310 where
1311 F: for<'b> FnMut(RefMut<'b, T, S>) -> bool,
1312 {
1313 let hash_state = self.tables.state.clone();
1314 let (_, mut dormant_items) = DormantMutRef::new(&mut self.items);
1315 let mut removed_item = None;
1316
1317 self.tables.key_to_item.retain(|index| {
1318 // Drop the previously-removed item here, at the top of the next
1319 // iteration.
1320 //
1321 // By now, the prior `key_to_item` entry has been erased, so if
1322 // `drop` below panics, `key_to_item` and `items` remain in sync.
1323 // Dropping the item at the end of the prior iteration would
1324 // unwind before the table erased the entry, leaving `key_to_item`
1325 // pointing at a slot we already removed from `items`.
1326 drop(removed_item.take());
1327
1328 let (item, dormant_items) = {
1329 // SAFETY: All uses of `items` ended in the previous iteration.
1330 let items = unsafe { dormant_items.reborrow() };
1331 let (items, dormant_items) = DormantMutRef::new(items);
1332 let item: &'a mut T = items
1333 .get_mut(index)
1334 .expect("all indexes are present in self.items");
1335 (item, dormant_items)
1336 };
1337
1338 let (hash, dormant_item) = {
1339 let (item, dormant_item): (&'a mut T, _) =
1340 DormantMutRef::new(item);
1341 // Use T::key(item) rather than item.key() to force the key
1342 // trait function to be called for T rather than &mut T.
1343 let key = T::key(item);
1344 let hash = hash_state.hash_one(key);
1345 (MapHash::new(hash), dormant_item)
1346 };
1347
1348 let retain = {
1349 // SAFETY: The original item is no longer used after the second
1350 // block above. dormant_items, from which item is derived, is
1351 // currently dormant.
1352 let item = unsafe { dormant_item.awaken() };
1353
1354 let ref_mut = RefMut::new(hash_state.clone(), hash, item);
1355 f(ref_mut)
1356 };
1357
1358 if retain {
1359 true
1360 } else {
1361 // SAFETY: The original items is no longer used after the first
1362 // block above, and item + dormant item have been used above.
1363 let items = unsafe { dormant_items.awaken() };
1364 removed_item = Some(
1365 items
1366 .remove(index)
1367 .expect("all indexes are present in self.items"),
1368 );
1369 false
1370 }
1371 });
1372
1373 // Anything in `removed_item` is implicitly dropped now.
1374 }
1375
1376 fn find_index<'a, Q>(&'a self, k: &Q) -> Option<ItemIndex>
1377 where
1378 Q: Hash + Equivalent<T::Key<'a>> + ?Sized,
1379 {
1380 self.tables
1381 .key_to_item
1382 .find_index(&self.tables.state, k, |index| self.items[index].key())
1383 }
1384
1385 fn make_hash(&self, item: &T) -> MapHash {
1386 self.tables.make_hash(item)
1387 }
1388
1389 fn make_key_hash(&self, key: &T::Key<'_>) -> MapHash {
1390 self.tables.make_key_hash::<T>(key)
1391 }
1392
1393 pub(super) fn get_by_index(&self, index: ItemIndex) -> Option<&T> {
1394 self.items.get(index)
1395 }
1396
1397 pub(super) fn get_by_index_mut(
1398 &mut self,
1399 index: ItemIndex,
1400 ) -> Option<RefMut<'_, T, S>> {
1401 let state = self.tables.state.clone();
1402 let hashes = self.make_hash(&self.items[index]);
1403 let item = &mut self.items[index];
1404 Some(RefMut::new(state, hashes, item))
1405 }
1406
1407 pub(super) fn insert_unique_impl(
1408 &mut self,
1409 value: T,
1410 ) -> Result<ItemIndex, DuplicateItem<T, &T>> {
1411 let mut duplicates = BTreeSet::new();
1412
1413 // Check for duplicates *before* inserting the new item, because we
1414 // don't want to partially insert the new item and then have to roll
1415 // back.
1416 let key = value.key();
1417 let state = &self.tables.state;
1418
1419 let entry = match self
1420 .tables
1421 .key_to_item
1422 .entry(state, key, |index| self.items[index].key())
1423 {
1424 hash_table::Entry::Occupied(slot) => {
1425 duplicates.insert(slot.get());
1426 None
1427 }
1428 hash_table::Entry::Vacant(slot) => Some(slot),
1429 };
1430
1431 if !duplicates.is_empty() {
1432 return Err(DuplicateItem::__internal_new(
1433 value,
1434 duplicates.iter().map(|ix| &self.items[*ix]).collect(),
1435 ));
1436 }
1437
1438 let next_index = self.items.assert_can_grow().insert(value);
1439 entry.unwrap().insert(next_index);
1440
1441 Ok(next_index)
1442 }
1443
1444 pub(super) fn remove_by_index(
1445 &mut self,
1446 remove_index: ItemIndex,
1447 ) -> Option<T> {
1448 // For panic safety, compute the key hash and look up the table entry
1449 // while `self.items` still holds the value, then remove from the table
1450 // and items in sequence. This lookup deliberately matches by
1451 // `ItemIndex` rather than by user `Eq`: at this point we already know
1452 // which item is being removed, and user `Eq` might be pathological.
1453 //
1454 // hashbrown's `find_entry_by_hash` is panic-safe because the table is
1455 // not mutated until `OccupiedEntry::remove` is called, so a panic while
1456 // hashing leaves both items and the table unmodified. (Unlike the
1457 // IdOrdMap path, we don't need a separate two-phase commit: the
1458 // BTreeMap analog has to guard against a user-`Ord` panic during the
1459 // tree walk, but the hash walk here never invokes user code.)
1460 //
1461 // If the hash lookup misses, which can happen when `mem::forget` is
1462 // called on a `RefMut` after the ID was changed, the item's current key
1463 // now hashes to a different bucket than the one its entry sits in. In
1464 // that case, we fall back to a linear scan by `ItemIndex`. This keeps
1465 // the table and item set consistent with each other across silent key
1466 // mutations, mirroring `MapBTreeTable::remove_exact`.
1467 //
1468 // This is not expected to be the common case (why are you calling
1469 // mem::forget on a RefMut?), but guarding against it explicitly makes
1470 // our invariants easier to reason about.
1471 let item = self.items.get(remove_index)?;
1472 let state = &self.tables.state;
1473 let hash = state.hash_one(item.key());
1474 match self
1475 .tables
1476 .key_to_item
1477 .find_entry_by_hash(hash, |index| index == remove_index)
1478 {
1479 Ok(entry) => entry.remove(),
1480 Err(()) => self.tables.key_to_item.remove_by_index(remove_index),
1481 }
1482 Some(
1483 self.items
1484 .remove(remove_index)
1485 .expect("items[remove_index] was Occupied above"),
1486 )
1487 }
1488
1489 pub(super) fn replace_at_index(&mut self, index: ItemIndex, value: T) -> T {
1490 // We check the key before removing it, to avoid leaving the map in an
1491 // inconsistent state.
1492 let old_key =
1493 self.get_by_index(index).expect("index is known to be valid").key();
1494 if T::upcast_key(old_key) != value.key() {
1495 panic!(
1496 "must insert a value with \
1497 the same key used to create the entry"
1498 );
1499 }
1500
1501 // Now that we know the key is the same, we can replace the value
1502 // directly without needing to tweak any tables.
1503 self.items.replace(index, value)
1504 }
1505}
1506
1507impl<'a, T, S: Clone + BuildHasher, A: Allocator> fmt::Debug
1508 for IdHashMap<T, S, A>
1509where
1510 T: IdHashItem + fmt::Debug,
1511 T::Key<'a>: fmt::Debug,
1512 T: 'a,
1513{
1514 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1515 let mut map = f.debug_map();
1516
1517 for item in self.iter() {
1518 let key = item.key();
1519
1520 // SAFETY:
1521 //
1522 // * Lifetime extension: for a type T and two lifetime params 'a and
1523 // 'b, T<'a> and T<'b> aren't guaranteed to have the same layout,
1524 // but (a) that is true today and (b) it would be shocking and
1525 // break half the Rust ecosystem if that were to change in the
1526 // future.
1527 // * We only use key within the scope of this block before immediately
1528 // dropping it. In particular, map.entry calls key.fmt() without
1529 // holding a reference to it.
1530 let key: T::Key<'a> =
1531 unsafe { core::mem::transmute::<T::Key<'_>, T::Key<'a>>(key) };
1532
1533 map.entry(&key, item);
1534 }
1535 map.finish()
1536 }
1537}
1538
1539impl<T: IdHashItem + PartialEq, S: Clone + BuildHasher, A: Allocator> PartialEq
1540 for IdHashMap<T, S, A>
1541{
1542 fn eq(&self, other: &Self) -> bool {
1543 // Implementing PartialEq for IdHashMap is tricky because IdHashMap is
1544 // not semantically like an IndexMap: two maps are equivalent even if
1545 // their items are in a different order. In other words, any permutation
1546 // of items is equivalent.
1547 //
1548 // We also can't sort the items because they're not necessarily Ord.
1549 //
1550 // So we write a custom equality check that checks that each key in one
1551 // map points to the same item as in the other map.
1552
1553 if self.items.len() != other.items.len() {
1554 return false;
1555 }
1556
1557 // Walk over all the items in the first map and check that they point to
1558 // the same item in the second map.
1559 for item in self.items.values() {
1560 let k1 = item.key();
1561
1562 // Check that the indexes are the same in the other map.
1563 let Some(other_ix) = other.find_index(&k1) else {
1564 return false;
1565 };
1566
1567 // Check that the other map's item is the same as this map's
1568 // item. (This is what we use the `PartialEq` bound on T for.)
1569 //
1570 // Because we've checked that other_ix is Some, we know that it is
1571 // valid and points to the expected item.
1572 let other_item = &other.items[other_ix];
1573 if item != other_item {
1574 return false;
1575 }
1576 }
1577
1578 true
1579 }
1580}
1581
1582// The Eq bound on T ensures that the TriHashMap forms an equivalence class.
1583impl<T: IdHashItem + Eq, S: Clone + BuildHasher, A: Allocator> Eq
1584 for IdHashMap<T, S, A>
1585{
1586}
1587
1588/// The `Extend` implementation overwrites duplicates. In the future, there will
1589/// also be an `extend_unique` method that will return an error.
1590///
1591/// # Examples
1592///
1593/// ```
1594/// # #[cfg(feature = "default-hasher")] {
1595/// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1596///
1597/// #[derive(Debug, PartialEq, Eq, Hash)]
1598/// struct Item {
1599/// id: String,
1600/// value: u32,
1601/// }
1602///
1603/// impl IdHashItem for Item {
1604/// type Key<'a> = &'a str;
1605/// fn key(&self) -> Self::Key<'_> {
1606/// &self.id
1607/// }
1608/// id_upcast!();
1609/// }
1610///
1611/// let mut map = IdHashMap::new();
1612/// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1613///
1614/// let new_items = vec![
1615/// Item { id: "foo".to_string(), value: 100 }, // overwrites existing
1616/// Item { id: "bar".to_string(), value: 20 }, // new item
1617/// ];
1618///
1619/// map.extend(new_items);
1620/// assert_eq!(map.len(), 2);
1621/// assert_eq!(map.get("foo").unwrap().value, 100); // overwritten
1622/// assert_eq!(map.get("bar").unwrap().value, 20); // new
1623///
1624/// # }
1625/// ```
1626impl<T: IdHashItem, S: Clone + BuildHasher, A: Allocator> Extend<T>
1627 for IdHashMap<T, S, A>
1628{
1629 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
1630 // Keys may already be present in the map, or multiple times in the
1631 // iterator. Reserve the entire hint lower bound if the map is empty.
1632 // Otherwise reserve half the hint (rounded up), so the map will only
1633 // resize twice in the worst case.
1634 let iter = iter.into_iter();
1635 let reserve = if self.is_empty() {
1636 iter.size_hint().0
1637 } else {
1638 iter.size_hint().0.div_ceil(2)
1639 };
1640 self.reserve(reserve);
1641 for item in iter {
1642 self.insert_overwrite(item);
1643 }
1644 }
1645}
1646
1647impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
1648 for &'a IdHashMap<T, S, A>
1649{
1650 type Item = &'a T;
1651 type IntoIter = Iter<'a, T>;
1652
1653 /// Creates an iterator over references to the items in the map.
1654 ///
1655 /// # Examples
1656 ///
1657 /// ```
1658 /// # #[cfg(feature = "default-hasher")] {
1659 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1660 ///
1661 /// #[derive(Debug, PartialEq, Eq, Hash)]
1662 /// struct Item {
1663 /// id: String,
1664 /// value: u32,
1665 /// }
1666 ///
1667 /// impl IdHashItem for Item {
1668 /// type Key<'a> = &'a str;
1669 /// fn key(&self) -> Self::Key<'_> {
1670 /// &self.id
1671 /// }
1672 /// id_upcast!();
1673 /// }
1674 ///
1675 /// let mut map = IdHashMap::new();
1676 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1677 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1678 ///
1679 /// let mut values: Vec<u32> =
1680 /// (&map).into_iter().map(|item| item.value).collect();
1681 /// values.sort();
1682 /// assert_eq!(values, vec![20, 42]);
1683 /// # }
1684 /// ```
1685 #[inline]
1686 fn into_iter(self) -> Self::IntoIter {
1687 self.iter()
1688 }
1689}
1690
1691impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
1692 for &'a mut IdHashMap<T, S, A>
1693{
1694 type Item = RefMut<'a, T, S>;
1695 type IntoIter = IterMut<'a, T, S, A>;
1696
1697 /// Creates an iterator over mutable references to the items in the map.
1698 ///
1699 /// # Examples
1700 ///
1701 /// ```
1702 /// # #[cfg(feature = "default-hasher")] {
1703 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1704 ///
1705 /// #[derive(Debug, PartialEq, Eq, Hash)]
1706 /// struct Item {
1707 /// id: String,
1708 /// value: u32,
1709 /// }
1710 ///
1711 /// impl IdHashItem for Item {
1712 /// type Key<'a> = &'a str;
1713 /// fn key(&self) -> Self::Key<'_> {
1714 /// &self.id
1715 /// }
1716 /// id_upcast!();
1717 /// }
1718 ///
1719 /// let mut map = IdHashMap::new();
1720 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1721 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1722 ///
1723 /// for mut item in &mut map {
1724 /// item.value *= 2;
1725 /// }
1726 ///
1727 /// assert_eq!(map.get("foo").unwrap().value, 84);
1728 /// assert_eq!(map.get("bar").unwrap().value, 40);
1729 /// # }
1730 /// ```
1731 #[inline]
1732 fn into_iter(self) -> Self::IntoIter {
1733 self.iter_mut()
1734 }
1735}
1736
1737impl<T: IdHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
1738 for IdHashMap<T, S, A>
1739{
1740 type Item = T;
1741 type IntoIter = IntoIter<T, A>;
1742
1743 /// Consumes the map and creates an iterator over the owned items.
1744 ///
1745 /// # Examples
1746 ///
1747 /// ```
1748 /// # #[cfg(feature = "default-hasher")] {
1749 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1750 ///
1751 /// #[derive(Debug, PartialEq, Eq, Hash)]
1752 /// struct Item {
1753 /// id: String,
1754 /// value: u32,
1755 /// }
1756 ///
1757 /// impl IdHashItem for Item {
1758 /// type Key<'a> = &'a str;
1759 /// fn key(&self) -> Self::Key<'_> {
1760 /// &self.id
1761 /// }
1762 /// id_upcast!();
1763 /// }
1764 ///
1765 /// let mut map = IdHashMap::new();
1766 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1767 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1768 ///
1769 /// let mut values: Vec<u32> = map.into_iter().map(|item| item.value).collect();
1770 /// values.sort();
1771 /// assert_eq!(values, vec![20, 42]);
1772 /// # }
1773 /// ```
1774 #[inline]
1775 fn into_iter(self) -> Self::IntoIter {
1776 IntoIter::new(self.items)
1777 }
1778}
1779
1780/// The `FromIterator` implementation for `IdHashMap` overwrites duplicate
1781/// items.
1782///
1783/// # Examples
1784///
1785/// ```
1786/// # #[cfg(feature = "default-hasher")] {
1787/// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1788///
1789/// #[derive(Debug, PartialEq, Eq, Hash)]
1790/// struct Item {
1791/// id: String,
1792/// value: u32,
1793/// }
1794///
1795/// impl IdHashItem for Item {
1796/// type Key<'a> = &'a str;
1797/// fn key(&self) -> Self::Key<'_> {
1798/// &self.id
1799/// }
1800/// id_upcast!();
1801/// }
1802///
1803/// let items = vec![
1804/// Item { id: "foo".to_string(), value: 42 },
1805/// Item { id: "bar".to_string(), value: 20 },
1806/// Item { id: "foo".to_string(), value: 100 }, // duplicate key, overwrites
1807/// ];
1808///
1809/// let map: IdHashMap<Item> = items.into_iter().collect();
1810/// assert_eq!(map.len(), 2);
1811/// assert_eq!(map.get("foo").unwrap().value, 100); // last value wins
1812/// assert_eq!(map.get("bar").unwrap().value, 20);
1813/// # }
1814/// ```
1815impl<T: IdHashItem, S: Default + Clone + BuildHasher, A: Allocator + Default>
1816 FromIterator<T> for IdHashMap<T, S, A>
1817{
1818 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1819 let mut map = IdHashMap::default();
1820 map.extend(iter);
1821 map
1822 }
1823}
1824
1825#[cfg(all(test, feature = "std"))]
1826mod tests {
1827 use super::*;
1828 use core::{cell::Cell, hash::Hasher};
1829
1830 std::thread_local! {
1831 static USER_HASH_CALLS: Cell<u32> = const { Cell::new(0) };
1832 }
1833
1834 #[derive(Debug)]
1835 struct CountedKey(u32);
1836
1837 impl Hash for CountedKey {
1838 fn hash<H: Hasher>(&self, state: &mut H) {
1839 USER_HASH_CALLS.with(|c| c.set(c.get() + 1));
1840 self.0.hash(state);
1841 }
1842 }
1843
1844 impl PartialEq for CountedKey {
1845 fn eq(&self, other: &Self) -> bool {
1846 self.0 == other.0
1847 }
1848 }
1849 impl Eq for CountedKey {}
1850
1851 #[derive(Debug)]
1852 struct CountedItem {
1853 id: u32,
1854 }
1855
1856 impl IdHashItem for CountedItem {
1857 type Key<'a> = CountedKey;
1858 fn key(&self) -> Self::Key<'_> {
1859 CountedKey(self.id)
1860 }
1861 id_upcast!();
1862 }
1863
1864 // This is a unit test and not an integration test to ensure rehashing
1865 // actually happens. (Rehashing is not externally observable in integration
1866 // tests.)
1867 #[test]
1868 fn reserve_rehash_uses_cached_hash() {
1869 let mut map = IdHashMap::<CountedItem, _>::with_hasher(
1870 foldhash::fast::FixedState::with_seed(0),
1871 );
1872 // Insert items (legitimately calls user Hash).
1873 for id in [
1874 0u32, 17, 1, 12, 5, 21, 8, 10, 18, 4, 16, 22, 9, 24, 23, 13, 7, 25,
1875 26, 20, 31, 11, 14, 2, 6,
1876 ] {
1877 let _ = map.insert_overwrite(CountedItem { id });
1878 }
1879 // Drop most entries, leaving the table heavy with tombstones so the
1880 // next reserve favors `rehash_in_place` over a fresh-allocation grow.
1881 map.retain(|item| item.id % 2 == 1 && item.id % 3 != 0);
1882
1883 USER_HASH_CALLS.with(|c| c.set(0));
1884 let rehash_calls = map.tables.key_to_item.reserve_counting_rehash(10);
1885 let user_calls = USER_HASH_CALLS.with(Cell::get);
1886
1887 assert!(
1888 rehash_calls > 0,
1889 "expected reserve to invoke the rehash callback at least once \
1890 (setup did not actually trigger a rehash; if hashbrown's \
1891 growth/rehash heuristic changed, retune the constants)",
1892 );
1893 assert_eq!(
1894 user_calls, 0,
1895 "reserve must not invoke user `Hash` during rehash; got \
1896 {user_calls} call(s) for {rehash_calls} rehash-callback \
1897 invocation(s)",
1898 );
1899
1900 map.validate(ValidateCompact::NonCompact)
1901 .expect("map remains valid after reserve");
1902 }
1903}