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