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 item_set::ItemSet,
14 map_hash::MapHash,
15 },
16};
17use alloc::collections::BTreeSet;
18use core::{
19 fmt,
20 hash::{BuildHasher, Hash},
21};
22use equivalent::Equivalent;
23use hashbrown::hash_table;
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 self.items.clear();
599 self.tables.key_to_item.clear();
600 }
601
602 /// Reserves capacity for at least `additional` more elements to be inserted
603 /// in the `IdHashMap`. The collection may reserve more space to
604 /// speculatively avoid frequent reallocations. After calling `reserve`,
605 /// capacity will be greater than or equal to `self.len() + additional`.
606 /// Does nothing if capacity is already sufficient.
607 ///
608 /// # Panics
609 ///
610 /// Panics if the new capacity overflows [`isize::MAX`] bytes, and
611 /// [`abort`]s the program in case of an allocation error. Use
612 /// [`try_reserve`](Self::try_reserve) instead if you want to handle memory
613 /// allocation failure.
614 ///
615 /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html
616 /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html
617 ///
618 /// # Examples
619 ///
620 /// ```
621 /// # #[cfg(feature = "default-hasher")] {
622 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
623 ///
624 /// #[derive(Debug, PartialEq, Eq, Hash)]
625 /// struct Item {
626 /// id: String,
627 /// value: u32,
628 /// }
629 ///
630 /// impl IdHashItem for Item {
631 /// type Key<'a> = &'a str;
632 /// fn key(&self) -> Self::Key<'_> {
633 /// &self.id
634 /// }
635 /// id_upcast!();
636 /// }
637 ///
638 /// let mut map: IdHashMap<Item> = IdHashMap::new();
639 /// map.reserve(100);
640 /// assert!(map.capacity() >= 100);
641 /// # }
642 /// ```
643 pub fn reserve(&mut self, additional: usize) {
644 self.items.reserve(additional);
645 let items = &self.items;
646 let state = &self.tables.state;
647 self.tables
648 .key_to_item
649 .reserve(additional, |ix| state.hash_one(items[*ix].key()));
650 }
651
652 /// Tries to reserve capacity for at least `additional` more elements to be
653 /// inserted in the `IdHashMap`. The collection may reserve more space to
654 /// speculatively avoid frequent reallocations. After calling `try_reserve`,
655 /// capacity will be greater than or equal to `self.len() + additional` if
656 /// it returns `Ok(())`. Does nothing if capacity is already sufficient.
657 ///
658 /// # Errors
659 ///
660 /// If the capacity overflows, or the allocator reports a failure, then an
661 /// error is returned.
662 ///
663 /// # Notes
664 ///
665 /// If reservation fails partway through, some internal structures may have
666 /// already increased their capacity. The map remains in a valid state but
667 /// may have uneven capacities across its internal structures.
668 ///
669 /// # Examples
670 ///
671 /// ```
672 /// # #[cfg(feature = "default-hasher")] {
673 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
674 ///
675 /// #[derive(Debug, PartialEq, Eq, Hash)]
676 /// struct Item {
677 /// id: String,
678 /// value: u32,
679 /// }
680 ///
681 /// impl IdHashItem for Item {
682 /// type Key<'a> = &'a str;
683 /// fn key(&self) -> Self::Key<'_> {
684 /// &self.id
685 /// }
686 /// id_upcast!();
687 /// }
688 ///
689 /// let mut map: IdHashMap<Item> = IdHashMap::new();
690 /// map.try_reserve(100).expect("allocation should succeed");
691 /// assert!(map.capacity() >= 100);
692 /// # }
693 /// ```
694 pub fn try_reserve(
695 &mut self,
696 additional: usize,
697 ) -> Result<(), crate::errors::TryReserveError> {
698 self.items.try_reserve(additional)?;
699 let items = &self.items;
700 let state = &self.tables.state;
701 self.tables
702 .key_to_item
703 .try_reserve(additional, |ix| state.hash_one(items[*ix].key()))
704 .map_err(crate::errors::TryReserveError::from_hashbrown)?;
705 Ok(())
706 }
707
708 /// Shrinks the capacity of the map as much as possible. It will drop
709 /// down as much as possible while maintaining the internal rules
710 /// and possibly leaving some space in accordance with the resize policy.
711 ///
712 /// # Examples
713 ///
714 /// ```
715 /// # #[cfg(feature = "default-hasher")] {
716 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
717 ///
718 /// #[derive(Debug, PartialEq, Eq, Hash)]
719 /// struct Item {
720 /// id: String,
721 /// value: u32,
722 /// }
723 ///
724 /// impl IdHashItem for Item {
725 /// type Key<'a> = &'a str;
726 /// fn key(&self) -> Self::Key<'_> {
727 /// &self.id
728 /// }
729 /// id_upcast!();
730 /// }
731 ///
732 /// let mut map: IdHashMap<Item> = IdHashMap::with_capacity(100);
733 /// map.insert_unique(Item { id: "foo".to_string(), value: 1 }).unwrap();
734 /// map.insert_unique(Item { id: "bar".to_string(), value: 2 }).unwrap();
735 /// assert!(map.capacity() >= 100);
736 /// map.shrink_to_fit();
737 /// assert!(map.capacity() >= 2);
738 /// # }
739 /// ```
740 pub fn shrink_to_fit(&mut self) {
741 let remap = self.items.shrink_to_fit();
742 if !remap.is_identity() {
743 self.tables.key_to_item.remap_indexes(&remap);
744 }
745 let items = &self.items;
746 let state = &self.tables.state;
747 self.tables
748 .key_to_item
749 .shrink_to_fit(|ix| state.hash_one(items[*ix].key()));
750 }
751
752 /// Shrinks the capacity of the map with a lower limit. It will drop
753 /// down no lower than the supplied limit while maintaining the internal
754 /// rules and possibly leaving some space in accordance with the resize
755 /// policy.
756 ///
757 /// If the current capacity is less than the lower limit, this is a no-op.
758 ///
759 /// # Examples
760 ///
761 /// ```
762 /// # #[cfg(feature = "default-hasher")] {
763 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
764 ///
765 /// #[derive(Debug, PartialEq, Eq, Hash)]
766 /// struct Item {
767 /// id: String,
768 /// value: u32,
769 /// }
770 ///
771 /// impl IdHashItem for Item {
772 /// type Key<'a> = &'a str;
773 /// fn key(&self) -> Self::Key<'_> {
774 /// &self.id
775 /// }
776 /// id_upcast!();
777 /// }
778 ///
779 /// let mut map: IdHashMap<Item> = IdHashMap::with_capacity(100);
780 /// map.insert_unique(Item { id: "foo".to_string(), value: 1 }).unwrap();
781 /// map.insert_unique(Item { id: "bar".to_string(), value: 2 }).unwrap();
782 /// assert!(map.capacity() >= 100);
783 /// map.shrink_to(10);
784 /// assert!(map.capacity() >= 10);
785 /// map.shrink_to(0);
786 /// assert!(map.capacity() >= 2);
787 /// # }
788 /// ```
789 pub fn shrink_to(&mut self, min_capacity: usize) {
790 let remap = self.items.shrink_to(min_capacity);
791 if !remap.is_identity() {
792 self.tables.key_to_item.remap_indexes(&remap);
793 }
794 let items = &self.items;
795 let state = &self.tables.state;
796 self.tables
797 .key_to_item
798 .shrink_to(min_capacity, |ix| state.hash_one(items[*ix].key()));
799 }
800
801 /// Iterates over the items in the map.
802 ///
803 /// Similar to [`HashMap`], the iteration order is arbitrary and not
804 /// guaranteed to be stable.
805 ///
806 /// # Examples
807 ///
808 /// ```
809 /// # #[cfg(feature = "default-hasher")] {
810 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
811 ///
812 /// #[derive(Debug, PartialEq, Eq, Hash)]
813 /// struct Item {
814 /// id: String,
815 /// value: u32,
816 /// }
817 ///
818 /// impl IdHashItem for Item {
819 /// type Key<'a> = &'a str;
820 /// fn key(&self) -> Self::Key<'_> {
821 /// &self.id
822 /// }
823 /// id_upcast!();
824 /// }
825 ///
826 /// let mut map = IdHashMap::new();
827 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
828 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
829 ///
830 /// let mut values: Vec<u32> = map.iter().map(|item| item.value).collect();
831 /// values.sort();
832 /// assert_eq!(values, vec![20, 42]);
833 /// # }
834 /// ```
835 ///
836 /// [`HashMap`]: std::collections::HashMap
837 #[inline]
838 pub fn iter(&self) -> Iter<'_, T> {
839 Iter::new(&self.items)
840 }
841
842 /// Iterates over the items in the map, allowing for mutation.
843 ///
844 /// Similar to [`HashMap`], the iteration order is arbitrary and not
845 /// guaranteed to be stable.
846 ///
847 /// # Examples
848 ///
849 /// ```
850 /// # #[cfg(feature = "default-hasher")] {
851 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
852 ///
853 /// #[derive(Debug, PartialEq, Eq, Hash)]
854 /// struct Item {
855 /// id: String,
856 /// value: u32,
857 /// }
858 ///
859 /// impl IdHashItem for Item {
860 /// type Key<'a> = &'a str;
861 /// fn key(&self) -> Self::Key<'_> {
862 /// &self.id
863 /// }
864 /// id_upcast!();
865 /// }
866 ///
867 /// let mut map = IdHashMap::new();
868 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
869 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
870 ///
871 /// for mut item in map.iter_mut() {
872 /// item.value *= 2;
873 /// }
874 ///
875 /// assert_eq!(map.get("foo").unwrap().value, 84);
876 /// assert_eq!(map.get("bar").unwrap().value, 40);
877 /// # }
878 /// ```
879 ///
880 /// [`HashMap`]: std::collections::HashMap
881 #[inline]
882 pub fn iter_mut(&mut self) -> IterMut<'_, T, S, A> {
883 IterMut::new(&self.tables, &mut self.items)
884 }
885
886 /// Checks general invariants of the map.
887 ///
888 /// The code below always upholds these invariants, but it's useful to have
889 /// an explicit check for tests.
890 #[doc(hidden)]
891 pub fn validate(
892 &self,
893 compactness: ValidateCompact,
894 ) -> Result<(), ValidationError>
895 where
896 T: fmt::Debug,
897 {
898 self.items.validate(compactness)?;
899 self.tables.validate(self.len(), compactness)?;
900
901 // Check that the indexes are all correct.
902 for (ix, item) in self.items.iter() {
903 let key = item.key();
904 let Some(ix1) = self.find_index(&key) else {
905 return Err(ValidationError::general(format!(
906 "item at index {ix} has no key1 index"
907 )));
908 };
909
910 if ix1 != ix {
911 return Err(ValidationError::General(format!(
912 "item at index {ix} has mismatched indexes: ix1: {ix1}",
913 )));
914 }
915 }
916
917 Ok(())
918 }
919
920 /// Inserts a value into the map, removing and returning the conflicting
921 /// item, if any.
922 ///
923 /// # Examples
924 ///
925 /// ```
926 /// # #[cfg(feature = "default-hasher")] {
927 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
928 ///
929 /// #[derive(Debug, PartialEq, Eq, Hash)]
930 /// struct Item {
931 /// id: String,
932 /// value: u32,
933 /// }
934 ///
935 /// impl IdHashItem for Item {
936 /// type Key<'a> = &'a str;
937 /// fn key(&self) -> Self::Key<'_> {
938 /// &self.id
939 /// }
940 /// id_upcast!();
941 /// }
942 ///
943 /// let mut map = IdHashMap::new();
944 ///
945 /// // First insertion returns None
946 /// let old = map.insert_overwrite(Item { id: "foo".to_string(), value: 42 });
947 /// assert!(old.is_none());
948 ///
949 /// // Second insertion with same key returns the old value
950 /// let old = map.insert_overwrite(Item { id: "foo".to_string(), value: 100 });
951 /// assert_eq!(old.unwrap().value, 42);
952 /// assert_eq!(map.get("foo").unwrap().value, 100);
953 /// # }
954 /// ```
955 #[doc(alias = "insert")]
956 pub fn insert_overwrite(&mut self, value: T) -> Option<T> {
957 // Go through the entry API so all user code is called before any table
958 // mutation. A panic in user code therefore leaves the map in its
959 // pre-call state.
960 //
961 // We use `vacant.insert_entry` rather than `vacant.insert` to avoid
962 // creating a `RefMut`, which would (unnecessarily) re-hash the key
963 // after the mutation when that `RefMut` is created.
964 match self.entry(value.key()) {
965 Entry::Occupied(mut occupied) => Some(occupied.insert(value)),
966 Entry::Vacant(vacant) => {
967 vacant.insert_entry(value);
968 None
969 }
970 }
971 }
972
973 /// Inserts a value into the set, returning an error if any duplicates were
974 /// added.
975 ///
976 /// # Examples
977 ///
978 /// ```
979 /// # #[cfg(feature = "default-hasher")] {
980 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
981 ///
982 /// #[derive(Debug, PartialEq, Eq, Hash)]
983 /// struct Item {
984 /// id: String,
985 /// value: u32,
986 /// }
987 ///
988 /// impl IdHashItem for Item {
989 /// type Key<'a> = &'a str;
990 /// fn key(&self) -> Self::Key<'_> {
991 /// &self.id
992 /// }
993 /// id_upcast!();
994 /// }
995 ///
996 /// let mut map = IdHashMap::new();
997 ///
998 /// // First insertion succeeds
999 /// assert!(
1000 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).is_ok()
1001 /// );
1002 ///
1003 /// // Second insertion with different key succeeds
1004 /// assert!(
1005 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).is_ok()
1006 /// );
1007 ///
1008 /// // Third insertion with duplicate key fails
1009 /// assert!(
1010 /// map.insert_unique(Item { id: "foo".to_string(), value: 100 }).is_err()
1011 /// );
1012 /// # }
1013 /// ```
1014 pub fn insert_unique(
1015 &mut self,
1016 value: T,
1017 ) -> Result<(), DuplicateItem<T, &T>> {
1018 let _ = self.insert_unique_impl(value)?;
1019 Ok(())
1020 }
1021
1022 /// Returns true if the map contains the given key.
1023 ///
1024 /// # Examples
1025 ///
1026 /// ```
1027 /// # #[cfg(feature = "default-hasher")] {
1028 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1029 ///
1030 /// #[derive(Debug, PartialEq, Eq, Hash)]
1031 /// struct Item {
1032 /// id: String,
1033 /// value: u32,
1034 /// }
1035 ///
1036 /// impl IdHashItem for Item {
1037 /// type Key<'a> = &'a str;
1038 /// fn key(&self) -> Self::Key<'_> {
1039 /// &self.id
1040 /// }
1041 /// id_upcast!();
1042 /// }
1043 ///
1044 /// let mut map = IdHashMap::new();
1045 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1046 ///
1047 /// assert!(map.contains_key("foo"));
1048 /// assert!(!map.contains_key("bar"));
1049 /// # }
1050 /// ```
1051 pub fn contains_key<'a, Q>(&'a self, key1: &Q) -> bool
1052 where
1053 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
1054 {
1055 self.find_index(key1).is_some()
1056 }
1057
1058 /// Gets a reference to the value associated with the given key.
1059 ///
1060 /// # Examples
1061 ///
1062 /// ```
1063 /// # #[cfg(feature = "default-hasher")] {
1064 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1065 ///
1066 /// #[derive(Debug, PartialEq, Eq, Hash)]
1067 /// struct Item {
1068 /// id: String,
1069 /// value: u32,
1070 /// }
1071 ///
1072 /// impl IdHashItem for Item {
1073 /// type Key<'a> = &'a str;
1074 /// fn key(&self) -> Self::Key<'_> {
1075 /// &self.id
1076 /// }
1077 /// id_upcast!();
1078 /// }
1079 ///
1080 /// let mut map = IdHashMap::new();
1081 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1082 ///
1083 /// assert_eq!(map.get("foo").unwrap().value, 42);
1084 /// assert!(map.get("bar").is_none());
1085 /// # }
1086 /// ```
1087 pub fn get<'a, Q>(&'a self, key: &Q) -> Option<&'a T>
1088 where
1089 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
1090 {
1091 self.find_index(key).map(|ix| &self.items[ix])
1092 }
1093
1094 /// Gets a mutable reference to the value associated with the given key.
1095 ///
1096 /// # Examples
1097 ///
1098 /// ```
1099 /// # #[cfg(feature = "default-hasher")] {
1100 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1101 ///
1102 /// #[derive(Debug, PartialEq, Eq, Hash)]
1103 /// struct Item {
1104 /// id: String,
1105 /// value: u32,
1106 /// }
1107 ///
1108 /// impl IdHashItem for Item {
1109 /// type Key<'a> = &'a str;
1110 /// fn key(&self) -> Self::Key<'_> {
1111 /// &self.id
1112 /// }
1113 /// id_upcast!();
1114 /// }
1115 ///
1116 /// let mut map = IdHashMap::new();
1117 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1118 ///
1119 /// if let Some(mut item) = map.get_mut("foo") {
1120 /// item.value = 100;
1121 /// }
1122 ///
1123 /// assert_eq!(map.get("foo").unwrap().value, 100);
1124 /// assert!(map.get_mut("bar").is_none());
1125 /// # }
1126 /// ```
1127 pub fn get_mut<'a, Q>(&'a mut self, key: &Q) -> Option<RefMut<'a, T, S>>
1128 where
1129 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
1130 {
1131 let (dormant_map, index) = {
1132 let (map, dormant_map) = DormantMutRef::new(self);
1133 let index = map.find_index(key)?;
1134 (dormant_map, index)
1135 };
1136
1137 // SAFETY: `map` is not used after this point.
1138 let awakened_map = unsafe { dormant_map.awaken() };
1139 let item = &mut awakened_map.items[index];
1140 let state = awakened_map.tables.state.clone();
1141 let hashes = awakened_map.tables.make_hash(item);
1142 Some(RefMut::new(state, hashes, item))
1143 }
1144
1145 /// Removes an item from the map by its key.
1146 ///
1147 /// # Examples
1148 ///
1149 /// ```
1150 /// # #[cfg(feature = "default-hasher")] {
1151 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1152 ///
1153 /// #[derive(Debug, PartialEq, Eq, Hash)]
1154 /// struct Item {
1155 /// id: String,
1156 /// value: u32,
1157 /// }
1158 ///
1159 /// impl IdHashItem for Item {
1160 /// type Key<'a> = &'a str;
1161 /// fn key(&self) -> Self::Key<'_> {
1162 /// &self.id
1163 /// }
1164 /// id_upcast!();
1165 /// }
1166 ///
1167 /// let mut map = IdHashMap::new();
1168 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1169 ///
1170 /// let removed = map.remove("foo");
1171 /// assert_eq!(removed.unwrap().value, 42);
1172 /// assert!(map.is_empty());
1173 ///
1174 /// // Removing non-existent key returns None
1175 /// assert!(map.remove("bar").is_none());
1176 /// # }
1177 /// ```
1178 pub fn remove<'a, Q>(&'a mut self, key: &Q) -> Option<T>
1179 where
1180 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
1181 {
1182 let (dormant_map, remove_index) = {
1183 let (map, dormant_map) = DormantMutRef::new(self);
1184 let remove_index = map.find_index(key)?;
1185 (dormant_map, remove_index)
1186 };
1187 // SAFETY: `map` is not used after this point.
1188 let awakened_map = unsafe { dormant_map.awaken() };
1189 awakened_map.remove_by_index(remove_index)
1190 }
1191
1192 /// Retrieves an entry by its key.
1193 ///
1194 /// Due to borrow checker limitations, this always accepts an owned key
1195 /// rather than a borrowed form of it.
1196 ///
1197 /// # Examples
1198 ///
1199 /// ```
1200 /// # #[cfg(feature = "default-hasher")] {
1201 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1202 ///
1203 /// #[derive(Debug, PartialEq, Eq, Hash)]
1204 /// struct Item {
1205 /// id: String,
1206 /// value: u32,
1207 /// }
1208 ///
1209 /// impl IdHashItem for Item {
1210 /// type Key<'a> = &'a str;
1211 /// fn key(&self) -> Self::Key<'_> {
1212 /// &self.id
1213 /// }
1214 /// id_upcast!();
1215 /// }
1216 ///
1217 /// let mut map = IdHashMap::new();
1218 ///
1219 /// // Use entry API for conditional insertion
1220 /// map.entry("foo").or_insert(Item { id: "foo".to_string(), value: 42 });
1221 /// map.entry("bar").or_insert(Item { id: "bar".to_string(), value: 20 });
1222 ///
1223 /// assert_eq!(map.len(), 2);
1224 /// # }
1225 /// ```
1226 pub fn entry<'a>(&'a mut self, key: T::Key<'_>) -> Entry<'a, T, S, A> {
1227 // Why does this always take an owned key? Well, it would seem like we
1228 // should be able to pass in any Q that is equivalent. That results in
1229 // *this* code compiling fine, but callers have trouble using it because
1230 // the borrow checker believes the keys are borrowed for the full 'a
1231 // rather than a shorter lifetime.
1232 //
1233 // By accepting owned keys, we can use the upcast functions to convert
1234 // them to a shorter lifetime (so this function accepts T::Key<'_>
1235 // rather than T::Key<'a>).
1236 //
1237 // Really, the solution here is to allow GATs to require covariant
1238 // parameters. If that were allowed, the borrow checker should be able
1239 // to figure out that keys don't need to be borrowed for the full 'a,
1240 // just for some shorter lifetime.
1241 let (map, dormant_map) = DormantMutRef::new(self);
1242 let key = T::upcast_key(key);
1243 {
1244 // index is explicitly typed to show that it has a trivial Drop impl
1245 // that doesn't capture anything from map.
1246 let index: Option<ItemIndex> = map.tables.key_to_item.find_index(
1247 &map.tables.state,
1248 &key,
1249 |index| map.items[index].key(),
1250 );
1251 if let Some(index) = index {
1252 drop(key);
1253 return Entry::Occupied(
1254 // SAFETY: `map` is not used after this point.
1255 unsafe { OccupiedEntry::new(dormant_map, index) },
1256 );
1257 }
1258 }
1259 let hash = map.make_key_hash(&key);
1260 Entry::Vacant(
1261 // SAFETY: `map` is not used after this point.
1262 unsafe { VacantEntry::new(dormant_map, hash) },
1263 )
1264 }
1265
1266 /// Retains only the elements specified by the predicate.
1267 ///
1268 /// In other words, remove all items `T` for which `f(RefMut<T>)` returns
1269 /// false. The elements are visited in an arbitrary order.
1270 ///
1271 /// # Examples
1272 ///
1273 /// ```
1274 /// # #[cfg(feature = "default-hasher")] {
1275 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1276 ///
1277 /// #[derive(Debug, PartialEq, Eq, Hash)]
1278 /// struct Item {
1279 /// id: String,
1280 /// value: u32,
1281 /// }
1282 ///
1283 /// impl IdHashItem for Item {
1284 /// type Key<'a> = &'a str;
1285 ///
1286 /// fn key(&self) -> Self::Key<'_> {
1287 /// &self.id
1288 /// }
1289 ///
1290 /// id_upcast!();
1291 /// }
1292 ///
1293 /// let mut map = IdHashMap::new();
1294 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1295 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1296 /// map.insert_unique(Item { id: "baz".to_string(), value: 99 }).unwrap();
1297 ///
1298 /// // Retain only items where value is greater than 30
1299 /// map.retain(|item| item.value > 30);
1300 ///
1301 /// assert_eq!(map.len(), 2);
1302 /// assert_eq!(map.get("foo").unwrap().value, 42);
1303 /// assert_eq!(map.get("baz").unwrap().value, 99);
1304 /// assert!(map.get("bar").is_none());
1305 /// # }
1306 /// ```
1307 pub fn retain<'a, F>(&'a mut self, mut f: F)
1308 where
1309 F: FnMut(RefMut<'a, T, S>) -> bool,
1310 {
1311 let hash_state = self.tables.state.clone();
1312 let (_, mut dormant_items) = DormantMutRef::new(&mut self.items);
1313
1314 self.tables.key_to_item.retain(|index| {
1315 let (item, dormant_items) = {
1316 // SAFETY: All uses of `items` ended in the previous iteration.
1317 let items = unsafe { dormant_items.reborrow() };
1318 let (items, dormant_items) = DormantMutRef::new(items);
1319 let item: &'a mut T = items
1320 .get_mut(index)
1321 .expect("all indexes are present in self.items");
1322 (item, dormant_items)
1323 };
1324
1325 let (hash, dormant_item) = {
1326 let (item, dormant_item): (&'a mut T, _) =
1327 DormantMutRef::new(item);
1328 // Use T::key(item) rather than item.key() to force the key
1329 // trait function to be called for T rather than &mut T.
1330 let key = T::key(item);
1331 let hash = hash_state.hash_one(key);
1332 (MapHash::new(hash), dormant_item)
1333 };
1334
1335 let retain = {
1336 // SAFETY: The original item is no longer used after the second
1337 // block above. dormant_items, from which item is derived, is
1338 // currently dormant.
1339 let item = unsafe { dormant_item.awaken() };
1340
1341 let ref_mut = RefMut::new(hash_state.clone(), hash, item);
1342 f(ref_mut)
1343 };
1344
1345 if retain {
1346 true
1347 } else {
1348 // SAFETY: The original items is no longer used after the first
1349 // block above, and item + dormant item have been used above.
1350 let items = unsafe { dormant_items.awaken() };
1351 items.remove(index);
1352 false
1353 }
1354 });
1355 }
1356
1357 fn find_index<'a, Q>(&'a self, k: &Q) -> Option<ItemIndex>
1358 where
1359 Q: Hash + Equivalent<T::Key<'a>> + ?Sized,
1360 {
1361 self.tables
1362 .key_to_item
1363 .find_index(&self.tables.state, k, |index| self.items[index].key())
1364 }
1365
1366 fn make_hash(&self, item: &T) -> MapHash {
1367 self.tables.make_hash(item)
1368 }
1369
1370 fn make_key_hash(&self, key: &T::Key<'_>) -> MapHash {
1371 self.tables.make_key_hash::<T>(key)
1372 }
1373
1374 pub(super) fn get_by_index(&self, index: ItemIndex) -> Option<&T> {
1375 self.items.get(index)
1376 }
1377
1378 pub(super) fn get_by_index_mut(
1379 &mut self,
1380 index: ItemIndex,
1381 ) -> Option<RefMut<'_, T, S>> {
1382 let state = self.tables.state.clone();
1383 let hashes = self.make_hash(&self.items[index]);
1384 let item = &mut self.items[index];
1385 Some(RefMut::new(state, hashes, item))
1386 }
1387
1388 pub(super) fn insert_unique_impl(
1389 &mut self,
1390 value: T,
1391 ) -> Result<ItemIndex, DuplicateItem<T, &T>> {
1392 let mut duplicates = BTreeSet::new();
1393
1394 // Check for duplicates *before* inserting the new item, because we
1395 // don't want to partially insert the new item and then have to roll
1396 // back.
1397 let key = value.key();
1398 let state = &self.tables.state;
1399
1400 let entry = match self
1401 .tables
1402 .key_to_item
1403 .entry(state, key, |index| self.items[index].key())
1404 {
1405 hash_table::Entry::Occupied(slot) => {
1406 duplicates.insert(*slot.get());
1407 None
1408 }
1409 hash_table::Entry::Vacant(slot) => Some(slot),
1410 };
1411
1412 if !duplicates.is_empty() {
1413 return Err(DuplicateItem::__internal_new(
1414 value,
1415 duplicates.iter().map(|ix| &self.items[*ix]).collect(),
1416 ));
1417 }
1418
1419 let next_index = self.items.assert_can_grow().insert(value);
1420 entry.unwrap().insert(next_index);
1421
1422 Ok(next_index)
1423 }
1424
1425 pub(super) fn remove_by_index(
1426 &mut self,
1427 remove_index: ItemIndex,
1428 ) -> Option<T> {
1429 // For panic safety, look up the table entry while `self.items` still
1430 // holds the value, then remove from the table and items in sequence.
1431 // hashbrown's `find_entry` is panic-safe under user-`Hash`/`Eq` panics
1432 // (the table is not mutated until `OccupiedEntry::remove` is called),
1433 // so a panic during the lookup leaves both items and the table
1434 // unmodified.
1435 let key = self.items.get(remove_index)?.key();
1436 let state = &self.tables.state;
1437 let Ok(item) =
1438 self.tables
1439 .key_to_item
1440 .find_entry(state, &key, |index| self.items[index].key())
1441 else {
1442 panic!("we just looked this item up");
1443 };
1444 // Drop the key so that `self.items` can be mutated below.
1445 drop(key);
1446 item.remove();
1447 Some(
1448 self.items
1449 .remove(remove_index)
1450 .expect("items[remove_index] was Occupied above"),
1451 )
1452 }
1453
1454 pub(super) fn replace_at_index(&mut self, index: ItemIndex, value: T) -> T {
1455 // We check the key before removing it, to avoid leaving the map in an
1456 // inconsistent state.
1457 let old_key =
1458 self.get_by_index(index).expect("index is known to be valid").key();
1459 if T::upcast_key(old_key) != value.key() {
1460 panic!(
1461 "must insert a value with \
1462 the same key used to create the entry"
1463 );
1464 }
1465
1466 // Now that we know the key is the same, we can replace the value
1467 // directly without needing to tweak any tables.
1468 self.items.replace(index, value)
1469 }
1470}
1471
1472impl<'a, T, S: Clone + BuildHasher, A: Allocator> fmt::Debug
1473 for IdHashMap<T, S, A>
1474where
1475 T: IdHashItem + fmt::Debug,
1476 T::Key<'a>: fmt::Debug,
1477 T: 'a,
1478{
1479 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1480 let mut map = f.debug_map();
1481
1482 for item in self.iter() {
1483 let key = item.key();
1484
1485 // SAFETY:
1486 //
1487 // * Lifetime extension: for a type T and two lifetime params 'a and
1488 // 'b, T<'a> and T<'b> aren't guaranteed to have the same layout,
1489 // but (a) that is true today and (b) it would be shocking and
1490 // break half the Rust ecosystem if that were to change in the
1491 // future.
1492 // * We only use key within the scope of this block before immediately
1493 // dropping it. In particular, map.entry calls key.fmt() without
1494 // holding a reference to it.
1495 let key: T::Key<'a> =
1496 unsafe { core::mem::transmute::<T::Key<'_>, T::Key<'a>>(key) };
1497
1498 map.entry(&key, item);
1499 }
1500 map.finish()
1501 }
1502}
1503
1504impl<T: IdHashItem + PartialEq, S: Clone + BuildHasher, A: Allocator> PartialEq
1505 for IdHashMap<T, S, A>
1506{
1507 fn eq(&self, other: &Self) -> bool {
1508 // Implementing PartialEq for IdHashMap is tricky because IdHashMap is
1509 // not semantically like an IndexMap: two maps are equivalent even if
1510 // their items are in a different order. In other words, any permutation
1511 // of items is equivalent.
1512 //
1513 // We also can't sort the items because they're not necessarily Ord.
1514 //
1515 // So we write a custom equality check that checks that each key in one
1516 // map points to the same item as in the other map.
1517
1518 if self.items.len() != other.items.len() {
1519 return false;
1520 }
1521
1522 // Walk over all the items in the first map and check that they point to
1523 // the same item in the second map.
1524 for item in self.items.values() {
1525 let k1 = item.key();
1526
1527 // Check that the indexes are the same in the other map.
1528 let Some(other_ix) = other.find_index(&k1) else {
1529 return false;
1530 };
1531
1532 // Check that the other map's item is the same as this map's
1533 // item. (This is what we use the `PartialEq` bound on T for.)
1534 //
1535 // Because we've checked that other_ix is Some, we know that it is
1536 // valid and points to the expected item.
1537 let other_item = &other.items[other_ix];
1538 if item != other_item {
1539 return false;
1540 }
1541 }
1542
1543 true
1544 }
1545}
1546
1547// The Eq bound on T ensures that the TriHashMap forms an equivalence class.
1548impl<T: IdHashItem + Eq, S: Clone + BuildHasher, A: Allocator> Eq
1549 for IdHashMap<T, S, A>
1550{
1551}
1552
1553/// The `Extend` implementation overwrites duplicates. In the future, there will
1554/// also be an `extend_unique` method that will return an error.
1555///
1556/// # Examples
1557///
1558/// ```
1559/// # #[cfg(feature = "default-hasher")] {
1560/// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1561///
1562/// #[derive(Debug, PartialEq, Eq, Hash)]
1563/// struct Item {
1564/// id: String,
1565/// value: u32,
1566/// }
1567///
1568/// impl IdHashItem for Item {
1569/// type Key<'a> = &'a str;
1570/// fn key(&self) -> Self::Key<'_> {
1571/// &self.id
1572/// }
1573/// id_upcast!();
1574/// }
1575///
1576/// let mut map = IdHashMap::new();
1577/// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1578///
1579/// let new_items = vec![
1580/// Item { id: "foo".to_string(), value: 100 }, // overwrites existing
1581/// Item { id: "bar".to_string(), value: 20 }, // new item
1582/// ];
1583///
1584/// map.extend(new_items);
1585/// assert_eq!(map.len(), 2);
1586/// assert_eq!(map.get("foo").unwrap().value, 100); // overwritten
1587/// assert_eq!(map.get("bar").unwrap().value, 20); // new
1588///
1589/// # }
1590/// ```
1591impl<T: IdHashItem, S: Clone + BuildHasher, A: Allocator> Extend<T>
1592 for IdHashMap<T, S, A>
1593{
1594 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
1595 // Keys may already be present in the map, or multiple times in the
1596 // iterator. Reserve the entire hint lower bound if the map is empty.
1597 // Otherwise reserve half the hint (rounded up), so the map will only
1598 // resize twice in the worst case.
1599 let iter = iter.into_iter();
1600 let reserve = if self.is_empty() {
1601 iter.size_hint().0
1602 } else {
1603 iter.size_hint().0.div_ceil(2)
1604 };
1605 self.reserve(reserve);
1606 for item in iter {
1607 self.insert_overwrite(item);
1608 }
1609 }
1610}
1611
1612impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
1613 for &'a IdHashMap<T, S, A>
1614{
1615 type Item = &'a T;
1616 type IntoIter = Iter<'a, T>;
1617
1618 /// Creates an iterator over references to the items in the map.
1619 ///
1620 /// # Examples
1621 ///
1622 /// ```
1623 /// # #[cfg(feature = "default-hasher")] {
1624 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1625 ///
1626 /// #[derive(Debug, PartialEq, Eq, Hash)]
1627 /// struct Item {
1628 /// id: String,
1629 /// value: u32,
1630 /// }
1631 ///
1632 /// impl IdHashItem for Item {
1633 /// type Key<'a> = &'a str;
1634 /// fn key(&self) -> Self::Key<'_> {
1635 /// &self.id
1636 /// }
1637 /// id_upcast!();
1638 /// }
1639 ///
1640 /// let mut map = IdHashMap::new();
1641 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1642 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1643 ///
1644 /// let mut values: Vec<u32> =
1645 /// (&map).into_iter().map(|item| item.value).collect();
1646 /// values.sort();
1647 /// assert_eq!(values, vec![20, 42]);
1648 /// # }
1649 /// ```
1650 #[inline]
1651 fn into_iter(self) -> Self::IntoIter {
1652 self.iter()
1653 }
1654}
1655
1656impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
1657 for &'a mut IdHashMap<T, S, A>
1658{
1659 type Item = RefMut<'a, T, S>;
1660 type IntoIter = IterMut<'a, T, S, A>;
1661
1662 /// Creates an iterator over mutable references to the items in the map.
1663 ///
1664 /// # Examples
1665 ///
1666 /// ```
1667 /// # #[cfg(feature = "default-hasher")] {
1668 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1669 ///
1670 /// #[derive(Debug, PartialEq, Eq, Hash)]
1671 /// struct Item {
1672 /// id: String,
1673 /// value: u32,
1674 /// }
1675 ///
1676 /// impl IdHashItem for Item {
1677 /// type Key<'a> = &'a str;
1678 /// fn key(&self) -> Self::Key<'_> {
1679 /// &self.id
1680 /// }
1681 /// id_upcast!();
1682 /// }
1683 ///
1684 /// let mut map = IdHashMap::new();
1685 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1686 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1687 ///
1688 /// for mut item in &mut map {
1689 /// item.value *= 2;
1690 /// }
1691 ///
1692 /// assert_eq!(map.get("foo").unwrap().value, 84);
1693 /// assert_eq!(map.get("bar").unwrap().value, 40);
1694 /// # }
1695 /// ```
1696 #[inline]
1697 fn into_iter(self) -> Self::IntoIter {
1698 self.iter_mut()
1699 }
1700}
1701
1702impl<T: IdHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
1703 for IdHashMap<T, S, A>
1704{
1705 type Item = T;
1706 type IntoIter = IntoIter<T, A>;
1707
1708 /// Consumes the map and creates an iterator over the owned items.
1709 ///
1710 /// # Examples
1711 ///
1712 /// ```
1713 /// # #[cfg(feature = "default-hasher")] {
1714 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1715 ///
1716 /// #[derive(Debug, PartialEq, Eq, Hash)]
1717 /// struct Item {
1718 /// id: String,
1719 /// value: u32,
1720 /// }
1721 ///
1722 /// impl IdHashItem for Item {
1723 /// type Key<'a> = &'a str;
1724 /// fn key(&self) -> Self::Key<'_> {
1725 /// &self.id
1726 /// }
1727 /// id_upcast!();
1728 /// }
1729 ///
1730 /// let mut map = IdHashMap::new();
1731 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1732 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1733 ///
1734 /// let mut values: Vec<u32> = map.into_iter().map(|item| item.value).collect();
1735 /// values.sort();
1736 /// assert_eq!(values, vec![20, 42]);
1737 /// # }
1738 /// ```
1739 #[inline]
1740 fn into_iter(self) -> Self::IntoIter {
1741 IntoIter::new(self.items)
1742 }
1743}
1744
1745/// The `FromIterator` implementation for `IdHashMap` overwrites duplicate
1746/// items.
1747///
1748/// # Examples
1749///
1750/// ```
1751/// # #[cfg(feature = "default-hasher")] {
1752/// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1753///
1754/// #[derive(Debug, PartialEq, Eq, Hash)]
1755/// struct Item {
1756/// id: String,
1757/// value: u32,
1758/// }
1759///
1760/// impl IdHashItem for Item {
1761/// type Key<'a> = &'a str;
1762/// fn key(&self) -> Self::Key<'_> {
1763/// &self.id
1764/// }
1765/// id_upcast!();
1766/// }
1767///
1768/// let items = vec![
1769/// Item { id: "foo".to_string(), value: 42 },
1770/// Item { id: "bar".to_string(), value: 20 },
1771/// Item { id: "foo".to_string(), value: 100 }, // duplicate key, overwrites
1772/// ];
1773///
1774/// let map: IdHashMap<Item> = items.into_iter().collect();
1775/// assert_eq!(map.len(), 2);
1776/// assert_eq!(map.get("foo").unwrap().value, 100); // last value wins
1777/// assert_eq!(map.get("bar").unwrap().value, 20);
1778/// # }
1779/// ```
1780impl<T: IdHashItem, S: Default + Clone + BuildHasher, A: Allocator + Default>
1781 FromIterator<T> for IdHashMap<T, S, A>
1782{
1783 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1784 let mut map = IdHashMap::default();
1785 for item in iter {
1786 map.insert_overwrite(item);
1787 }
1788 map
1789 }
1790}