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