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