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