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