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