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