Skip to main content

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}