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