iddqd/tri_hash_map/imp.rs
1use super::{IntoIter, Iter, IterMut, RefMut, tables::TriHashMapTables};
2use crate::{
3 DefaultHashBuilder, TriHashItem,
4 errors::DuplicateItem,
5 internal::ValidationError,
6 support::{
7 ItemIndex,
8 alloc::{AllocWrapper, Allocator, Global, global_alloc},
9 borrow::DormantMutRef,
10 fmt_utils::StrDisplayAsDebug,
11 item_set::ItemSet,
12 map_hash::MapHash,
13 },
14};
15use alloc::{collections::BTreeSet, vec::Vec};
16use core::{
17 fmt,
18 hash::{BuildHasher, Hash},
19};
20use equivalent::Equivalent;
21use hashbrown::hash_table::{Entry, VacantEntry};
22
23/// A 1:1:1 (trijective) map for three keys and a value.
24///
25/// The storage mechanism is a fast hash table of integer indexes to items, with
26/// these indexes stored in three hashmaps. This allows for efficient lookups by
27/// any of the three keys, while preventing duplicates.
28///
29/// # Examples
30///
31/// ```
32/// # #[cfg(feature = "default-hasher")] {
33/// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
34///
35/// #[derive(Debug, PartialEq, Eq)]
36/// struct Person {
37/// id: u32,
38/// email: String,
39/// phone: String,
40/// name: String,
41/// }
42///
43/// // Implement TriHashItem to define the three key types.
44/// impl TriHashItem for Person {
45/// type K1<'a> = u32;
46/// type K2<'a> = &'a str;
47/// type K3<'a> = &'a str;
48///
49/// fn key1(&self) -> Self::K1<'_> {
50/// self.id
51/// }
52///
53/// fn key2(&self) -> Self::K2<'_> {
54/// &self.email
55/// }
56///
57/// fn key3(&self) -> Self::K3<'_> {
58/// &self.phone
59/// }
60///
61/// tri_upcast!();
62/// }
63///
64/// // Create a TriHashMap and insert items.
65/// let mut people = TriHashMap::new();
66/// people
67/// .insert_unique(Person {
68/// id: 1,
69/// email: "alice@example.com".to_string(),
70/// phone: "555-1234".to_string(),
71/// name: "Alice".to_string(),
72/// })
73/// .unwrap();
74///
75/// // Lookup by any of the three keys.
76/// let person = people.get1(&1).unwrap();
77/// assert_eq!(person.name, "Alice");
78///
79/// let person = people.get2("alice@example.com").unwrap();
80/// assert_eq!(person.id, 1);
81///
82/// let person = people.get3("555-1234").unwrap();
83/// assert_eq!(person.email, "alice@example.com");
84/// # }
85/// ```
86#[derive(Clone)]
87pub struct TriHashMap<T, S = DefaultHashBuilder, A: Allocator = Global> {
88 pub(super) items: ItemSet<T, A>,
89 // Invariant: the values (ItemIndex) in these tables are valid indexes into
90 // `items`, and are a 1:1 mapping.
91 tables: TriHashMapTables<S, A>,
92}
93
94impl<T: TriHashItem, S: Default, A: Allocator + Default> Default
95 for TriHashMap<T, S, A>
96{
97 fn default() -> Self {
98 Self {
99 items: ItemSet::with_capacity_in(0, A::default()),
100 tables: TriHashMapTables::default(),
101 }
102 }
103}
104
105#[cfg(feature = "default-hasher")]
106impl<T: TriHashItem> TriHashMap<T> {
107 /// Creates a new, empty `TriHashMap`.
108 ///
109 /// # Examples
110 ///
111 /// ```
112 /// # #[cfg(feature = "default-hasher")] {
113 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
114 ///
115 /// #[derive(Debug, PartialEq, Eq)]
116 /// struct Person {
117 /// id: u32,
118 /// email: String,
119 /// phone: String,
120 /// name: String,
121 /// }
122 ///
123 /// impl TriHashItem for Person {
124 /// type K1<'a> = u32;
125 /// type K2<'a> = &'a str;
126 /// type K3<'a> = &'a str;
127 ///
128 /// fn key1(&self) -> Self::K1<'_> {
129 /// self.id
130 /// }
131 /// fn key2(&self) -> Self::K2<'_> {
132 /// &self.email
133 /// }
134 /// fn key3(&self) -> Self::K3<'_> {
135 /// &self.phone
136 /// }
137 /// tri_upcast!();
138 /// }
139 ///
140 /// let map: TriHashMap<Person> = TriHashMap::new();
141 /// assert!(map.is_empty());
142 /// assert_eq!(map.len(), 0);
143 /// # }
144 /// ```
145 #[inline]
146 pub fn new() -> Self {
147 Self { items: ItemSet::new(), tables: TriHashMapTables::default() }
148 }
149
150 /// Creates a new `TriHashMap` with the given capacity.
151 ///
152 /// # Examples
153 ///
154 /// ```
155 /// # #[cfg(feature = "default-hasher")] {
156 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
157 ///
158 /// #[derive(Debug, PartialEq, Eq)]
159 /// struct Person {
160 /// id: u32,
161 /// email: String,
162 /// phone: String,
163 /// name: String,
164 /// }
165 ///
166 /// impl TriHashItem for Person {
167 /// type K1<'a> = u32;
168 /// type K2<'a> = &'a str;
169 /// type K3<'a> = &'a str;
170 ///
171 /// fn key1(&self) -> Self::K1<'_> {
172 /// self.id
173 /// }
174 /// fn key2(&self) -> Self::K2<'_> {
175 /// &self.email
176 /// }
177 /// fn key3(&self) -> Self::K3<'_> {
178 /// &self.phone
179 /// }
180 /// tri_upcast!();
181 /// }
182 ///
183 /// let map: TriHashMap<Person> = TriHashMap::with_capacity(10);
184 /// assert!(map.capacity() >= 10);
185 /// assert!(map.is_empty());
186 /// # }
187 /// ```
188 pub fn with_capacity(capacity: usize) -> Self {
189 Self {
190 items: ItemSet::with_capacity_in(capacity, global_alloc()),
191 tables: TriHashMapTables::with_capacity_and_hasher_in(
192 capacity,
193 DefaultHashBuilder::default(),
194 global_alloc(),
195 ),
196 }
197 }
198}
199
200impl<T: TriHashItem, S: BuildHasher> TriHashMap<T, S> {
201 /// Creates a new, empty `TriHashMap` with the given hasher.
202 ///
203 /// # Examples
204 ///
205 /// ```
206 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
207 /// use std::collections::hash_map::RandomState;
208 ///
209 /// #[derive(Debug, PartialEq, Eq)]
210 /// struct Person {
211 /// id: u32,
212 /// email: String,
213 /// phone: String,
214 /// name: String,
215 /// }
216 ///
217 /// impl TriHashItem for Person {
218 /// type K1<'a> = u32;
219 /// type K2<'a> = &'a str;
220 /// type K3<'a> = &'a str;
221 ///
222 /// fn key1(&self) -> Self::K1<'_> {
223 /// self.id
224 /// }
225 /// fn key2(&self) -> Self::K2<'_> {
226 /// &self.email
227 /// }
228 /// fn key3(&self) -> Self::K3<'_> {
229 /// &self.phone
230 /// }
231 /// tri_upcast!();
232 /// }
233 ///
234 /// let map: TriHashMap<Person, RandomState> =
235 /// TriHashMap::with_hasher(RandomState::new());
236 /// assert!(map.is_empty());
237 /// ```
238 pub const fn with_hasher(hasher: S) -> Self {
239 Self {
240 items: ItemSet::new(),
241 tables: TriHashMapTables::with_hasher(hasher),
242 }
243 }
244
245 /// Creates a new `TriHashMap` with the given capacity and hasher.
246 ///
247 /// # Examples
248 ///
249 /// ```
250 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
251 /// use std::collections::hash_map::RandomState;
252 ///
253 /// #[derive(Debug, PartialEq, Eq)]
254 /// struct Person {
255 /// id: u32,
256 /// email: String,
257 /// phone: String,
258 /// name: String,
259 /// }
260 ///
261 /// impl TriHashItem for Person {
262 /// type K1<'a> = u32;
263 /// type K2<'a> = &'a str;
264 /// type K3<'a> = &'a str;
265 ///
266 /// fn key1(&self) -> Self::K1<'_> {
267 /// self.id
268 /// }
269 /// fn key2(&self) -> Self::K2<'_> {
270 /// &self.email
271 /// }
272 /// fn key3(&self) -> Self::K3<'_> {
273 /// &self.phone
274 /// }
275 /// tri_upcast!();
276 /// }
277 ///
278 /// let map: TriHashMap<Person, RandomState> =
279 /// TriHashMap::with_capacity_and_hasher(10, RandomState::new());
280 /// assert!(map.capacity() >= 10);
281 /// assert!(map.is_empty());
282 /// ```
283 pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
284 Self {
285 items: ItemSet::with_capacity_in(capacity, global_alloc()),
286 tables: TriHashMapTables::with_capacity_and_hasher_in(
287 capacity,
288 hasher,
289 global_alloc(),
290 ),
291 }
292 }
293}
294
295#[cfg(feature = "default-hasher")]
296impl<T: TriHashItem, A: Clone + Allocator>
297 TriHashMap<T, DefaultHashBuilder, A>
298{
299 /// Creates a new empty `TriHashMap` using the given allocator.
300 ///
301 /// Requires the `allocator-api2` feature to be enabled.
302 ///
303 /// # Examples
304 ///
305 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
306 ///
307 /// ```
308 /// # #[cfg(all(feature = "default-hasher", feature = "allocator-api2"))] {
309 /// use iddqd::{TriHashMap, TriHashItem, tri_upcast};
310 /// # use iddqd_test_utils::bumpalo;
311 ///
312 /// #[derive(Debug, PartialEq, Eq)]
313 /// struct Person {
314 /// id: u32,
315 /// email: String,
316 /// phone: String,
317 /// name: String,
318 /// }
319 ///
320 /// impl TriHashItem for Person {
321 /// type K1<'a> = u32;
322 /// type K2<'a> = &'a str;
323 /// type K3<'a> = &'a str;
324 ///
325 /// fn key1(&self) -> Self::K1<'_> {
326 /// self.id
327 /// }
328 /// fn key2(&self) -> Self::K2<'_> {
329 /// &self.email
330 /// }
331 /// fn key3(&self) -> Self::K3<'_> {
332 /// &self.phone
333 /// }
334 /// tri_upcast!();
335 /// }
336 ///
337 /// // Define a new allocator.
338 /// let bump = bumpalo::Bump::new();
339 /// // Create a new TriHashMap using the allocator.
340 /// let map: TriHashMap<Person, _, &bumpalo::Bump> = TriHashMap::new_in(&bump);
341 /// assert!(map.is_empty());
342 /// # }
343 /// ```
344 pub fn new_in(alloc: A) -> Self {
345 Self {
346 items: ItemSet::with_capacity_in(0, alloc.clone()),
347 tables: TriHashMapTables::with_capacity_and_hasher_in(
348 0,
349 DefaultHashBuilder::default(),
350 alloc,
351 ),
352 }
353 }
354
355 /// Creates an empty `TriHashMap` with the specified capacity using the given
356 /// allocator.
357 ///
358 /// Requires the `allocator-api2` feature to be enabled.
359 ///
360 /// # Examples
361 ///
362 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
363 ///
364 /// ```
365 /// # #[cfg(all(feature = "default-hasher", feature = "allocator-api2"))] {
366 /// use iddqd::{TriHashMap, TriHashItem, tri_upcast};
367 /// # use iddqd_test_utils::bumpalo;
368 ///
369 /// #[derive(Debug, PartialEq, Eq)]
370 /// struct Person {
371 /// id: u32,
372 /// email: String,
373 /// phone: String,
374 /// name: String,
375 /// }
376 ///
377 /// impl TriHashItem for Person {
378 /// type K1<'a> = u32;
379 /// type K2<'a> = &'a str;
380 /// type K3<'a> = &'a str;
381 ///
382 /// fn key1(&self) -> Self::K1<'_> {
383 /// self.id
384 /// }
385 /// fn key2(&self) -> Self::K2<'_> {
386 /// &self.email
387 /// }
388 /// fn key3(&self) -> Self::K3<'_> {
389 /// &self.phone
390 /// }
391 /// tri_upcast!();
392 /// }
393 ///
394 /// // Define a new allocator.
395 /// let bump = bumpalo::Bump::new();
396 /// // Create a new TriHashMap with capacity using the allocator.
397 /// let map: TriHashMap<Person, _, &bumpalo::Bump> = TriHashMap::with_capacity_in(10, &bump);
398 /// assert!(map.capacity() >= 10);
399 /// assert!(map.is_empty());
400 /// # }
401 /// ```
402 pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
403 Self {
404 items: ItemSet::with_capacity_in(capacity, alloc.clone()),
405 tables: TriHashMapTables::with_capacity_and_hasher_in(
406 capacity,
407 DefaultHashBuilder::default(),
408 alloc,
409 ),
410 }
411 }
412}
413
414impl<T: TriHashItem, S: Clone + BuildHasher, A: Clone + Allocator>
415 TriHashMap<T, S, A>
416{
417 /// Creates a new, empty `TriHashMap` with the given hasher and allocator.
418 ///
419 /// Requires the `allocator-api2` feature to be enabled.
420 ///
421 /// # Examples
422 ///
423 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
424 ///
425 /// ```
426 /// # #[cfg(feature = "allocator-api2")] {
427 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
428 /// use std::collections::hash_map::RandomState;
429 /// # use iddqd_test_utils::bumpalo;
430 ///
431 /// #[derive(Debug, PartialEq, Eq)]
432 /// struct Person {
433 /// id: u32,
434 /// email: String,
435 /// phone: String,
436 /// name: String,
437 /// }
438 ///
439 /// impl TriHashItem for Person {
440 /// type K1<'a> = u32;
441 /// type K2<'a> = &'a str;
442 /// type K3<'a> = &'a str;
443 ///
444 /// fn key1(&self) -> Self::K1<'_> {
445 /// self.id
446 /// }
447 /// fn key2(&self) -> Self::K2<'_> {
448 /// &self.email
449 /// }
450 /// fn key3(&self) -> Self::K3<'_> {
451 /// &self.phone
452 /// }
453 /// tri_upcast!();
454 /// }
455 ///
456 /// // Define a new allocator.
457 /// let bump = bumpalo::Bump::new();
458 /// let hasher = RandomState::new();
459 /// // Create a new TriHashMap with hasher using the allocator.
460 /// let map: TriHashMap<Person, _, &bumpalo::Bump> =
461 /// TriHashMap::with_hasher_in(hasher, &bump);
462 /// assert!(map.is_empty());
463 /// # }
464 /// ```
465 pub fn with_hasher_in(hasher: S, alloc: A) -> Self {
466 Self {
467 items: ItemSet::with_capacity_in(0, alloc.clone()),
468 tables: TriHashMapTables::with_capacity_and_hasher_in(
469 0,
470 hasher.clone(),
471 alloc,
472 ),
473 }
474 }
475
476 /// Creates a new `TriHashMap` with the given capacity, hasher, and
477 /// allocator.
478 ///
479 /// Requires the `allocator-api2` feature to be enabled.
480 ///
481 /// # Examples
482 ///
483 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
484 ///
485 /// ```
486 /// # #[cfg(feature = "allocator-api2")] {
487 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
488 /// use std::collections::hash_map::RandomState;
489 /// # use iddqd_test_utils::bumpalo;
490 ///
491 /// #[derive(Debug, PartialEq, Eq)]
492 /// struct Person {
493 /// id: u32,
494 /// email: String,
495 /// phone: String,
496 /// name: String,
497 /// }
498 ///
499 /// impl TriHashItem for Person {
500 /// type K1<'a> = u32;
501 /// type K2<'a> = &'a str;
502 /// type K3<'a> = &'a str;
503 ///
504 /// fn key1(&self) -> Self::K1<'_> {
505 /// self.id
506 /// }
507 /// fn key2(&self) -> Self::K2<'_> {
508 /// &self.email
509 /// }
510 /// fn key3(&self) -> Self::K3<'_> {
511 /// &self.phone
512 /// }
513 /// tri_upcast!();
514 /// }
515 ///
516 /// // Define a new allocator.
517 /// let bump = bumpalo::Bump::new();
518 /// let hasher = RandomState::new();
519 /// // Create a new TriHashMap with capacity and hasher using the allocator.
520 /// let map: TriHashMap<Person, _, &bumpalo::Bump> =
521 /// TriHashMap::with_capacity_and_hasher_in(10, hasher, &bump);
522 /// assert!(map.capacity() >= 10);
523 /// assert!(map.is_empty());
524 /// # }
525 /// ```
526 pub fn with_capacity_and_hasher_in(
527 capacity: usize,
528 hasher: S,
529 alloc: A,
530 ) -> Self {
531 Self {
532 items: ItemSet::with_capacity_in(capacity, alloc.clone()),
533 tables: TriHashMapTables::with_capacity_and_hasher_in(
534 capacity, hasher, alloc,
535 ),
536 }
537 }
538}
539
540impl<T: TriHashItem, S: Clone + BuildHasher, A: Allocator> TriHashMap<T, S, A> {
541 /// Returns the hasher.
542 #[cfg(feature = "daft")]
543 #[inline]
544 pub(crate) fn hasher(&self) -> &S {
545 self.tables.hasher()
546 }
547
548 /// Returns the allocator.
549 ///
550 /// Requires the `allocator-api2` feature to be enabled.
551 ///
552 /// # Examples
553 ///
554 /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
555 ///
556 /// ```
557 /// # #[cfg(all(feature = "default-hasher", feature = "allocator-api2"))] {
558 /// use iddqd::{TriHashMap, TriHashItem, tri_upcast};
559 /// # use iddqd_test_utils::bumpalo;
560 ///
561 /// #[derive(Debug, PartialEq, Eq)]
562 /// struct Person {
563 /// id: u32,
564 /// email: String,
565 /// phone: String,
566 /// name: String,
567 /// }
568 ///
569 /// impl TriHashItem for Person {
570 /// type K1<'a> = u32;
571 /// type K2<'a> = &'a str;
572 /// type K3<'a> = &'a str;
573 ///
574 /// fn key1(&self) -> Self::K1<'_> {
575 /// self.id
576 /// }
577 /// fn key2(&self) -> Self::K2<'_> {
578 /// &self.email
579 /// }
580 /// fn key3(&self) -> Self::K3<'_> {
581 /// &self.phone
582 /// }
583 /// tri_upcast!();
584 /// }
585 ///
586 /// // Define a new allocator.
587 /// let bump = bumpalo::Bump::new();
588 /// // Create a new TriHashMap using the allocator.
589 /// let map: TriHashMap<Person, _, &bumpalo::Bump> = TriHashMap::new_in(&bump);
590 /// // Access the allocator.
591 /// let allocator = map.allocator();
592 /// # }
593 /// ```
594 #[inline]
595 pub fn allocator(&self) -> &A {
596 self.items.allocator()
597 }
598
599 /// Returns the currently allocated capacity of the map.
600 ///
601 /// # Examples
602 ///
603 /// ```
604 /// # #[cfg(feature = "default-hasher")] {
605 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
606 ///
607 /// #[derive(Debug, PartialEq, Eq)]
608 /// struct Person {
609 /// id: u32,
610 /// email: String,
611 /// phone: String,
612 /// name: String,
613 /// }
614 ///
615 /// impl TriHashItem for Person {
616 /// type K1<'a> = u32;
617 /// type K2<'a> = &'a str;
618 /// type K3<'a> = &'a str;
619 ///
620 /// fn key1(&self) -> Self::K1<'_> {
621 /// self.id
622 /// }
623 /// fn key2(&self) -> Self::K2<'_> {
624 /// &self.email
625 /// }
626 /// fn key3(&self) -> Self::K3<'_> {
627 /// &self.phone
628 /// }
629 /// tri_upcast!();
630 /// }
631 ///
632 /// let map: TriHashMap<Person> = TriHashMap::with_capacity(10);
633 /// assert!(map.capacity() >= 10);
634 /// # }
635 /// ```
636 pub fn capacity(&self) -> usize {
637 // items and tables.capacity might theoretically diverge: use
638 // items.capacity.
639 self.items.capacity()
640 }
641
642 /// Returns true if the map is empty.
643 ///
644 /// # Examples
645 ///
646 /// ```
647 /// # #[cfg(feature = "default-hasher")] {
648 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
649 ///
650 /// #[derive(Debug, PartialEq, Eq)]
651 /// struct Person {
652 /// id: u32,
653 /// email: String,
654 /// phone: String,
655 /// name: String,
656 /// }
657 ///
658 /// impl TriHashItem for Person {
659 /// type K1<'a> = u32;
660 /// type K2<'a> = &'a str;
661 /// type K3<'a> = &'a str;
662 ///
663 /// fn key1(&self) -> Self::K1<'_> {
664 /// self.id
665 /// }
666 /// fn key2(&self) -> Self::K2<'_> {
667 /// &self.email
668 /// }
669 /// fn key3(&self) -> Self::K3<'_> {
670 /// &self.phone
671 /// }
672 /// tri_upcast!();
673 /// }
674 ///
675 /// let mut map = TriHashMap::new();
676 /// assert!(map.is_empty());
677 ///
678 /// map.insert_unique(Person {
679 /// id: 1,
680 /// email: "alice@example.com".to_string(),
681 /// phone: "555-1234".to_string(),
682 /// name: "Alice".to_string(),
683 /// })
684 /// .unwrap();
685 /// assert!(!map.is_empty());
686 /// # }
687 /// ```
688 #[inline]
689 pub fn is_empty(&self) -> bool {
690 self.items.is_empty()
691 }
692
693 /// Returns the number of items in the map.
694 ///
695 /// # Examples
696 ///
697 /// ```
698 /// # #[cfg(feature = "default-hasher")] {
699 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
700 ///
701 /// #[derive(Debug, PartialEq, Eq)]
702 /// struct Person {
703 /// id: u32,
704 /// email: String,
705 /// phone: String,
706 /// name: String,
707 /// }
708 ///
709 /// impl TriHashItem for Person {
710 /// type K1<'a> = u32;
711 /// type K2<'a> = &'a str;
712 /// type K3<'a> = &'a str;
713 ///
714 /// fn key1(&self) -> Self::K1<'_> {
715 /// self.id
716 /// }
717 /// fn key2(&self) -> Self::K2<'_> {
718 /// &self.email
719 /// }
720 /// fn key3(&self) -> Self::K3<'_> {
721 /// &self.phone
722 /// }
723 /// tri_upcast!();
724 /// }
725 ///
726 /// let mut map = TriHashMap::new();
727 /// assert_eq!(map.len(), 0);
728 ///
729 /// map.insert_unique(Person {
730 /// id: 1,
731 /// email: "alice@example.com".to_string(),
732 /// phone: "555-1234".to_string(),
733 /// name: "Alice".to_string(),
734 /// })
735 /// .unwrap();
736 /// map.insert_unique(Person {
737 /// id: 2,
738 /// email: "bob@example.com".to_string(),
739 /// phone: "555-5678".to_string(),
740 /// name: "Bob".to_string(),
741 /// })
742 /// .unwrap();
743 /// assert_eq!(map.len(), 2);
744 /// # }
745 /// ```
746 #[inline]
747 pub fn len(&self) -> usize {
748 self.items.len()
749 }
750
751 /// Clears the map, removing all items.
752 ///
753 /// # Examples
754 ///
755 /// ```
756 /// # #[cfg(feature = "default-hasher")] {
757 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
758 ///
759 /// #[derive(Debug, PartialEq, Eq)]
760 /// struct Person {
761 /// id: u32,
762 /// email: String,
763 /// phone: String,
764 /// name: String,
765 /// }
766 ///
767 /// impl TriHashItem for Person {
768 /// type K1<'a> = u32;
769 /// type K2<'a> = &'a str;
770 /// type K3<'a> = &'a str;
771 ///
772 /// fn key1(&self) -> Self::K1<'_> {
773 /// self.id
774 /// }
775 /// fn key2(&self) -> Self::K2<'_> {
776 /// &self.email
777 /// }
778 /// fn key3(&self) -> Self::K3<'_> {
779 /// &self.phone
780 /// }
781 /// tri_upcast!();
782 /// }
783 ///
784 /// let mut map = TriHashMap::new();
785 /// map.insert_unique(Person {
786 /// id: 1,
787 /// email: "alice@example.com".to_string(),
788 /// phone: "555-1234".to_string(),
789 /// name: "Alice".to_string(),
790 /// })
791 /// .unwrap();
792 /// assert_eq!(map.len(), 1);
793 ///
794 /// map.clear();
795 /// assert!(map.is_empty());
796 /// assert_eq!(map.len(), 0);
797 /// # }
798 /// ```
799 pub fn clear(&mut self) {
800 self.items.clear();
801 self.tables.k1_to_item.clear();
802 self.tables.k2_to_item.clear();
803 self.tables.k3_to_item.clear();
804 }
805
806 /// Reserves capacity for at least `additional` more elements to be inserted
807 /// in the `TriHashMap`. The collection may reserve more space to
808 /// speculatively avoid frequent reallocations. After calling `reserve`,
809 /// capacity will be greater than or equal to `self.len() + additional`.
810 /// Does nothing if capacity is already sufficient.
811 ///
812 /// # Panics
813 ///
814 /// Panics if the new capacity overflows [`isize::MAX`] bytes, and
815 /// [`abort`]s the program in case of an allocation error. Use
816 /// [`try_reserve`](Self::try_reserve) instead if you want to handle memory
817 /// allocation failure.
818 ///
819 /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html
820 /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html
821 ///
822 /// # Examples
823 ///
824 /// ```
825 /// # #[cfg(feature = "default-hasher")] {
826 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
827 ///
828 /// #[derive(Debug, PartialEq, Eq, Hash)]
829 /// struct Item {
830 /// id: u32,
831 /// name: String,
832 /// email: String,
833 /// }
834 ///
835 /// impl TriHashItem for Item {
836 /// type K1<'a> = u32;
837 /// type K2<'a> = &'a str;
838 /// type K3<'a> = &'a str;
839 /// fn key1(&self) -> Self::K1<'_> {
840 /// self.id
841 /// }
842 /// fn key2(&self) -> Self::K2<'_> {
843 /// &self.name
844 /// }
845 /// fn key3(&self) -> Self::K3<'_> {
846 /// &self.email
847 /// }
848 /// tri_upcast!();
849 /// }
850 ///
851 /// let mut map: TriHashMap<Item> = TriHashMap::new();
852 /// map.reserve(100);
853 /// assert!(map.capacity() >= 100);
854 /// # }
855 /// ```
856 pub fn reserve(&mut self, additional: usize) {
857 self.items.reserve(additional);
858 let items = &self.items;
859 let state = &self.tables.state;
860 self.tables
861 .k1_to_item
862 .reserve(additional, |ix| state.hash_one(items[*ix].key1()));
863 self.tables
864 .k2_to_item
865 .reserve(additional, |ix| state.hash_one(items[*ix].key2()));
866 self.tables
867 .k3_to_item
868 .reserve(additional, |ix| state.hash_one(items[*ix].key3()));
869 }
870
871 /// Tries to reserve capacity for at least `additional` more elements to be
872 /// inserted in the `TriHashMap`. The collection may reserve more space to
873 /// speculatively avoid frequent reallocations. After calling `try_reserve`,
874 /// capacity will be greater than or equal to `self.len() + additional` if
875 /// it returns `Ok(())`. Does nothing if capacity is already sufficient.
876 ///
877 /// # Errors
878 ///
879 /// If the capacity overflows, or the allocator reports a failure, then an
880 /// error is returned.
881 ///
882 /// # Notes
883 ///
884 /// If reservation fails partway through, some internal structures may have
885 /// already increased their capacity. The map remains in a valid state but
886 /// may have uneven capacities across its internal structures.
887 ///
888 /// # Examples
889 ///
890 /// ```
891 /// # #[cfg(feature = "default-hasher")] {
892 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
893 ///
894 /// #[derive(Debug, PartialEq, Eq, Hash)]
895 /// struct Item {
896 /// id: u32,
897 /// name: String,
898 /// email: String,
899 /// }
900 ///
901 /// impl TriHashItem for Item {
902 /// type K1<'a> = u32;
903 /// type K2<'a> = &'a str;
904 /// type K3<'a> = &'a str;
905 /// fn key1(&self) -> Self::K1<'_> {
906 /// self.id
907 /// }
908 /// fn key2(&self) -> Self::K2<'_> {
909 /// &self.name
910 /// }
911 /// fn key3(&self) -> Self::K3<'_> {
912 /// &self.email
913 /// }
914 /// tri_upcast!();
915 /// }
916 ///
917 /// let mut map: TriHashMap<Item> = TriHashMap::new();
918 /// map.try_reserve(100).expect("allocation should succeed");
919 /// assert!(map.capacity() >= 100);
920 /// # }
921 /// ```
922 pub fn try_reserve(
923 &mut self,
924 additional: usize,
925 ) -> Result<(), crate::errors::TryReserveError> {
926 self.items.try_reserve(additional)?;
927 let items = &self.items;
928 let state = &self.tables.state;
929 self.tables
930 .k1_to_item
931 .try_reserve(additional, |ix| state.hash_one(items[*ix].key1()))
932 .map_err(crate::errors::TryReserveError::from_hashbrown)?;
933 self.tables
934 .k2_to_item
935 .try_reserve(additional, |ix| state.hash_one(items[*ix].key2()))
936 .map_err(crate::errors::TryReserveError::from_hashbrown)?;
937 self.tables
938 .k3_to_item
939 .try_reserve(additional, |ix| state.hash_one(items[*ix].key3()))
940 .map_err(crate::errors::TryReserveError::from_hashbrown)?;
941 Ok(())
942 }
943
944 /// Shrinks the capacity of the map as much as possible. It will drop
945 /// down as much as possible while maintaining the internal rules
946 /// and possibly leaving some space in accordance with the resize policy.
947 ///
948 /// # Examples
949 ///
950 /// ```
951 /// # #[cfg(feature = "default-hasher")] {
952 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
953 ///
954 /// #[derive(Debug, PartialEq, Eq, Hash)]
955 /// struct Item {
956 /// id: u32,
957 /// name: String,
958 /// email: String,
959 /// }
960 ///
961 /// impl TriHashItem for Item {
962 /// type K1<'a> = u32;
963 /// type K2<'a> = &'a str;
964 /// type K3<'a> = &'a str;
965 /// fn key1(&self) -> Self::K1<'_> {
966 /// self.id
967 /// }
968 /// fn key2(&self) -> Self::K2<'_> {
969 /// &self.name
970 /// }
971 /// fn key3(&self) -> Self::K3<'_> {
972 /// &self.email
973 /// }
974 /// tri_upcast!();
975 /// }
976 ///
977 /// let mut map: TriHashMap<Item> = TriHashMap::with_capacity(100);
978 /// map.insert_unique(Item {
979 /// id: 1,
980 /// name: "foo".to_string(),
981 /// email: "foo@example.com".to_string(),
982 /// })
983 /// .unwrap();
984 /// map.insert_unique(Item {
985 /// id: 2,
986 /// name: "bar".to_string(),
987 /// email: "bar@example.com".to_string(),
988 /// })
989 /// .unwrap();
990 /// assert!(map.capacity() >= 100);
991 /// map.shrink_to_fit();
992 /// assert!(map.capacity() >= 2);
993 /// # }
994 /// ```
995 pub fn shrink_to_fit(&mut self) {
996 let remap = self.items.shrink_to_fit();
997 if !remap.is_identity() {
998 self.tables.k1_to_item.remap_indexes(&remap);
999 self.tables.k2_to_item.remap_indexes(&remap);
1000 self.tables.k3_to_item.remap_indexes(&remap);
1001 }
1002 let items = &self.items;
1003 let state = &self.tables.state;
1004 self.tables
1005 .k1_to_item
1006 .shrink_to_fit(|ix| state.hash_one(items[*ix].key1()));
1007 self.tables
1008 .k2_to_item
1009 .shrink_to_fit(|ix| state.hash_one(items[*ix].key2()));
1010 self.tables
1011 .k3_to_item
1012 .shrink_to_fit(|ix| state.hash_one(items[*ix].key3()));
1013 }
1014
1015 /// Shrinks the capacity of the map with a lower limit. It will drop
1016 /// down no lower than the supplied limit while maintaining the internal
1017 /// rules and possibly leaving some space in accordance with the resize
1018 /// policy.
1019 ///
1020 /// If the current capacity is less than the lower limit, this is a no-op.
1021 ///
1022 /// # Examples
1023 ///
1024 /// ```
1025 /// # #[cfg(feature = "default-hasher")] {
1026 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1027 ///
1028 /// #[derive(Debug, PartialEq, Eq, Hash)]
1029 /// struct Item {
1030 /// id: u32,
1031 /// name: String,
1032 /// email: String,
1033 /// }
1034 ///
1035 /// impl TriHashItem for Item {
1036 /// type K1<'a> = u32;
1037 /// type K2<'a> = &'a str;
1038 /// type K3<'a> = &'a str;
1039 /// fn key1(&self) -> Self::K1<'_> {
1040 /// self.id
1041 /// }
1042 /// fn key2(&self) -> Self::K2<'_> {
1043 /// &self.name
1044 /// }
1045 /// fn key3(&self) -> Self::K3<'_> {
1046 /// &self.email
1047 /// }
1048 /// tri_upcast!();
1049 /// }
1050 ///
1051 /// let mut map: TriHashMap<Item> = TriHashMap::with_capacity(100);
1052 /// map.insert_unique(Item {
1053 /// id: 1,
1054 /// name: "foo".to_string(),
1055 /// email: "foo@example.com".to_string(),
1056 /// })
1057 /// .unwrap();
1058 /// map.insert_unique(Item {
1059 /// id: 2,
1060 /// name: "bar".to_string(),
1061 /// email: "bar@example.com".to_string(),
1062 /// })
1063 /// .unwrap();
1064 /// assert!(map.capacity() >= 100);
1065 /// map.shrink_to(10);
1066 /// assert!(map.capacity() >= 10);
1067 /// map.shrink_to(0);
1068 /// assert!(map.capacity() >= 2);
1069 /// # }
1070 /// ```
1071 pub fn shrink_to(&mut self, min_capacity: usize) {
1072 let remap = self.items.shrink_to(min_capacity);
1073 if !remap.is_identity() {
1074 self.tables.k1_to_item.remap_indexes(&remap);
1075 self.tables.k2_to_item.remap_indexes(&remap);
1076 self.tables.k3_to_item.remap_indexes(&remap);
1077 }
1078 let items = &self.items;
1079 let state = &self.tables.state;
1080 self.tables
1081 .k1_to_item
1082 .shrink_to(min_capacity, |ix| state.hash_one(items[*ix].key1()));
1083 self.tables
1084 .k2_to_item
1085 .shrink_to(min_capacity, |ix| state.hash_one(items[*ix].key2()));
1086 self.tables
1087 .k3_to_item
1088 .shrink_to(min_capacity, |ix| state.hash_one(items[*ix].key3()));
1089 }
1090
1091 /// Iterates over the items in the map.
1092 ///
1093 /// Similar to [`HashMap`], the iteration order is arbitrary and not
1094 /// guaranteed to be stable.
1095 ///
1096 /// # Examples
1097 ///
1098 /// ```
1099 /// # #[cfg(feature = "default-hasher")] {
1100 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1101 ///
1102 /// #[derive(Debug, PartialEq, Eq)]
1103 /// struct Person {
1104 /// id: u32,
1105 /// email: String,
1106 /// phone: String,
1107 /// name: String,
1108 /// }
1109 ///
1110 /// impl TriHashItem for Person {
1111 /// type K1<'a> = u32;
1112 /// type K2<'a> = &'a str;
1113 /// type K3<'a> = &'a str;
1114 ///
1115 /// fn key1(&self) -> Self::K1<'_> {
1116 /// self.id
1117 /// }
1118 /// fn key2(&self) -> Self::K2<'_> {
1119 /// &self.email
1120 /// }
1121 /// fn key3(&self) -> Self::K3<'_> {
1122 /// &self.phone
1123 /// }
1124 /// tri_upcast!();
1125 /// }
1126 ///
1127 /// let mut map = TriHashMap::new();
1128 /// map.insert_unique(Person {
1129 /// id: 1,
1130 /// email: "alice@example.com".to_string(),
1131 /// phone: "555-1234".to_string(),
1132 /// name: "Alice".to_string(),
1133 /// })
1134 /// .unwrap();
1135 /// map.insert_unique(Person {
1136 /// id: 2,
1137 /// email: "bob@example.com".to_string(),
1138 /// phone: "555-5678".to_string(),
1139 /// name: "Bob".to_string(),
1140 /// })
1141 /// .unwrap();
1142 ///
1143 /// let mut count = 0;
1144 /// for person in map.iter() {
1145 /// assert!(person.id == 1 || person.id == 2);
1146 /// count += 1;
1147 /// }
1148 /// assert_eq!(count, 2);
1149 /// # }
1150 /// ```
1151 ///
1152 /// [`HashMap`]: std::collections::HashMap
1153 #[inline]
1154 pub fn iter(&self) -> Iter<'_, T> {
1155 Iter::new(&self.items)
1156 }
1157
1158 /// Iterates over the items in the map, allowing for mutation.
1159 ///
1160 /// Similar to [`HashMap`], the iteration order is arbitrary and not
1161 /// guaranteed to be stable.
1162 ///
1163 /// # Examples
1164 ///
1165 /// ```
1166 /// # #[cfg(feature = "default-hasher")] {
1167 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1168 ///
1169 /// #[derive(Debug, PartialEq, Eq)]
1170 /// struct Person {
1171 /// id: u32,
1172 /// email: String,
1173 /// phone: String,
1174 /// name: String,
1175 /// }
1176 ///
1177 /// impl TriHashItem for Person {
1178 /// type K1<'a> = u32;
1179 /// type K2<'a> = &'a str;
1180 /// type K3<'a> = &'a str;
1181 ///
1182 /// fn key1(&self) -> Self::K1<'_> {
1183 /// self.id
1184 /// }
1185 /// fn key2(&self) -> Self::K2<'_> {
1186 /// &self.email
1187 /// }
1188 /// fn key3(&self) -> Self::K3<'_> {
1189 /// &self.phone
1190 /// }
1191 /// tri_upcast!();
1192 /// }
1193 ///
1194 /// let mut map = TriHashMap::new();
1195 /// map.insert_unique(Person {
1196 /// id: 1,
1197 /// email: "alice@example.com".to_string(),
1198 /// phone: "555-1234".to_string(),
1199 /// name: "Alice".to_string(),
1200 /// })
1201 /// .unwrap();
1202 ///
1203 /// for mut person in map.iter_mut() {
1204 /// person.name.push_str(" Updated");
1205 /// }
1206 ///
1207 /// let person = map.get1(&1).unwrap();
1208 /// assert_eq!(person.name, "Alice Updated");
1209 /// # }
1210 /// ```
1211 ///
1212 /// [`HashMap`]: std::collections::HashMap
1213 #[inline]
1214 pub fn iter_mut(&mut self) -> IterMut<'_, T, S, A> {
1215 IterMut::new(&self.tables, &mut self.items)
1216 }
1217
1218 /// Checks general invariants of the map.
1219 ///
1220 /// The code below always upholds these invariants, but it's useful to have
1221 /// an explicit check for tests.
1222 #[doc(hidden)]
1223 pub fn validate(
1224 &self,
1225 compactness: crate::internal::ValidateCompact,
1226 ) -> Result<(), ValidationError>
1227 where
1228 T: fmt::Debug,
1229 {
1230 self.items.validate(compactness)?;
1231 self.tables.validate(self.len(), compactness)?;
1232
1233 // Check that the indexes are all correct.
1234 for (ix, item) in self.items.iter() {
1235 let key1 = item.key1();
1236 let key2 = item.key2();
1237 let key3 = item.key3();
1238
1239 let Some(ix1) = self.find1_index(&key1) else {
1240 return Err(ValidationError::general(format!(
1241 "item at index {ix} has no key1 index"
1242 )));
1243 };
1244 let Some(ix2) = self.find2_index(&key2) else {
1245 return Err(ValidationError::general(format!(
1246 "item at index {ix} has no key2 index"
1247 )));
1248 };
1249 let Some(ix3) = self.find3_index(&key3) else {
1250 return Err(ValidationError::general(format!(
1251 "item at index {ix} has no key3 index"
1252 )));
1253 };
1254
1255 if ix1 != ix || ix2 != ix || ix3 != ix {
1256 return Err(ValidationError::general(format!(
1257 "item at index {ix} has inconsistent indexes: {ix1}/{ix2}/{ix3}"
1258 )));
1259 }
1260 }
1261
1262 Ok(())
1263 }
1264
1265 /// Inserts a value into the map, removing any conflicting items and
1266 /// returning a list of those items.
1267 ///
1268 /// # Examples
1269 ///
1270 /// ```
1271 /// # #[cfg(feature = "default-hasher")] {
1272 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1273 ///
1274 /// #[derive(Debug, PartialEq, Eq)]
1275 /// struct Person {
1276 /// id: u32,
1277 /// email: String,
1278 /// phone: String,
1279 /// name: String,
1280 /// }
1281 ///
1282 /// impl TriHashItem for Person {
1283 /// type K1<'a> = u32;
1284 /// type K2<'a> = &'a str;
1285 /// type K3<'a> = &'a str;
1286 ///
1287 /// fn key1(&self) -> Self::K1<'_> {
1288 /// self.id
1289 /// }
1290 /// fn key2(&self) -> Self::K2<'_> {
1291 /// &self.email
1292 /// }
1293 /// fn key3(&self) -> Self::K3<'_> {
1294 /// &self.phone
1295 /// }
1296 /// tri_upcast!();
1297 /// }
1298 ///
1299 /// let mut map = TriHashMap::new();
1300 ///
1301 /// // First insertion - no conflicts
1302 /// let overwritten = map.insert_overwrite(Person {
1303 /// id: 1,
1304 /// email: "alice@example.com".to_string(),
1305 /// phone: "555-1234".to_string(),
1306 /// name: "Alice".to_string(),
1307 /// });
1308 /// assert!(overwritten.is_empty());
1309 ///
1310 /// // Overwrite with same id - returns the old item
1311 /// let overwritten = map.insert_overwrite(Person {
1312 /// id: 1,
1313 /// email: "alice.new@example.com".to_string(),
1314 /// phone: "555-9999".to_string(),
1315 /// name: "Alice New".to_string(),
1316 /// });
1317 /// assert_eq!(overwritten.len(), 1);
1318 /// assert_eq!(overwritten[0].name, "Alice");
1319 /// # }
1320 /// ```
1321 #[doc(alias = "insert")]
1322 pub fn insert_overwrite(&mut self, value: T) -> Vec<T> {
1323 // Trying to write this function for maximal efficiency can get very
1324 // tricky, requiring delicate handling of indexes. We follow a very
1325 // simple approach instead:
1326 //
1327 // 1. Remove items corresponding to keys that are already in the map.
1328 // 2. Add the item to the map.
1329
1330 let mut duplicates = Vec::new();
1331 duplicates.extend(self.remove1(&value.key1()));
1332 duplicates.extend(self.remove2(&value.key2()));
1333 duplicates.extend(self.remove3(&value.key3()));
1334
1335 if self.insert_unique(value).is_err() {
1336 // We should never get here, because we just removed all the
1337 // duplicates.
1338 panic!("insert_unique failed after removing duplicates");
1339 }
1340
1341 duplicates
1342 }
1343
1344 /// Inserts a value into the set, returning an error if any duplicates were
1345 /// added.
1346 ///
1347 /// # Examples
1348 ///
1349 /// ```
1350 /// # #[cfg(feature = "default-hasher")] {
1351 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1352 ///
1353 /// #[derive(Debug, PartialEq, Eq)]
1354 /// struct Person {
1355 /// id: u32,
1356 /// email: String,
1357 /// phone: String,
1358 /// name: String,
1359 /// }
1360 ///
1361 /// impl TriHashItem for Person {
1362 /// type K1<'a> = u32;
1363 /// type K2<'a> = &'a str;
1364 /// type K3<'a> = &'a str;
1365 ///
1366 /// fn key1(&self) -> Self::K1<'_> {
1367 /// self.id
1368 /// }
1369 /// fn key2(&self) -> Self::K2<'_> {
1370 /// &self.email
1371 /// }
1372 /// fn key3(&self) -> Self::K3<'_> {
1373 /// &self.phone
1374 /// }
1375 /// tri_upcast!();
1376 /// }
1377 ///
1378 /// let mut map = TriHashMap::new();
1379 ///
1380 /// // Successful insertion
1381 /// assert!(
1382 /// map.insert_unique(Person {
1383 /// id: 1,
1384 /// email: "alice@example.com".to_string(),
1385 /// phone: "555-1234".to_string(),
1386 /// name: "Alice".to_string(),
1387 /// })
1388 /// .is_ok()
1389 /// );
1390 /// assert!(
1391 /// map.insert_unique(Person {
1392 /// id: 2,
1393 /// email: "bob@example.com".to_string(),
1394 /// phone: "555-5678".to_string(),
1395 /// name: "Bob".to_string(),
1396 /// })
1397 /// .is_ok()
1398 /// );
1399 ///
1400 /// // Duplicate key1
1401 /// assert!(
1402 /// map.insert_unique(Person {
1403 /// id: 1,
1404 /// email: "charlie@example.com".to_string(),
1405 /// phone: "555-9999".to_string(),
1406 /// name: "Charlie".to_string(),
1407 /// })
1408 /// .is_err()
1409 /// );
1410 ///
1411 /// // Duplicate key2
1412 /// assert!(
1413 /// map.insert_unique(Person {
1414 /// id: 3,
1415 /// email: "alice@example.com".to_string(),
1416 /// phone: "555-7777".to_string(),
1417 /// name: "Alice2".to_string(),
1418 /// })
1419 /// .is_err()
1420 /// );
1421 ///
1422 /// // Duplicate key3
1423 /// assert!(
1424 /// map.insert_unique(Person {
1425 /// id: 4,
1426 /// email: "dave@example.com".to_string(),
1427 /// phone: "555-1234".to_string(),
1428 /// name: "Dave".to_string(),
1429 /// })
1430 /// .is_err()
1431 /// );
1432 /// # }
1433 /// ```
1434 pub fn insert_unique(
1435 &mut self,
1436 value: T,
1437 ) -> Result<(), DuplicateItem<T, &T>> {
1438 let mut duplicates = BTreeSet::new();
1439
1440 // Check for duplicates *before* inserting the new item, because we
1441 // don't want to partially insert the new item and then have to roll
1442 // back.
1443 let state = &self.tables.state;
1444 let (e1, e2, e3) = {
1445 let k1 = value.key1();
1446 let k2 = value.key2();
1447 let k3 = value.key3();
1448
1449 let e1 = detect_dup_or_insert(
1450 self.tables
1451 .k1_to_item
1452 .entry(state, k1, |index| self.items[index].key1()),
1453 &mut duplicates,
1454 );
1455 let e2 = detect_dup_or_insert(
1456 self.tables
1457 .k2_to_item
1458 .entry(state, k2, |index| self.items[index].key2()),
1459 &mut duplicates,
1460 );
1461 let e3 = detect_dup_or_insert(
1462 self.tables
1463 .k3_to_item
1464 .entry(state, k3, |index| self.items[index].key3()),
1465 &mut duplicates,
1466 );
1467 (e1, e2, e3)
1468 };
1469
1470 if !duplicates.is_empty() {
1471 return Err(DuplicateItem::__internal_new(
1472 value,
1473 duplicates.iter().map(|ix| &self.items[*ix]).collect(),
1474 ));
1475 }
1476
1477 let next_index = self.items.assert_can_grow().insert(value);
1478 // e1, e2 and e3 are all Some because if they were None, duplicates
1479 // would be non-empty, and we'd have bailed out earlier.
1480 e1.unwrap().insert(next_index);
1481 e2.unwrap().insert(next_index);
1482 e3.unwrap().insert(next_index);
1483
1484 Ok(())
1485 }
1486
1487 /// Returns true if the map contains a single item that matches all three
1488 /// keys.
1489 ///
1490 /// # Examples
1491 ///
1492 /// ```
1493 /// # #[cfg(feature = "default-hasher")] {
1494 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1495 ///
1496 /// #[derive(Debug, PartialEq, Eq)]
1497 /// struct Person {
1498 /// id: u32,
1499 /// email: String,
1500 /// phone: String,
1501 /// name: String,
1502 /// }
1503 ///
1504 /// impl TriHashItem for Person {
1505 /// type K1<'a> = u32;
1506 /// type K2<'a> = &'a str;
1507 /// type K3<'a> = &'a str;
1508 ///
1509 /// fn key1(&self) -> Self::K1<'_> {
1510 /// self.id
1511 /// }
1512 /// fn key2(&self) -> Self::K2<'_> {
1513 /// &self.email
1514 /// }
1515 /// fn key3(&self) -> Self::K3<'_> {
1516 /// &self.phone
1517 /// }
1518 /// tri_upcast!();
1519 /// }
1520 ///
1521 /// let mut map = TriHashMap::new();
1522 /// map.insert_unique(Person {
1523 /// id: 1,
1524 /// email: "alice@example.com".to_string(),
1525 /// phone: "555-1234".to_string(),
1526 /// name: "Alice".to_string(),
1527 /// }).unwrap();
1528 /// map.insert_unique(Person {
1529 /// id: 2,
1530 /// email: "bob@example.com".to_string(),
1531 /// phone: "555-5678".to_string(),
1532 /// name: "Bob".to_string(),
1533 /// }).unwrap();
1534 ///
1535 /// assert!(map.contains_key_unique(&1, &"alice@example.com", &"555-1234"));
1536 /// assert!(map.contains_key_unique(&2, &"bob@example.com", &"555-5678"));
1537 /// assert!(!map.contains_key_unique(&1, &"bob@example.com", &"555-1234")); // key1 exists but key2 doesn't match
1538 /// assert!(!map.contains_key_unique(&3, &"charlie@example.com", &"555-9999")); // none of the keys exist
1539 /// # }
1540 /// ```
1541 pub fn contains_key_unique<'a, Q1, Q2, Q3>(
1542 &'a self,
1543 key1: &Q1,
1544 key2: &Q2,
1545 key3: &Q3,
1546 ) -> bool
1547 where
1548 Q1: Hash + Equivalent<T::K1<'a>> + ?Sized,
1549 Q2: Hash + Equivalent<T::K2<'a>> + ?Sized,
1550 Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,
1551 {
1552 self.get_unique(key1, key2, key3).is_some()
1553 }
1554
1555 /// Gets a reference to the unique item associated with the given `key1`,
1556 /// `key2`, and `key3`, if it exists.
1557 ///
1558 /// # Examples
1559 ///
1560 /// ```
1561 /// # #[cfg(feature = "default-hasher")] {
1562 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1563 ///
1564 /// #[derive(Debug, PartialEq, Eq)]
1565 /// struct Person {
1566 /// id: u32,
1567 /// email: String,
1568 /// phone: String,
1569 /// name: String,
1570 /// }
1571 ///
1572 /// impl TriHashItem for Person {
1573 /// type K1<'a> = u32;
1574 /// type K2<'a> = &'a str;
1575 /// type K3<'a> = &'a str;
1576 ///
1577 /// fn key1(&self) -> Self::K1<'_> {
1578 /// self.id
1579 /// }
1580 /// fn key2(&self) -> Self::K2<'_> {
1581 /// &self.email
1582 /// }
1583 /// fn key3(&self) -> Self::K3<'_> {
1584 /// &self.phone
1585 /// }
1586 /// tri_upcast!();
1587 /// }
1588 ///
1589 /// let mut map = TriHashMap::new();
1590 /// map.insert_unique(Person {
1591 /// id: 1,
1592 /// email: "alice@example.com".to_string(),
1593 /// phone: "555-1234".to_string(),
1594 /// name: "Alice".to_string(),
1595 /// })
1596 /// .unwrap();
1597 ///
1598 /// // All three keys must match
1599 /// assert_eq!(
1600 /// map.get_unique(&1, &"alice@example.com", &"555-1234").unwrap().name,
1601 /// "Alice"
1602 /// );
1603 ///
1604 /// // If any key doesn't match, returns None
1605 /// assert!(map.get_unique(&1, &"wrong@example.com", &"555-1234").is_none());
1606 /// assert!(map.get_unique(&2, &"alice@example.com", &"555-1234").is_none());
1607 /// # }
1608 /// ```
1609 pub fn get_unique<'a, Q1, Q2, Q3>(
1610 &'a self,
1611 key1: &Q1,
1612 key2: &Q2,
1613 key3: &Q3,
1614 ) -> Option<&'a T>
1615 where
1616 Q1: Hash + Equivalent<T::K1<'a>> + ?Sized,
1617 Q2: Hash + Equivalent<T::K2<'a>> + ?Sized,
1618 Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,
1619 {
1620 let index = self.find1_index(key1)?;
1621 let item = &self.items[index];
1622 if key2.equivalent(&item.key2()) && key3.equivalent(&item.key3()) {
1623 Some(item)
1624 } else {
1625 None
1626 }
1627 }
1628
1629 /// Gets a mutable reference to the unique item associated with the given
1630 /// `key1`, `key2`, and `key3`, if it exists.
1631 ///
1632 /// # Examples
1633 ///
1634 /// ```
1635 /// # #[cfg(feature = "default-hasher")] {
1636 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1637 ///
1638 /// #[derive(Debug, PartialEq, Eq)]
1639 /// struct Person {
1640 /// id: u32,
1641 /// email: String,
1642 /// phone: String,
1643 /// name: String,
1644 /// }
1645 ///
1646 /// impl TriHashItem for Person {
1647 /// type K1<'a> = u32;
1648 /// type K2<'a> = &'a str;
1649 /// type K3<'a> = &'a str;
1650 ///
1651 /// fn key1(&self) -> Self::K1<'_> {
1652 /// self.id
1653 /// }
1654 /// fn key2(&self) -> Self::K2<'_> {
1655 /// &self.email
1656 /// }
1657 /// fn key3(&self) -> Self::K3<'_> {
1658 /// &self.phone
1659 /// }
1660 /// tri_upcast!();
1661 /// }
1662 ///
1663 /// let mut map = TriHashMap::new();
1664 /// map.insert_unique(Person {
1665 /// id: 1,
1666 /// email: "alice@example.com".to_string(),
1667 /// phone: "555-1234".to_string(),
1668 /// name: "Alice".to_string(),
1669 /// })
1670 /// .unwrap();
1671 ///
1672 /// // Modify the item through the mutable reference
1673 /// if let Some(mut person) =
1674 /// map.get_mut_unique(&1, &"alice@example.com", &"555-1234")
1675 /// {
1676 /// person.name = "Alice Updated".to_string();
1677 /// }
1678 ///
1679 /// // Verify the change
1680 /// assert_eq!(map.get1(&1).unwrap().name, "Alice Updated");
1681 /// # }
1682 /// ```
1683 pub fn get_mut_unique<'a, Q1, Q2, Q3>(
1684 &'a mut self,
1685 key1: &Q1,
1686 key2: &Q2,
1687 key3: &Q3,
1688 ) -> Option<RefMut<'a, T, S>>
1689 where
1690 Q1: Hash + Equivalent<T::K1<'a>> + ?Sized,
1691 Q2: Hash + Equivalent<T::K2<'a>> + ?Sized,
1692 Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,
1693 {
1694 let (dormant_map, index) = {
1695 let (map, dormant_map) = DormantMutRef::new(self);
1696 let index = map.find1_index(key1)?;
1697 let item = &map.items[index];
1698 if !key2.equivalent(&item.key2()) || !key3.equivalent(&item.key3())
1699 {
1700 return None;
1701 }
1702 (dormant_map, index)
1703 };
1704
1705 // SAFETY: `map` is not used after this point.
1706 let awakened_map = unsafe { dormant_map.awaken() };
1707 let item = &mut awakened_map.items[index];
1708 let state = awakened_map.tables.state.clone();
1709 let hashes = awakened_map.tables.make_hashes(&item);
1710 Some(RefMut::new(state, hashes, item))
1711 }
1712
1713 /// Removes the item uniquely identified by `key1`, `key2`, and `key3`, if
1714 /// it exists.
1715 ///
1716 /// # Examples
1717 ///
1718 /// ```
1719 /// # #[cfg(feature = "default-hasher")] {
1720 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1721 ///
1722 /// #[derive(Debug, PartialEq, Eq)]
1723 /// struct Person {
1724 /// id: u32,
1725 /// email: String,
1726 /// phone: String,
1727 /// name: String,
1728 /// }
1729 ///
1730 /// impl TriHashItem for Person {
1731 /// type K1<'a> = u32;
1732 /// type K2<'a> = &'a str;
1733 /// type K3<'a> = &'a str;
1734 ///
1735 /// fn key1(&self) -> Self::K1<'_> {
1736 /// self.id
1737 /// }
1738 /// fn key2(&self) -> Self::K2<'_> {
1739 /// &self.email
1740 /// }
1741 /// fn key3(&self) -> Self::K3<'_> {
1742 /// &self.phone
1743 /// }
1744 /// tri_upcast!();
1745 /// }
1746 ///
1747 /// let mut map = TriHashMap::new();
1748 /// map.insert_unique(Person {
1749 /// id: 1,
1750 /// email: "alice@example.com".to_string(),
1751 /// phone: "555-1234".to_string(),
1752 /// name: "Alice".to_string(),
1753 /// })
1754 /// .unwrap();
1755 ///
1756 /// // Remove the item using all three keys
1757 /// let removed = map.remove_unique(&1, &"alice@example.com", &"555-1234");
1758 /// assert!(removed.is_some());
1759 /// assert_eq!(removed.unwrap().name, "Alice");
1760 ///
1761 /// // Map is now empty
1762 /// assert!(map.is_empty());
1763 ///
1764 /// // Trying to remove again returns None
1765 /// assert!(map.remove_unique(&1, &"alice@example.com", &"555-1234").is_none());
1766 /// # }
1767 /// ```
1768 pub fn remove_unique<'a, Q1, Q2, Q3>(
1769 &'a mut self,
1770 key1: &Q1,
1771 key2: &Q2,
1772 key3: &Q3,
1773 ) -> Option<T>
1774 where
1775 Q1: Hash + Equivalent<T::K1<'a>> + ?Sized,
1776 Q2: Hash + Equivalent<T::K2<'a>> + ?Sized,
1777 Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,
1778 {
1779 let (dormant_map, remove_index) = {
1780 let (map, dormant_map) = DormantMutRef::new(self);
1781 let remove_index = map.find1_index(key1)?;
1782 let item = &map.items[remove_index];
1783 if !key2.equivalent(&item.key2()) && !key3.equivalent(&item.key3())
1784 {
1785 return None;
1786 }
1787 (dormant_map, remove_index)
1788 };
1789
1790 // SAFETY: `map` is not used after this point.
1791 let awakened_map = unsafe { dormant_map.awaken() };
1792
1793 awakened_map.remove_by_index(remove_index)
1794 }
1795
1796 /// Returns true if the map contains the given `key1`.
1797 ///
1798 /// # Examples
1799 ///
1800 /// ```
1801 /// # #[cfg(feature = "default-hasher")] {
1802 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1803 ///
1804 /// #[derive(Debug, PartialEq, Eq)]
1805 /// struct Person {
1806 /// id: u32,
1807 /// email: String,
1808 /// phone: String,
1809 /// name: String,
1810 /// }
1811 ///
1812 /// impl TriHashItem for Person {
1813 /// type K1<'a> = u32;
1814 /// type K2<'a> = &'a str;
1815 /// type K3<'a> = &'a str;
1816 ///
1817 /// fn key1(&self) -> Self::K1<'_> {
1818 /// self.id
1819 /// }
1820 /// fn key2(&self) -> Self::K2<'_> {
1821 /// &self.email
1822 /// }
1823 /// fn key3(&self) -> Self::K3<'_> {
1824 /// &self.phone
1825 /// }
1826 /// tri_upcast!();
1827 /// }
1828 ///
1829 /// let mut map = TriHashMap::new();
1830 /// map.insert_unique(Person {
1831 /// id: 1,
1832 /// email: "alice@example.com".to_string(),
1833 /// phone: "555-1234".to_string(),
1834 /// name: "Alice".to_string(),
1835 /// })
1836 /// .unwrap();
1837 ///
1838 /// assert!(map.contains_key1(&1));
1839 /// assert!(!map.contains_key1(&2));
1840 /// # }
1841 /// ```
1842 pub fn contains_key1<'a, Q>(&'a self, key1: &Q) -> bool
1843 where
1844 Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
1845 {
1846 self.find1_index(key1).is_some()
1847 }
1848
1849 /// Gets a reference to the value associated with the given `key1`.
1850 ///
1851 /// # Examples
1852 ///
1853 /// ```
1854 /// # #[cfg(feature = "default-hasher")] {
1855 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1856 ///
1857 /// #[derive(Debug, PartialEq, Eq)]
1858 /// struct Person {
1859 /// id: u32,
1860 /// email: String,
1861 /// phone: String,
1862 /// name: String,
1863 /// }
1864 ///
1865 /// impl TriHashItem for Person {
1866 /// type K1<'a> = u32;
1867 /// type K2<'a> = &'a str;
1868 /// type K3<'a> = &'a str;
1869 ///
1870 /// fn key1(&self) -> Self::K1<'_> {
1871 /// self.id
1872 /// }
1873 /// fn key2(&self) -> Self::K2<'_> {
1874 /// &self.email
1875 /// }
1876 /// fn key3(&self) -> Self::K3<'_> {
1877 /// &self.phone
1878 /// }
1879 /// tri_upcast!();
1880 /// }
1881 ///
1882 /// let mut map = TriHashMap::new();
1883 /// map.insert_unique(Person {
1884 /// id: 1,
1885 /// email: "alice@example.com".to_string(),
1886 /// phone: "555-1234".to_string(),
1887 /// name: "Alice".to_string(),
1888 /// })
1889 /// .unwrap();
1890 ///
1891 /// assert_eq!(map.get1(&1).unwrap().name, "Alice");
1892 /// assert!(map.get1(&2).is_none());
1893 /// # }
1894 /// ```
1895 pub fn get1<'a, Q>(&'a self, key1: &Q) -> Option<&'a T>
1896 where
1897 Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
1898 {
1899 self.find1(key1)
1900 }
1901
1902 /// Gets a mutable reference to the value associated with the given `key1`.
1903 ///
1904 /// # Examples
1905 ///
1906 /// ```
1907 /// # #[cfg(feature = "default-hasher")] {
1908 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1909 ///
1910 /// #[derive(Debug, PartialEq, Eq)]
1911 /// struct Person {
1912 /// id: u32,
1913 /// email: String,
1914 /// phone: String,
1915 /// name: String,
1916 /// }
1917 ///
1918 /// impl TriHashItem for Person {
1919 /// type K1<'a> = u32;
1920 /// type K2<'a> = &'a str;
1921 /// type K3<'a> = &'a str;
1922 ///
1923 /// fn key1(&self) -> Self::K1<'_> {
1924 /// self.id
1925 /// }
1926 /// fn key2(&self) -> Self::K2<'_> {
1927 /// &self.email
1928 /// }
1929 /// fn key3(&self) -> Self::K3<'_> {
1930 /// &self.phone
1931 /// }
1932 /// tri_upcast!();
1933 /// }
1934 ///
1935 /// let mut map = TriHashMap::new();
1936 /// map.insert_unique(Person {
1937 /// id: 1,
1938 /// email: "alice@example.com".to_string(),
1939 /// phone: "555-1234".to_string(),
1940 /// name: "Alice".to_string(),
1941 /// })
1942 /// .unwrap();
1943 ///
1944 /// if let Some(mut person) = map.get1_mut(&1) {
1945 /// person.name = "Alice Updated".to_string();
1946 /// }
1947 ///
1948 /// assert_eq!(map.get1(&1).unwrap().name, "Alice Updated");
1949 /// # }
1950 /// ```
1951 pub fn get1_mut<'a, Q>(&'a mut self, key1: &Q) -> Option<RefMut<'a, T, S>>
1952 where
1953 Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
1954 {
1955 let (dormant_map, index) = {
1956 let (map, dormant_map) = DormantMutRef::new(self);
1957 let index = map.find1_index(key1)?;
1958 (dormant_map, index)
1959 };
1960
1961 // SAFETY: `map` is not used after this point.
1962 let awakened_map = unsafe { dormant_map.awaken() };
1963 let item = &mut awakened_map.items[index];
1964 let state = awakened_map.tables.state.clone();
1965 let hashes = awakened_map.tables.make_hashes(&item);
1966 Some(RefMut::new(state, hashes, item))
1967 }
1968
1969 /// Removes an item from the map by its `key1`.
1970 ///
1971 /// # Examples
1972 ///
1973 /// ```
1974 /// # #[cfg(feature = "default-hasher")] {
1975 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1976 ///
1977 /// #[derive(Debug, PartialEq, Eq)]
1978 /// struct Person {
1979 /// id: u32,
1980 /// email: String,
1981 /// phone: String,
1982 /// name: String,
1983 /// }
1984 ///
1985 /// impl TriHashItem for Person {
1986 /// type K1<'a> = u32;
1987 /// type K2<'a> = &'a str;
1988 /// type K3<'a> = &'a str;
1989 ///
1990 /// fn key1(&self) -> Self::K1<'_> {
1991 /// self.id
1992 /// }
1993 /// fn key2(&self) -> Self::K2<'_> {
1994 /// &self.email
1995 /// }
1996 /// fn key3(&self) -> Self::K3<'_> {
1997 /// &self.phone
1998 /// }
1999 /// tri_upcast!();
2000 /// }
2001 ///
2002 /// let mut map = TriHashMap::new();
2003 /// map.insert_unique(Person {
2004 /// id: 1,
2005 /// email: "alice@example.com".to_string(),
2006 /// phone: "555-1234".to_string(),
2007 /// name: "Alice".to_string(),
2008 /// })
2009 /// .unwrap();
2010 ///
2011 /// let removed = map.remove1(&1);
2012 /// assert!(removed.is_some());
2013 /// assert_eq!(removed.unwrap().name, "Alice");
2014 /// assert!(map.is_empty());
2015 /// # }
2016 /// ```
2017 pub fn remove1<'a, Q>(&'a mut self, key1: &Q) -> Option<T>
2018 where
2019 Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
2020 {
2021 let (dormant_map, remove_index) = {
2022 let (map, dormant_map) = DormantMutRef::new(self);
2023 let remove_index = map.find1_index(key1)?;
2024 (dormant_map, remove_index)
2025 };
2026
2027 // SAFETY: `map` is not used after this point.
2028 let awakened_map = unsafe { dormant_map.awaken() };
2029
2030 awakened_map.remove_by_index(remove_index)
2031 }
2032
2033 /// Returns true if the map contains the given `key2`.
2034 ///
2035 /// # Examples
2036 ///
2037 /// ```
2038 /// # #[cfg(feature = "default-hasher")] {
2039 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2040 ///
2041 /// #[derive(Debug, PartialEq, Eq)]
2042 /// struct Person {
2043 /// id: u32,
2044 /// email: String,
2045 /// phone: String,
2046 /// name: String,
2047 /// }
2048 ///
2049 /// impl TriHashItem for Person {
2050 /// type K1<'a> = u32;
2051 /// type K2<'a> = &'a str;
2052 /// type K3<'a> = &'a str;
2053 ///
2054 /// fn key1(&self) -> Self::K1<'_> {
2055 /// self.id
2056 /// }
2057 /// fn key2(&self) -> Self::K2<'_> {
2058 /// &self.email
2059 /// }
2060 /// fn key3(&self) -> Self::K3<'_> {
2061 /// &self.phone
2062 /// }
2063 /// tri_upcast!();
2064 /// }
2065 ///
2066 /// let mut map = TriHashMap::new();
2067 /// map.insert_unique(Person {
2068 /// id: 1,
2069 /// email: "alice@example.com".to_string(),
2070 /// phone: "555-1234".to_string(),
2071 /// name: "Alice".to_string(),
2072 /// })
2073 /// .unwrap();
2074 ///
2075 /// assert!(map.contains_key2("alice@example.com"));
2076 /// assert!(!map.contains_key2("bob@example.com"));
2077 /// # }
2078 /// ```
2079 pub fn contains_key2<'a, Q>(&'a self, key2: &Q) -> bool
2080 where
2081 Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2082 {
2083 self.find2_index(key2).is_some()
2084 }
2085
2086 /// Gets a reference to the value associated with the given `key2`.
2087 ///
2088 /// # Examples
2089 ///
2090 /// ```
2091 /// # #[cfg(feature = "default-hasher")] {
2092 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2093 ///
2094 /// #[derive(Debug, PartialEq, Eq)]
2095 /// struct Person {
2096 /// id: u32,
2097 /// email: String,
2098 /// phone: String,
2099 /// name: String,
2100 /// }
2101 ///
2102 /// impl TriHashItem for Person {
2103 /// type K1<'a> = u32;
2104 /// type K2<'a> = &'a str;
2105 /// type K3<'a> = &'a str;
2106 ///
2107 /// fn key1(&self) -> Self::K1<'_> {
2108 /// self.id
2109 /// }
2110 /// fn key2(&self) -> Self::K2<'_> {
2111 /// &self.email
2112 /// }
2113 /// fn key3(&self) -> Self::K3<'_> {
2114 /// &self.phone
2115 /// }
2116 /// tri_upcast!();
2117 /// }
2118 ///
2119 /// let mut map = TriHashMap::new();
2120 /// map.insert_unique(Person {
2121 /// id: 1,
2122 /// email: "alice@example.com".to_string(),
2123 /// phone: "555-1234".to_string(),
2124 /// name: "Alice".to_string(),
2125 /// })
2126 /// .unwrap();
2127 ///
2128 /// assert_eq!(map.get2("alice@example.com").unwrap().name, "Alice");
2129 /// assert!(map.get2("bob@example.com").is_none());
2130 /// # }
2131 /// ```
2132 pub fn get2<'a, Q>(&'a self, key2: &Q) -> Option<&'a T>
2133 where
2134 Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2135 {
2136 self.find2(key2)
2137 }
2138
2139 /// Gets a mutable reference to the value associated with the given `key2`.
2140 ///
2141 /// # Examples
2142 ///
2143 /// ```
2144 /// # #[cfg(feature = "default-hasher")] {
2145 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2146 ///
2147 /// #[derive(Debug, PartialEq, Eq)]
2148 /// struct Person {
2149 /// id: u32,
2150 /// email: String,
2151 /// phone: String,
2152 /// name: String,
2153 /// }
2154 ///
2155 /// impl TriHashItem for Person {
2156 /// type K1<'a> = u32;
2157 /// type K2<'a> = &'a str;
2158 /// type K3<'a> = &'a str;
2159 ///
2160 /// fn key1(&self) -> Self::K1<'_> {
2161 /// self.id
2162 /// }
2163 /// fn key2(&self) -> Self::K2<'_> {
2164 /// &self.email
2165 /// }
2166 /// fn key3(&self) -> Self::K3<'_> {
2167 /// &self.phone
2168 /// }
2169 /// tri_upcast!();
2170 /// }
2171 ///
2172 /// let mut map = TriHashMap::new();
2173 /// map.insert_unique(Person {
2174 /// id: 1,
2175 /// email: "alice@example.com".to_string(),
2176 /// phone: "555-1234".to_string(),
2177 /// name: "Alice".to_string(),
2178 /// })
2179 /// .unwrap();
2180 ///
2181 /// if let Some(mut person) = map.get2_mut("alice@example.com") {
2182 /// person.name = "Alice Updated".to_string();
2183 /// }
2184 ///
2185 /// assert_eq!(map.get2("alice@example.com").unwrap().name, "Alice Updated");
2186 /// # }
2187 /// ```
2188 pub fn get2_mut<'a, Q>(&'a mut self, key2: &Q) -> Option<RefMut<'a, T, S>>
2189 where
2190 Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2191 {
2192 let (dormant_map, index) = {
2193 let (map, dormant_map) = DormantMutRef::new(self);
2194 let index = map.find2_index(key2)?;
2195 (dormant_map, index)
2196 };
2197
2198 // SAFETY: `map` is not used after this point.
2199 let awakened_map = unsafe { dormant_map.awaken() };
2200 let item = &mut awakened_map.items[index];
2201 let state = awakened_map.tables.state.clone();
2202 let hashes = awakened_map.tables.make_hashes(&item);
2203 Some(RefMut::new(state, hashes, item))
2204 }
2205
2206 /// Removes an item from the map by its `key2`.
2207 ///
2208 /// # Examples
2209 ///
2210 /// ```
2211 /// # #[cfg(feature = "default-hasher")] {
2212 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2213 ///
2214 /// #[derive(Debug, PartialEq, Eq)]
2215 /// struct Person {
2216 /// id: u32,
2217 /// email: String,
2218 /// phone: String,
2219 /// name: String,
2220 /// }
2221 ///
2222 /// impl TriHashItem for Person {
2223 /// type K1<'a> = u32;
2224 /// type K2<'a> = &'a str;
2225 /// type K3<'a> = &'a str;
2226 ///
2227 /// fn key1(&self) -> Self::K1<'_> {
2228 /// self.id
2229 /// }
2230 /// fn key2(&self) -> Self::K2<'_> {
2231 /// &self.email
2232 /// }
2233 /// fn key3(&self) -> Self::K3<'_> {
2234 /// &self.phone
2235 /// }
2236 /// tri_upcast!();
2237 /// }
2238 ///
2239 /// let mut map = TriHashMap::new();
2240 /// map.insert_unique(Person {
2241 /// id: 1,
2242 /// email: "alice@example.com".to_string(),
2243 /// phone: "555-1234".to_string(),
2244 /// name: "Alice".to_string(),
2245 /// })
2246 /// .unwrap();
2247 ///
2248 /// let removed = map.remove2("alice@example.com");
2249 /// assert!(removed.is_some());
2250 /// assert_eq!(removed.unwrap().name, "Alice");
2251 /// assert!(map.is_empty());
2252 /// # }
2253 /// ```
2254 pub fn remove2<'a, Q>(&'a mut self, key2: &Q) -> Option<T>
2255 where
2256 Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2257 {
2258 let (dormant_map, remove_index) = {
2259 let (map, dormant_map) = DormantMutRef::new(self);
2260 let remove_index = map.find2_index(key2)?;
2261 (dormant_map, remove_index)
2262 };
2263
2264 // SAFETY: `map` is not used after this point.
2265 let awakened_map = unsafe { dormant_map.awaken() };
2266
2267 awakened_map.remove_by_index(remove_index)
2268 }
2269
2270 /// Returns true if the map contains the given `key3`.
2271 ///
2272 /// # Examples
2273 ///
2274 /// ```
2275 /// # #[cfg(feature = "default-hasher")] {
2276 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2277 ///
2278 /// #[derive(Debug, PartialEq, Eq)]
2279 /// struct Person {
2280 /// id: u32,
2281 /// email: String,
2282 /// phone: String,
2283 /// name: String,
2284 /// }
2285 ///
2286 /// impl TriHashItem for Person {
2287 /// type K1<'a> = u32;
2288 /// type K2<'a> = &'a str;
2289 /// type K3<'a> = &'a str;
2290 ///
2291 /// fn key1(&self) -> Self::K1<'_> {
2292 /// self.id
2293 /// }
2294 /// fn key2(&self) -> Self::K2<'_> {
2295 /// &self.email
2296 /// }
2297 /// fn key3(&self) -> Self::K3<'_> {
2298 /// &self.phone
2299 /// }
2300 /// tri_upcast!();
2301 /// }
2302 ///
2303 /// let mut map = TriHashMap::new();
2304 /// map.insert_unique(Person {
2305 /// id: 1,
2306 /// email: "alice@example.com".to_string(),
2307 /// phone: "555-1234".to_string(),
2308 /// name: "Alice".to_string(),
2309 /// })
2310 /// .unwrap();
2311 ///
2312 /// assert!(map.contains_key3("555-1234"));
2313 /// assert!(!map.contains_key3("555-5678"));
2314 /// # }
2315 /// ```
2316 pub fn contains_key3<'a, Q>(&'a self, key3: &Q) -> bool
2317 where
2318 Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2319 {
2320 self.find3_index(key3).is_some()
2321 }
2322
2323 /// Gets a reference to the value associated with the given `key3`.
2324 ///
2325 /// # Examples
2326 ///
2327 /// ```
2328 /// # #[cfg(feature = "default-hasher")] {
2329 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2330 ///
2331 /// #[derive(Debug, PartialEq, Eq)]
2332 /// struct Person {
2333 /// id: u32,
2334 /// email: String,
2335 /// phone: String,
2336 /// name: String,
2337 /// }
2338 ///
2339 /// impl TriHashItem for Person {
2340 /// type K1<'a> = u32;
2341 /// type K2<'a> = &'a str;
2342 /// type K3<'a> = &'a str;
2343 ///
2344 /// fn key1(&self) -> Self::K1<'_> {
2345 /// self.id
2346 /// }
2347 /// fn key2(&self) -> Self::K2<'_> {
2348 /// &self.email
2349 /// }
2350 /// fn key3(&self) -> Self::K3<'_> {
2351 /// &self.phone
2352 /// }
2353 /// tri_upcast!();
2354 /// }
2355 ///
2356 /// let mut map = TriHashMap::new();
2357 /// map.insert_unique(Person {
2358 /// id: 1,
2359 /// email: "alice@example.com".to_string(),
2360 /// phone: "555-1234".to_string(),
2361 /// name: "Alice".to_string(),
2362 /// })
2363 /// .unwrap();
2364 ///
2365 /// assert_eq!(map.get3("555-1234").unwrap().name, "Alice");
2366 /// assert!(map.get3("555-5678").is_none());
2367 /// # }
2368 /// ```
2369 pub fn get3<'a, Q>(&'a self, key3: &Q) -> Option<&'a T>
2370 where
2371 Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2372 {
2373 self.find3(key3)
2374 }
2375
2376 /// Gets a mutable reference to the value associated with the given `key3`.
2377 ///
2378 /// # Examples
2379 ///
2380 /// ```
2381 /// # #[cfg(feature = "default-hasher")] {
2382 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2383 ///
2384 /// #[derive(Debug, PartialEq, Eq)]
2385 /// struct Person {
2386 /// id: u32,
2387 /// email: String,
2388 /// phone: String,
2389 /// name: String,
2390 /// }
2391 ///
2392 /// impl TriHashItem for Person {
2393 /// type K1<'a> = u32;
2394 /// type K2<'a> = &'a str;
2395 /// type K3<'a> = &'a str;
2396 ///
2397 /// fn key1(&self) -> Self::K1<'_> {
2398 /// self.id
2399 /// }
2400 /// fn key2(&self) -> Self::K2<'_> {
2401 /// &self.email
2402 /// }
2403 /// fn key3(&self) -> Self::K3<'_> {
2404 /// &self.phone
2405 /// }
2406 /// tri_upcast!();
2407 /// }
2408 ///
2409 /// let mut map = TriHashMap::new();
2410 /// map.insert_unique(Person {
2411 /// id: 1,
2412 /// email: "alice@example.com".to_string(),
2413 /// phone: "555-1234".to_string(),
2414 /// name: "Alice".to_string(),
2415 /// })
2416 /// .unwrap();
2417 ///
2418 /// if let Some(mut person) = map.get3_mut("555-1234") {
2419 /// person.name = "Alice Updated".to_string();
2420 /// }
2421 ///
2422 /// assert_eq!(map.get3("555-1234").unwrap().name, "Alice Updated");
2423 /// # }
2424 /// ```
2425 pub fn get3_mut<'a, Q>(&'a mut self, key3: &Q) -> Option<RefMut<'a, T, S>>
2426 where
2427 Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2428 {
2429 let (dormant_map, index) = {
2430 let (map, dormant_map) = DormantMutRef::new(self);
2431 let index = map.find3_index(key3)?;
2432 (dormant_map, index)
2433 };
2434
2435 // SAFETY: `map` is not used after this point.
2436 let awakened_map = unsafe { dormant_map.awaken() };
2437 let item = &mut awakened_map.items[index];
2438 let state = awakened_map.tables.state.clone();
2439 let hashes = awakened_map.tables.make_hashes(&item);
2440 Some(RefMut::new(state, hashes, item))
2441 }
2442
2443 /// Removes an item from the map by its `key3`.
2444 ///
2445 /// # Examples
2446 ///
2447 /// ```
2448 /// # #[cfg(feature = "default-hasher")] {
2449 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2450 ///
2451 /// #[derive(Debug, PartialEq, Eq)]
2452 /// struct Person {
2453 /// id: u32,
2454 /// email: String,
2455 /// phone: String,
2456 /// name: String,
2457 /// }
2458 ///
2459 /// impl TriHashItem for Person {
2460 /// type K1<'a> = u32;
2461 /// type K2<'a> = &'a str;
2462 /// type K3<'a> = &'a str;
2463 ///
2464 /// fn key1(&self) -> Self::K1<'_> {
2465 /// self.id
2466 /// }
2467 /// fn key2(&self) -> Self::K2<'_> {
2468 /// &self.email
2469 /// }
2470 /// fn key3(&self) -> Self::K3<'_> {
2471 /// &self.phone
2472 /// }
2473 /// tri_upcast!();
2474 /// }
2475 ///
2476 /// let mut map = TriHashMap::new();
2477 /// map.insert_unique(Person {
2478 /// id: 1,
2479 /// email: "alice@example.com".to_string(),
2480 /// phone: "555-1234".to_string(),
2481 /// name: "Alice".to_string(),
2482 /// })
2483 /// .unwrap();
2484 ///
2485 /// let removed = map.remove3("555-1234");
2486 /// assert!(removed.is_some());
2487 /// assert_eq!(removed.unwrap().name, "Alice");
2488 /// assert!(map.is_empty());
2489 /// # }
2490 /// ```
2491 pub fn remove3<'a, Q>(&'a mut self, key3: &Q) -> Option<T>
2492 where
2493 Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2494 {
2495 let (dormant_map, remove_index) = {
2496 let (map, dormant_map) = DormantMutRef::new(self);
2497 let remove_index = map.find3_index(key3)?;
2498 (dormant_map, remove_index)
2499 };
2500
2501 // SAFETY: `map` is not used after this point.
2502 let awakened_map = unsafe { dormant_map.awaken() };
2503
2504 awakened_map.remove_by_index(remove_index)
2505 }
2506
2507 /// Retains only the elements specified by the predicate.
2508 ///
2509 /// In other words, remove all items `T` for which `f(RefMut<T>)` returns
2510 /// false. The elements are visited in an arbitrary order.
2511 ///
2512 /// The `RefMut<T, S>` wrapper allows mutable access to the item while
2513 /// enforcing that the three keys (`K1`, `K2`, `K3`) remain unchanged. If
2514 /// a key is modified during iteration, the method will panic.
2515 ///
2516 /// # Performance considerations
2517 ///
2518 /// This method may leave the internal storage fragmented. If you need
2519 /// compact storage afterward, call `make_compact()`.
2520 ///
2521 /// # Examples
2522 ///
2523 /// ```
2524 /// # #[cfg(feature = "default-hasher")] {
2525 /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2526 ///
2527 /// #[derive(Debug, PartialEq, Eq, Hash)]
2528 /// struct Item {
2529 /// id: u32,
2530 /// name: String,
2531 /// code: String,
2532 /// value: u32,
2533 /// }
2534 ///
2535 /// impl TriHashItem for Item {
2536 /// type K1<'a> = u32;
2537 /// type K2<'a> = &'a str;
2538 /// type K3<'a> = &'a str;
2539 ///
2540 /// fn key1(&self) -> Self::K1<'_> {
2541 /// self.id
2542 /// }
2543 /// fn key2(&self) -> Self::K2<'_> {
2544 /// &self.name
2545 /// }
2546 /// fn key3(&self) -> Self::K3<'_> {
2547 /// &self.code
2548 /// }
2549 ///
2550 /// tri_upcast!();
2551 /// }
2552 ///
2553 /// let mut map = TriHashMap::new();
2554 /// map.insert_unique(Item {
2555 /// id: 1,
2556 /// name: "foo".to_string(),
2557 /// code: "x".to_string(),
2558 /// value: 42,
2559 /// })
2560 /// .unwrap();
2561 /// map.insert_unique(Item {
2562 /// id: 2,
2563 /// name: "bar".to_string(),
2564 /// code: "y".to_string(),
2565 /// value: 20,
2566 /// })
2567 /// .unwrap();
2568 /// map.insert_unique(Item {
2569 /// id: 3,
2570 /// name: "baz".to_string(),
2571 /// code: "z".to_string(),
2572 /// value: 99,
2573 /// })
2574 /// .unwrap();
2575 ///
2576 /// // Retain only items where value is greater than 30
2577 /// map.retain(|item| item.value > 30);
2578 ///
2579 /// assert_eq!(map.len(), 2);
2580 /// assert_eq!(map.get1(&1).unwrap().value, 42);
2581 /// assert_eq!(map.get1(&3).unwrap().value, 99);
2582 /// assert!(map.get1(&2).is_none());
2583 /// # }
2584 /// ```
2585 pub fn retain<'a, F>(&'a mut self, mut f: F)
2586 where
2587 F: FnMut(RefMut<'a, T, S>) -> bool,
2588 {
2589 let hash_state = self.tables.state.clone();
2590 let (_, mut dormant_items) = DormantMutRef::new(&mut self.items);
2591
2592 self.tables.k1_to_item.retain(|index| {
2593 let (item, dormant_items) = {
2594 // SAFETY: All uses of `items` ended in the previous iteration.
2595 let items = unsafe { dormant_items.reborrow() };
2596 let (items, dormant_items) = DormantMutRef::new(items);
2597 let item: &'a mut T = items
2598 .get_mut(index)
2599 .expect("all indexes are present in self.items");
2600 (item, dormant_items)
2601 };
2602
2603 let (hashes, dormant_item) = {
2604 let (item, dormant_item): (&'a mut T, _) =
2605 DormantMutRef::new(item);
2606 // Use T::k1(item) rather than item.key() to force the key
2607 // trait function to be called for T rather than &mut T.
2608 let key1 = T::key1(item);
2609 let key2 = T::key2(item);
2610 let key3 = T::key3(item);
2611 let hash1 = hash_state.hash_one(key1);
2612 let hash2 = hash_state.hash_one(key2);
2613 let hash3 = hash_state.hash_one(key3);
2614 (
2615 [
2616 MapHash::new(hash1),
2617 MapHash::new(hash2),
2618 MapHash::new(hash3),
2619 ],
2620 dormant_item,
2621 )
2622 };
2623
2624 let hash2 = hashes[1].hash();
2625 let hash3 = hashes[2].hash();
2626 let retain = {
2627 // SAFETY: The original item is no longer used after the second
2628 // block above. dormant_items, from which item is derived, is
2629 // currently dormant.
2630 let item = unsafe { dormant_item.awaken() };
2631
2632 let ref_mut = RefMut::new(hash_state.clone(), hashes, item);
2633 f(ref_mut)
2634 };
2635
2636 if retain {
2637 true
2638 } else {
2639 // SAFETY: The original items is no longer used after the first
2640 // block above, and item + dormant_item have been dropped after
2641 // being used above.
2642 let items = unsafe { dormant_items.awaken() };
2643 items.remove(index);
2644 let k2_entry = self
2645 .tables
2646 .k2_to_item
2647 .find_entry_by_hash(hash2, |map2_index| {
2648 map2_index == index
2649 });
2650 let k3_entry = self
2651 .tables
2652 .k3_to_item
2653 .find_entry_by_hash(hash3, |map3_index| {
2654 map3_index == index
2655 });
2656
2657 let mut is_inconsistent = false;
2658 if let Ok(k2_entry) = k2_entry {
2659 k2_entry.remove();
2660 } else {
2661 is_inconsistent = true;
2662 }
2663 if let Ok(k3_entry) = k3_entry {
2664 k3_entry.remove();
2665 } else {
2666 is_inconsistent = true;
2667 }
2668 if is_inconsistent {
2669 // This happening means there's an inconsistency among
2670 // the maps.
2671 panic!(
2672 "inconsistency among k1_to_item, k2_to_item, k3_to_item"
2673 );
2674 }
2675
2676 false
2677 }
2678 });
2679 }
2680
2681 fn find1<'a, Q>(&'a self, k: &Q) -> Option<&'a T>
2682 where
2683 Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
2684 {
2685 self.find1_index(k).map(|ix| &self.items[ix])
2686 }
2687
2688 fn find1_index<'a, Q>(&'a self, k: &Q) -> Option<ItemIndex>
2689 where
2690 Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
2691 {
2692 self.tables
2693 .k1_to_item
2694 .find_index(&self.tables.state, k, |index| self.items[index].key1())
2695 }
2696
2697 fn find2<'a, Q>(&'a self, k: &Q) -> Option<&'a T>
2698 where
2699 Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2700 {
2701 self.find2_index(k).map(|ix| &self.items[ix])
2702 }
2703
2704 fn find2_index<'a, Q>(&'a self, k: &Q) -> Option<ItemIndex>
2705 where
2706 Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2707 {
2708 self.tables
2709 .k2_to_item
2710 .find_index(&self.tables.state, k, |index| self.items[index].key2())
2711 }
2712
2713 fn find3<'a, Q>(&'a self, k: &Q) -> Option<&'a T>
2714 where
2715 Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2716 {
2717 self.find3_index(k).map(|ix| &self.items[ix])
2718 }
2719
2720 fn find3_index<'a, Q>(&'a self, k: &Q) -> Option<ItemIndex>
2721 where
2722 Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2723 {
2724 self.tables
2725 .k3_to_item
2726 .find_index(&self.tables.state, k, |index| self.items[index].key3())
2727 }
2728
2729 pub(super) fn remove_by_index(
2730 &mut self,
2731 remove_index: ItemIndex,
2732 ) -> Option<T> {
2733 // For panic safety, look up all three table entries while `self.items`
2734 // still holds the value, then remove from all three tables and items
2735 // in sequence. hashbrown's `find_entry` is panic-safe under
2736 // user-`Hash`/`Eq` panics (the table is not mutated until
2737 // `OccupiedEntry::remove` is called), so a panic during the lookups
2738 // leaves items and all three tables unmodified.
2739 let item = self.items.get(remove_index)?;
2740 let key1 = item.key1();
2741 let key2 = item.key2();
2742 let key3 = item.key3();
2743 let state = &self.tables.state;
2744 let Ok(entry1) =
2745 self.tables
2746 .k1_to_item
2747 .find_entry(state, &key1, |index| self.items[index].key1())
2748 else {
2749 panic!("remove_index {remove_index} not found in k1_to_item");
2750 };
2751 let Ok(entry2) =
2752 self.tables
2753 .k2_to_item
2754 .find_entry(state, &key2, |index| self.items[index].key2())
2755 else {
2756 panic!("remove_index {remove_index} not found in k2_to_item");
2757 };
2758 let Ok(entry3) =
2759 self.tables
2760 .k3_to_item
2761 .find_entry(state, &key3, |index| self.items[index].key3())
2762 else {
2763 panic!("remove_index {remove_index} not found in k3_to_item");
2764 };
2765 // Drop the keys so that `self.items` can be mutated below.
2766 drop((key1, key2, key3));
2767 entry1.remove();
2768 entry2.remove();
2769 entry3.remove();
2770 Some(
2771 self.items
2772 .remove(remove_index)
2773 .expect("items[remove_index] was Occupied above"),
2774 )
2775 }
2776}
2777
2778impl<'a, T, S, A: Allocator> fmt::Debug for TriHashMap<T, S, A>
2779where
2780 T: TriHashItem + fmt::Debug,
2781 T::K1<'a>: fmt::Debug,
2782 T::K2<'a>: fmt::Debug,
2783 T::K3<'a>: fmt::Debug,
2784 T: 'a,
2785{
2786 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2787 let mut map = f.debug_map();
2788 for item in self.items.values() {
2789 let key: KeyMap<'_, T> = KeyMap {
2790 key1: item.key1(),
2791 key2: item.key2(),
2792 key3: item.key3(),
2793 };
2794
2795 // SAFETY:
2796 //
2797 // * Lifetime extension: for a type T and two lifetime params 'a and
2798 // 'b, T<'a> and T<'b> aren't guaranteed to have the same layout,
2799 // but (a) that is true today and (b) it would be shocking and
2800 // break half the Rust ecosystem if that were to change in the
2801 // future.
2802 // * We only use key within the scope of this block before immediately
2803 // dropping it. In particular, map.entry calls key.fmt() without
2804 // holding a reference to it.
2805 let key: KeyMap<'a, T> = unsafe {
2806 core::mem::transmute::<KeyMap<'_, T>, KeyMap<'a, T>>(key)
2807 };
2808
2809 map.entry(&key, item);
2810 }
2811 map.finish()
2812 }
2813}
2814
2815struct KeyMap<'a, T: TriHashItem + 'a> {
2816 key1: T::K1<'a>,
2817 key2: T::K2<'a>,
2818 key3: T::K3<'a>,
2819}
2820
2821impl<'a, T: TriHashItem> fmt::Debug for KeyMap<'a, T>
2822where
2823 T::K1<'a>: fmt::Debug,
2824 T::K2<'a>: fmt::Debug,
2825 T::K3<'a>: fmt::Debug,
2826{
2827 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2828 // We don't want to show key1 and key2 as a tuple since it's
2829 // misleading (suggests maps of tuples). The best we can do
2830 // instead is to show "{k1: abc, k2: xyz, k3: def}"
2831 f.debug_map()
2832 .entry(&StrDisplayAsDebug("k1"), &self.key1)
2833 .entry(&StrDisplayAsDebug("k2"), &self.key2)
2834 .entry(&StrDisplayAsDebug("k3"), &self.key3)
2835 .finish()
2836 }
2837}
2838
2839impl<T: TriHashItem + PartialEq, S: Clone + BuildHasher, A: Allocator> PartialEq
2840 for TriHashMap<T, S, A>
2841{
2842 fn eq(&self, other: &Self) -> bool {
2843 // Implementing PartialEq for TriHashMap is tricky because TriHashMap is
2844 // not semantically like an IndexMap: two maps are equivalent even if
2845 // their items are in a different order. In other words, any permutation
2846 // of items is equivalent.
2847 //
2848 // We also can't sort the items because they're not necessarily Ord.
2849 //
2850 // So we write a custom equality check that checks that each key in one
2851 // map points to the same item as in the other map.
2852
2853 if self.items.len() != other.items.len() {
2854 return false;
2855 }
2856
2857 // Walk over all the items in the first map and check that they point to
2858 // the same item in the second map.
2859 for item in self.items.values() {
2860 let k1 = item.key1();
2861 let k2 = item.key2();
2862 let k3 = item.key3();
2863
2864 // Check that the indexes are the same in the other map.
2865 let Some(other_ix1) = other.find1_index(&k1) else {
2866 return false;
2867 };
2868 let Some(other_ix2) = other.find2_index(&k2) else {
2869 return false;
2870 };
2871 let Some(other_ix3) = other.find3_index(&k3) else {
2872 return false;
2873 };
2874
2875 if other_ix1 != other_ix2 || other_ix1 != other_ix3 {
2876 // All the keys were present but they didn't point to the same
2877 // item.
2878 return false;
2879 }
2880
2881 // Check that the other map's item is the same as this map's
2882 // item. (This is what we use the `PartialEq` bound on T for.)
2883 //
2884 // Because we've checked that other_ix1, other_ix2 and other_ix3 are
2885 // Some, we know that it is valid and points to the expected item.
2886 let other_item = &other.items[other_ix1];
2887 if item != other_item {
2888 return false;
2889 }
2890 }
2891
2892 true
2893 }
2894}
2895
2896// The Eq bound on T ensures that the TriHashMap forms an equivalence class.
2897impl<T: TriHashItem + Eq, S: Clone + BuildHasher, A: Allocator> Eq
2898 for TriHashMap<T, S, A>
2899{
2900}
2901
2902/// The `Extend` implementation overwrites duplicates. In the future, there will
2903/// also be an `extend_unique` method that will return an error.
2904impl<T: TriHashItem, S: Clone + BuildHasher, A: Allocator> Extend<T>
2905 for TriHashMap<T, S, A>
2906{
2907 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
2908 // Keys may already be present in the map, or multiple times in the
2909 // iterator. Reserve the entire hint lower bound if the map is empty.
2910 // Otherwise reserve half the hint (rounded up), so the map will only
2911 // resize twice in the worst case.
2912 let iter = iter.into_iter();
2913 let reserve = if self.is_empty() {
2914 iter.size_hint().0
2915 } else {
2916 iter.size_hint().0.div_ceil(2)
2917 };
2918 self.reserve(reserve);
2919 for item in iter {
2920 self.insert_overwrite(item);
2921 }
2922 }
2923}
2924
2925fn detect_dup_or_insert<'a, A: Allocator>(
2926 item: Entry<'a, ItemIndex, AllocWrapper<A>>,
2927 duplicates: &mut BTreeSet<ItemIndex>,
2928) -> Option<VacantEntry<'a, ItemIndex, AllocWrapper<A>>> {
2929 match item {
2930 Entry::Vacant(slot) => Some(slot),
2931 Entry::Occupied(slot) => {
2932 duplicates.insert(*slot.get());
2933 None
2934 }
2935 }
2936}
2937
2938impl<'a, T: TriHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
2939 for &'a TriHashMap<T, S, A>
2940{
2941 type Item = &'a T;
2942 type IntoIter = Iter<'a, T>;
2943
2944 #[inline]
2945 fn into_iter(self) -> Self::IntoIter {
2946 self.iter()
2947 }
2948}
2949
2950impl<'a, T: TriHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
2951 for &'a mut TriHashMap<T, S, A>
2952{
2953 type Item = RefMut<'a, T, S>;
2954 type IntoIter = IterMut<'a, T, S, A>;
2955
2956 #[inline]
2957 fn into_iter(self) -> Self::IntoIter {
2958 self.iter_mut()
2959 }
2960}
2961
2962impl<T: TriHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
2963 for TriHashMap<T, S, A>
2964{
2965 type Item = T;
2966 type IntoIter = IntoIter<T, A>;
2967
2968 #[inline]
2969 fn into_iter(self) -> Self::IntoIter {
2970 IntoIter::new(self.items)
2971 }
2972}
2973
2974/// The `FromIterator` implementation for `TriHashMap` overwrites duplicate
2975/// items.
2976impl<T: TriHashItem, S: Default + Clone + BuildHasher, A: Default + Allocator>
2977 FromIterator<T> for TriHashMap<T, S, A>
2978{
2979 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
2980 let mut map = TriHashMap::default();
2981 for item in iter {
2982 map.insert_overwrite(item);
2983 }
2984 map
2985 }
2986}