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