Skip to main content

iddqd/id_hash_map/
entry.rs

1use super::{IdHashItem, IdHashMap, RefMut};
2use crate::{
3    DefaultHashBuilder,
4    support::{
5        ItemIndex,
6        alloc::{Allocator, Global},
7        borrow::DormantMutRef,
8        map_hash::MapHash,
9    },
10};
11use core::{fmt, hash::BuildHasher};
12
13/// An implementation of the Entry API for [`IdHashMap`].
14pub enum Entry<'a, T: IdHashItem, S = DefaultHashBuilder, A: Allocator = Global>
15{
16    /// A vacant entry.
17    Vacant(VacantEntry<'a, T, S, A>),
18    /// An occupied entry.
19    Occupied(OccupiedEntry<'a, T, S, A>),
20}
21
22impl<'a, T: IdHashItem, 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: IdHashItem, 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 [`IdHashMap::entry`].
45    #[inline]
46    pub fn or_insert(self, default: T) -> RefMut<'a, T, S> {
47        match self {
48            Entry::Occupied(entry) => entry.into_mut(),
49            Entry::Vacant(entry) => entry.insert(default),
50        }
51    }
52
53    /// Ensures a value is in the entry by inserting the result of the default
54    /// function if empty, and returns a mutable reference to the value in the
55    /// entry.
56    ///
57    /// # Panics
58    ///
59    /// Panics if the key hashes to a different value than the one passed
60    /// into [`IdHashMap::entry`].
61    #[inline]
62    pub fn or_insert_with<F: FnOnce() -> T>(
63        self,
64        default: F,
65    ) -> RefMut<'a, T, S> {
66        match self {
67            Entry::Occupied(entry) => entry.into_mut(),
68            Entry::Vacant(entry) => entry.insert(default()),
69        }
70    }
71
72    /// Provides in-place mutable access to an occupied entry before any
73    /// potential inserts into the map.
74    #[inline]
75    pub fn and_modify<F>(self, f: F) -> Self
76    where
77        F: FnOnce(RefMut<'_, T, S>),
78    {
79        match self {
80            Entry::Occupied(mut entry) => {
81                f(entry.get_mut());
82                Entry::Occupied(entry)
83            }
84            Entry::Vacant(entry) => Entry::Vacant(entry),
85        }
86    }
87}
88
89/// A vacant entry.
90pub struct VacantEntry<
91    'a,
92    T: IdHashItem,
93    S = DefaultHashBuilder,
94    A: Allocator = Global,
95> {
96    map: DormantMutRef<'a, IdHashMap<T, S, A>>,
97    hash: MapHash,
98}
99
100impl<'a, T: IdHashItem, S, A: Allocator> fmt::Debug
101    for VacantEntry<'a, T, S, A>
102{
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        f.debug_struct("VacantEntry")
105            .field("hash", &self.hash)
106            .finish_non_exhaustive()
107    }
108}
109
110impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator>
111    VacantEntry<'a, T, S, A>
112{
113    pub(super) unsafe fn new(
114        map: DormantMutRef<'a, IdHashMap<T, S, A>>,
115        hash: MapHash,
116    ) -> Self {
117        VacantEntry { map, hash }
118    }
119
120    /// Sets the entry to a new value, returning a mutable reference to the
121    /// value.
122    pub fn insert(self, value: T) -> RefMut<'a, T, S> {
123        // SAFETY: The safety assumption behind `Self::new` guarantees that the
124        // original reference to the map is not used at this point.
125        let map = unsafe { self.map.awaken() };
126        let state = &map.tables.state;
127        if !self.hash.is_same_hash(state, value.key()) {
128            panic!("key hashes do not match");
129        }
130        let Ok(index) = map.insert_unique_impl(value) else {
131            panic!("key already present in map");
132        };
133        map.get_by_index_mut(index).expect("index is known to be valid")
134    }
135
136    /// Sets the entry to a new value without checking for duplicates or
137    /// recomputing its key hash.
138    ///
139    /// Only call this on a vacant entry obtained from `value.key()`. Unlike
140    /// `insert`, this method does not validate the hash or recheck uniqueness.
141    #[inline]
142    pub(super) fn insert_known_unique(self, value: T) {
143        // SAFETY: The safety assumption behind `Self::new` guarantees that the
144        // original reference to the map is not used at this point.
145        let map = unsafe { self.map.awaken() };
146        map.try_reserve_insert_overwrite_commit()
147            .expect("reserved space successfully");
148        let next_index = map.items.assert_can_grow().insert(value);
149        map.tables
150            .key_to_item
151            .insert_prehashed_unchecked(self.hash, next_index);
152    }
153
154    /// Sets the value of the entry, and returns an `OccupiedEntry`.
155    #[inline]
156    pub fn insert_entry(mut self, value: T) -> OccupiedEntry<'a, T, S, A> {
157        let index = {
158            // SAFETY: The safety assumption behind `Self::new` guarantees that the
159            // original reference to the map is not used at this point.
160            let map = unsafe { self.map.reborrow() };
161            let state = &map.tables.state;
162            if !self.hash.is_same_hash(state, value.key()) {
163                panic!("key hashes do not match");
164            }
165            let Ok(index) = map.insert_unique_impl(value) else {
166                panic!("key already present in map");
167            };
168            index
169        };
170
171        // SAFETY: map, as well as anything that was borrowed from it, is
172        // dropped once the above block exits.
173        unsafe { OccupiedEntry::new(self.map, index) }
174    }
175}
176
177/// A view into an occupied entry in an [`IdHashMap`]. Part of the [`Entry`]
178/// enum.
179pub struct OccupiedEntry<
180    'a,
181    T: IdHashItem,
182    S = DefaultHashBuilder,
183    A: Allocator = Global,
184> {
185    map: DormantMutRef<'a, IdHashMap<T, S, A>>,
186    // index is a valid index into the map's internal hash table.
187    index: ItemIndex,
188}
189
190impl<'a, T: IdHashItem, S, A: Allocator> fmt::Debug
191    for OccupiedEntry<'a, T, S, A>
192{
193    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194        f.debug_struct("OccupiedEntry")
195            .field("index", &self.index)
196            .finish_non_exhaustive()
197    }
198}
199
200impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator>
201    OccupiedEntry<'a, T, S, A>
202{
203    /// # Safety
204    ///
205    /// After self is created, the original reference created by
206    /// `DormantMutRef::new` must not be used.
207    pub(super) unsafe fn new(
208        map: DormantMutRef<'a, IdHashMap<T, S, A>>,
209        index: ItemIndex,
210    ) -> Self {
211        OccupiedEntry { map, index }
212    }
213
214    /// Gets a reference to the value.
215    ///
216    /// If you need a reference to `T` that may outlive the destruction of the
217    /// `Entry` value, see [`into_ref`](Self::into_ref).
218    pub fn get(&self) -> &T {
219        // SAFETY: The safety assumption behind `Self::new` guarantees that the
220        // original reference to the map is not used at this point.
221        unsafe { self.map.reborrow_shared() }
222            .get_by_index(self.index)
223            .expect("index is known to be valid")
224    }
225
226    /// Gets a mutable reference to the value.
227    ///
228    /// If you need a reference to `T` that may outlive the destruction of the
229    /// `Entry` value, see [`into_mut`](Self::into_mut).
230    pub fn get_mut(&mut self) -> RefMut<'_, T, S> {
231        // SAFETY: The safety assumption behind `Self::new` guarantees that the
232        // original reference to the map is not used at this point.
233        unsafe { self.map.reborrow() }
234            .get_by_index_mut(self.index)
235            .expect("index is known to be valid")
236    }
237
238    /// Converts self into a reference to the value.
239    ///
240    /// If you need multiple references to the `OccupiedEntry`, see
241    /// [`get`](Self::get).
242    pub fn into_ref(self) -> &'a T {
243        // SAFETY: The safety assumption behind `Self::new` guarantees that the
244        // original reference to the map is not used at this point.
245        unsafe { self.map.awaken() }
246            .get_by_index(self.index)
247            .expect("index is known to be valid")
248    }
249
250    /// Converts self into a mutable reference to the value.
251    ///
252    /// If you need multiple references to the `OccupiedEntry`, see
253    /// [`get_mut`](Self::get_mut).
254    pub fn into_mut(self) -> RefMut<'a, T, S> {
255        // SAFETY: The safety assumption behind `Self::new` guarantees that the
256        // original reference to the map is not used at this point.
257        unsafe { self.map.awaken() }
258            .get_by_index_mut(self.index)
259            .expect("index is known to be valid")
260    }
261
262    /// Sets the entry to a new value, returning the old value.
263    ///
264    /// # Panics
265    ///
266    /// Panics if `value.key()` is different from the key of the entry.
267    pub fn insert(&mut self, value: T) -> T {
268        // SAFETY: The safety assumption behind `Self::new` guarantees that the
269        // original reference to the map is not used at this point.
270        //
271        // Note that `replace_at_index` panics if the keys don't match.
272        unsafe { self.map.reborrow() }.replace_at_index(self.index, value)
273    }
274
275    /// Takes ownership of the value from the map.
276    pub fn remove(mut self) -> T {
277        // SAFETY: The safety assumption behind `Self::new` guarantees that the
278        // original reference to the map is not used at this point.
279        unsafe { self.map.reborrow() }
280            .remove_by_index(self.index)
281            .expect("index is known to be valid")
282    }
283}