Skip to main content

indexmap/inner/
entry.rs

1use core::{cmp::Ordering, mem};
2
3use super::{Bucket, Core, equal, get_hash};
4use crate::{
5    HashValue,
6    map::{Entry, IndexedEntry},
7    util::assert_index_lt,
8};
9
10impl<'a, K, V> Entry<'a, K, V> {
11    pub(crate) fn new(map: &'a mut Core<K, V>, hash: HashValue, key: K) -> Self
12    where
13        K: Eq,
14    {
15        let eq = equal(&key, &map.entries);
16        match map.indices.find_entry(hash.get(), eq) {
17            Ok(entry) => Entry::Occupied(OccupiedEntry {
18                bucket: entry.bucket_index(),
19                index: *entry.get(),
20                map,
21            }),
22            Err(_) => Entry::Vacant(VacantEntry {
23                map,
24                hash,
25                key,
26            }),
27        }
28    }
29}
30
31/// A view into an occupied entry in an [`IndexMap`][crate::IndexMap].
32/// It is part of the [`Entry`] enum.
33pub struct OccupiedEntry<'a, K, V> {
34    map: &'a mut Core<K, V>,
35    // We have a mutable reference to the map, which keeps these two
36    // indices valid and pointing to the correct entry.
37    index: usize,
38    bucket: usize,
39}
40
41impl<'a, K, V> OccupiedEntry<'a, K, V> {
42    /// Constructor for `RawEntryMut::from_hash`
43    pub(crate) fn from_hash<F>(
44        map: &'a mut Core<K, V>,
45        hash: HashValue,
46        mut is_match: F,
47    ) -> Result<Self, &'a mut Core<K, V>>
48    where
49        F: FnMut(&K) -> bool,
50    {
51        let entries = &*map.entries;
52        let eq = move |&i: &usize| is_match(&entries[i].key);
53        match map.indices.find_entry(hash.get(), eq) {
54            Ok(entry) => Ok(OccupiedEntry {
55                bucket: entry.bucket_index(),
56                index: *entry.get(),
57                map,
58            }),
59            Err(_) => Err(map),
60        }
61    }
62
63    pub(crate) fn into_core(self) -> &'a mut Core<K, V> {
64        self.map
65    }
66
67    pub(crate) fn get_bucket(&self) -> &Bucket<K, V> {
68        &self.map.entries[self.index]
69    }
70
71    pub(crate) fn get_bucket_mut(&mut self) -> &mut Bucket<K, V> {
72        &mut self.map.entries[self.index]
73    }
74
75    pub(crate) fn into_bucket(self) -> &'a mut Bucket<K, V> {
76        &mut self.map.entries[self.index]
77    }
78
79    /// Return the index of the key-value pair
80    #[inline]
81    pub fn index(&self) -> usize {
82        self.index
83    }
84
85    /// Gets a reference to the entry's key in the map.
86    ///
87    /// Note that this is not the key that was used to find the entry. There may be an observable
88    /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like
89    /// extra fields or the memory address of an allocation.
90    pub fn key(&self) -> &K {
91        &self.get_bucket().key
92    }
93
94    /// Gets a reference to the entry's value in the map.
95    pub fn get(&self) -> &V {
96        &self.get_bucket().value
97    }
98
99    /// Gets a mutable reference to the entry's value in the map.
100    ///
101    /// If you need a reference which may outlive the destruction of the
102    /// [`Entry`] value, see [`into_mut`][Self::into_mut].
103    pub fn get_mut(&mut self) -> &mut V {
104        &mut self.get_bucket_mut().value
105    }
106
107    /// Converts into a mutable reference to the entry's value in the map,
108    /// with a lifetime bound to the map itself.
109    pub fn into_mut(self) -> &'a mut V {
110        &mut self.into_bucket().value
111    }
112
113    /// Sets the value of the entry to `value`, and returns the entry's old value.
114    pub fn insert(&mut self, value: V) -> V {
115        mem::replace(self.get_mut(), value)
116    }
117
118    /// Remove the key, value pair stored in the map for this entry, and return the value.
119    ///
120    /// **NOTE:** This is equivalent to [`.swap_remove()`][Self::swap_remove], replacing this
121    /// entry's position with the last element, and it is deprecated in favor of calling that
122    /// explicitly. If you need to preserve the relative order of the keys in the map, use
123    /// [`.shift_remove()`][Self::shift_remove] instead.
124    #[deprecated(note = "`remove` disrupts the map order -- \
125        use `swap_remove` or `shift_remove` for explicit behavior.")]
126    pub fn remove(self) -> V {
127        self.swap_remove()
128    }
129
130    /// Remove the key, value pair stored in the map for this entry, and return the value.
131    ///
132    /// Like [`Vec::swap_remove`][alloc::vec::Vec::swap_remove], the pair is removed by swapping it
133    /// with the last element of the map and popping it off.
134    /// **This perturbs the position of what used to be the last element!**
135    ///
136    /// Computes in **O(1)** time (average).
137    pub fn swap_remove(self) -> V {
138        self.swap_remove_entry().1
139    }
140
141    /// Remove the key, value pair stored in the map for this entry, and return the value.
142    ///
143    /// Like [`Vec::remove`][alloc::vec::Vec::remove], the pair is removed by shifting all of the
144    /// elements that follow it, preserving their relative order.
145    /// **This perturbs the index of all of those elements!**
146    ///
147    /// Computes in **O(n)** time (average).
148    pub fn shift_remove(self) -> V {
149        self.shift_remove_entry().1
150    }
151
152    /// Remove and return the key, value pair stored in the map for this entry
153    ///
154    /// **NOTE:** This is equivalent to [`.swap_remove_entry()`][Self::swap_remove_entry],
155    /// replacing this entry's position with the last element, and it is deprecated in favor of
156    /// calling that explicitly. If you need to preserve the relative order of the keys in the map,
157    /// use [`.shift_remove_entry()`][Self::shift_remove_entry] instead.
158    #[deprecated(note = "`remove_entry` disrupts the map order -- \
159        use `swap_remove_entry` or `shift_remove_entry` for explicit behavior.")]
160    pub fn remove_entry(self) -> (K, V) {
161        self.swap_remove_entry()
162    }
163
164    /// Remove and return the key, value pair stored in the map for this entry
165    ///
166    /// Like [`Vec::swap_remove`][alloc::vec::Vec::swap_remove], the pair is removed by swapping it
167    /// with the last element of the map and popping it off.
168    /// **This perturbs the position of what used to be the last element!**
169    ///
170    /// Computes in **O(1)** time (average).
171    pub fn swap_remove_entry(mut self) -> (K, V) {
172        self.remove_index();
173        self.map.swap_remove_finish(self.index)
174    }
175
176    /// Remove and return the key, value pair stored in the map for this entry
177    ///
178    /// Like [`Vec::remove`][alloc::vec::Vec::remove], the pair is removed by shifting all of the
179    /// elements that follow it, preserving their relative order.
180    /// **This perturbs the index of all of those elements!**
181    ///
182    /// Computes in **O(n)** time (average).
183    pub fn shift_remove_entry(mut self) -> (K, V) {
184        self.remove_index();
185        self.map.shift_remove_finish(self.index)
186    }
187
188    fn remove_index(&mut self) {
189        let entry = self.map.indices.get_bucket_entry(self.bucket).unwrap();
190        debug_assert_eq!(*entry.get(), self.index);
191        entry.remove();
192    }
193
194    /// Moves the position of the entry to a new index
195    /// by shifting all other entries in-between.
196    ///
197    /// This is equivalent to [`IndexMap::move_index`][`crate::IndexMap::move_index`]
198    /// coming `from` the current [`.index()`][Self::index].
199    ///
200    /// * If `self.index() < to`, the other pairs will shift down while the targeted pair moves up.
201    /// * If `self.index() > to`, the other pairs will shift up while the targeted pair moves down.
202    ///
203    /// ***Panics*** if `to` is out of bounds.
204    ///
205    /// Computes in **O(n)** time (average).
206    #[track_caller]
207    pub fn move_index(self, to: usize) {
208        if self.index != to {
209            assert_index_lt(to, self.map.len());
210            self.map.move_index_inner(self.index, to);
211            self.update_index(to);
212        }
213    }
214
215    /// Swaps the position of entry with another.
216    ///
217    /// This is equivalent to [`IndexMap::swap_indices`][`crate::IndexMap::swap_indices`]
218    /// with the current [`.index()`][Self::index] as one of the two being swapped.
219    ///
220    /// ***Panics*** if the `other` index is out of bounds.
221    ///
222    /// Computes in **O(1)** time (average).
223    #[track_caller]
224    pub fn swap_indices(self, other: usize) {
225        if self.index != other {
226            assert_index_lt(other, self.map.len());
227
228            // Since we already know where our bucket is, we only need to find the other.
229            let hash = self.map.entries[other].hash;
230            let other_mut = self.map.indices.find_mut(hash.get(), move |&i| i == other);
231            *other_mut.expect("index not found") = self.index;
232
233            self.map.entries.swap(self.index, other);
234            self.update_index(other);
235        }
236    }
237
238    fn update_index(self, to: usize) {
239        let index = self.map.indices.get_bucket_mut(self.bucket).unwrap();
240        debug_assert_eq!(*index, self.index);
241        *index = to;
242    }
243}
244
245impl<'a, K, V> From<IndexedEntry<'a, K, V>> for OccupiedEntry<'a, K, V> {
246    fn from(other: IndexedEntry<'a, K, V>) -> Self {
247        let index = other.index();
248        let map = other.into_core();
249        let hash = map.entries[index].hash;
250        let bucket = map
251            .indices
252            .find_bucket_index(hash.get(), move |&i| i == index)
253            .expect("index not found");
254        Self {
255            map,
256            index,
257            bucket,
258        }
259    }
260}
261
262/// A view into a vacant entry in an [`IndexMap`][crate::IndexMap].
263/// It is part of the [`Entry`] enum.
264pub struct VacantEntry<'a, K, V> {
265    map: &'a mut Core<K, V>,
266    hash: HashValue,
267    key: K,
268}
269
270impl<'a, K, V> VacantEntry<'a, K, V> {
271    /// Return the index where a key-value pair may be inserted.
272    pub fn index(&self) -> usize {
273        self.map.indices.len()
274    }
275
276    /// Gets a reference to the key that was used to find the entry.
277    pub fn key(&self) -> &K {
278        &self.key
279    }
280
281    pub(crate) fn key_mut(&mut self) -> &mut K {
282        &mut self.key
283    }
284
285    /// Takes ownership of the key, leaving the entry vacant.
286    pub fn into_key(self) -> K {
287        self.key
288    }
289
290    /// Inserts the entry's key and the given value into the map, and returns a mutable reference
291    /// to the value.
292    ///
293    /// Computes in **O(1)** time (amortized average).
294    pub fn insert(self, value: V) -> &'a mut V {
295        let Self {
296            map,
297            hash,
298            key,
299        } = self;
300        map.insert_unique(hash, key, value).value_mut()
301    }
302
303    /// Inserts the entry's key and the given value into the map, and returns an `OccupiedEntry`.
304    ///
305    /// Computes in **O(1)** time (amortized average).
306    pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> {
307        let Self {
308            map,
309            hash,
310            key,
311        } = self;
312        let index = map.indices.len();
313        debug_assert_eq!(index, map.entries.len());
314        let bucket = map
315            .indices
316            .insert_unique(hash.get(), index, get_hash(&map.entries))
317            .bucket_index();
318        map.push_entry(hash, key, value);
319        OccupiedEntry {
320            map,
321            index,
322            bucket,
323        }
324    }
325
326    /// Inserts the entry's key and the given value into the map at its ordered
327    /// position among sorted keys, and returns the new index and a mutable
328    /// reference to the value.
329    ///
330    /// If the existing keys are **not** already sorted, then the insertion
331    /// index is unspecified (like [`slice::binary_search`]), but the key-value
332    /// pair is inserted at that position regardless.
333    ///
334    /// Computes in **O(n)** time (average).
335    pub fn insert_sorted(self, value: V) -> (usize, &'a mut V)
336    where
337        K: Ord,
338    {
339        let slice = crate::map::Slice::from_slice(&self.map.entries);
340        let i = slice.binary_search_keys(&self.key).unwrap_err();
341        (i, self.shift_insert(i, value))
342    }
343
344    /// Inserts the entry's key and the given value into the map at its ordered
345    /// position among keys sorted by `cmp`, and returns the new index and a
346    /// mutable reference to the value.
347    ///
348    /// If the existing keys are **not** already sorted, then the insertion
349    /// index is unspecified (like [`slice::binary_search`]), but the key-value
350    /// pair is inserted at that position regardless.
351    ///
352    /// Computes in **O(n)** time (average).
353    pub fn insert_sorted_by<F>(self, value: V, mut cmp: F) -> (usize, &'a mut V)
354    where
355        F: FnMut(&K, &V, &K, &V) -> Ordering,
356    {
357        let slice = crate::map::Slice::from_slice(&self.map.entries);
358        let (Ok(i) | Err(i)) = slice.binary_search_by(|k, v| cmp(k, v, &self.key, &value));
359        (i, self.shift_insert(i, value))
360    }
361
362    /// Inserts the entry's key and the given value into the map at its ordered
363    /// position using a sort-key extraction function, and returns the new index
364    /// and a mutable reference to the value.
365    ///
366    /// If the existing keys are **not** already sorted, then the insertion
367    /// index is unspecified (like [`slice::binary_search`]), but the key-value
368    /// pair is inserted at that position regardless.
369    ///
370    /// Computes in **O(n)** time (average).
371    pub fn insert_sorted_by_key<B, F>(self, value: V, mut sort_key: F) -> (usize, &'a mut V)
372    where
373        B: Ord,
374        F: FnMut(&K, &V) -> B,
375    {
376        let search_key = sort_key(&self.key, &value);
377        let slice = crate::map::Slice::from_slice(&self.map.entries);
378        let (Ok(i) | Err(i)) = slice.binary_search_by_key(&search_key, sort_key);
379        (i, self.shift_insert(i, value))
380    }
381
382    /// Inserts the entry's key and the given value into the map at the given index,
383    /// shifting others to the right, and returns a mutable reference to the value.
384    ///
385    /// ***Panics*** if `index` is out of bounds.
386    ///
387    /// Computes in **O(n)** time (average).
388    #[track_caller]
389    pub fn shift_insert(self, index: usize, value: V) -> &'a mut V {
390        self.map
391            .shift_insert_unique(index, self.hash, self.key, value)
392            .value_mut()
393    }
394
395    /// Replaces the key at the given index with this entry's key, returning the
396    /// old key and an `OccupiedEntry` for that index.
397    ///
398    /// ***Panics*** if `index` is out of bounds.
399    ///
400    /// Computes in **O(1)** time (average).
401    #[track_caller]
402    pub fn replace_index(self, index: usize) -> (K, OccupiedEntry<'a, K, V>) {
403        let Self {
404            map,
405            hash,
406            key,
407        } = self;
408        assert_index_lt(index, map.len());
409
410        // NB: This removal and insertion isn't "no grow" (with unreachable hasher)
411        // because hashbrown's tombstones might force a resize anyway.
412        let old_hash = map.entries[index].hash;
413        map.indices
414            .find_entry(old_hash.get(), move |&i| i == index)
415            .expect("index not found")
416            .remove();
417        let bucket = map
418            .indices
419            .insert_unique(hash.get(), index, get_hash(&map.entries))
420            .bucket_index();
421
422        let entry = &mut map.entries[index];
423        entry.hash = hash;
424        let old_key = mem::replace(&mut entry.key, key);
425
426        (
427            old_key,
428            OccupiedEntry {
429                map,
430                index,
431                bucket,
432            },
433        )
434    }
435}