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