iddqd/bi_hash_map/
entry.rs

1use super::{BiHashItem, BiHashMap, RefMut, entry_indexes::EntryIndexes};
2use crate::{
3    DefaultHashBuilder,
4    support::{
5        alloc::{Allocator, Global},
6        borrow::DormantMutRef,
7        map_hash::MapHash,
8    },
9};
10use alloc::vec::Vec;
11use core::{fmt, hash::BuildHasher};
12
13/// An implementation of the Entry API for [`BiHashMap`].
14pub enum Entry<'a, T: BiHashItem, S = DefaultHashBuilder, A: Allocator = Global>
15{
16    /// A vacant entry: none of the provided keys are present.
17    Vacant(VacantEntry<'a, T, S, A>),
18    /// An occupied entry where at least one of the keys is present in the map.
19    Occupied(OccupiedEntry<'a, T, S, A>),
20}
21
22impl<'a, T: BiHashItem, S, A: Allocator> fmt::Debug for Entry<'a, T, S, A> {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        match self {
25            Entry::Vacant(entry) => {
26                f.debug_tuple("Vacant").field(entry).finish()
27            }
28            Entry::Occupied(entry) => {
29                f.debug_tuple("Occupied").field(entry).finish()
30            }
31        }
32    }
33}
34
35impl<'a, T: BiHashItem, S: Clone + BuildHasher, A: Allocator>
36    Entry<'a, T, S, A>
37{
38    /// Ensures a value is in the entry by inserting the default if empty, and
39    /// returns a mutable reference to the value in the entry.
40    ///
41    /// # Panics
42    ///
43    /// Panics if the key hashes to a different value than the one passed
44    /// into [`BiHashMap::entry`].
45    #[inline]
46    pub fn or_insert(self, default: T) -> OccupiedEntryMut<'a, T, S> {
47        match self {
48            Entry::Occupied(entry) => entry.into_mut(),
49            Entry::Vacant(entry) => {
50                OccupiedEntryMut::Unique(entry.insert(default))
51            }
52        }
53    }
54
55    /// Ensures a value is in the entry by inserting the result of the default
56    /// function if empty, and returns a mutable reference to the value in the
57    /// entry.
58    ///
59    /// # Panics
60    ///
61    /// Panics if the key hashes to a different value than the one passed
62    /// into [`BiHashMap::entry`].
63    #[inline]
64    pub fn or_insert_with<F: FnOnce() -> T>(
65        self,
66        default: F,
67    ) -> OccupiedEntryMut<'a, T, S> {
68        match self {
69            Entry::Occupied(entry) => entry.into_mut(),
70            Entry::Vacant(entry) => {
71                OccupiedEntryMut::Unique(entry.insert(default()))
72            }
73        }
74    }
75
76    /// Provides in-place mutable access to occupied entries before any
77    /// potential inserts into the map.
78    ///
79    /// `F` is called for each entry that matches the provided keys.
80    #[inline]
81    pub fn and_modify<F>(self, f: F) -> Self
82    where
83        F: FnMut(RefMut<'_, T, S>),
84    {
85        match self {
86            Entry::Occupied(mut entry) => {
87                entry.get_mut().for_each(f);
88                Entry::Occupied(entry)
89            }
90            Entry::Vacant(entry) => Entry::Vacant(entry),
91        }
92    }
93}
94
95/// A vacant entry.
96pub struct VacantEntry<
97    'a,
98    T: BiHashItem,
99    S = DefaultHashBuilder,
100    A: Allocator = Global,
101> {
102    map: DormantMutRef<'a, BiHashMap<T, S, A>>,
103    hashes: [MapHash<S>; 2],
104}
105
106impl<'a, T: BiHashItem, S, A: Allocator> fmt::Debug
107    for VacantEntry<'a, T, S, A>
108{
109    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110        f.debug_struct("VacantEntry")
111            .field("hashes", &self.hashes)
112            .finish_non_exhaustive()
113    }
114}
115
116impl<'a, T: BiHashItem, S: Clone + BuildHasher, A: Allocator>
117    VacantEntry<'a, T, S, A>
118{
119    pub(super) unsafe fn new(
120        map: DormantMutRef<'a, BiHashMap<T, S, A>>,
121        hashes: [MapHash<S>; 2],
122    ) -> Self {
123        VacantEntry { map, hashes }
124    }
125
126    /// Sets the entry to a new value, returning a mutable reference to the
127    /// value.
128    pub fn insert(self, value: T) -> RefMut<'a, T, S> {
129        if !self.hashes[0].is_same_hash(value.key1()) {
130            panic!("key1 hashes do not match");
131        }
132        if !self.hashes[1].is_same_hash(value.key2()) {
133            panic!("key2 hashes do not match");
134        }
135
136        // SAFETY: The safety assumption behind `Self::new` guarantees that the
137        // original reference to the map is not used at this point.
138        let map = unsafe { self.map.awaken() };
139        let Ok(index) = map.insert_unique_impl(value) else {
140            panic!("key already present in map");
141        };
142        map.get_by_index_mut(index).expect("index is known to be valid")
143    }
144
145    /// Sets the value of the entry, and returns an `OccupiedEntry`.
146    #[inline]
147    pub fn insert_entry(mut self, value: T) -> OccupiedEntry<'a, T, S, A> {
148        if !self.hashes[0].is_same_hash(value.key1()) {
149            panic!("key1 hashes do not match");
150        }
151        if !self.hashes[1].is_same_hash(value.key2()) {
152            panic!("key2 hashes do not match");
153        }
154
155        let index = {
156            // SAFETY: The safety assumption behind `Self::new` guarantees that the
157            // original reference to the map is not used at this point.
158            let map = unsafe { self.map.reborrow() };
159            let Ok(index) = map.insert_unique_impl(value) else {
160                panic!("key already present in map");
161            };
162            index
163        };
164
165        // SAFETY: map, as well as anything that was borrowed from it, is
166        // dropped once the above block exits.
167        unsafe { OccupiedEntry::new(self.map, EntryIndexes::Unique(index)) }
168    }
169}
170
171/// A view into an occupied entry in a [`BiHashMap`]. Part of the [`Entry`]
172/// enum.
173pub struct OccupiedEntry<
174    'a,
175    T: BiHashItem,
176    S = DefaultHashBuilder,
177    A: Allocator = Global,
178> {
179    map: DormantMutRef<'a, BiHashMap<T, S, A>>,
180    indexes: EntryIndexes,
181}
182
183impl<'a, T: BiHashItem, S, A: Allocator> fmt::Debug
184    for OccupiedEntry<'a, T, S, A>
185{
186    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187        f.debug_struct("OccupiedEntry")
188            .field("indexes", &self.indexes)
189            .finish_non_exhaustive()
190    }
191}
192
193impl<'a, T: BiHashItem, S: Clone + BuildHasher, A: Allocator>
194    OccupiedEntry<'a, T, S, A>
195{
196    /// # Safety
197    ///
198    /// After self is created, the original reference created by
199    /// `DormantMutRef::new` must not be used.
200    pub(super) unsafe fn new(
201        map: DormantMutRef<'a, BiHashMap<T, S, A>>,
202        indexes: EntryIndexes,
203    ) -> Self {
204        OccupiedEntry { map, indexes }
205    }
206
207    /// Returns true if the entry is unique.
208    ///
209    /// Since [`BiHashMap`] is keyed by two keys, it's possible for
210    /// `OccupiedEntry` to match up to two separate items. This function returns
211    /// true if the entry is unique, meaning all keys point to exactly one item.
212    pub fn is_unique(&self) -> bool {
213        self.indexes.is_unique()
214    }
215
216    /// Returns true if the `OccupiedEntry` represents more than one item, or if
217    /// some keys are not present.
218    #[inline]
219    pub fn is_non_unique(&self) -> bool {
220        !self.is_unique()
221    }
222
223    /// Returns references to values that match the provided keys.
224    ///
225    /// If you need a reference to `T` that may outlive the destruction of the
226    /// `Entry` value, see [`into_ref`](Self::into_ref).
227    pub fn get(&self) -> OccupiedEntryRef<'_, T> {
228        // SAFETY: The safety assumption behind `Self::new` guarantees that the
229        // original reference to the map is not used at this point.
230        let map = unsafe { self.map.reborrow_shared() };
231        map.get_by_entry_index(self.indexes)
232    }
233
234    /// Returns mutable references to values that match the provided keys.
235    ///
236    /// If you need a reference to `T` that may outlive the destruction of the
237    /// `Entry` value, see [`into_mut`](Self::into_mut).
238    pub fn get_mut(&mut self) -> OccupiedEntryMut<'_, T, S> {
239        // SAFETY: The safety assumption behind `Self::new` guarantees that the
240        // original reference to the map is not used at this point.
241        let map = unsafe { self.map.reborrow() };
242        map.get_by_entry_index_mut(self.indexes)
243    }
244
245    /// Converts self into shared references to items that match the provided
246    /// keys.
247    ///
248    /// If you need multiple references to the `OccupiedEntry`, see
249    /// [`get`](Self::get).
250    pub fn into_ref(self) -> OccupiedEntryRef<'a, T> {
251        // SAFETY: The safety assumption behind `Self::new` guarantees that the
252        // original reference to the map is not used at this point.
253        let map = unsafe { self.map.awaken() };
254        map.get_by_entry_index(self.indexes)
255    }
256
257    /// Converts self into mutable references to items that match the provided
258    /// keys.
259    ///
260    /// If you need multiple references to the `OccupiedEntry`, see
261    /// [`get_mut`](Self::get_mut).
262    pub fn into_mut(self) -> OccupiedEntryMut<'a, T, S> {
263        // SAFETY: The safety assumption behind `Self::new` guarantees that the
264        // original reference to the map is not used at this point.
265        let map = unsafe { self.map.awaken() };
266        map.get_by_entry_index_mut(self.indexes)
267    }
268
269    /// Sets the entry to a new value, returning all values that conflict.
270    ///
271    /// # Panics
272    ///
273    /// Panics if the passed-in key is different from the key of the entry.
274    pub fn insert(&mut self, value: T) -> Vec<T> {
275        // SAFETY: The safety assumption behind `Self::new` guarantees that the
276        // original reference to the map is not used at this point.
277        //
278        // Note that `replace_at_indexes` panics if the keys don't match.
279        let map = unsafe { self.map.reborrow() };
280        let (index, old_items) = map.replace_at_indexes(self.indexes, value);
281        self.indexes = EntryIndexes::Unique(index);
282        old_items
283    }
284
285    /// Takes ownership of the values from the map.
286    pub fn remove(mut self) -> Vec<T> {
287        // SAFETY: The safety assumption behind `Self::new` guarantees that the
288        // original reference to the map is not used at this point.
289        let map = unsafe { self.map.reborrow() };
290        map.remove_by_entry_index(self.indexes)
291    }
292}
293
294/// A view into an occupied entry in a [`BiHashMap`].
295///
296/// Returned by [`OccupiedEntry::get`].
297#[derive(Debug)]
298pub enum OccupiedEntryRef<'a, T: BiHashItem> {
299    /// All keys point to the same entry.
300    Unique(&'a T),
301
302    /// The keys point to different entries, or some keys are not present.
303    ///
304    /// At least one of `by_key1` and `by_key2` is `Some`.
305    NonUnique {
306        /// The value fetched by the first key.
307        by_key1: Option<&'a T>,
308
309        /// The value fetched by the second key.
310        by_key2: Option<&'a T>,
311    },
312}
313
314impl<'a, T: BiHashItem> OccupiedEntryRef<'a, T> {
315    /// Returns true if the entry is unique.
316    ///
317    /// Since [`BiHashMap`] is keyed by two keys, it's possible for
318    /// `OccupiedEntry` to match up to two separate items. This function returns
319    /// true if the entry is unique, meaning all keys point to exactly one item.
320    #[inline]
321    pub fn is_unique(&self) -> bool {
322        matches!(self, Self::Unique(_))
323    }
324
325    /// Returns true if the `OccupiedEntryRef` represents more than one item, or
326    /// if some keys are not present.
327    #[inline]
328    pub fn is_non_unique(&self) -> bool {
329        matches!(self, Self::NonUnique { .. })
330    }
331
332    /// Returns a reference to the value if it is unique.
333    #[inline]
334    pub fn as_unique(&self) -> Option<&'a T> {
335        match self {
336            Self::Unique(v) => Some(v),
337            Self::NonUnique { .. } => None,
338        }
339    }
340
341    /// Returns a reference to the value fetched by the first key.
342    #[inline]
343    pub fn by_key1(&self) -> Option<&'a T> {
344        match self {
345            Self::Unique(v) => Some(v),
346            Self::NonUnique { by_key1, .. } => *by_key1,
347        }
348    }
349
350    /// Returns a reference to the value fetched by the second key.
351    #[inline]
352    pub fn by_key2(&self) -> Option<&'a T> {
353        match self {
354            Self::Unique(v) => Some(v),
355            Self::NonUnique { by_key2, .. } => *by_key2,
356        }
357    }
358}
359
360/// A mutable view into an occupied entry in a [`BiHashMap`].
361///
362/// Returned by [`OccupiedEntry::get_mut`].
363pub enum OccupiedEntryMut<
364    'a,
365    T: BiHashItem,
366    S: Clone + BuildHasher = DefaultHashBuilder,
367> {
368    /// All keys point to the same entry.
369    Unique(RefMut<'a, T, S>),
370
371    /// The keys point to different entries, or some keys are not present.
372    NonUnique {
373        /// The value fetched by the first key.
374        by_key1: Option<RefMut<'a, T, S>>,
375
376        /// The value fetched by the second key.
377        by_key2: Option<RefMut<'a, T, S>>,
378    },
379}
380
381impl<'a, T: BiHashItem + fmt::Debug, S: Clone + BuildHasher> fmt::Debug
382    for OccupiedEntryMut<'a, T, S>
383{
384    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
385        match self {
386            OccupiedEntryMut::Unique(ref_mut) => {
387                f.debug_tuple("Unique").field(ref_mut).finish()
388            }
389            OccupiedEntryMut::NonUnique { by_key1, by_key2 } => f
390                .debug_struct("NonUnique")
391                .field("by_key1", by_key1)
392                .field("by_key2", by_key2)
393                .finish(),
394        }
395    }
396}
397
398impl<'a, T: BiHashItem, S: Clone + BuildHasher> OccupiedEntryMut<'a, T, S> {
399    /// Returns true if the entry is unique.
400    #[inline]
401    pub fn is_unique(&self) -> bool {
402        matches!(self, Self::Unique(_))
403    }
404
405    /// Returns true if the `OccupiedEntryMut` represents more than one item, or
406    /// if some keys are not present.
407    #[inline]
408    pub fn is_non_unique(&self) -> bool {
409        matches!(self, Self::NonUnique { .. })
410    }
411
412    /// Returns a reference to the value if it is unique.
413    #[inline]
414    pub fn as_unique(&mut self) -> Option<RefMut<'_, T, S>> {
415        match self {
416            Self::Unique(v) => Some(v.reborrow()),
417            Self::NonUnique { .. } => None,
418        }
419    }
420
421    /// Returns a mutable reference to the value fetched by the first key.
422    #[inline]
423    pub fn by_key1(&mut self) -> Option<RefMut<'_, T, S>> {
424        match self {
425            Self::Unique(v) => Some(v.reborrow()),
426            Self::NonUnique { by_key1, .. } => {
427                by_key1.as_mut().map(|v| v.reborrow())
428            }
429        }
430    }
431
432    /// Returns a mutable reference to the value fetched by the second key.
433    #[inline]
434    pub fn by_key2(&mut self) -> Option<RefMut<'_, T, S>> {
435        match self {
436            Self::Unique(v) => Some(v.reborrow()),
437            Self::NonUnique { by_key2, .. } => {
438                by_key2.as_mut().map(|v| v.reborrow())
439            }
440        }
441    }
442
443    /// Calls a callback for each value.
444    pub fn for_each<F>(&mut self, mut f: F)
445    where
446        F: FnMut(RefMut<'_, T, S>),
447    {
448        match self {
449            Self::Unique(v) => f(v.reborrow()),
450            Self::NonUnique { by_key1, by_key2 } => {
451                if let Some(v) = by_key1 {
452                    f(v.reborrow());
453                }
454                if let Some(v) = by_key2 {
455                    f(v.reborrow());
456                }
457            }
458        }
459    }
460}