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