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