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