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