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<
68 T: IdHashItem,
69 S = DefaultHashBuilder,
70 A: Allocator = Global,
71> {
72 pub(super) items: ItemSet<T, A>,
73 tables: IdHashMapTables<S, A>,
74}
75
76impl<T: IdHashItem, S: Default, A: Allocator + Default> Default
77 for IdHashMap<T, S, A>
78{
79 fn default() -> Self {
80 Self {
81 items: ItemSet::with_capacity_in(0, A::default()),
82 tables: IdHashMapTables::default(),
83 }
84 }
85}
86
87#[cfg(feature = "default-hasher")]
88impl<T: IdHashItem> IdHashMap<T> {
89 /// Creates a new, empty `IdHashMap`.
90 ///
91 /// # Examples
92 ///
93 /// ```
94 /// # #[cfg(feature = "default-hasher")] {
95 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
96 ///
97 /// #[derive(Debug, PartialEq, Eq, Hash)]
98 /// struct Item {
99 /// id: String,
100 /// value: u32,
101 /// }
102 ///
103 /// impl IdHashItem for Item {
104 /// type Key<'a> = &'a str;
105 /// fn key(&self) -> Self::Key<'_> {
106 /// &self.id
107 /// }
108 /// id_upcast!();
109 /// }
110 ///
111 /// let map: IdHashMap<Item> = IdHashMap::new();
112 /// assert!(map.is_empty());
113 /// assert_eq!(map.len(), 0);
114 /// # }
115 /// ```
116 #[inline]
117 pub fn new() -> Self {
118 Self { items: ItemSet::default(), tables: IdHashMapTables::default() }
119 }
120
121 /// Creates a new `IdHashMap` with the given capacity.
122 ///
123 /// # Examples
124 ///
125 /// ```
126 /// # #[cfg(feature = "default-hasher")] {
127 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
128 ///
129 /// #[derive(Debug, PartialEq, Eq, Hash)]
130 /// struct Item {
131 /// id: String,
132 /// value: u32,
133 /// }
134 ///
135 /// impl IdHashItem for Item {
136 /// type Key<'a> = &'a str;
137 /// fn key(&self) -> Self::Key<'_> {
138 /// &self.id
139 /// }
140 /// id_upcast!();
141 /// }
142 ///
143 /// let map: IdHashMap<Item> = IdHashMap::with_capacity(10);
144 /// assert!(map.capacity() >= 10);
145 /// assert!(map.is_empty());
146 /// # }
147 /// ```
148 pub fn with_capacity(capacity: usize) -> Self {
149 Self {
150 items: ItemSet::with_capacity_in(capacity, global_alloc()),
151 tables: IdHashMapTables::with_capacity_and_hasher_in(
152 capacity,
153 DefaultHashBuilder::default(),
154 global_alloc(),
155 ),
156 }
157 }
158}
159
160impl<T: IdHashItem, S: Clone + BuildHasher> IdHashMap<T, S> {
161 /// Creates a new, empty `IdHashMap` with the given hasher.
162 ///
163 /// # Examples
164 ///
165 /// ```
166 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
167 /// use std::collections::hash_map::RandomState;
168 ///
169 /// #[derive(Debug, PartialEq, Eq, Hash)]
170 /// struct Item {
171 /// id: String,
172 /// value: u32,
173 /// }
174 ///
175 /// impl IdHashItem for Item {
176 /// type Key<'a> = &'a str;
177 /// fn key(&self) -> Self::Key<'_> {
178 /// &self.id
179 /// }
180 /// id_upcast!();
181 /// }
182 ///
183 /// let hasher = RandomState::new();
184 /// let map: IdHashMap<Item, _> = IdHashMap::with_hasher(hasher);
185 /// assert!(map.is_empty());
186 /// ```
187 pub fn with_hasher(hasher: S) -> Self {
188 Self {
189 items: ItemSet::default(),
190 tables: IdHashMapTables::with_capacity_and_hasher_in(
191 0,
192 hasher,
193 global_alloc(),
194 ),
195 }
196 }
197
198 /// Creates a new `IdHashMap` with the given capacity and hasher.
199 ///
200 /// # Examples
201 ///
202 /// ```
203 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
204 /// use std::collections::hash_map::RandomState;
205 ///
206 /// #[derive(Debug, PartialEq, Eq, Hash)]
207 /// struct Item {
208 /// id: String,
209 /// value: u32,
210 /// }
211 ///
212 /// impl IdHashItem for Item {
213 /// type Key<'a> = &'a str;
214 /// fn key(&self) -> Self::Key<'_> {
215 /// &self.id
216 /// }
217 /// id_upcast!();
218 /// }
219 ///
220 /// let hasher = RandomState::new();
221 /// let map: IdHashMap<Item, _> =
222 /// IdHashMap::with_capacity_and_hasher(10, hasher);
223 /// assert!(map.capacity() >= 10);
224 /// assert!(map.is_empty());
225 /// ```
226 pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
227 Self {
228 items: ItemSet::with_capacity_in(capacity, global_alloc()),
229 tables: IdHashMapTables::with_capacity_and_hasher_in(
230 capacity,
231 hasher,
232 global_alloc(),
233 ),
234 }
235 }
236}
237
238#[cfg(feature = "default-hasher")]
239impl<T: IdHashItem, A: Clone + Allocator> IdHashMap<T, DefaultHashBuilder, A> {
240 /// Creates a new empty `IdHashMap` using the given allocator.
241 ///
242 /// Requires the `allocator-api2` feature to be enabled.
243 ///
244 /// # Examples
245 ///
246 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
247 ///
248 /// ```
249 /// # #[cfg(all(feature = "default-hasher", feature = "allocator-api2"))] {
250 /// use iddqd::{IdHashMap, IdHashItem, id_upcast};
251 /// # use iddqd_test_utils::bumpalo;
252 ///
253 /// #[derive(Debug, PartialEq, Eq, Hash)]
254 /// struct Item {
255 /// id: String,
256 /// value: u32,
257 /// }
258 ///
259 /// impl IdHashItem for Item {
260 /// type Key<'a> = &'a str;
261 /// fn key(&self) -> Self::Key<'_> { &self.id }
262 /// id_upcast!();
263 /// }
264 ///
265 /// // Define a new allocator.
266 /// let bump = bumpalo::Bump::new();
267 /// // Create a new IdHashMap using the allocator.
268 /// let map: IdHashMap<Item, _, &bumpalo::Bump> = IdHashMap::new_in(&bump);
269 /// assert!(map.is_empty());
270 /// # }
271 /// ```
272 pub fn new_in(alloc: A) -> Self {
273 Self {
274 items: ItemSet::with_capacity_in(0, alloc.clone()),
275 tables: IdHashMapTables::with_capacity_and_hasher_in(
276 0,
277 DefaultHashBuilder::default(),
278 alloc,
279 ),
280 }
281 }
282
283 /// Creates an empty `IdHashMap` with the specified capacity using the given
284 /// allocator.
285 ///
286 /// Requires the `allocator-api2` feature to be enabled.
287 ///
288 /// # Examples
289 ///
290 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
291 ///
292 /// ```
293 /// # #[cfg(all(feature = "default-hasher", feature = "allocator-api2"))] {
294 /// use iddqd::{IdHashMap, IdHashItem, id_upcast};
295 /// # use iddqd_test_utils::bumpalo;
296 ///
297 /// #[derive(Debug, PartialEq, Eq, Hash)]
298 /// struct Item {
299 /// id: String,
300 /// value: u32,
301 /// }
302 ///
303 /// impl IdHashItem for Item {
304 /// type Key<'a> = &'a str;
305 /// fn key(&self) -> Self::Key<'_> { &self.id }
306 /// id_upcast!();
307 /// }
308 ///
309 /// // Define a new allocator.
310 /// let bump = bumpalo::Bump::new();
311 /// // Create a new IdHashMap with capacity using the allocator.
312 /// let map: IdHashMap<Item, _, &bumpalo::Bump> = IdHashMap::with_capacity_in(10, &bump);
313 /// assert!(map.capacity() >= 10);
314 /// assert!(map.is_empty());
315 /// # }
316 /// ```
317 pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
318 Self {
319 items: ItemSet::with_capacity_in(capacity, alloc.clone()),
320 tables: IdHashMapTables::with_capacity_and_hasher_in(
321 capacity,
322 DefaultHashBuilder::default(),
323 alloc,
324 ),
325 }
326 }
327}
328
329impl<T: IdHashItem, S: Clone + BuildHasher, A: Clone + Allocator>
330 IdHashMap<T, S, A>
331{
332 /// Creates a new, empty `IdHashMap` with the given hasher and allocator.
333 ///
334 /// Requires the `allocator-api2` feature to be enabled.
335 ///
336 /// # Examples
337 ///
338 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
339 ///
340 /// ```
341 /// # #[cfg(feature = "allocator-api2")] {
342 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
343 /// use std::collections::hash_map::RandomState;
344 /// # use iddqd_test_utils::bumpalo;
345 ///
346 /// #[derive(Debug, PartialEq, Eq, Hash)]
347 /// struct Item {
348 /// id: String,
349 /// value: u32,
350 /// }
351 ///
352 /// impl IdHashItem for Item {
353 /// type Key<'a> = &'a str;
354 /// fn key(&self) -> Self::Key<'_> {
355 /// &self.id
356 /// }
357 /// id_upcast!();
358 /// }
359 ///
360 /// // Define a new allocator.
361 /// let bump = bumpalo::Bump::new();
362 /// let hasher = RandomState::new();
363 /// // Create a new IdHashMap with hasher using the allocator.
364 /// let map: IdHashMap<Item, _, &bumpalo::Bump> =
365 /// IdHashMap::with_hasher_in(hasher, &bump);
366 /// assert!(map.is_empty());
367 /// # }
368 /// ```
369 pub fn with_hasher_in(hasher: S, alloc: A) -> Self {
370 Self {
371 items: ItemSet::with_capacity_in(0, alloc.clone()),
372 tables: IdHashMapTables::with_capacity_and_hasher_in(
373 0, hasher, alloc,
374 ),
375 }
376 }
377
378 /// Creates a new, empty `IdHashMap` with the given capacity, hasher, and
379 /// allocator.
380 ///
381 /// Requires the `allocator-api2` feature to be enabled.
382 ///
383 /// # Examples
384 ///
385 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
386 ///
387 /// ```
388 /// # #[cfg(feature = "allocator-api2")] {
389 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
390 /// use std::collections::hash_map::RandomState;
391 /// # use iddqd_test_utils::bumpalo;
392 ///
393 /// #[derive(Debug, PartialEq, Eq, Hash)]
394 /// struct Item {
395 /// id: String,
396 /// value: u32,
397 /// }
398 ///
399 /// impl IdHashItem for Item {
400 /// type Key<'a> = &'a str;
401 /// fn key(&self) -> Self::Key<'_> {
402 /// &self.id
403 /// }
404 /// id_upcast!();
405 /// }
406 ///
407 /// // Define a new allocator.
408 /// let bump = bumpalo::Bump::new();
409 /// let hasher = RandomState::new();
410 /// // Create a new IdHashMap with capacity and hasher using the allocator.
411 /// let map: IdHashMap<Item, _, &bumpalo::Bump> =
412 /// IdHashMap::with_capacity_and_hasher_in(10, hasher, &bump);
413 /// assert!(map.capacity() >= 10);
414 /// assert!(map.is_empty());
415 /// # }
416 /// ```
417 pub fn with_capacity_and_hasher_in(
418 capacity: usize,
419 hasher: S,
420 alloc: A,
421 ) -> Self {
422 Self {
423 items: ItemSet::with_capacity_in(capacity, alloc.clone()),
424 tables: IdHashMapTables::with_capacity_and_hasher_in(
425 capacity, hasher, alloc,
426 ),
427 }
428 }
429}
430
431impl<T: IdHashItem, S: Clone + BuildHasher, A: Allocator> IdHashMap<T, S, A> {
432 #[cfg(feature = "daft")]
433 pub(crate) fn hasher(&self) -> &S {
434 self.tables.hasher()
435 }
436
437 /// Returns the allocator.
438 ///
439 /// Requires the `allocator-api2` feature to be enabled.
440 ///
441 /// # Examples
442 ///
443 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
444 ///
445 /// ```
446 /// # #[cfg(all(feature = "default-hasher", feature = "allocator-api2"))] {
447 /// use iddqd::{IdHashMap, IdHashItem, id_upcast};
448 /// # use iddqd_test_utils::bumpalo;
449 ///
450 /// #[derive(Debug, PartialEq, Eq, Hash)]
451 /// struct Item {
452 /// id: String,
453 /// value: u32,
454 /// }
455 ///
456 /// impl IdHashItem for Item {
457 /// type Key<'a> = &'a str;
458 /// fn key(&self) -> Self::Key<'_> { &self.id }
459 /// id_upcast!();
460 /// }
461 ///
462 /// // Define a new allocator.
463 /// let bump = bumpalo::Bump::new();
464 /// // Create a new IdHashMap using the allocator.
465 /// let map: IdHashMap<Item, _, &bumpalo::Bump> = IdHashMap::new_in(&bump);
466 /// let _allocator = map.allocator();
467 /// # }
468 /// ```
469 pub fn allocator(&self) -> &A {
470 self.items.allocator()
471 }
472
473 /// Returns the currently allocated capacity of the map.
474 ///
475 /// # Examples
476 ///
477 /// ```
478 /// # #[cfg(feature = "default-hasher")] {
479 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
480 ///
481 /// #[derive(Debug, PartialEq, Eq, Hash)]
482 /// struct Item {
483 /// id: String,
484 /// value: u32,
485 /// }
486 ///
487 /// impl IdHashItem for Item {
488 /// type Key<'a> = &'a str;
489 /// fn key(&self) -> Self::Key<'_> {
490 /// &self.id
491 /// }
492 /// id_upcast!();
493 /// }
494 ///
495 /// let map: IdHashMap<Item> = IdHashMap::with_capacity(10);
496 /// assert!(map.capacity() >= 10);
497 /// # }
498 /// ```
499 pub fn capacity(&self) -> usize {
500 // items and tables.capacity might theoretically diverge: use
501 // items.capacity.
502 self.items.capacity()
503 }
504
505 /// Returns true if the map is empty.
506 ///
507 /// # Examples
508 ///
509 /// ```
510 /// # #[cfg(feature = "default-hasher")] {
511 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
512 ///
513 /// #[derive(Debug, PartialEq, Eq, Hash)]
514 /// struct Item {
515 /// id: String,
516 /// value: u32,
517 /// }
518 ///
519 /// impl IdHashItem for Item {
520 /// type Key<'a> = &'a str;
521 /// fn key(&self) -> Self::Key<'_> {
522 /// &self.id
523 /// }
524 /// id_upcast!();
525 /// }
526 ///
527 /// let mut map = IdHashMap::new();
528 /// assert!(map.is_empty());
529 ///
530 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
531 /// assert!(!map.is_empty());
532 /// # }
533 /// ```
534 #[inline]
535 pub fn is_empty(&self) -> bool {
536 self.items.is_empty()
537 }
538
539 /// Returns the number of items in the map.
540 ///
541 /// # Examples
542 ///
543 /// ```
544 /// # #[cfg(feature = "default-hasher")] {
545 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
546 ///
547 /// #[derive(Debug, PartialEq, Eq, Hash)]
548 /// struct Item {
549 /// id: String,
550 /// value: u32,
551 /// }
552 ///
553 /// impl IdHashItem for Item {
554 /// type Key<'a> = &'a str;
555 /// fn key(&self) -> Self::Key<'_> {
556 /// &self.id
557 /// }
558 /// id_upcast!();
559 /// }
560 ///
561 /// let mut map = IdHashMap::new();
562 /// assert_eq!(map.len(), 0);
563 ///
564 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
565 /// assert_eq!(map.len(), 1);
566 ///
567 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
568 /// assert_eq!(map.len(), 2);
569 /// # }
570 /// ```
571 #[inline]
572 pub fn len(&self) -> usize {
573 self.items.len()
574 }
575
576 /// Iterates over the items in the map.
577 ///
578 /// Similar to [`HashMap`], the iteration order is arbitrary and not
579 /// guaranteed to be stable.
580 ///
581 /// # Examples
582 ///
583 /// ```
584 /// # #[cfg(feature = "default-hasher")] {
585 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
586 ///
587 /// #[derive(Debug, PartialEq, Eq, Hash)]
588 /// struct Item {
589 /// id: String,
590 /// value: u32,
591 /// }
592 ///
593 /// impl IdHashItem for Item {
594 /// type Key<'a> = &'a str;
595 /// fn key(&self) -> Self::Key<'_> {
596 /// &self.id
597 /// }
598 /// id_upcast!();
599 /// }
600 ///
601 /// let mut map = IdHashMap::new();
602 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
603 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
604 ///
605 /// let mut values: Vec<u32> = map.iter().map(|item| item.value).collect();
606 /// values.sort();
607 /// assert_eq!(values, vec![20, 42]);
608 /// # }
609 /// ```
610 ///
611 /// [`HashMap`]: std::collections::HashMap
612 #[inline]
613 pub fn iter(&self) -> Iter<'_, T> {
614 Iter::new(&self.items)
615 }
616
617 /// Iterates over the items in the map, allowing for mutation.
618 ///
619 /// Similar to [`HashMap`], the iteration order is arbitrary and not
620 /// guaranteed to be stable.
621 ///
622 /// # Examples
623 ///
624 /// ```
625 /// # #[cfg(feature = "default-hasher")] {
626 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
627 ///
628 /// #[derive(Debug, PartialEq, Eq, Hash)]
629 /// struct Item {
630 /// id: String,
631 /// value: u32,
632 /// }
633 ///
634 /// impl IdHashItem for Item {
635 /// type Key<'a> = &'a str;
636 /// fn key(&self) -> Self::Key<'_> {
637 /// &self.id
638 /// }
639 /// id_upcast!();
640 /// }
641 ///
642 /// let mut map = IdHashMap::new();
643 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
644 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
645 ///
646 /// for mut item in map.iter_mut() {
647 /// item.value *= 2;
648 /// }
649 ///
650 /// assert_eq!(map.get("foo").unwrap().value, 84);
651 /// assert_eq!(map.get("bar").unwrap().value, 40);
652 /// # }
653 /// ```
654 ///
655 /// [`HashMap`]: std::collections::HashMap
656 #[inline]
657 pub fn iter_mut(&mut self) -> IterMut<'_, T, S, A> {
658 IterMut::new(&self.tables, &mut self.items)
659 }
660
661 /// Checks general invariants of the map.
662 ///
663 /// The code below always upholds these invariants, but it's useful to have
664 /// an explicit check for tests.
665 #[doc(hidden)]
666 pub fn validate(
667 &self,
668 compactness: ValidateCompact,
669 ) -> Result<(), ValidationError>
670 where
671 T: fmt::Debug,
672 {
673 self.items.validate(compactness)?;
674 self.tables.validate(self.len(), compactness)?;
675
676 // Check that the indexes are all correct.
677 for (&ix, item) in self.items.iter() {
678 let key = item.key();
679 let Some(ix1) = self.find_index(&key) else {
680 return Err(ValidationError::general(format!(
681 "item at index {ix} has no key1 index"
682 )));
683 };
684
685 if ix1 != ix {
686 return Err(ValidationError::General(format!(
687 "item at index {ix} has mismatched indexes: ix1: {ix1}",
688 )));
689 }
690 }
691
692 Ok(())
693 }
694
695 /// Inserts a value into the map, removing and returning the conflicting
696 /// item, if any.
697 ///
698 /// # Examples
699 ///
700 /// ```
701 /// # #[cfg(feature = "default-hasher")] {
702 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
703 ///
704 /// #[derive(Debug, PartialEq, Eq, Hash)]
705 /// struct Item {
706 /// id: String,
707 /// value: u32,
708 /// }
709 ///
710 /// impl IdHashItem for Item {
711 /// type Key<'a> = &'a str;
712 /// fn key(&self) -> Self::Key<'_> {
713 /// &self.id
714 /// }
715 /// id_upcast!();
716 /// }
717 ///
718 /// let mut map = IdHashMap::new();
719 ///
720 /// // First insertion returns None
721 /// let old = map.insert_overwrite(Item { id: "foo".to_string(), value: 42 });
722 /// assert!(old.is_none());
723 ///
724 /// // Second insertion with same key returns the old value
725 /// let old = map.insert_overwrite(Item { id: "foo".to_string(), value: 100 });
726 /// assert_eq!(old.unwrap().value, 42);
727 /// assert_eq!(map.get("foo").unwrap().value, 100);
728 /// # }
729 /// ```
730 #[doc(alias = "insert")]
731 pub fn insert_overwrite(&mut self, value: T) -> Option<T> {
732 // Trying to write this function for maximal efficiency can get very
733 // tricky, requiring delicate handling of indexes. We follow a very
734 // simple approach instead:
735 //
736 // 1. Remove items corresponding to the key that is already in the map.
737 // 2. Add the item to the map.
738
739 let duplicate = self.remove(&value.key());
740
741 if self.insert_unique(value).is_err() {
742 // We should never get here, because we just removed all the
743 // duplicates.
744 panic!("insert_unique failed after removing duplicates");
745 }
746
747 duplicate
748 }
749
750 /// Inserts a value into the set, returning an error if any duplicates were
751 /// added.
752 ///
753 /// # Examples
754 ///
755 /// ```
756 /// # #[cfg(feature = "default-hasher")] {
757 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
758 ///
759 /// #[derive(Debug, PartialEq, Eq, Hash)]
760 /// struct Item {
761 /// id: String,
762 /// value: u32,
763 /// }
764 ///
765 /// impl IdHashItem for Item {
766 /// type Key<'a> = &'a str;
767 /// fn key(&self) -> Self::Key<'_> {
768 /// &self.id
769 /// }
770 /// id_upcast!();
771 /// }
772 ///
773 /// let mut map = IdHashMap::new();
774 ///
775 /// // First insertion succeeds
776 /// assert!(
777 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).is_ok()
778 /// );
779 ///
780 /// // Second insertion with different key succeeds
781 /// assert!(
782 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).is_ok()
783 /// );
784 ///
785 /// // Third insertion with duplicate key fails
786 /// assert!(
787 /// map.insert_unique(Item { id: "foo".to_string(), value: 100 }).is_err()
788 /// );
789 /// # }
790 /// ```
791 pub fn insert_unique(
792 &mut self,
793 value: T,
794 ) -> Result<(), DuplicateItem<T, &T>> {
795 let _ = self.insert_unique_impl(value)?;
796 Ok(())
797 }
798
799 /// Returns true if the map contains the given key.
800 ///
801 /// # Examples
802 ///
803 /// ```
804 /// # #[cfg(feature = "default-hasher")] {
805 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
806 ///
807 /// #[derive(Debug, PartialEq, Eq, Hash)]
808 /// struct Item {
809 /// id: String,
810 /// value: u32,
811 /// }
812 ///
813 /// impl IdHashItem for Item {
814 /// type Key<'a> = &'a str;
815 /// fn key(&self) -> Self::Key<'_> {
816 /// &self.id
817 /// }
818 /// id_upcast!();
819 /// }
820 ///
821 /// let mut map = IdHashMap::new();
822 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
823 ///
824 /// assert!(map.contains_key("foo"));
825 /// assert!(!map.contains_key("bar"));
826 /// # }
827 /// ```
828 pub fn contains_key<'a, Q>(&'a self, key1: &Q) -> bool
829 where
830 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
831 {
832 self.find_index(key1).is_some()
833 }
834
835 /// Gets a reference to the value associated with the given key.
836 ///
837 /// # Examples
838 ///
839 /// ```
840 /// # #[cfg(feature = "default-hasher")] {
841 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
842 ///
843 /// #[derive(Debug, PartialEq, Eq, Hash)]
844 /// struct Item {
845 /// id: String,
846 /// value: u32,
847 /// }
848 ///
849 /// impl IdHashItem for Item {
850 /// type Key<'a> = &'a str;
851 /// fn key(&self) -> Self::Key<'_> {
852 /// &self.id
853 /// }
854 /// id_upcast!();
855 /// }
856 ///
857 /// let mut map = IdHashMap::new();
858 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
859 ///
860 /// assert_eq!(map.get("foo").unwrap().value, 42);
861 /// assert!(map.get("bar").is_none());
862 /// # }
863 /// ```
864 pub fn get<'a, Q>(&'a self, key: &Q) -> Option<&'a T>
865 where
866 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
867 {
868 self.find_index(key).map(|ix| &self.items[ix])
869 }
870
871 /// Gets a mutable reference to the value associated with the given key.
872 ///
873 /// # Examples
874 ///
875 /// ```
876 /// # #[cfg(feature = "default-hasher")] {
877 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
878 ///
879 /// #[derive(Debug, PartialEq, Eq, Hash)]
880 /// struct Item {
881 /// id: String,
882 /// value: u32,
883 /// }
884 ///
885 /// impl IdHashItem for Item {
886 /// type Key<'a> = &'a str;
887 /// fn key(&self) -> Self::Key<'_> {
888 /// &self.id
889 /// }
890 /// id_upcast!();
891 /// }
892 ///
893 /// let mut map = IdHashMap::new();
894 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
895 ///
896 /// if let Some(mut item) = map.get_mut("foo") {
897 /// item.value = 100;
898 /// }
899 ///
900 /// assert_eq!(map.get("foo").unwrap().value, 100);
901 /// assert!(map.get_mut("bar").is_none());
902 /// # }
903 /// ```
904 pub fn get_mut<'a, Q>(&'a mut self, key: &Q) -> Option<RefMut<'a, T, S>>
905 where
906 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
907 {
908 let (dormant_map, index) = {
909 let (map, dormant_map) = DormantMutRef::new(self);
910 let index = map.find_index(key)?;
911 (dormant_map, index)
912 };
913
914 // SAFETY: `map` is not used after this point.
915 let awakened_map = unsafe { dormant_map.awaken() };
916 let item = &mut awakened_map.items[index];
917 let hashes = awakened_map.tables.make_hash(item);
918 Some(RefMut::new(hashes, item))
919 }
920
921 /// Removes an item from the map by its key.
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 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
945 ///
946 /// let removed = map.remove("foo");
947 /// assert_eq!(removed.unwrap().value, 42);
948 /// assert!(map.is_empty());
949 ///
950 /// // Removing non-existent key returns None
951 /// assert!(map.remove("bar").is_none());
952 /// # }
953 /// ```
954 pub fn remove<'a, Q>(&'a mut self, key: &Q) -> Option<T>
955 where
956 Q: ?Sized + Hash + Equivalent<T::Key<'a>>,
957 {
958 let (dormant_map, remove_index) = {
959 let (map, dormant_map) = DormantMutRef::new(self);
960 let remove_index = map.find_index(key)?;
961 (dormant_map, remove_index)
962 };
963
964 // SAFETY: `map` is not used after this point.
965 let awakened_map = unsafe { dormant_map.awaken() };
966
967 let value = awakened_map
968 .items
969 .remove(remove_index)
970 .expect("items missing key1 that was just retrieved");
971
972 // Remove the value from the tables.
973 let Ok(item1) =
974 awakened_map.tables.key_to_item.find_entry(&value.key(), |index| {
975 if index == remove_index {
976 value.key()
977 } else {
978 awakened_map.items[index].key()
979 }
980 })
981 else {
982 // The item was not found.
983 panic!("we just looked this item up");
984 };
985
986 item1.remove();
987
988 Some(value)
989 }
990
991 /// Retrieves an entry by its key.
992 ///
993 /// Due to borrow checker limitations, this always accepts an owned key
994 /// rather than a borrowed form of it.
995 ///
996 /// # Examples
997 ///
998 /// ```
999 /// # #[cfg(feature = "default-hasher")] {
1000 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1001 ///
1002 /// #[derive(Debug, PartialEq, Eq, Hash)]
1003 /// struct Item {
1004 /// id: String,
1005 /// value: u32,
1006 /// }
1007 ///
1008 /// impl IdHashItem for Item {
1009 /// type Key<'a> = &'a str;
1010 /// fn key(&self) -> Self::Key<'_> {
1011 /// &self.id
1012 /// }
1013 /// id_upcast!();
1014 /// }
1015 ///
1016 /// let mut map = IdHashMap::new();
1017 ///
1018 /// // Use entry API for conditional insertion
1019 /// map.entry("foo").or_insert(Item { id: "foo".to_string(), value: 42 });
1020 /// map.entry("bar").or_insert(Item { id: "bar".to_string(), value: 20 });
1021 ///
1022 /// assert_eq!(map.len(), 2);
1023 /// # }
1024 /// ```
1025 pub fn entry<'a>(&'a mut self, key: T::Key<'_>) -> Entry<'a, T, S, A> {
1026 // Why does this always take an owned key? Well, it would seem like we
1027 // should be able to pass in any Q that is equivalent. That results in
1028 // *this* code compiling fine, but callers have trouble using it because
1029 // the borrow checker believes the keys are borrowed for the full 'a
1030 // rather than a shorter lifetime.
1031 //
1032 // By accepting owned keys, we can use the upcast functions to convert
1033 // them to a shorter lifetime (so this function accepts T::Key<'_>
1034 // rather than T::Key<'a>).
1035 //
1036 // Really, the solution here is to allow GATs to require covariant
1037 // parameters. If that were allowed, the borrow checker should be able
1038 // to figure out that keys don't need to be borrowed for the full 'a,
1039 // just for some shorter lifetime.
1040 let (map, dormant_map) = DormantMutRef::new(self);
1041 let key = T::upcast_key(key);
1042 {
1043 // index is explicitly typed to show that it has a trivial Drop impl
1044 // that doesn't capture anything from map.
1045 let index: Option<usize> = map
1046 .tables
1047 .key_to_item
1048 .find_index(&key, |index| map.items[index].key());
1049 if let Some(index) = index {
1050 drop(key);
1051 return Entry::Occupied(
1052 // SAFETY: `map` is not used after this point.
1053 unsafe { OccupiedEntry::new(dormant_map, index) },
1054 );
1055 }
1056 }
1057 let hash = map.make_key_hash(&key);
1058 Entry::Vacant(
1059 // SAFETY: `map` is not used after this point.
1060 unsafe { VacantEntry::new(dormant_map, hash) },
1061 )
1062 }
1063
1064 fn find_index<'a, Q>(&'a self, k: &Q) -> Option<usize>
1065 where
1066 Q: Hash + Equivalent<T::Key<'a>> + ?Sized,
1067 {
1068 self.tables.key_to_item.find_index(k, |index| self.items[index].key())
1069 }
1070
1071 fn make_hash(&self, item: &T) -> MapHash<S> {
1072 self.tables.make_hash(item)
1073 }
1074
1075 fn make_key_hash(&self, key: &T::Key<'_>) -> MapHash<S> {
1076 self.tables.make_key_hash::<T>(key)
1077 }
1078
1079 pub(super) fn get_by_index(&self, index: usize) -> Option<&T> {
1080 self.items.get(index)
1081 }
1082
1083 pub(super) fn get_by_index_mut(
1084 &mut self,
1085 index: usize,
1086 ) -> Option<RefMut<'_, T, S>> {
1087 let hashes = self.make_hash(&self.items[index]);
1088 let item = &mut self.items[index];
1089 Some(RefMut::new(hashes, item))
1090 }
1091
1092 pub(super) fn insert_unique_impl(
1093 &mut self,
1094 value: T,
1095 ) -> Result<usize, DuplicateItem<T, &T>> {
1096 let mut duplicates = BTreeSet::new();
1097
1098 // Check for duplicates *before* inserting the new item, because we
1099 // don't want to partially insert the new item and then have to roll
1100 // back.
1101 let key = value.key();
1102
1103 let entry = match self
1104 .tables
1105 .key_to_item
1106 .entry(key, |index| self.items[index].key())
1107 {
1108 hash_table::Entry::Occupied(slot) => {
1109 duplicates.insert(*slot.get());
1110 None
1111 }
1112 hash_table::Entry::Vacant(slot) => Some(slot),
1113 };
1114
1115 if !duplicates.is_empty() {
1116 return Err(DuplicateItem::__internal_new(
1117 value,
1118 duplicates.iter().map(|ix| &self.items[*ix]).collect(),
1119 ));
1120 }
1121
1122 let next_index = self.items.insert_at_next_index(value);
1123 entry.unwrap().insert(next_index);
1124
1125 Ok(next_index)
1126 }
1127
1128 pub(super) fn remove_by_index(&mut self, remove_index: usize) -> Option<T> {
1129 let value = self.items.remove(remove_index)?;
1130
1131 // Remove the value from the tables.
1132 let Ok(item) =
1133 self.tables.key_to_item.find_entry(&value.key(), |index| {
1134 if index == remove_index {
1135 value.key()
1136 } else {
1137 self.items[index].key()
1138 }
1139 })
1140 else {
1141 // The item was not found.
1142 panic!("we just looked this item up");
1143 };
1144
1145 item.remove();
1146
1147 Some(value)
1148 }
1149
1150 pub(super) fn replace_at_index(&mut self, index: usize, value: T) -> T {
1151 // We check the key before removing it, to avoid leaving the map in an
1152 // inconsistent state.
1153 let old_key =
1154 self.get_by_index(index).expect("index is known to be valid").key();
1155 if T::upcast_key(old_key) != value.key() {
1156 panic!(
1157 "must insert a value with \
1158 the same key used to create the entry"
1159 );
1160 }
1161
1162 // Now that we know the key is the same, we can replace the value
1163 // directly without needing to tweak any tables.
1164 self.items.replace(index, value)
1165 }
1166}
1167
1168impl<'a, T, S: Clone + BuildHasher, A: Allocator> fmt::Debug
1169 for IdHashMap<T, S, A>
1170where
1171 T: IdHashItem + fmt::Debug,
1172 T::Key<'a>: fmt::Debug,
1173 T: 'a,
1174{
1175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1176 let mut map = f.debug_map();
1177
1178 for item in self.iter() {
1179 let key = item.key();
1180
1181 // SAFETY:
1182 //
1183 // * Lifetime extension: for a type T and two lifetime params 'a and
1184 // 'b, T<'a> and T<'b> aren't guaranteed to have the same layout,
1185 // but (a) that is true today and (b) it would be shocking and
1186 // break half the Rust ecosystem if that were to change in the
1187 // future.
1188 // * We only use key within the scope of this block before immediately
1189 // dropping it. In particular, map.entry calls key.fmt() without
1190 // holding a reference to it.
1191 let key: T::Key<'a> =
1192 unsafe { core::mem::transmute::<T::Key<'_>, T::Key<'a>>(key) };
1193
1194 map.entry(&key, item);
1195 }
1196 map.finish()
1197 }
1198}
1199
1200impl<T: IdHashItem + PartialEq, S: Clone + BuildHasher, A: Allocator> PartialEq
1201 for IdHashMap<T, S, A>
1202{
1203 fn eq(&self, other: &Self) -> bool {
1204 // Implementing PartialEq for IdHashMap is tricky because IdHashMap is
1205 // not semantically like an IndexMap: two maps are equivalent even if
1206 // their items are in a different order. In other words, any permutation
1207 // of items is equivalent.
1208 //
1209 // We also can't sort the items because they're not necessarily Ord.
1210 //
1211 // So we write a custom equality check that checks that each key in one
1212 // map points to the same item as in the other map.
1213
1214 if self.items.len() != other.items.len() {
1215 return false;
1216 }
1217
1218 // Walk over all the items in the first map and check that they point to
1219 // the same item in the second map.
1220 for item in self.items.values() {
1221 let k1 = item.key();
1222
1223 // Check that the indexes are the same in the other map.
1224 let Some(other_ix) = other.find_index(&k1) else {
1225 return false;
1226 };
1227
1228 // Check that the other map's item is the same as this map's
1229 // item. (This is what we use the `PartialEq` bound on T for.)
1230 //
1231 // Because we've checked that other_ix is Some, we know that it is
1232 // valid and points to the expected item.
1233 let other_item = &other.items[other_ix];
1234 if item != other_item {
1235 return false;
1236 }
1237 }
1238
1239 true
1240 }
1241}
1242
1243// The Eq bound on T ensures that the TriHashMap forms an equivalence class.
1244impl<T: IdHashItem + Eq, S: Clone + BuildHasher, A: Allocator> Eq
1245 for IdHashMap<T, S, A>
1246{
1247}
1248
1249/// The `Extend` implementation overwrites duplicates. In the future, there will
1250/// also be an `extend_unique` method that will return an error.
1251///
1252/// # Examples
1253///
1254/// ```
1255/// # #[cfg(feature = "default-hasher")] {
1256/// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1257///
1258/// #[derive(Debug, PartialEq, Eq, Hash)]
1259/// struct Item {
1260/// id: String,
1261/// value: u32,
1262/// }
1263///
1264/// impl IdHashItem for Item {
1265/// type Key<'a> = &'a str;
1266/// fn key(&self) -> Self::Key<'_> {
1267/// &self.id
1268/// }
1269/// id_upcast!();
1270/// }
1271///
1272/// let mut map = IdHashMap::new();
1273/// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1274///
1275/// let new_items = vec![
1276/// Item { id: "foo".to_string(), value: 100 }, // overwrites existing
1277/// Item { id: "bar".to_string(), value: 20 }, // new item
1278/// ];
1279///
1280/// map.extend(new_items);
1281/// assert_eq!(map.len(), 2);
1282/// assert_eq!(map.get("foo").unwrap().value, 100); // overwritten
1283/// assert_eq!(map.get("bar").unwrap().value, 20); // new
1284///
1285/// # }
1286/// ```
1287impl<T: IdHashItem, S: Clone + BuildHasher, A: Allocator> Extend<T>
1288 for IdHashMap<T, S, A>
1289{
1290 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
1291 for item in iter {
1292 self.insert_overwrite(item);
1293 }
1294 }
1295}
1296
1297impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
1298 for &'a IdHashMap<T, S, A>
1299{
1300 type Item = &'a T;
1301 type IntoIter = Iter<'a, T>;
1302
1303 /// Creates an iterator over references to the items in the map.
1304 ///
1305 /// # Examples
1306 ///
1307 /// ```
1308 /// # #[cfg(feature = "default-hasher")] {
1309 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1310 ///
1311 /// #[derive(Debug, PartialEq, Eq, Hash)]
1312 /// struct Item {
1313 /// id: String,
1314 /// value: u32,
1315 /// }
1316 ///
1317 /// impl IdHashItem for Item {
1318 /// type Key<'a> = &'a str;
1319 /// fn key(&self) -> Self::Key<'_> {
1320 /// &self.id
1321 /// }
1322 /// id_upcast!();
1323 /// }
1324 ///
1325 /// let mut map = IdHashMap::new();
1326 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1327 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1328 ///
1329 /// let mut values: Vec<u32> =
1330 /// (&map).into_iter().map(|item| item.value).collect();
1331 /// values.sort();
1332 /// assert_eq!(values, vec![20, 42]);
1333 /// # }
1334 /// ```
1335 #[inline]
1336 fn into_iter(self) -> Self::IntoIter {
1337 self.iter()
1338 }
1339}
1340
1341impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
1342 for &'a mut IdHashMap<T, S, A>
1343{
1344 type Item = RefMut<'a, T, S>;
1345 type IntoIter = IterMut<'a, T, S, A>;
1346
1347 /// Creates an iterator over mutable references to the items in the map.
1348 ///
1349 /// # Examples
1350 ///
1351 /// ```
1352 /// # #[cfg(feature = "default-hasher")] {
1353 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1354 ///
1355 /// #[derive(Debug, PartialEq, Eq, Hash)]
1356 /// struct Item {
1357 /// id: String,
1358 /// value: u32,
1359 /// }
1360 ///
1361 /// impl IdHashItem for Item {
1362 /// type Key<'a> = &'a str;
1363 /// fn key(&self) -> Self::Key<'_> {
1364 /// &self.id
1365 /// }
1366 /// id_upcast!();
1367 /// }
1368 ///
1369 /// let mut map = IdHashMap::new();
1370 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1371 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1372 ///
1373 /// for mut item in &mut map {
1374 /// item.value *= 2;
1375 /// }
1376 ///
1377 /// assert_eq!(map.get("foo").unwrap().value, 84);
1378 /// assert_eq!(map.get("bar").unwrap().value, 40);
1379 /// # }
1380 /// ```
1381 #[inline]
1382 fn into_iter(self) -> Self::IntoIter {
1383 self.iter_mut()
1384 }
1385}
1386
1387impl<T: IdHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
1388 for IdHashMap<T, S, A>
1389{
1390 type Item = T;
1391 type IntoIter = IntoIter<T, A>;
1392
1393 /// Consumes the map and creates an iterator over the owned items.
1394 ///
1395 /// # Examples
1396 ///
1397 /// ```
1398 /// # #[cfg(feature = "default-hasher")] {
1399 /// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1400 ///
1401 /// #[derive(Debug, PartialEq, Eq, Hash)]
1402 /// struct Item {
1403 /// id: String,
1404 /// value: u32,
1405 /// }
1406 ///
1407 /// impl IdHashItem for Item {
1408 /// type Key<'a> = &'a str;
1409 /// fn key(&self) -> Self::Key<'_> {
1410 /// &self.id
1411 /// }
1412 /// id_upcast!();
1413 /// }
1414 ///
1415 /// let mut map = IdHashMap::new();
1416 /// map.insert_unique(Item { id: "foo".to_string(), value: 42 }).unwrap();
1417 /// map.insert_unique(Item { id: "bar".to_string(), value: 20 }).unwrap();
1418 ///
1419 /// let mut values: Vec<u32> = map.into_iter().map(|item| item.value).collect();
1420 /// values.sort();
1421 /// assert_eq!(values, vec![20, 42]);
1422 /// # }
1423 /// ```
1424 #[inline]
1425 fn into_iter(self) -> Self::IntoIter {
1426 IntoIter::new(self.items)
1427 }
1428}
1429
1430/// The `FromIterator` implementation for `IdHashMap` overwrites duplicate
1431/// items.
1432///
1433/// # Examples
1434///
1435/// ```
1436/// # #[cfg(feature = "default-hasher")] {
1437/// use iddqd::{IdHashItem, IdHashMap, id_upcast};
1438///
1439/// #[derive(Debug, PartialEq, Eq, Hash)]
1440/// struct Item {
1441/// id: String,
1442/// value: u32,
1443/// }
1444///
1445/// impl IdHashItem for Item {
1446/// type Key<'a> = &'a str;
1447/// fn key(&self) -> Self::Key<'_> {
1448/// &self.id
1449/// }
1450/// id_upcast!();
1451/// }
1452///
1453/// let items = vec![
1454/// Item { id: "foo".to_string(), value: 42 },
1455/// Item { id: "bar".to_string(), value: 20 },
1456/// Item { id: "foo".to_string(), value: 100 }, // duplicate key, overwrites
1457/// ];
1458///
1459/// let map: IdHashMap<Item> = items.into_iter().collect();
1460/// assert_eq!(map.len(), 2);
1461/// assert_eq!(map.get("foo").unwrap().value, 100); // last value wins
1462/// assert_eq!(map.get("bar").unwrap().value, 20);
1463/// # }
1464/// ```
1465impl<T: IdHashItem, S: Default + Clone + BuildHasher, A: Allocator + Default>
1466 FromIterator<T> for IdHashMap<T, S, A>
1467{
1468 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1469 let mut map = IdHashMap::default();
1470 for item in iter {
1471 map.insert_overwrite(item);
1472 }
1473 map
1474 }
1475}