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.items.validate(compactness)?;
1269        self.tables.validate(self.len(), compactness)?;
1270
1271        // Check that the indexes are all correct.
1272        for (ix, item) in self.items.iter() {
1273            let key1 = item.key1();
1274            let key2 = item.key2();
1275            let key3 = item.key3();
1276
1277            let Some(ix1) = self.find1_index(&key1) else {
1278                return Err(ValidationError::general(format!(
1279                    "item at index {ix} has no key1 index"
1280                )));
1281            };
1282            let Some(ix2) = self.find2_index(&key2) else {
1283                return Err(ValidationError::general(format!(
1284                    "item at index {ix} has no key2 index"
1285                )));
1286            };
1287            let Some(ix3) = self.find3_index(&key3) else {
1288                return Err(ValidationError::general(format!(
1289                    "item at index {ix} has no key3 index"
1290                )));
1291            };
1292
1293            if ix1 != ix || ix2 != ix || ix3 != ix {
1294                return Err(ValidationError::general(format!(
1295                    "item at index {ix} has inconsistent indexes: {ix1}/{ix2}/{ix3}"
1296                )));
1297            }
1298        }
1299
1300        Ok(())
1301    }
1302
1303    /// Inserts a value into the map, removing any conflicting items and
1304    /// returning a list of those items.
1305    ///
1306    /// # Examples
1307    ///
1308    /// ```
1309    /// # #[cfg(feature = "default-hasher")] {
1310    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1311    ///
1312    /// #[derive(Debug, PartialEq, Eq)]
1313    /// struct Person {
1314    ///     id: u32,
1315    ///     email: String,
1316    ///     phone: String,
1317    ///     name: String,
1318    /// }
1319    ///
1320    /// impl TriHashItem for Person {
1321    ///     type K1<'a> = u32;
1322    ///     type K2<'a> = &'a str;
1323    ///     type K3<'a> = &'a str;
1324    ///
1325    ///     fn key1(&self) -> Self::K1<'_> {
1326    ///         self.id
1327    ///     }
1328    ///     fn key2(&self) -> Self::K2<'_> {
1329    ///         &self.email
1330    ///     }
1331    ///     fn key3(&self) -> Self::K3<'_> {
1332    ///         &self.phone
1333    ///     }
1334    ///     tri_upcast!();
1335    /// }
1336    ///
1337    /// let mut map = TriHashMap::new();
1338    ///
1339    /// // First insertion - no conflicts
1340    /// let overwritten = map.insert_overwrite(Person {
1341    ///     id: 1,
1342    ///     email: "alice@example.com".to_string(),
1343    ///     phone: "555-1234".to_string(),
1344    ///     name: "Alice".to_string(),
1345    /// });
1346    /// assert!(overwritten.is_empty());
1347    ///
1348    /// // Overwrite with same id - returns the old item
1349    /// let overwritten = map.insert_overwrite(Person {
1350    ///     id: 1,
1351    ///     email: "alice.new@example.com".to_string(),
1352    ///     phone: "555-9999".to_string(),
1353    ///     name: "Alice New".to_string(),
1354    /// });
1355    /// assert_eq!(overwritten.len(), 1);
1356    /// assert_eq!(overwritten[0].name, "Alice");
1357    /// # }
1358    /// ```
1359    #[doc(alias = "insert")]
1360    pub fn insert_overwrite(&mut self, value: T) -> Vec<T> {
1361        let prepared = self.prepare_insert_overwrite(&value);
1362
1363        let mut duplicates = Vec::with_capacity(prepared.duplicate_count());
1364
1365        self.try_reserve_insert_overwrite_commit(
1366            prepared.needs_new_item_slot(),
1367        )
1368        .expect("reserved space successfully");
1369
1370        self.commit_insert_overwrite(value, prepared, &mut duplicates);
1371
1372        duplicates
1373    }
1374
1375    /// Inserts a value into the set, returning an error if any duplicates were
1376    /// added.
1377    ///
1378    /// # Examples
1379    ///
1380    /// ```
1381    /// # #[cfg(feature = "default-hasher")] {
1382    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1383    ///
1384    /// #[derive(Debug, PartialEq, Eq)]
1385    /// struct Person {
1386    ///     id: u32,
1387    ///     email: String,
1388    ///     phone: String,
1389    ///     name: String,
1390    /// }
1391    ///
1392    /// impl TriHashItem for Person {
1393    ///     type K1<'a> = u32;
1394    ///     type K2<'a> = &'a str;
1395    ///     type K3<'a> = &'a str;
1396    ///
1397    ///     fn key1(&self) -> Self::K1<'_> {
1398    ///         self.id
1399    ///     }
1400    ///     fn key2(&self) -> Self::K2<'_> {
1401    ///         &self.email
1402    ///     }
1403    ///     fn key3(&self) -> Self::K3<'_> {
1404    ///         &self.phone
1405    ///     }
1406    ///     tri_upcast!();
1407    /// }
1408    ///
1409    /// let mut map = TriHashMap::new();
1410    ///
1411    /// // Successful insertion
1412    /// assert!(
1413    ///     map.insert_unique(Person {
1414    ///         id: 1,
1415    ///         email: "alice@example.com".to_string(),
1416    ///         phone: "555-1234".to_string(),
1417    ///         name: "Alice".to_string(),
1418    ///     })
1419    ///     .is_ok()
1420    /// );
1421    /// assert!(
1422    ///     map.insert_unique(Person {
1423    ///         id: 2,
1424    ///         email: "bob@example.com".to_string(),
1425    ///         phone: "555-5678".to_string(),
1426    ///         name: "Bob".to_string(),
1427    ///     })
1428    ///     .is_ok()
1429    /// );
1430    ///
1431    /// // Duplicate key1
1432    /// assert!(
1433    ///     map.insert_unique(Person {
1434    ///         id: 1,
1435    ///         email: "charlie@example.com".to_string(),
1436    ///         phone: "555-9999".to_string(),
1437    ///         name: "Charlie".to_string(),
1438    ///     })
1439    ///     .is_err()
1440    /// );
1441    ///
1442    /// // Duplicate key2
1443    /// assert!(
1444    ///     map.insert_unique(Person {
1445    ///         id: 3,
1446    ///         email: "alice@example.com".to_string(),
1447    ///         phone: "555-7777".to_string(),
1448    ///         name: "Alice2".to_string(),
1449    ///     })
1450    ///     .is_err()
1451    /// );
1452    ///
1453    /// // Duplicate key3
1454    /// assert!(
1455    ///     map.insert_unique(Person {
1456    ///         id: 4,
1457    ///         email: "dave@example.com".to_string(),
1458    ///         phone: "555-1234".to_string(),
1459    ///         name: "Dave".to_string(),
1460    ///     })
1461    ///     .is_err()
1462    /// );
1463    /// # }
1464    /// ```
1465    pub fn insert_unique(
1466        &mut self,
1467        value: T,
1468    ) -> Result<(), DuplicateItem<T, &T>> {
1469        let mut duplicates = BTreeSet::new();
1470
1471        // Check for duplicates *before* inserting the new item, because we
1472        // don't want to partially insert the new item and then have to roll
1473        // back.
1474        let state = &self.tables.state;
1475        let (e1, e2, e3) = {
1476            let k1 = value.key1();
1477            let k2 = value.key2();
1478            let k3 = value.key3();
1479
1480            let e1 = detect_dup_or_insert(
1481                self.tables
1482                    .k1_to_item
1483                    .entry(state, k1, |index| self.items[index].key1()),
1484                &mut duplicates,
1485            );
1486            let e2 = detect_dup_or_insert(
1487                self.tables
1488                    .k2_to_item
1489                    .entry(state, k2, |index| self.items[index].key2()),
1490                &mut duplicates,
1491            );
1492            let e3 = detect_dup_or_insert(
1493                self.tables
1494                    .k3_to_item
1495                    .entry(state, k3, |index| self.items[index].key3()),
1496                &mut duplicates,
1497            );
1498            (e1, e2, e3)
1499        };
1500
1501        if !duplicates.is_empty() {
1502            return Err(DuplicateItem::__internal_new(
1503                value,
1504                duplicates.iter().map(|ix| &self.items[*ix]).collect(),
1505            ));
1506        }
1507
1508        let next_index = self.items.assert_can_grow().insert(value);
1509        // e1, e2 and e3 are all Some because if they were None, duplicates
1510        // would be non-empty, and we'd have bailed out earlier.
1511        e1.unwrap().insert(next_index);
1512        e2.unwrap().insert(next_index);
1513        e3.unwrap().insert(next_index);
1514
1515        Ok(())
1516    }
1517
1518    /// Returns true if the map contains a single item that matches all three
1519    /// keys.
1520    ///
1521    /// # Examples
1522    ///
1523    /// ```
1524    /// # #[cfg(feature = "default-hasher")] {
1525    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1526    ///
1527    /// #[derive(Debug, PartialEq, Eq)]
1528    /// struct Person {
1529    ///     id: u32,
1530    ///     email: String,
1531    ///     phone: String,
1532    ///     name: String,
1533    /// }
1534    ///
1535    /// impl TriHashItem for Person {
1536    ///     type K1<'a> = u32;
1537    ///     type K2<'a> = &'a str;
1538    ///     type K3<'a> = &'a str;
1539    ///
1540    ///     fn key1(&self) -> Self::K1<'_> {
1541    ///         self.id
1542    ///     }
1543    ///     fn key2(&self) -> Self::K2<'_> {
1544    ///         &self.email
1545    ///     }
1546    ///     fn key3(&self) -> Self::K3<'_> {
1547    ///         &self.phone
1548    ///     }
1549    ///     tri_upcast!();
1550    /// }
1551    ///
1552    /// let mut map = TriHashMap::new();
1553    /// map.insert_unique(Person {
1554    ///     id: 1,
1555    ///     email: "alice@example.com".to_string(),
1556    ///     phone: "555-1234".to_string(),
1557    ///     name: "Alice".to_string(),
1558    /// }).unwrap();
1559    /// map.insert_unique(Person {
1560    ///     id: 2,
1561    ///     email: "bob@example.com".to_string(),
1562    ///     phone: "555-5678".to_string(),
1563    ///     name: "Bob".to_string(),
1564    /// }).unwrap();
1565    ///
1566    /// assert!(map.contains_key_unique(&1, &"alice@example.com", &"555-1234"));
1567    /// assert!(map.contains_key_unique(&2, &"bob@example.com", &"555-5678"));
1568    /// assert!(!map.contains_key_unique(&1, &"bob@example.com", &"555-1234")); // key1 exists but key2 doesn't match
1569    /// assert!(!map.contains_key_unique(&3, &"charlie@example.com", &"555-9999")); // none of the keys exist
1570    /// # }
1571    /// ```
1572    pub fn contains_key_unique<'a, Q1, Q2, Q3>(
1573        &'a self,
1574        key1: &Q1,
1575        key2: &Q2,
1576        key3: &Q3,
1577    ) -> bool
1578    where
1579        Q1: Hash + Equivalent<T::K1<'a>> + ?Sized,
1580        Q2: Hash + Equivalent<T::K2<'a>> + ?Sized,
1581        Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,
1582    {
1583        self.get_unique(key1, key2, key3).is_some()
1584    }
1585
1586    /// Gets a reference to the unique item associated with the given `key1`,
1587    /// `key2`, and `key3`, if it exists.
1588    ///
1589    /// # Examples
1590    ///
1591    /// ```
1592    /// # #[cfg(feature = "default-hasher")] {
1593    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1594    ///
1595    /// #[derive(Debug, PartialEq, Eq)]
1596    /// struct Person {
1597    ///     id: u32,
1598    ///     email: String,
1599    ///     phone: String,
1600    ///     name: String,
1601    /// }
1602    ///
1603    /// impl TriHashItem for Person {
1604    ///     type K1<'a> = u32;
1605    ///     type K2<'a> = &'a str;
1606    ///     type K3<'a> = &'a str;
1607    ///
1608    ///     fn key1(&self) -> Self::K1<'_> {
1609    ///         self.id
1610    ///     }
1611    ///     fn key2(&self) -> Self::K2<'_> {
1612    ///         &self.email
1613    ///     }
1614    ///     fn key3(&self) -> Self::K3<'_> {
1615    ///         &self.phone
1616    ///     }
1617    ///     tri_upcast!();
1618    /// }
1619    ///
1620    /// let mut map = TriHashMap::new();
1621    /// map.insert_unique(Person {
1622    ///     id: 1,
1623    ///     email: "alice@example.com".to_string(),
1624    ///     phone: "555-1234".to_string(),
1625    ///     name: "Alice".to_string(),
1626    /// })
1627    /// .unwrap();
1628    ///
1629    /// // All three keys must match
1630    /// assert_eq!(
1631    ///     map.get_unique(&1, &"alice@example.com", &"555-1234").unwrap().name,
1632    ///     "Alice"
1633    /// );
1634    ///
1635    /// // If any key doesn't match, returns None
1636    /// assert!(map.get_unique(&1, &"wrong@example.com", &"555-1234").is_none());
1637    /// assert!(map.get_unique(&2, &"alice@example.com", &"555-1234").is_none());
1638    /// # }
1639    /// ```
1640    pub fn get_unique<'a, Q1, Q2, Q3>(
1641        &'a self,
1642        key1: &Q1,
1643        key2: &Q2,
1644        key3: &Q3,
1645    ) -> Option<&'a T>
1646    where
1647        Q1: Hash + Equivalent<T::K1<'a>> + ?Sized,
1648        Q2: Hash + Equivalent<T::K2<'a>> + ?Sized,
1649        Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,
1650    {
1651        let index = self.find1_index(key1)?;
1652        let item = &self.items[index];
1653        if key2.equivalent(&item.key2()) && key3.equivalent(&item.key3()) {
1654            Some(item)
1655        } else {
1656            None
1657        }
1658    }
1659
1660    /// Gets a mutable reference to the unique item associated with the given
1661    /// `key1`, `key2`, and `key3`, if it exists.
1662    ///
1663    /// # Examples
1664    ///
1665    /// ```
1666    /// # #[cfg(feature = "default-hasher")] {
1667    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1668    ///
1669    /// #[derive(Debug, PartialEq, Eq)]
1670    /// struct Person {
1671    ///     id: u32,
1672    ///     email: String,
1673    ///     phone: String,
1674    ///     name: String,
1675    /// }
1676    ///
1677    /// impl TriHashItem for Person {
1678    ///     type K1<'a> = u32;
1679    ///     type K2<'a> = &'a str;
1680    ///     type K3<'a> = &'a str;
1681    ///
1682    ///     fn key1(&self) -> Self::K1<'_> {
1683    ///         self.id
1684    ///     }
1685    ///     fn key2(&self) -> Self::K2<'_> {
1686    ///         &self.email
1687    ///     }
1688    ///     fn key3(&self) -> Self::K3<'_> {
1689    ///         &self.phone
1690    ///     }
1691    ///     tri_upcast!();
1692    /// }
1693    ///
1694    /// let mut map = TriHashMap::new();
1695    /// map.insert_unique(Person {
1696    ///     id: 1,
1697    ///     email: "alice@example.com".to_string(),
1698    ///     phone: "555-1234".to_string(),
1699    ///     name: "Alice".to_string(),
1700    /// })
1701    /// .unwrap();
1702    ///
1703    /// // Modify the item through the mutable reference
1704    /// if let Some(mut person) =
1705    ///     map.get_mut_unique(&1, &"alice@example.com", &"555-1234")
1706    /// {
1707    ///     person.name = "Alice Updated".to_string();
1708    /// }
1709    ///
1710    /// // Verify the change
1711    /// assert_eq!(map.get1(&1).unwrap().name, "Alice Updated");
1712    /// # }
1713    /// ```
1714    pub fn get_mut_unique<'a, Q1, Q2, Q3>(
1715        &'a mut self,
1716        key1: &Q1,
1717        key2: &Q2,
1718        key3: &Q3,
1719    ) -> Option<RefMut<'a, T, S>>
1720    where
1721        Q1: Hash + Equivalent<T::K1<'a>> + ?Sized,
1722        Q2: Hash + Equivalent<T::K2<'a>> + ?Sized,
1723        Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,
1724    {
1725        let (dormant_map, index) = {
1726            let (map, dormant_map) = DormantMutRef::new(self);
1727            let index = map.find1_index(key1)?;
1728            let item = &map.items[index];
1729            if !key2.equivalent(&item.key2()) || !key3.equivalent(&item.key3())
1730            {
1731                return None;
1732            }
1733            (dormant_map, index)
1734        };
1735
1736        // SAFETY: `map` is not used after this point.
1737        let awakened_map = unsafe { dormant_map.awaken() };
1738        let item = &mut awakened_map.items[index];
1739        let state = awakened_map.tables.state.clone();
1740        let hashes = awakened_map.tables.make_hashes(&item);
1741        Some(RefMut::new(state, hashes, item))
1742    }
1743
1744    /// Removes the item uniquely identified by `key1`, `key2`, and `key3`, if
1745    /// it exists.
1746    ///
1747    /// # Examples
1748    ///
1749    /// ```
1750    /// # #[cfg(feature = "default-hasher")] {
1751    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1752    ///
1753    /// #[derive(Debug, PartialEq, Eq)]
1754    /// struct Person {
1755    ///     id: u32,
1756    ///     email: String,
1757    ///     phone: String,
1758    ///     name: String,
1759    /// }
1760    ///
1761    /// impl TriHashItem for Person {
1762    ///     type K1<'a> = u32;
1763    ///     type K2<'a> = &'a str;
1764    ///     type K3<'a> = &'a str;
1765    ///
1766    ///     fn key1(&self) -> Self::K1<'_> {
1767    ///         self.id
1768    ///     }
1769    ///     fn key2(&self) -> Self::K2<'_> {
1770    ///         &self.email
1771    ///     }
1772    ///     fn key3(&self) -> Self::K3<'_> {
1773    ///         &self.phone
1774    ///     }
1775    ///     tri_upcast!();
1776    /// }
1777    ///
1778    /// let mut map = TriHashMap::new();
1779    /// map.insert_unique(Person {
1780    ///     id: 1,
1781    ///     email: "alice@example.com".to_string(),
1782    ///     phone: "555-1234".to_string(),
1783    ///     name: "Alice".to_string(),
1784    /// })
1785    /// .unwrap();
1786    ///
1787    /// // Remove the item using all three keys
1788    /// let removed = map.remove_unique(&1, &"alice@example.com", &"555-1234");
1789    /// assert!(removed.is_some());
1790    /// assert_eq!(removed.unwrap().name, "Alice");
1791    ///
1792    /// // Map is now empty
1793    /// assert!(map.is_empty());
1794    ///
1795    /// // Trying to remove again returns None
1796    /// assert!(map.remove_unique(&1, &"alice@example.com", &"555-1234").is_none());
1797    /// # }
1798    /// ```
1799    pub fn remove_unique<'a, Q1, Q2, Q3>(
1800        &'a mut self,
1801        key1: &Q1,
1802        key2: &Q2,
1803        key3: &Q3,
1804    ) -> Option<T>
1805    where
1806        Q1: Hash + Equivalent<T::K1<'a>> + ?Sized,
1807        Q2: Hash + Equivalent<T::K2<'a>> + ?Sized,
1808        Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,
1809    {
1810        let (dormant_map, remove_index) = {
1811            let (map, dormant_map) = DormantMutRef::new(self);
1812            let remove_index = map.find1_index(key1)?;
1813            let item = &map.items[remove_index];
1814            if !key2.equivalent(&item.key2()) || !key3.equivalent(&item.key3())
1815            {
1816                return None;
1817            }
1818            (dormant_map, remove_index)
1819        };
1820
1821        // SAFETY: `map` is not used after this point.
1822        let awakened_map = unsafe { dormant_map.awaken() };
1823
1824        awakened_map.remove_by_index(remove_index)
1825    }
1826
1827    /// Returns true if the map contains the given `key1`.
1828    ///
1829    /// # Examples
1830    ///
1831    /// ```
1832    /// # #[cfg(feature = "default-hasher")] {
1833    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1834    ///
1835    /// #[derive(Debug, PartialEq, Eq)]
1836    /// struct Person {
1837    ///     id: u32,
1838    ///     email: String,
1839    ///     phone: String,
1840    ///     name: String,
1841    /// }
1842    ///
1843    /// impl TriHashItem for Person {
1844    ///     type K1<'a> = u32;
1845    ///     type K2<'a> = &'a str;
1846    ///     type K3<'a> = &'a str;
1847    ///
1848    ///     fn key1(&self) -> Self::K1<'_> {
1849    ///         self.id
1850    ///     }
1851    ///     fn key2(&self) -> Self::K2<'_> {
1852    ///         &self.email
1853    ///     }
1854    ///     fn key3(&self) -> Self::K3<'_> {
1855    ///         &self.phone
1856    ///     }
1857    ///     tri_upcast!();
1858    /// }
1859    ///
1860    /// let mut map = TriHashMap::new();
1861    /// map.insert_unique(Person {
1862    ///     id: 1,
1863    ///     email: "alice@example.com".to_string(),
1864    ///     phone: "555-1234".to_string(),
1865    ///     name: "Alice".to_string(),
1866    /// })
1867    /// .unwrap();
1868    ///
1869    /// assert!(map.contains_key1(&1));
1870    /// assert!(!map.contains_key1(&2));
1871    /// # }
1872    /// ```
1873    pub fn contains_key1<'a, Q>(&'a self, key1: &Q) -> bool
1874    where
1875        Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
1876    {
1877        self.find1_index(key1).is_some()
1878    }
1879
1880    /// Gets a reference to the value associated with the given `key1`.
1881    ///
1882    /// # Examples
1883    ///
1884    /// ```
1885    /// # #[cfg(feature = "default-hasher")] {
1886    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1887    ///
1888    /// #[derive(Debug, PartialEq, Eq)]
1889    /// struct Person {
1890    ///     id: u32,
1891    ///     email: String,
1892    ///     phone: String,
1893    ///     name: String,
1894    /// }
1895    ///
1896    /// impl TriHashItem for Person {
1897    ///     type K1<'a> = u32;
1898    ///     type K2<'a> = &'a str;
1899    ///     type K3<'a> = &'a str;
1900    ///
1901    ///     fn key1(&self) -> Self::K1<'_> {
1902    ///         self.id
1903    ///     }
1904    ///     fn key2(&self) -> Self::K2<'_> {
1905    ///         &self.email
1906    ///     }
1907    ///     fn key3(&self) -> Self::K3<'_> {
1908    ///         &self.phone
1909    ///     }
1910    ///     tri_upcast!();
1911    /// }
1912    ///
1913    /// let mut map = TriHashMap::new();
1914    /// map.insert_unique(Person {
1915    ///     id: 1,
1916    ///     email: "alice@example.com".to_string(),
1917    ///     phone: "555-1234".to_string(),
1918    ///     name: "Alice".to_string(),
1919    /// })
1920    /// .unwrap();
1921    ///
1922    /// assert_eq!(map.get1(&1).unwrap().name, "Alice");
1923    /// assert!(map.get1(&2).is_none());
1924    /// # }
1925    /// ```
1926    pub fn get1<'a, Q>(&'a self, key1: &Q) -> Option<&'a T>
1927    where
1928        Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
1929    {
1930        self.find1(key1)
1931    }
1932
1933    /// Gets a mutable reference to the value associated with the given `key1`.
1934    ///
1935    /// # Examples
1936    ///
1937    /// ```
1938    /// # #[cfg(feature = "default-hasher")] {
1939    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1940    ///
1941    /// #[derive(Debug, PartialEq, Eq)]
1942    /// struct Person {
1943    ///     id: u32,
1944    ///     email: String,
1945    ///     phone: String,
1946    ///     name: String,
1947    /// }
1948    ///
1949    /// impl TriHashItem for Person {
1950    ///     type K1<'a> = u32;
1951    ///     type K2<'a> = &'a str;
1952    ///     type K3<'a> = &'a str;
1953    ///
1954    ///     fn key1(&self) -> Self::K1<'_> {
1955    ///         self.id
1956    ///     }
1957    ///     fn key2(&self) -> Self::K2<'_> {
1958    ///         &self.email
1959    ///     }
1960    ///     fn key3(&self) -> Self::K3<'_> {
1961    ///         &self.phone
1962    ///     }
1963    ///     tri_upcast!();
1964    /// }
1965    ///
1966    /// let mut map = TriHashMap::new();
1967    /// map.insert_unique(Person {
1968    ///     id: 1,
1969    ///     email: "alice@example.com".to_string(),
1970    ///     phone: "555-1234".to_string(),
1971    ///     name: "Alice".to_string(),
1972    /// })
1973    /// .unwrap();
1974    ///
1975    /// if let Some(mut person) = map.get1_mut(&1) {
1976    ///     person.name = "Alice Updated".to_string();
1977    /// }
1978    ///
1979    /// assert_eq!(map.get1(&1).unwrap().name, "Alice Updated");
1980    /// # }
1981    /// ```
1982    pub fn get1_mut<'a, Q>(&'a mut self, key1: &Q) -> Option<RefMut<'a, T, S>>
1983    where
1984        Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
1985    {
1986        let (dormant_map, index) = {
1987            let (map, dormant_map) = DormantMutRef::new(self);
1988            let index = map.find1_index(key1)?;
1989            (dormant_map, index)
1990        };
1991
1992        // SAFETY: `map` is not used after this point.
1993        let awakened_map = unsafe { dormant_map.awaken() };
1994        let item = &mut awakened_map.items[index];
1995        let state = awakened_map.tables.state.clone();
1996        let hashes = awakened_map.tables.make_hashes(&item);
1997        Some(RefMut::new(state, hashes, item))
1998    }
1999
2000    /// Removes an item from the map by its `key1`.
2001    ///
2002    /// # Examples
2003    ///
2004    /// ```
2005    /// # #[cfg(feature = "default-hasher")] {
2006    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2007    ///
2008    /// #[derive(Debug, PartialEq, Eq)]
2009    /// struct Person {
2010    ///     id: u32,
2011    ///     email: String,
2012    ///     phone: String,
2013    ///     name: String,
2014    /// }
2015    ///
2016    /// impl TriHashItem for Person {
2017    ///     type K1<'a> = u32;
2018    ///     type K2<'a> = &'a str;
2019    ///     type K3<'a> = &'a str;
2020    ///
2021    ///     fn key1(&self) -> Self::K1<'_> {
2022    ///         self.id
2023    ///     }
2024    ///     fn key2(&self) -> Self::K2<'_> {
2025    ///         &self.email
2026    ///     }
2027    ///     fn key3(&self) -> Self::K3<'_> {
2028    ///         &self.phone
2029    ///     }
2030    ///     tri_upcast!();
2031    /// }
2032    ///
2033    /// let mut map = TriHashMap::new();
2034    /// map.insert_unique(Person {
2035    ///     id: 1,
2036    ///     email: "alice@example.com".to_string(),
2037    ///     phone: "555-1234".to_string(),
2038    ///     name: "Alice".to_string(),
2039    /// })
2040    /// .unwrap();
2041    ///
2042    /// let removed = map.remove1(&1);
2043    /// assert!(removed.is_some());
2044    /// assert_eq!(removed.unwrap().name, "Alice");
2045    /// assert!(map.is_empty());
2046    /// # }
2047    /// ```
2048    pub fn remove1<'a, Q>(&'a mut self, key1: &Q) -> Option<T>
2049    where
2050        Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
2051    {
2052        let (dormant_map, remove_index) = {
2053            let (map, dormant_map) = DormantMutRef::new(self);
2054            let remove_index = map.find1_index(key1)?;
2055            (dormant_map, remove_index)
2056        };
2057
2058        // SAFETY: `map` is not used after this point.
2059        let awakened_map = unsafe { dormant_map.awaken() };
2060
2061        awakened_map.remove_by_index(remove_index)
2062    }
2063
2064    /// Returns true if the map contains the given `key2`.
2065    ///
2066    /// # Examples
2067    ///
2068    /// ```
2069    /// # #[cfg(feature = "default-hasher")] {
2070    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2071    ///
2072    /// #[derive(Debug, PartialEq, Eq)]
2073    /// struct Person {
2074    ///     id: u32,
2075    ///     email: String,
2076    ///     phone: String,
2077    ///     name: String,
2078    /// }
2079    ///
2080    /// impl TriHashItem for Person {
2081    ///     type K1<'a> = u32;
2082    ///     type K2<'a> = &'a str;
2083    ///     type K3<'a> = &'a str;
2084    ///
2085    ///     fn key1(&self) -> Self::K1<'_> {
2086    ///         self.id
2087    ///     }
2088    ///     fn key2(&self) -> Self::K2<'_> {
2089    ///         &self.email
2090    ///     }
2091    ///     fn key3(&self) -> Self::K3<'_> {
2092    ///         &self.phone
2093    ///     }
2094    ///     tri_upcast!();
2095    /// }
2096    ///
2097    /// let mut map = TriHashMap::new();
2098    /// map.insert_unique(Person {
2099    ///     id: 1,
2100    ///     email: "alice@example.com".to_string(),
2101    ///     phone: "555-1234".to_string(),
2102    ///     name: "Alice".to_string(),
2103    /// })
2104    /// .unwrap();
2105    ///
2106    /// assert!(map.contains_key2("alice@example.com"));
2107    /// assert!(!map.contains_key2("bob@example.com"));
2108    /// # }
2109    /// ```
2110    pub fn contains_key2<'a, Q>(&'a self, key2: &Q) -> bool
2111    where
2112        Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2113    {
2114        self.find2_index(key2).is_some()
2115    }
2116
2117    /// Gets a reference to the value associated with the given `key2`.
2118    ///
2119    /// # Examples
2120    ///
2121    /// ```
2122    /// # #[cfg(feature = "default-hasher")] {
2123    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2124    ///
2125    /// #[derive(Debug, PartialEq, Eq)]
2126    /// struct Person {
2127    ///     id: u32,
2128    ///     email: String,
2129    ///     phone: String,
2130    ///     name: String,
2131    /// }
2132    ///
2133    /// impl TriHashItem for Person {
2134    ///     type K1<'a> = u32;
2135    ///     type K2<'a> = &'a str;
2136    ///     type K3<'a> = &'a str;
2137    ///
2138    ///     fn key1(&self) -> Self::K1<'_> {
2139    ///         self.id
2140    ///     }
2141    ///     fn key2(&self) -> Self::K2<'_> {
2142    ///         &self.email
2143    ///     }
2144    ///     fn key3(&self) -> Self::K3<'_> {
2145    ///         &self.phone
2146    ///     }
2147    ///     tri_upcast!();
2148    /// }
2149    ///
2150    /// let mut map = TriHashMap::new();
2151    /// map.insert_unique(Person {
2152    ///     id: 1,
2153    ///     email: "alice@example.com".to_string(),
2154    ///     phone: "555-1234".to_string(),
2155    ///     name: "Alice".to_string(),
2156    /// })
2157    /// .unwrap();
2158    ///
2159    /// assert_eq!(map.get2("alice@example.com").unwrap().name, "Alice");
2160    /// assert!(map.get2("bob@example.com").is_none());
2161    /// # }
2162    /// ```
2163    pub fn get2<'a, Q>(&'a self, key2: &Q) -> Option<&'a T>
2164    where
2165        Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2166    {
2167        self.find2(key2)
2168    }
2169
2170    /// Gets a mutable reference to the value associated with the given `key2`.
2171    ///
2172    /// # Examples
2173    ///
2174    /// ```
2175    /// # #[cfg(feature = "default-hasher")] {
2176    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2177    ///
2178    /// #[derive(Debug, PartialEq, Eq)]
2179    /// struct Person {
2180    ///     id: u32,
2181    ///     email: String,
2182    ///     phone: String,
2183    ///     name: String,
2184    /// }
2185    ///
2186    /// impl TriHashItem for Person {
2187    ///     type K1<'a> = u32;
2188    ///     type K2<'a> = &'a str;
2189    ///     type K3<'a> = &'a str;
2190    ///
2191    ///     fn key1(&self) -> Self::K1<'_> {
2192    ///         self.id
2193    ///     }
2194    ///     fn key2(&self) -> Self::K2<'_> {
2195    ///         &self.email
2196    ///     }
2197    ///     fn key3(&self) -> Self::K3<'_> {
2198    ///         &self.phone
2199    ///     }
2200    ///     tri_upcast!();
2201    /// }
2202    ///
2203    /// let mut map = TriHashMap::new();
2204    /// map.insert_unique(Person {
2205    ///     id: 1,
2206    ///     email: "alice@example.com".to_string(),
2207    ///     phone: "555-1234".to_string(),
2208    ///     name: "Alice".to_string(),
2209    /// })
2210    /// .unwrap();
2211    ///
2212    /// if let Some(mut person) = map.get2_mut("alice@example.com") {
2213    ///     person.name = "Alice Updated".to_string();
2214    /// }
2215    ///
2216    /// assert_eq!(map.get2("alice@example.com").unwrap().name, "Alice Updated");
2217    /// # }
2218    /// ```
2219    pub fn get2_mut<'a, Q>(&'a mut self, key2: &Q) -> Option<RefMut<'a, T, S>>
2220    where
2221        Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2222    {
2223        let (dormant_map, index) = {
2224            let (map, dormant_map) = DormantMutRef::new(self);
2225            let index = map.find2_index(key2)?;
2226            (dormant_map, index)
2227        };
2228
2229        // SAFETY: `map` is not used after this point.
2230        let awakened_map = unsafe { dormant_map.awaken() };
2231        let item = &mut awakened_map.items[index];
2232        let state = awakened_map.tables.state.clone();
2233        let hashes = awakened_map.tables.make_hashes(&item);
2234        Some(RefMut::new(state, hashes, item))
2235    }
2236
2237    /// Removes an item from the map by its `key2`.
2238    ///
2239    /// # Examples
2240    ///
2241    /// ```
2242    /// # #[cfg(feature = "default-hasher")] {
2243    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2244    ///
2245    /// #[derive(Debug, PartialEq, Eq)]
2246    /// struct Person {
2247    ///     id: u32,
2248    ///     email: String,
2249    ///     phone: String,
2250    ///     name: String,
2251    /// }
2252    ///
2253    /// impl TriHashItem for Person {
2254    ///     type K1<'a> = u32;
2255    ///     type K2<'a> = &'a str;
2256    ///     type K3<'a> = &'a str;
2257    ///
2258    ///     fn key1(&self) -> Self::K1<'_> {
2259    ///         self.id
2260    ///     }
2261    ///     fn key2(&self) -> Self::K2<'_> {
2262    ///         &self.email
2263    ///     }
2264    ///     fn key3(&self) -> Self::K3<'_> {
2265    ///         &self.phone
2266    ///     }
2267    ///     tri_upcast!();
2268    /// }
2269    ///
2270    /// let mut map = TriHashMap::new();
2271    /// map.insert_unique(Person {
2272    ///     id: 1,
2273    ///     email: "alice@example.com".to_string(),
2274    ///     phone: "555-1234".to_string(),
2275    ///     name: "Alice".to_string(),
2276    /// })
2277    /// .unwrap();
2278    ///
2279    /// let removed = map.remove2("alice@example.com");
2280    /// assert!(removed.is_some());
2281    /// assert_eq!(removed.unwrap().name, "Alice");
2282    /// assert!(map.is_empty());
2283    /// # }
2284    /// ```
2285    pub fn remove2<'a, Q>(&'a mut self, key2: &Q) -> Option<T>
2286    where
2287        Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2288    {
2289        let (dormant_map, remove_index) = {
2290            let (map, dormant_map) = DormantMutRef::new(self);
2291            let remove_index = map.find2_index(key2)?;
2292            (dormant_map, remove_index)
2293        };
2294
2295        // SAFETY: `map` is not used after this point.
2296        let awakened_map = unsafe { dormant_map.awaken() };
2297
2298        awakened_map.remove_by_index(remove_index)
2299    }
2300
2301    /// Returns true if the map contains the given `key3`.
2302    ///
2303    /// # Examples
2304    ///
2305    /// ```
2306    /// # #[cfg(feature = "default-hasher")] {
2307    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2308    ///
2309    /// #[derive(Debug, PartialEq, Eq)]
2310    /// struct Person {
2311    ///     id: u32,
2312    ///     email: String,
2313    ///     phone: String,
2314    ///     name: String,
2315    /// }
2316    ///
2317    /// impl TriHashItem for Person {
2318    ///     type K1<'a> = u32;
2319    ///     type K2<'a> = &'a str;
2320    ///     type K3<'a> = &'a str;
2321    ///
2322    ///     fn key1(&self) -> Self::K1<'_> {
2323    ///         self.id
2324    ///     }
2325    ///     fn key2(&self) -> Self::K2<'_> {
2326    ///         &self.email
2327    ///     }
2328    ///     fn key3(&self) -> Self::K3<'_> {
2329    ///         &self.phone
2330    ///     }
2331    ///     tri_upcast!();
2332    /// }
2333    ///
2334    /// let mut map = TriHashMap::new();
2335    /// map.insert_unique(Person {
2336    ///     id: 1,
2337    ///     email: "alice@example.com".to_string(),
2338    ///     phone: "555-1234".to_string(),
2339    ///     name: "Alice".to_string(),
2340    /// })
2341    /// .unwrap();
2342    ///
2343    /// assert!(map.contains_key3("555-1234"));
2344    /// assert!(!map.contains_key3("555-5678"));
2345    /// # }
2346    /// ```
2347    pub fn contains_key3<'a, Q>(&'a self, key3: &Q) -> bool
2348    where
2349        Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2350    {
2351        self.find3_index(key3).is_some()
2352    }
2353
2354    /// Gets a reference to the value associated with the given `key3`.
2355    ///
2356    /// # Examples
2357    ///
2358    /// ```
2359    /// # #[cfg(feature = "default-hasher")] {
2360    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2361    ///
2362    /// #[derive(Debug, PartialEq, Eq)]
2363    /// struct Person {
2364    ///     id: u32,
2365    ///     email: String,
2366    ///     phone: String,
2367    ///     name: String,
2368    /// }
2369    ///
2370    /// impl TriHashItem for Person {
2371    ///     type K1<'a> = u32;
2372    ///     type K2<'a> = &'a str;
2373    ///     type K3<'a> = &'a str;
2374    ///
2375    ///     fn key1(&self) -> Self::K1<'_> {
2376    ///         self.id
2377    ///     }
2378    ///     fn key2(&self) -> Self::K2<'_> {
2379    ///         &self.email
2380    ///     }
2381    ///     fn key3(&self) -> Self::K3<'_> {
2382    ///         &self.phone
2383    ///     }
2384    ///     tri_upcast!();
2385    /// }
2386    ///
2387    /// let mut map = TriHashMap::new();
2388    /// map.insert_unique(Person {
2389    ///     id: 1,
2390    ///     email: "alice@example.com".to_string(),
2391    ///     phone: "555-1234".to_string(),
2392    ///     name: "Alice".to_string(),
2393    /// })
2394    /// .unwrap();
2395    ///
2396    /// assert_eq!(map.get3("555-1234").unwrap().name, "Alice");
2397    /// assert!(map.get3("555-5678").is_none());
2398    /// # }
2399    /// ```
2400    pub fn get3<'a, Q>(&'a self, key3: &Q) -> Option<&'a T>
2401    where
2402        Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2403    {
2404        self.find3(key3)
2405    }
2406
2407    /// Gets a mutable reference to the value associated with the given `key3`.
2408    ///
2409    /// # Examples
2410    ///
2411    /// ```
2412    /// # #[cfg(feature = "default-hasher")] {
2413    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2414    ///
2415    /// #[derive(Debug, PartialEq, Eq)]
2416    /// struct Person {
2417    ///     id: u32,
2418    ///     email: String,
2419    ///     phone: String,
2420    ///     name: String,
2421    /// }
2422    ///
2423    /// impl TriHashItem for Person {
2424    ///     type K1<'a> = u32;
2425    ///     type K2<'a> = &'a str;
2426    ///     type K3<'a> = &'a str;
2427    ///
2428    ///     fn key1(&self) -> Self::K1<'_> {
2429    ///         self.id
2430    ///     }
2431    ///     fn key2(&self) -> Self::K2<'_> {
2432    ///         &self.email
2433    ///     }
2434    ///     fn key3(&self) -> Self::K3<'_> {
2435    ///         &self.phone
2436    ///     }
2437    ///     tri_upcast!();
2438    /// }
2439    ///
2440    /// let mut map = TriHashMap::new();
2441    /// map.insert_unique(Person {
2442    ///     id: 1,
2443    ///     email: "alice@example.com".to_string(),
2444    ///     phone: "555-1234".to_string(),
2445    ///     name: "Alice".to_string(),
2446    /// })
2447    /// .unwrap();
2448    ///
2449    /// if let Some(mut person) = map.get3_mut("555-1234") {
2450    ///     person.name = "Alice Updated".to_string();
2451    /// }
2452    ///
2453    /// assert_eq!(map.get3("555-1234").unwrap().name, "Alice Updated");
2454    /// # }
2455    /// ```
2456    pub fn get3_mut<'a, Q>(&'a mut self, key3: &Q) -> Option<RefMut<'a, T, S>>
2457    where
2458        Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2459    {
2460        let (dormant_map, index) = {
2461            let (map, dormant_map) = DormantMutRef::new(self);
2462            let index = map.find3_index(key3)?;
2463            (dormant_map, index)
2464        };
2465
2466        // SAFETY: `map` is not used after this point.
2467        let awakened_map = unsafe { dormant_map.awaken() };
2468        let item = &mut awakened_map.items[index];
2469        let state = awakened_map.tables.state.clone();
2470        let hashes = awakened_map.tables.make_hashes(&item);
2471        Some(RefMut::new(state, hashes, item))
2472    }
2473
2474    /// Removes an item from the map by its `key3`.
2475    ///
2476    /// # Examples
2477    ///
2478    /// ```
2479    /// # #[cfg(feature = "default-hasher")] {
2480    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2481    ///
2482    /// #[derive(Debug, PartialEq, Eq)]
2483    /// struct Person {
2484    ///     id: u32,
2485    ///     email: String,
2486    ///     phone: String,
2487    ///     name: String,
2488    /// }
2489    ///
2490    /// impl TriHashItem for Person {
2491    ///     type K1<'a> = u32;
2492    ///     type K2<'a> = &'a str;
2493    ///     type K3<'a> = &'a str;
2494    ///
2495    ///     fn key1(&self) -> Self::K1<'_> {
2496    ///         self.id
2497    ///     }
2498    ///     fn key2(&self) -> Self::K2<'_> {
2499    ///         &self.email
2500    ///     }
2501    ///     fn key3(&self) -> Self::K3<'_> {
2502    ///         &self.phone
2503    ///     }
2504    ///     tri_upcast!();
2505    /// }
2506    ///
2507    /// let mut map = TriHashMap::new();
2508    /// map.insert_unique(Person {
2509    ///     id: 1,
2510    ///     email: "alice@example.com".to_string(),
2511    ///     phone: "555-1234".to_string(),
2512    ///     name: "Alice".to_string(),
2513    /// })
2514    /// .unwrap();
2515    ///
2516    /// let removed = map.remove3("555-1234");
2517    /// assert!(removed.is_some());
2518    /// assert_eq!(removed.unwrap().name, "Alice");
2519    /// assert!(map.is_empty());
2520    /// # }
2521    /// ```
2522    pub fn remove3<'a, Q>(&'a mut self, key3: &Q) -> Option<T>
2523    where
2524        Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2525    {
2526        let (dormant_map, remove_index) = {
2527            let (map, dormant_map) = DormantMutRef::new(self);
2528            let remove_index = map.find3_index(key3)?;
2529            (dormant_map, remove_index)
2530        };
2531
2532        // SAFETY: `map` is not used after this point.
2533        let awakened_map = unsafe { dormant_map.awaken() };
2534
2535        awakened_map.remove_by_index(remove_index)
2536    }
2537
2538    /// Retains only the elements specified by the predicate.
2539    ///
2540    /// In other words, remove all items `T` for which `f(RefMut<T>)` returns
2541    /// false. The elements are visited in an arbitrary order.
2542    ///
2543    /// The `RefMut<T, S>` wrapper allows mutable access to the item while
2544    /// enforcing that the three keys (`K1`, `K2`, `K3`) remain unchanged. If
2545    /// a key is modified during iteration, the method will panic.
2546    ///
2547    /// # Performance considerations
2548    ///
2549    /// This method may leave the internal storage fragmented. If you need
2550    /// compact storage afterward, call `make_compact()`.
2551    ///
2552    /// # Examples
2553    ///
2554    /// ```
2555    /// # #[cfg(feature = "default-hasher")] {
2556    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2557    ///
2558    /// #[derive(Debug, PartialEq, Eq, Hash)]
2559    /// struct Item {
2560    ///     id: u32,
2561    ///     name: String,
2562    ///     code: String,
2563    ///     value: u32,
2564    /// }
2565    ///
2566    /// impl TriHashItem for Item {
2567    ///     type K1<'a> = u32;
2568    ///     type K2<'a> = &'a str;
2569    ///     type K3<'a> = &'a str;
2570    ///
2571    ///     fn key1(&self) -> Self::K1<'_> {
2572    ///         self.id
2573    ///     }
2574    ///     fn key2(&self) -> Self::K2<'_> {
2575    ///         &self.name
2576    ///     }
2577    ///     fn key3(&self) -> Self::K3<'_> {
2578    ///         &self.code
2579    ///     }
2580    ///
2581    ///     tri_upcast!();
2582    /// }
2583    ///
2584    /// let mut map = TriHashMap::new();
2585    /// map.insert_unique(Item {
2586    ///     id: 1,
2587    ///     name: "foo".to_string(),
2588    ///     code: "x".to_string(),
2589    ///     value: 42,
2590    /// })
2591    /// .unwrap();
2592    /// map.insert_unique(Item {
2593    ///     id: 2,
2594    ///     name: "bar".to_string(),
2595    ///     code: "y".to_string(),
2596    ///     value: 20,
2597    /// })
2598    /// .unwrap();
2599    /// map.insert_unique(Item {
2600    ///     id: 3,
2601    ///     name: "baz".to_string(),
2602    ///     code: "z".to_string(),
2603    ///     value: 99,
2604    /// })
2605    /// .unwrap();
2606    ///
2607    /// // Retain only items where value is greater than 30
2608    /// map.retain(|item| item.value > 30);
2609    ///
2610    /// assert_eq!(map.len(), 2);
2611    /// assert_eq!(map.get1(&1).unwrap().value, 42);
2612    /// assert_eq!(map.get1(&3).unwrap().value, 99);
2613    /// assert!(map.get1(&2).is_none());
2614    /// # }
2615    /// ```
2616    pub fn retain<'a, F>(&'a mut self, mut f: F)
2617    where
2618        F: for<'b> FnMut(RefMut<'b, T, S>) -> bool,
2619    {
2620        let hash_state = self.tables.state.clone();
2621        let (_, mut dormant_items) = DormantMutRef::new(&mut self.items);
2622        let mut removed_item = None;
2623
2624        self.tables.k1_to_item.retain(|index| {
2625            // Drop the previously-removed item here, at the top of the next
2626            // iteration.
2627            //
2628            // By now, the prior `k1_to_item` entry has been erased, so if
2629            // `drop` below panics, `k1_to_item`, `k2_to_item`, `k3_to_item`,
2630            // and `items` remain in sync. Dropping the item at the end of the
2631            // prior iteration would unwind before the table erased the entry,
2632            // leaving `k1_to_item` pointing at a slot we already removed from
2633            // `items`, `k2_to_item`, and `k3_to_item`.
2634            drop(removed_item.take());
2635
2636            let (item, dormant_items) = {
2637                // SAFETY: All uses of `items` ended in the previous iteration.
2638                let items = unsafe { dormant_items.reborrow() };
2639                let (items, dormant_items) = DormantMutRef::new(items);
2640                let item: &'a mut T = items
2641                    .get_mut(index)
2642                    .expect("all indexes are present in self.items");
2643                (item, dormant_items)
2644            };
2645
2646            let (hashes, dormant_item) = {
2647                let (item, dormant_item): (&'a mut T, _) =
2648                    DormantMutRef::new(item);
2649                // Use T::k1(item) rather than item.key() to force the key
2650                // trait function to be called for T rather than &mut T.
2651                let key1 = T::key1(item);
2652                let key2 = T::key2(item);
2653                let key3 = T::key3(item);
2654                let hash1 = hash_state.hash_one(key1);
2655                let hash2 = hash_state.hash_one(key2);
2656                let hash3 = hash_state.hash_one(key3);
2657                (
2658                    [
2659                        MapHash::new(hash1),
2660                        MapHash::new(hash2),
2661                        MapHash::new(hash3),
2662                    ],
2663                    dormant_item,
2664                )
2665            };
2666
2667            let hash2 = hashes[1].hash();
2668            let hash3 = hashes[2].hash();
2669            let retain = {
2670                // SAFETY: The original item is no longer used after the second
2671                // block above. dormant_items, from which item is derived, is
2672                // currently dormant.
2673                let item = unsafe { dormant_item.awaken() };
2674
2675                let ref_mut = RefMut::new(hash_state.clone(), hashes, item);
2676                f(ref_mut)
2677            };
2678
2679            if retain {
2680                true
2681            } else {
2682                let k2_entry = self
2683                    .tables
2684                    .k2_to_item
2685                    .find_entry_by_hash(hash2, |map2_index| {
2686                        map2_index == index
2687                    });
2688                let k3_entry = self
2689                    .tables
2690                    .k3_to_item
2691                    .find_entry_by_hash(hash3, |map3_index| {
2692                        map3_index == index
2693                    });
2694
2695                if let Ok(k2_entry) = k2_entry {
2696                    k2_entry.remove();
2697                } else {
2698                    self.tables.k2_to_item.remove_by_index(index);
2699                }
2700                if let Ok(k3_entry) = k3_entry {
2701                    k3_entry.remove();
2702                } else {
2703                    self.tables.k3_to_item.remove_by_index(index);
2704                }
2705
2706                // SAFETY: The original items is no longer used after the first
2707                // block above, and item + dormant_item have been dropped after
2708                // being used above. The k2/k3 work between them borrows only
2709                // `self.tables.k2_to_item` and `self.tables.k3_to_item`,
2710                // which are disjoint from `self.items`.
2711                let items = unsafe { dormant_items.awaken() };
2712                removed_item = Some(
2713                    items
2714                        .remove(index)
2715                        .expect("all indexes are present in self.items"),
2716                );
2717
2718                false
2719            }
2720        });
2721
2722        // Anything in `removed_item` is implicitly dropped now.
2723    }
2724
2725    fn find1<'a, Q>(&'a self, k: &Q) -> Option<&'a T>
2726    where
2727        Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
2728    {
2729        self.find1_index(k).map(|ix| &self.items[ix])
2730    }
2731
2732    fn find1_index<'a, Q>(&'a self, k: &Q) -> Option<ItemIndex>
2733    where
2734        Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
2735    {
2736        self.tables
2737            .k1_to_item
2738            .find_index(&self.tables.state, k, |index| self.items[index].key1())
2739    }
2740
2741    fn find2<'a, Q>(&'a self, k: &Q) -> Option<&'a T>
2742    where
2743        Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2744    {
2745        self.find2_index(k).map(|ix| &self.items[ix])
2746    }
2747
2748    fn find2_index<'a, Q>(&'a self, k: &Q) -> Option<ItemIndex>
2749    where
2750        Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2751    {
2752        self.tables
2753            .k2_to_item
2754            .find_index(&self.tables.state, k, |index| self.items[index].key2())
2755    }
2756
2757    fn find3<'a, Q>(&'a self, k: &Q) -> Option<&'a T>
2758    where
2759        Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2760    {
2761        self.find3_index(k).map(|ix| &self.items[ix])
2762    }
2763
2764    fn find3_index<'a, Q>(&'a self, k: &Q) -> Option<ItemIndex>
2765    where
2766        Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2767    {
2768        self.tables
2769            .k3_to_item
2770            .find_index(&self.tables.state, k, |index| self.items[index].key3())
2771    }
2772
2773    fn prepare_insert_overwrite(&self, value: &T) -> PreparedInsertOverwrite {
2774        let key1 = value.key1();
2775        let key2 = value.key2();
2776        let key3 = value.key3();
2777
2778        let index1 = self.find1_index(&key1);
2779        let index2 = self.find2_index(&key2);
2780        let index3 = self.find3_index(&key3);
2781        let hashes = self.tables.make_hashes_for_keys::<T>(&key1, &key2, &key3);
2782
2783        let duplicates = PreparedDuplicate::from_indexes(
2784            [index1, index2, index3],
2785            |index| self.prepare_duplicate(index),
2786        );
2787
2788        PreparedInsertOverwrite { duplicates, hashes }
2789    }
2790
2791    fn prepare_duplicate(&self, index: ItemIndex) -> PreparedDuplicate {
2792        let item = &self.items[index];
2793        let hashes = self.tables.make_hashes::<T>(item);
2794
2795        PreparedDuplicate { index, hashes }
2796    }
2797
2798    fn try_reserve_insert_overwrite_commit(
2799        &mut self,
2800        needs_new_item_slot: bool,
2801    ) -> Result<(), TryReserveError> {
2802        if needs_new_item_slot {
2803            self.items.try_reserve(1)?;
2804        }
2805
2806        self.tables
2807            .k1_to_item
2808            .try_reserve(1)
2809            .map_err(TryReserveError::from_hashbrown)?;
2810
2811        self.tables
2812            .k2_to_item
2813            .try_reserve(1)
2814            .map_err(TryReserveError::from_hashbrown)?;
2815
2816        self.tables
2817            .k3_to_item
2818            .try_reserve(1)
2819            .map_err(TryReserveError::from_hashbrown)?;
2820
2821        Ok(())
2822    }
2823
2824    fn commit_insert_overwrite(
2825        &mut self,
2826        value: T,
2827        prepared: PreparedInsertOverwrite,
2828        duplicates: &mut Vec<T>,
2829    ) -> ItemIndex {
2830        // From here until insertion completes, do not call user code or
2831        // allocate. The caller prepared hashes/indexes and reserved capacity.
2832        for duplicate in prepared.duplicates {
2833            duplicates.push(
2834                self.remove_duplicate(duplicate)
2835                    .expect("duplicate index was prepared"),
2836            );
2837        }
2838
2839        self.insert_unique_with_prepared_hashes(value, prepared.hashes)
2840    }
2841
2842    fn insert_unique_with_prepared_hashes(
2843        &mut self,
2844        value: T,
2845        hashes: [MapHash; 3],
2846    ) -> ItemIndex {
2847        let [hash1, hash2, hash3] = hashes;
2848        let next_index = self.items.assert_can_grow().insert(value);
2849
2850        self.tables.k1_to_item.insert_prehashed_unchecked(hash1, next_index);
2851        self.tables.k2_to_item.insert_prehashed_unchecked(hash2, next_index);
2852        self.tables.k3_to_item.insert_prehashed_unchecked(hash3, next_index);
2853
2854        next_index
2855    }
2856
2857    pub(super) fn remove_by_index(
2858        &mut self,
2859        remove_index: ItemIndex,
2860    ) -> Option<T> {
2861        // For panic safety, compute all three key hashes and look up all three
2862        // table entries while `self.items` still holds the value, then remove
2863        // from all three tables and items in sequence. These lookups
2864        // deliberately match by `ItemIndex` rather than by user `Eq`: at this
2865        // point we already know which item is being removed, and user `Eq`
2866        // might be pathological. hashbrown's `find_entry_by_hash` is
2867        // panic-safe because the table is not mutated until
2868        // `OccupiedEntry::remove` is called, so a panic while hashing leaves
2869        // items and all three tables unmodified. (Unlike the IdOrdMap path,
2870        // no separate two-phase commit is needed: the BTreeMap analog has to
2871        // guard against a user-`Ord` panic during the tree walk, but the
2872        // hash walk here never invokes user code.)
2873        //
2874        // If any hash lookup misses — which happens when a `mem::forget` on
2875        // a `RefMut` bypassed the drop-time hash check and one of the item's
2876        // keys now hashes to a different bucket than its entry sits in —
2877        // fall back to a linear scan by `ItemIndex` for that table. The
2878        // fallback never invokes user `Hash`, so cleanup remains panic-safe.
2879        let item = self.items.get(remove_index)?;
2880        let state = &self.tables.state;
2881        let hash1 = state.hash_one(item.key1());
2882        let hash2 = state.hash_one(item.key2());
2883        let hash3 = state.hash_one(item.key3());
2884        match self
2885            .tables
2886            .k1_to_item
2887            .find_entry_by_hash(hash1, |index| index == remove_index)
2888        {
2889            Ok(entry) => entry.remove(),
2890            Err(()) => self.tables.k1_to_item.remove_by_index(remove_index),
2891        }
2892        match self
2893            .tables
2894            .k2_to_item
2895            .find_entry_by_hash(hash2, |index| index == remove_index)
2896        {
2897            Ok(entry) => entry.remove(),
2898            Err(()) => self.tables.k2_to_item.remove_by_index(remove_index),
2899        }
2900        match self
2901            .tables
2902            .k3_to_item
2903            .find_entry_by_hash(hash3, |index| index == remove_index)
2904        {
2905            Ok(entry) => entry.remove(),
2906            Err(()) => self.tables.k3_to_item.remove_by_index(remove_index),
2907        }
2908        Some(
2909            self.items
2910                .remove(remove_index)
2911                .expect("items[remove_index] was Occupied above"),
2912        )
2913    }
2914
2915    /// Removes the item at `duplicate`, using already-computed key hashes when
2916    /// possible.
2917    ///
2918    /// The caller must ensure:
2919    ///
2920    /// * all user-controlled key extraction and hashing for the item at
2921    ///   `duplicate.index` has already completed;
2922    /// * the item at `duplicate.index` has not changed since those hashes were
2923    ///   computed;
2924    /// * removing this index from the item store and key tables preserves the
2925    ///   map/table invariants.
2926    ///
2927    /// The provided `duplicate.hashes` allow the normal commit path to remove
2928    /// key-table entries without recomputing user-controlled hashes. If a
2929    /// prehashed lookup misses, this falls back to removing by `ItemIndex`,
2930    /// which performs a linear scan over cached indexes and does not re-enter
2931    /// user code.
2932    fn remove_duplicate(&mut self, duplicate: PreparedDuplicate) -> Option<T> {
2933        let _ = self.items.get(duplicate.index)?;
2934
2935        let [hash1, hash2, hash3] = duplicate.hashes;
2936
2937        match self
2938            .tables
2939            .k1_to_item
2940            .find_entry_by_hash(hash1.hash(), |index| index == duplicate.index)
2941        {
2942            Ok(entry) => entry.remove(),
2943            Err(()) => self.tables.k1_to_item.remove_by_index(duplicate.index),
2944        }
2945
2946        match self
2947            .tables
2948            .k2_to_item
2949            .find_entry_by_hash(hash2.hash(), |index| index == duplicate.index)
2950        {
2951            Ok(entry) => entry.remove(),
2952            Err(()) => self.tables.k2_to_item.remove_by_index(duplicate.index),
2953        }
2954
2955        match self
2956            .tables
2957            .k3_to_item
2958            .find_entry_by_hash(hash3.hash(), |index| index == duplicate.index)
2959        {
2960            Ok(entry) => entry.remove(),
2961            Err(()) => self.tables.k3_to_item.remove_by_index(duplicate.index),
2962        }
2963
2964        Some(
2965            self.items
2966                .remove(duplicate.index)
2967                .expect("items[duplicate.index] was Occupied above"),
2968        )
2969    }
2970}
2971
2972impl<'a, T, S, A: Allocator> fmt::Debug for TriHashMap<T, S, A>
2973where
2974    T: TriHashItem + fmt::Debug,
2975    T::K1<'a>: fmt::Debug,
2976    T::K2<'a>: fmt::Debug,
2977    T::K3<'a>: fmt::Debug,
2978    T: 'a,
2979{
2980    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2981        let mut map = f.debug_map();
2982        for item in self.items.values() {
2983            let key: KeyMap<'_, T> = KeyMap {
2984                key1: item.key1(),
2985                key2: item.key2(),
2986                key3: item.key3(),
2987            };
2988
2989            // SAFETY:
2990            //
2991            // * Lifetime extension: for a type T and two lifetime params 'a and
2992            //   'b, T<'a> and T<'b> aren't guaranteed to have the same layout,
2993            //   but (a) that is true today and (b) it would be shocking and
2994            //   break half the Rust ecosystem if that were to change in the
2995            //   future.
2996            // * We only use key within the scope of this block before immediately
2997            //   dropping it. In particular, map.entry calls key.fmt() without
2998            //   holding a reference to it.
2999            let key: KeyMap<'a, T> = unsafe {
3000                core::mem::transmute::<KeyMap<'_, T>, KeyMap<'a, T>>(key)
3001            };
3002
3003            map.entry(&key, item);
3004        }
3005        map.finish()
3006    }
3007}
3008
3009struct KeyMap<'a, T: TriHashItem + 'a> {
3010    key1: T::K1<'a>,
3011    key2: T::K2<'a>,
3012    key3: T::K3<'a>,
3013}
3014
3015impl<'a, T: TriHashItem> fmt::Debug for KeyMap<'a, T>
3016where
3017    T::K1<'a>: fmt::Debug,
3018    T::K2<'a>: fmt::Debug,
3019    T::K3<'a>: fmt::Debug,
3020{
3021    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3022        // We don't want to show key1 and key2 as a tuple since it's
3023        // misleading (suggests maps of tuples). The best we can do
3024        // instead is to show "{k1: abc, k2: xyz, k3: def}"
3025        f.debug_map()
3026            .entry(&StrDisplayAsDebug("k1"), &self.key1)
3027            .entry(&StrDisplayAsDebug("k2"), &self.key2)
3028            .entry(&StrDisplayAsDebug("k3"), &self.key3)
3029            .finish()
3030    }
3031}
3032
3033impl<T: TriHashItem + PartialEq, S: Clone + BuildHasher, A: Allocator> PartialEq
3034    for TriHashMap<T, S, A>
3035{
3036    fn eq(&self, other: &Self) -> bool {
3037        // Implementing PartialEq for TriHashMap is tricky because TriHashMap is
3038        // not semantically like an IndexMap: two maps are equivalent even if
3039        // their items are in a different order. In other words, any permutation
3040        // of items is equivalent.
3041        //
3042        // We also can't sort the items because they're not necessarily Ord.
3043        //
3044        // So we write a custom equality check that checks that each key in one
3045        // map points to the same item as in the other map.
3046
3047        if self.items.len() != other.items.len() {
3048            return false;
3049        }
3050
3051        // Walk over all the items in the first map and check that they point to
3052        // the same item in the second map.
3053        for item in self.items.values() {
3054            let k1 = item.key1();
3055            let k2 = item.key2();
3056            let k3 = item.key3();
3057
3058            // Check that the indexes are the same in the other map.
3059            let Some(other_ix1) = other.find1_index(&k1) else {
3060                return false;
3061            };
3062            let Some(other_ix2) = other.find2_index(&k2) else {
3063                return false;
3064            };
3065            let Some(other_ix3) = other.find3_index(&k3) else {
3066                return false;
3067            };
3068
3069            if other_ix1 != other_ix2 || other_ix1 != other_ix3 {
3070                // All the keys were present but they didn't point to the same
3071                // item.
3072                return false;
3073            }
3074
3075            // Check that the other map's item is the same as this map's
3076            // item. (This is what we use the `PartialEq` bound on T for.)
3077            //
3078            // Because we've checked that other_ix1, other_ix2 and other_ix3 are
3079            // Some, we know that it is valid and points to the expected item.
3080            let other_item = &other.items[other_ix1];
3081            if item != other_item {
3082                return false;
3083            }
3084        }
3085
3086        true
3087    }
3088}
3089
3090// The Eq bound on T ensures that the TriHashMap forms an equivalence class.
3091impl<T: TriHashItem + Eq, S: Clone + BuildHasher, A: Allocator> Eq
3092    for TriHashMap<T, S, A>
3093{
3094}
3095
3096/// The `Extend` implementation overwrites duplicates. In the future, there will
3097/// also be an `extend_unique` method that will return an error.
3098impl<T: TriHashItem, S: Clone + BuildHasher, A: Allocator> Extend<T>
3099    for TriHashMap<T, S, A>
3100{
3101    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
3102        // Keys may already be present in the map, or multiple times in the
3103        // iterator. Reserve the entire hint lower bound if the map is empty.
3104        // Otherwise reserve half the hint (rounded up), so the map will only
3105        // resize twice in the worst case.
3106        let iter = iter.into_iter();
3107        let reserve = if self.is_empty() {
3108            iter.size_hint().0
3109        } else {
3110            iter.size_hint().0.div_ceil(2)
3111        };
3112        self.reserve(reserve);
3113        for item in iter {
3114            self.insert_overwrite(item);
3115        }
3116    }
3117}
3118
3119fn detect_dup_or_insert<'a, A: Allocator>(
3120    item: hash_table::Entry<'a, A>,
3121    duplicates: &mut BTreeSet<ItemIndex>,
3122) -> Option<hash_table::VacantEntry<'a, A>> {
3123    match item {
3124        hash_table::Entry::Vacant(slot) => Some(slot),
3125        hash_table::Entry::Occupied(slot) => {
3126            duplicates.insert(slot.get());
3127            None
3128        }
3129    }
3130}
3131
3132impl<'a, T: TriHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
3133    for &'a TriHashMap<T, S, A>
3134{
3135    type Item = &'a T;
3136    type IntoIter = Iter<'a, T>;
3137
3138    #[inline]
3139    fn into_iter(self) -> Self::IntoIter {
3140        self.iter()
3141    }
3142}
3143
3144impl<'a, T: TriHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
3145    for &'a mut TriHashMap<T, S, A>
3146{
3147    type Item = RefMut<'a, T, S>;
3148    type IntoIter = IterMut<'a, T, S, A>;
3149
3150    #[inline]
3151    fn into_iter(self) -> Self::IntoIter {
3152        self.iter_mut()
3153    }
3154}
3155
3156impl<T: TriHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
3157    for TriHashMap<T, S, A>
3158{
3159    type Item = T;
3160    type IntoIter = IntoIter<T, A>;
3161
3162    #[inline]
3163    fn into_iter(self) -> Self::IntoIter {
3164        IntoIter::new(self.items)
3165    }
3166}
3167
3168/// The `FromIterator` implementation for `TriHashMap` overwrites duplicate
3169/// items.
3170///
3171/// # Examples
3172///
3173/// ```
3174/// # #[cfg(feature = "default-hasher")] {
3175/// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
3176///
3177/// #[derive(Debug, PartialEq, Eq)]
3178/// struct Item {
3179///     id: u32,
3180///     name: String,
3181///     email: String,
3182/// }
3183///
3184/// impl TriHashItem for Item {
3185///     type K1<'a> = u32;
3186///     type K2<'a> = &'a str;
3187///     type K3<'a> = &'a str;
3188///     fn key1(&self) -> Self::K1<'_> {
3189///         self.id
3190///     }
3191///     fn key2(&self) -> Self::K2<'_> {
3192///         &self.name
3193///     }
3194///     fn key3(&self) -> Self::K3<'_> {
3195///         &self.email
3196///     }
3197///     tri_upcast!();
3198/// }
3199///
3200/// let items = vec![
3201///     Item {
3202///         id: 1,
3203///         name: "foo".to_string(),
3204///         email: "foo@example.com".to_string(),
3205///     },
3206///     Item {
3207///         id: 2,
3208///         name: "bar".to_string(),
3209///         email: "bar@example.com".to_string(),
3210///     },
3211///     Item {
3212///         id: 1,
3213///         name: "baz".to_string(),
3214///         email: "baz@example.com".to_string(),
3215///     }, // overwrites first item
3216/// ];
3217///
3218/// let map: TriHashMap<Item> = items.into_iter().collect();
3219/// assert_eq!(map.len(), 2);
3220/// assert_eq!(map.get1(&1).unwrap().name, "baz"); // overwritten
3221/// assert_eq!(map.get1(&1).unwrap().email, "baz@example.com");
3222/// assert_eq!(map.get1(&2).unwrap().name, "bar");
3223/// # }
3224/// ```
3225impl<T: TriHashItem, S: Default + Clone + BuildHasher, A: Default + Allocator>
3226    FromIterator<T> for TriHashMap<T, S, A>
3227{
3228    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
3229        let mut map = TriHashMap::default();
3230        map.extend(iter);
3231        map
3232    }
3233}