/rust/registry/src/index.crates.io-1949cf8c6b5b557f/indexmap-2.14.1/src/inner.rs
Line | Count | Source |
1 | | //! This is the core implementation that doesn't depend on the hasher at all. |
2 | | //! |
3 | | //! The methods of `Core` don't use any Hash properties of K. |
4 | | //! |
5 | | //! It's cleaner to separate them out, then the compiler checks that we are not |
6 | | //! using Hash at all in these methods. |
7 | | //! |
8 | | //! However, we should probably not let this show in the public API or docs. |
9 | | |
10 | | mod entry; |
11 | | mod extract; |
12 | | |
13 | | use alloc::vec::{self, Vec}; |
14 | | use core::mem; |
15 | | use core::ops::RangeBounds; |
16 | | use hashbrown::hash_table; |
17 | | |
18 | | use crate::util::{assert_index_le, assert_index_lt, simplify_range}; |
19 | | use crate::{Bucket, Equivalent, HashValue, TryReserveError}; |
20 | | |
21 | | type Indices = hash_table::HashTable<usize>; |
22 | | type Entries<K, V> = Vec<Bucket<K, V>>; |
23 | | |
24 | | pub use entry::{OccupiedEntry, VacantEntry}; |
25 | | pub(crate) use extract::ExtractCore; |
26 | | |
27 | | /// Core of the map that does not depend on S |
28 | | #[cfg_attr(feature = "test_debug", derive(Debug))] |
29 | | pub(crate) struct Core<K, V> { |
30 | | /// indices mapping from the entry hash to its index. |
31 | | indices: Indices, |
32 | | /// entries is a dense vec maintaining entry order. |
33 | | entries: Entries<K, V>, |
34 | | } |
35 | | |
36 | | #[inline(always)] |
37 | 0 | fn get_hash<K, V>(entries: &[Bucket<K, V>]) -> impl Fn(&usize) -> u64 + use<'_, K, V> { |
38 | 0 | move |&i| entries[i].hash.get() Unexecuted instantiation: indexmap::inner::get_hash::<gimli::write::cfi::CommonInformationEntry, ()>::{closure#0}Unexecuted instantiation: indexmap::inner::get_hash::<gimli::write::loc::LocationList, ()>::{closure#0}Unexecuted instantiation: indexmap::inner::get_hash::<gimli::write::line::LineString, ()>::{closure#0}Unexecuted instantiation: indexmap::inner::get_hash::<gimli::write::range::RangeList, ()>::{closure#0}Unexecuted instantiation: indexmap::inner::get_hash::<gimli::write::abbrev::Abbreviation, ()>::{closure#0}Unexecuted instantiation: indexmap::inner::get_hash::<(gimli::write::line::LineString, gimli::write::line::DirectoryId), gimli::write::line::FileInfo>::{closure#0} |
39 | 0 | } Unexecuted instantiation: indexmap::inner::get_hash::<gimli::write::cfi::CommonInformationEntry, ()> Unexecuted instantiation: indexmap::inner::get_hash::<gimli::write::loc::LocationList, ()> Unexecuted instantiation: indexmap::inner::get_hash::<gimli::write::line::LineString, ()> Unexecuted instantiation: indexmap::inner::get_hash::<gimli::write::range::RangeList, ()> Unexecuted instantiation: indexmap::inner::get_hash::<gimli::write::abbrev::Abbreviation, ()> Unexecuted instantiation: indexmap::inner::get_hash::<(gimli::write::line::LineString, gimli::write::line::DirectoryId), gimli::write::line::FileInfo> |
40 | | |
41 | | #[inline] |
42 | 0 | fn equal<'a, K: Eq, V>( |
43 | 0 | key: &'a K, |
44 | 0 | entries: &'a [Bucket<K, V>], |
45 | 0 | ) -> impl Fn(&usize) -> bool + use<'a, K, V> { |
46 | 0 | move |&i| K::eq(key, &entries[i].key) Unexecuted instantiation: indexmap::inner::equal::<gimli::write::cfi::CommonInformationEntry, ()>::{closure#0}Unexecuted instantiation: indexmap::inner::equal::<gimli::write::loc::LocationList, ()>::{closure#0}Unexecuted instantiation: indexmap::inner::equal::<gimli::write::line::LineString, ()>::{closure#0}Unexecuted instantiation: indexmap::inner::equal::<gimli::write::range::RangeList, ()>::{closure#0}Unexecuted instantiation: indexmap::inner::equal::<gimli::write::abbrev::Abbreviation, ()>::{closure#0}Unexecuted instantiation: indexmap::inner::equal::<(gimli::write::line::LineString, gimli::write::line::DirectoryId), gimli::write::line::FileInfo>::{closure#0} |
47 | 0 | } Unexecuted instantiation: indexmap::inner::equal::<gimli::write::cfi::CommonInformationEntry, ()> Unexecuted instantiation: indexmap::inner::equal::<gimli::write::loc::LocationList, ()> Unexecuted instantiation: indexmap::inner::equal::<gimli::write::line::LineString, ()> Unexecuted instantiation: indexmap::inner::equal::<gimli::write::range::RangeList, ()> Unexecuted instantiation: indexmap::inner::equal::<gimli::write::abbrev::Abbreviation, ()> Unexecuted instantiation: indexmap::inner::equal::<(gimli::write::line::LineString, gimli::write::line::DirectoryId), gimli::write::line::FileInfo> |
48 | | |
49 | | #[inline] |
50 | | fn equivalent<'a, K, V, Q: ?Sized + Equivalent<K>>( |
51 | | key: &'a Q, |
52 | | entries: &'a [Bucket<K, V>], |
53 | | ) -> impl Fn(&usize) -> bool + use<'a, K, V, Q> { |
54 | | move |&i| Q::equivalent(key, &entries[i].key) |
55 | | } |
56 | | |
57 | | #[inline] |
58 | | fn erase_index(table: &mut Indices, hash: HashValue, index: usize) { |
59 | | if let Ok(entry) = table.find_entry(hash.get(), move |&i| i == index) { |
60 | | entry.remove(); |
61 | | } else if cfg!(debug_assertions) { |
62 | | panic!("index not found"); |
63 | | } |
64 | | } |
65 | | |
66 | | #[inline] |
67 | | fn update_index(table: &mut Indices, hash: HashValue, old: usize, new: usize) { |
68 | | let index = table |
69 | | .find_mut(hash.get(), move |&i| i == old) |
70 | | .expect("index not found"); |
71 | | *index = new; |
72 | | } |
73 | | |
74 | | /// Inserts many entries into the indices table without reallocating, |
75 | | /// and without regard for duplication. |
76 | | /// |
77 | | /// ***Panics*** if there is not sufficient capacity already. |
78 | | fn insert_bulk_no_grow<K, V>(indices: &mut Indices, entries: &[Bucket<K, V>]) { |
79 | | assert!(indices.capacity() - indices.len() >= entries.len()); |
80 | | for entry in entries { |
81 | | indices.insert_unique(entry.hash.get(), indices.len(), |_| unreachable!()); |
82 | | } |
83 | | } |
84 | | |
85 | | impl<K, V> Clone for Core<K, V> |
86 | | where |
87 | | K: Clone, |
88 | | V: Clone, |
89 | | { |
90 | | fn clone(&self) -> Self { |
91 | | let mut new = Self::new(); |
92 | | new.clone_from(self); |
93 | | new |
94 | | } |
95 | | |
96 | | fn clone_from(&mut self, other: &Self) { |
97 | | self.indices.clone_from(&other.indices); |
98 | | if self.entries.capacity() < other.entries.len() { |
99 | | // If we must resize, match the indices capacity. |
100 | | let additional = other.entries.len() - self.entries.len(); |
101 | | self.reserve_entries(additional); |
102 | | } |
103 | | self.entries.clone_from(&other.entries); |
104 | | } |
105 | | } |
106 | | |
107 | | impl<K, V> Core<K, V> { |
108 | | /// The maximum capacity before the `entries` allocation would exceed `isize::MAX`. |
109 | | const MAX_ENTRIES_CAPACITY: usize = (isize::MAX as usize) / size_of::<Bucket<K, V>>(); |
110 | | |
111 | | #[inline] |
112 | 0 | pub(crate) const fn new() -> Self { |
113 | 0 | Core { |
114 | 0 | indices: Indices::new(), |
115 | 0 | entries: Vec::new(), |
116 | 0 | } |
117 | 0 | } Unexecuted instantiation: <indexmap::inner::Core<alloc::vec::Vec<u8>, ()>>::new Unexecuted instantiation: <indexmap::inner::Core<gimli::write::loc::LocationList, ()>>::new Unexecuted instantiation: <indexmap::inner::Core<gimli::write::line::LineString, ()>>::new Unexecuted instantiation: <indexmap::inner::Core<gimli::write::range::RangeList, ()>>::new Unexecuted instantiation: <indexmap::inner::Core<(gimli::write::line::LineString, gimli::write::line::DirectoryId), gimli::write::line::FileInfo>>::new |
118 | | |
119 | | #[inline] |
120 | 0 | pub(crate) fn with_capacity(n: usize) -> Self { |
121 | 0 | Core { |
122 | 0 | indices: Indices::with_capacity(n), |
123 | 0 | entries: Vec::with_capacity(n), |
124 | 0 | } |
125 | 0 | } Unexecuted instantiation: <indexmap::inner::Core<alloc::vec::Vec<u8>, ()>>::with_capacity Unexecuted instantiation: <indexmap::inner::Core<gimli::write::loc::LocationList, ()>>::with_capacity Unexecuted instantiation: <indexmap::inner::Core<gimli::write::line::LineString, ()>>::with_capacity Unexecuted instantiation: <indexmap::inner::Core<gimli::write::range::RangeList, ()>>::with_capacity Unexecuted instantiation: <indexmap::inner::Core<(gimli::write::line::LineString, gimli::write::line::DirectoryId), gimli::write::line::FileInfo>>::with_capacity |
126 | | |
127 | | #[inline] |
128 | | pub(crate) fn into_entries(self) -> Entries<K, V> { |
129 | | self.entries |
130 | | } |
131 | | |
132 | | #[inline] |
133 | 0 | pub(crate) fn as_entries(&self) -> &[Bucket<K, V>] { |
134 | 0 | &self.entries |
135 | 0 | } Unexecuted instantiation: <indexmap::inner::Core<alloc::vec::Vec<u8>, ()>>::as_entries Unexecuted instantiation: <indexmap::inner::Core<gimli::write::line::LineString, ()>>::as_entries Unexecuted instantiation: <indexmap::inner::Core<(gimli::write::line::LineString, gimli::write::line::DirectoryId), gimli::write::line::FileInfo>>::as_entries |
136 | | |
137 | | #[inline] |
138 | 0 | pub(crate) fn as_entries_mut(&mut self) -> &mut [Bucket<K, V>] { |
139 | 0 | &mut self.entries |
140 | 0 | } |
141 | | |
142 | | pub(crate) fn with_entries<F>(&mut self, f: F) |
143 | | where |
144 | | F: FnOnce(&mut [Bucket<K, V>]), |
145 | | { |
146 | | f(&mut self.entries); |
147 | | self.rebuild_hash_table(); |
148 | | } |
149 | | |
150 | | #[inline] |
151 | 0 | pub(crate) fn len(&self) -> usize { |
152 | 0 | debug_assert_eq!(self.entries.len(), self.indices.len()); |
153 | 0 | self.indices.len() |
154 | 0 | } Unexecuted instantiation: <indexmap::inner::Core<gimli::write::cfi::CommonInformationEntry, ()>>::len Unexecuted instantiation: <indexmap::inner::Core<gimli::write::line::LineString, ()>>::len |
155 | | |
156 | | #[inline] |
157 | | pub(crate) fn capacity(&self) -> usize { |
158 | | Ord::min(self.indices.capacity(), self.entries.capacity()) |
159 | | } |
160 | | |
161 | | pub(crate) fn clear(&mut self) { |
162 | | self.indices.clear(); |
163 | | self.entries.clear(); |
164 | | } |
165 | | |
166 | | pub(crate) fn truncate(&mut self, len: usize) { |
167 | | if len < self.len() { |
168 | | self.erase_indices(len, self.entries.len()); |
169 | | self.entries.truncate(len); |
170 | | } |
171 | | } |
172 | | |
173 | | #[track_caller] |
174 | | pub(crate) fn drain<R>(&mut self, range: R) -> vec::Drain<'_, Bucket<K, V>> |
175 | | where |
176 | | R: RangeBounds<usize>, |
177 | | { |
178 | | let range = simplify_range(range, self.entries.len()); |
179 | | self.erase_indices(range.start, range.end); |
180 | | self.entries.drain(range) |
181 | | } |
182 | | |
183 | | #[cfg(feature = "rayon")] |
184 | | pub(crate) fn par_drain<R>(&mut self, range: R) -> rayon::vec::Drain<'_, Bucket<K, V>> |
185 | | where |
186 | | K: Send, |
187 | | V: Send, |
188 | | R: RangeBounds<usize>, |
189 | | { |
190 | | use rayon::iter::ParallelDrainRange; |
191 | | let range = simplify_range(range, self.entries.len()); |
192 | | self.erase_indices(range.start, range.end); |
193 | | self.entries.par_drain(range) |
194 | | } |
195 | | |
196 | | #[track_caller] |
197 | | pub(crate) fn split_off(&mut self, at: usize) -> Self { |
198 | | assert_index_le(at, self.len()); |
199 | | |
200 | | self.erase_indices(at, self.entries.len()); |
201 | | let entries = self.entries.split_off(at); |
202 | | |
203 | | let mut indices = Indices::with_capacity(entries.len()); |
204 | | insert_bulk_no_grow(&mut indices, &entries); |
205 | | Self { indices, entries } |
206 | | } |
207 | | |
208 | | #[track_caller] |
209 | | pub(crate) fn split_splice<R>(&mut self, range: R) -> (Self, vec::IntoIter<Bucket<K, V>>) |
210 | | where |
211 | | R: RangeBounds<usize>, |
212 | | { |
213 | | let range = simplify_range(range, self.len()); |
214 | | self.erase_indices(range.start, self.entries.len()); |
215 | | let entries = self.entries.split_off(range.end); |
216 | | let drained = self.entries.split_off(range.start); |
217 | | |
218 | | let mut indices = Indices::with_capacity(entries.len()); |
219 | | insert_bulk_no_grow(&mut indices, &entries); |
220 | | (Self { indices, entries }, drained.into_iter()) |
221 | | } |
222 | | |
223 | | /// Append from another map without checking whether items already exist. |
224 | | pub(crate) fn append_unchecked(&mut self, other: &mut Self) { |
225 | | self.reserve(other.len()); |
226 | | insert_bulk_no_grow(&mut self.indices, &other.entries); |
227 | | self.entries.append(&mut other.entries); |
228 | | other.indices.clear(); |
229 | | } |
230 | | |
231 | | /// Reserve capacity for `additional` more key-value pairs. |
232 | | pub(crate) fn reserve(&mut self, additional: usize) { |
233 | | self.indices.reserve(additional, get_hash(&self.entries)); |
234 | | // Only grow entries if necessary, since we also round up capacity. |
235 | | if additional > self.entries.capacity() - self.entries.len() { |
236 | | self.reserve_entries(additional); |
237 | | } |
238 | | } |
239 | | |
240 | | /// Reserve capacity for `additional` more key-value pairs, without over-allocating. |
241 | | pub(crate) fn reserve_exact(&mut self, additional: usize) { |
242 | | self.indices.reserve(additional, get_hash(&self.entries)); |
243 | | self.entries.reserve_exact(additional); |
244 | | } |
245 | | |
246 | | /// Try to reserve capacity for `additional` more key-value pairs. |
247 | | pub(crate) fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { |
248 | | self.indices |
249 | | .try_reserve(additional, get_hash(&self.entries)) |
250 | | .map_err(TryReserveError::from_hashbrown)?; |
251 | | // Only grow entries if necessary, since we also round up capacity. |
252 | | if additional > self.entries.capacity() - self.entries.len() { |
253 | | self.try_reserve_entries(additional) |
254 | | } else { |
255 | | Ok(()) |
256 | | } |
257 | | } |
258 | | |
259 | | /// Try to reserve entries capacity, rounded up to match the indices |
260 | | fn try_reserve_entries(&mut self, additional: usize) -> Result<(), TryReserveError> { |
261 | | // Use a soft-limit on the maximum capacity, but if the caller explicitly |
262 | | // requested more, do it and let them have the resulting error. |
263 | | let new_capacity = Ord::min(self.indices.capacity(), Self::MAX_ENTRIES_CAPACITY); |
264 | | let try_add = new_capacity - self.entries.len(); |
265 | | if try_add > additional && self.entries.try_reserve_exact(try_add).is_ok() { |
266 | | return Ok(()); |
267 | | } |
268 | | self.entries |
269 | | .try_reserve_exact(additional) |
270 | | .map_err(TryReserveError::from_alloc) |
271 | | } |
272 | | |
273 | | /// Try to reserve capacity for `additional` more key-value pairs, without over-allocating. |
274 | | pub(crate) fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { |
275 | | self.indices |
276 | | .try_reserve(additional, get_hash(&self.entries)) |
277 | | .map_err(TryReserveError::from_hashbrown)?; |
278 | | self.entries |
279 | | .try_reserve_exact(additional) |
280 | | .map_err(TryReserveError::from_alloc) |
281 | | } |
282 | | |
283 | | /// Shrink the capacity of the map with a lower bound |
284 | | pub(crate) fn shrink_to(&mut self, min_capacity: usize) { |
285 | | self.indices |
286 | | .shrink_to(min_capacity, get_hash(&self.entries)); |
287 | | self.entries.shrink_to(min_capacity); |
288 | | } |
289 | | |
290 | | /// Remove the last key-value pair |
291 | | pub(crate) fn pop(&mut self) -> Option<(K, V)> { |
292 | | if let Some(entry) = self.entries.pop() { |
293 | | let last = self.entries.len(); |
294 | | erase_index(&mut self.indices, entry.hash, last); |
295 | | Some((entry.key, entry.value)) |
296 | | } else { |
297 | | None |
298 | | } |
299 | | } |
300 | | |
301 | | /// Return the index in `entries` where an equivalent key can be found |
302 | | pub(crate) fn get_index_of<Q>(&self, hash: HashValue, key: &Q) -> Option<usize> |
303 | | where |
304 | | Q: ?Sized + Equivalent<K>, |
305 | | { |
306 | | let eq = equivalent(key, &self.entries); |
307 | | self.indices.find(hash.get(), eq).copied() |
308 | | } |
309 | | |
310 | | /// Return the index in `entries` where an equivalent key can be found |
311 | | pub(crate) fn get_index_of_raw<F>(&self, hash: HashValue, mut is_match: F) -> Option<usize> |
312 | | where |
313 | | F: FnMut(&K) -> bool, |
314 | | { |
315 | | let eq = move |&i: &usize| is_match(&self.entries[i].key); |
316 | | self.indices.find(hash.get(), eq).copied() |
317 | | } |
318 | | |
319 | | /// Append a key-value pair to `entries`, |
320 | | /// *without* checking whether it already exists. |
321 | 0 | fn push_entry(&mut self, hash: HashValue, key: K, value: V) { |
322 | 0 | if self.entries.len() == self.entries.capacity() { |
323 | 0 | // Reserve our own capacity synced to the indices, |
324 | 0 | // rather than letting `Vec::push` just double it. |
325 | 0 | self.reserve_entries(1); |
326 | 0 | } |
327 | 0 | self.entries.push(Bucket { hash, key, value }); |
328 | 0 | } Unexecuted instantiation: <indexmap::inner::Core<gimli::write::cfi::CommonInformationEntry, ()>>::push_entry Unexecuted instantiation: <indexmap::inner::Core<gimli::write::loc::LocationList, ()>>::push_entry Unexecuted instantiation: <indexmap::inner::Core<gimli::write::line::LineString, ()>>::push_entry Unexecuted instantiation: <indexmap::inner::Core<gimli::write::range::RangeList, ()>>::push_entry Unexecuted instantiation: <indexmap::inner::Core<gimli::write::abbrev::Abbreviation, ()>>::push_entry Unexecuted instantiation: <indexmap::inner::Core<(gimli::write::line::LineString, gimli::write::line::DirectoryId), gimli::write::line::FileInfo>>::push_entry |
329 | | |
330 | 0 | pub(crate) fn insert_full(&mut self, hash: HashValue, key: K, value: V) -> (usize, Option<V>) |
331 | 0 | where |
332 | 0 | K: Eq, |
333 | | { |
334 | 0 | let eq = equal(&key, &self.entries); |
335 | 0 | let hasher = get_hash(&self.entries); |
336 | 0 | match self.indices.entry(hash.get(), eq, hasher) { |
337 | 0 | hash_table::Entry::Occupied(entry) => { |
338 | 0 | let i = *entry.get(); |
339 | 0 | (i, Some(mem::replace(&mut self.entries[i].value, value))) |
340 | | } |
341 | 0 | hash_table::Entry::Vacant(entry) => { |
342 | 0 | let i = self.entries.len(); |
343 | 0 | entry.insert(i); |
344 | 0 | self.push_entry(hash, key, value); |
345 | 0 | debug_assert_eq!(self.indices.len(), self.entries.len()); |
346 | 0 | (i, None) |
347 | | } |
348 | | } |
349 | 0 | } Unexecuted instantiation: <indexmap::inner::Core<gimli::write::cfi::CommonInformationEntry, ()>>::insert_full Unexecuted instantiation: <indexmap::inner::Core<gimli::write::loc::LocationList, ()>>::insert_full Unexecuted instantiation: <indexmap::inner::Core<gimli::write::line::LineString, ()>>::insert_full Unexecuted instantiation: <indexmap::inner::Core<gimli::write::range::RangeList, ()>>::insert_full Unexecuted instantiation: <indexmap::inner::Core<gimli::write::abbrev::Abbreviation, ()>>::insert_full Unexecuted instantiation: <indexmap::inner::Core<(gimli::write::line::LineString, gimli::write::line::DirectoryId), gimli::write::line::FileInfo>>::insert_full |
350 | | |
351 | | /// Same as `insert_full`, except it also replaces the key |
352 | | pub(crate) fn replace_full( |
353 | | &mut self, |
354 | | hash: HashValue, |
355 | | key: K, |
356 | | value: V, |
357 | | ) -> (usize, Option<(K, V)>) |
358 | | where |
359 | | K: Eq, |
360 | | { |
361 | | let eq = equal(&key, &self.entries); |
362 | | let hasher = get_hash(&self.entries); |
363 | | match self.indices.entry(hash.get(), eq, hasher) { |
364 | | hash_table::Entry::Occupied(entry) => { |
365 | | let i = *entry.get(); |
366 | | let entry = &mut self.entries[i]; |
367 | | let kv = ( |
368 | | mem::replace(&mut entry.key, key), |
369 | | mem::replace(&mut entry.value, value), |
370 | | ); |
371 | | (i, Some(kv)) |
372 | | } |
373 | | hash_table::Entry::Vacant(entry) => { |
374 | | let i = self.entries.len(); |
375 | | entry.insert(i); |
376 | | self.push_entry(hash, key, value); |
377 | | debug_assert_eq!(self.indices.len(), self.entries.len()); |
378 | | (i, None) |
379 | | } |
380 | | } |
381 | | } |
382 | | |
383 | | /// Remove an entry by shifting all entries that follow it |
384 | | pub(crate) fn shift_remove_full<Q>(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)> |
385 | | where |
386 | | Q: ?Sized + Equivalent<K>, |
387 | | { |
388 | | let eq = equivalent(key, &self.entries); |
389 | | let (index, _) = self.indices.find_entry(hash.get(), eq).ok()?.remove(); |
390 | | let (key, value) = self.shift_remove_finish(index); |
391 | | Some((index, key, value)) |
392 | | } |
393 | | |
394 | | /// Remove an entry by swapping it with the last |
395 | | pub(crate) fn swap_remove_full<Q>(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)> |
396 | | where |
397 | | Q: ?Sized + Equivalent<K>, |
398 | | { |
399 | | let eq = equivalent(key, &self.entries); |
400 | | let (index, _) = self.indices.find_entry(hash.get(), eq).ok()?.remove(); |
401 | | let (key, value) = self.swap_remove_finish(index); |
402 | | Some((index, key, value)) |
403 | | } |
404 | | |
405 | | /// Erase `start..end` from `indices`, and shift `end..` indices down to `start..` |
406 | | /// |
407 | | /// All of these items should still be at their original location in `entries`. |
408 | | /// This is used by `drain`, which will let `Vec::drain` do the work on `entries`. |
409 | | fn erase_indices(&mut self, start: usize, end: usize) { |
410 | | let (init, shifted_entries) = self.entries.split_at(end); |
411 | | let (start_entries, erased_entries) = init.split_at(start); |
412 | | |
413 | | let erased = erased_entries.len(); |
414 | | let shifted = shifted_entries.len(); |
415 | | let half_capacity = self.indices.capacity() / 2; |
416 | | |
417 | | // Use a heuristic between different strategies |
418 | | if erased == 0 { |
419 | | // Degenerate case, nothing to do |
420 | | } else if start + shifted < half_capacity && start < erased { |
421 | | // Reinsert everything, as there are few kept indices |
422 | | self.indices.clear(); |
423 | | |
424 | | // Reinsert stable indices, then shifted indices |
425 | | insert_bulk_no_grow(&mut self.indices, start_entries); |
426 | | insert_bulk_no_grow(&mut self.indices, shifted_entries); |
427 | | } else if erased + shifted < half_capacity { |
428 | | // Find each affected index, as there are few to adjust |
429 | | |
430 | | // Find erased indices |
431 | | for (i, entry) in (start..).zip(erased_entries) { |
432 | | erase_index(&mut self.indices, entry.hash, i); |
433 | | } |
434 | | |
435 | | // Find shifted indices |
436 | | for ((new, old), entry) in (start..).zip(end..).zip(shifted_entries) { |
437 | | update_index(&mut self.indices, entry.hash, old, new); |
438 | | } |
439 | | } else { |
440 | | // Sweep the whole table for adjustments |
441 | | let offset = end - start; |
442 | | self.indices.retain(move |i| { |
443 | | if *i >= end { |
444 | | *i -= offset; |
445 | | true |
446 | | } else { |
447 | | *i < start |
448 | | } |
449 | | }); |
450 | | } |
451 | | |
452 | | debug_assert_eq!(self.indices.len(), start + shifted); |
453 | | } |
454 | | |
455 | | pub(crate) fn retain_in_order<F>(&mut self, mut keep: F) |
456 | | where |
457 | | F: FnMut(&mut K, &mut V) -> bool, |
458 | | { |
459 | | self.entries |
460 | | .retain_mut(|entry| keep(&mut entry.key, &mut entry.value)); |
461 | | if self.entries.len() < self.indices.len() { |
462 | | self.rebuild_hash_table(); |
463 | | } |
464 | | } |
465 | | |
466 | | fn rebuild_hash_table(&mut self) { |
467 | | self.indices.clear(); |
468 | | insert_bulk_no_grow(&mut self.indices, &self.entries); |
469 | | } |
470 | | |
471 | | pub(crate) fn reverse(&mut self) { |
472 | | self.entries.reverse(); |
473 | | |
474 | | // No need to save hash indices, can easily calculate what they should |
475 | | // be, given that this is an in-place reversal. |
476 | | let len = self.entries.len(); |
477 | | for i in &mut self.indices { |
478 | | *i = len - *i - 1; |
479 | | } |
480 | | } |
481 | | |
482 | | /// Reserve entries capacity, rounded up to match the indices |
483 | | #[inline] |
484 | 0 | fn reserve_entries(&mut self, additional: usize) { |
485 | | // Use a soft-limit on the maximum capacity, but if the caller explicitly |
486 | | // requested more, do it and let them have the resulting panic. |
487 | 0 | let try_capacity = Ord::min(self.indices.capacity(), Self::MAX_ENTRIES_CAPACITY); |
488 | 0 | let try_add = try_capacity - self.entries.len(); |
489 | 0 | if try_add > additional && self.entries.try_reserve_exact(try_add).is_ok() { |
490 | 0 | return; |
491 | 0 | } |
492 | 0 | self.entries.reserve_exact(additional); |
493 | 0 | } Unexecuted instantiation: <indexmap::inner::Core<gimli::write::cfi::CommonInformationEntry, ()>>::reserve_entries Unexecuted instantiation: <indexmap::inner::Core<gimli::write::loc::LocationList, ()>>::reserve_entries Unexecuted instantiation: <indexmap::inner::Core<gimli::write::line::LineString, ()>>::reserve_entries Unexecuted instantiation: <indexmap::inner::Core<gimli::write::range::RangeList, ()>>::reserve_entries Unexecuted instantiation: <indexmap::inner::Core<gimli::write::abbrev::Abbreviation, ()>>::reserve_entries Unexecuted instantiation: <indexmap::inner::Core<(gimli::write::line::LineString, gimli::write::line::DirectoryId), gimli::write::line::FileInfo>>::reserve_entries |
494 | | |
495 | | /// Insert a key-value pair in `entries`, |
496 | | /// *without* checking whether it already exists. |
497 | 0 | pub(super) fn insert_unique(&mut self, hash: HashValue, key: K, value: V) -> &mut Bucket<K, V> { |
498 | 0 | let i = self.indices.len(); |
499 | 0 | debug_assert_eq!(i, self.entries.len()); |
500 | 0 | self.indices |
501 | 0 | .insert_unique(hash.get(), i, get_hash(&self.entries)); |
502 | 0 | self.push_entry(hash, key, value); |
503 | 0 | &mut self.entries[i] |
504 | 0 | } |
505 | | |
506 | | /// Replaces the key at the given index, |
507 | | /// *without* checking whether it already exists. |
508 | | #[track_caller] |
509 | | pub(crate) fn replace_index_unique(&mut self, index: usize, hash: HashValue, key: K) -> K { |
510 | | // NB: This removal and insertion isn't "no grow" (with unreachable hasher) |
511 | | // because hashbrown's tombstones might force a resize anyway. |
512 | | erase_index(&mut self.indices, self.entries[index].hash, index); |
513 | | self.indices |
514 | | .insert_unique(hash.get(), index, get_hash(&self.entries)); |
515 | | |
516 | | let entry = &mut self.entries[index]; |
517 | | entry.hash = hash; |
518 | | mem::replace(&mut entry.key, key) |
519 | | } |
520 | | |
521 | | /// Insert a key-value pair in `entries` at a particular index, |
522 | | /// *without* checking whether it already exists. |
523 | | pub(crate) fn shift_insert_unique( |
524 | | &mut self, |
525 | | index: usize, |
526 | | hash: HashValue, |
527 | | key: K, |
528 | | value: V, |
529 | | ) -> &mut Bucket<K, V> { |
530 | | let end = self.indices.len(); |
531 | | assert!(index <= end); |
532 | | // Increment others first so we don't have duplicate indices. |
533 | | self.increment_indices(index, end); |
534 | | let entries = &*self.entries; |
535 | | self.indices.insert_unique(hash.get(), index, move |&i| { |
536 | | // Adjust for the incremented indices to find hashes. |
537 | | debug_assert_ne!(i, index); |
538 | | let i = if i < index { i } else { i - 1 }; |
539 | | entries[i].hash.get() |
540 | | }); |
541 | | if self.entries.len() == self.entries.capacity() { |
542 | | // Reserve our own capacity synced to the indices, |
543 | | // rather than letting `Vec::insert` just double it. |
544 | | self.reserve_entries(1); |
545 | | } |
546 | | self.entries.insert(index, Bucket { hash, key, value }); |
547 | | &mut self.entries[index] |
548 | | } |
549 | | |
550 | | /// Remove an entry by shifting all entries that follow it |
551 | | pub(crate) fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> { |
552 | | match self.entries.get(index) { |
553 | | Some(entry) => { |
554 | | erase_index(&mut self.indices, entry.hash, index); |
555 | | Some(self.shift_remove_finish(index)) |
556 | | } |
557 | | None => None, |
558 | | } |
559 | | } |
560 | | |
561 | | /// Remove an entry by shifting all entries that follow it |
562 | | /// |
563 | | /// The index should already be removed from `self.indices`. |
564 | | fn shift_remove_finish(&mut self, index: usize) -> (K, V) { |
565 | | // Correct indices that point to the entries that followed the removed entry. |
566 | | self.decrement_indices(index + 1, self.entries.len()); |
567 | | |
568 | | // Use Vec::remove to actually remove the entry. |
569 | | let entry = self.entries.remove(index); |
570 | | (entry.key, entry.value) |
571 | | } |
572 | | |
573 | | /// Remove an entry by swapping it with the last |
574 | | pub(crate) fn swap_remove_index(&mut self, index: usize) -> Option<(K, V)> { |
575 | | match self.entries.get(index) { |
576 | | Some(entry) => { |
577 | | erase_index(&mut self.indices, entry.hash, index); |
578 | | Some(self.swap_remove_finish(index)) |
579 | | } |
580 | | None => None, |
581 | | } |
582 | | } |
583 | | |
584 | | /// Finish removing an entry by swapping it with the last |
585 | | /// |
586 | | /// The index should already be removed from `self.indices`. |
587 | | fn swap_remove_finish(&mut self, index: usize) -> (K, V) { |
588 | | // use swap_remove, but then we need to update the index that points |
589 | | // to the other entry that has to move |
590 | | let entry = self.entries.swap_remove(index); |
591 | | |
592 | | // correct index that points to the entry that had to swap places |
593 | | if let Some(entry) = self.entries.get(index) { |
594 | | // was not last element |
595 | | // examine new element in `index` and find it in indices |
596 | | let last = self.entries.len(); |
597 | | update_index(&mut self.indices, entry.hash, last, index); |
598 | | } |
599 | | |
600 | | (entry.key, entry.value) |
601 | | } |
602 | | |
603 | | /// Decrement all indices in the range `start..end`. |
604 | | /// |
605 | | /// The index `start - 1` should not exist in `self.indices`. |
606 | | /// All entries should still be in their original positions. |
607 | | fn decrement_indices(&mut self, start: usize, end: usize) { |
608 | | // Use a heuristic between a full sweep vs. a `find()` for every shifted item. |
609 | | let shifted_entries = &self.entries[start..end]; |
610 | | if shifted_entries.len() > self.indices.capacity() / 2 { |
611 | | // Shift all indices in range. |
612 | | for i in &mut self.indices { |
613 | | if start <= *i && *i < end { |
614 | | *i -= 1; |
615 | | } |
616 | | } |
617 | | } else { |
618 | | // Find each entry in range to shift its index. |
619 | | for (i, entry) in (start..end).zip(shifted_entries) { |
620 | | update_index(&mut self.indices, entry.hash, i, i - 1); |
621 | | } |
622 | | } |
623 | | } |
624 | | |
625 | | /// Increment all indices in the range `start..end`. |
626 | | /// |
627 | | /// The index `end` should not exist in `self.indices`. |
628 | | /// All entries should still be in their original positions. |
629 | | fn increment_indices(&mut self, start: usize, end: usize) { |
630 | | // Use a heuristic between a full sweep vs. a `find()` for every shifted item. |
631 | | let shifted_entries = &self.entries[start..end]; |
632 | | if shifted_entries.len() > self.indices.capacity() / 2 { |
633 | | // Shift all indices in range. |
634 | | for i in &mut self.indices { |
635 | | if start <= *i && *i < end { |
636 | | *i += 1; |
637 | | } |
638 | | } |
639 | | } else { |
640 | | // Find each entry in range to shift its index, updated in reverse so |
641 | | // we never have duplicated indices that might have a hash collision. |
642 | | for (i, entry) in (start..end).zip(shifted_entries).rev() { |
643 | | update_index(&mut self.indices, entry.hash, i, i + 1); |
644 | | } |
645 | | } |
646 | | } |
647 | | |
648 | | #[track_caller] |
649 | | pub(super) fn move_index(&mut self, from: usize, to: usize) { |
650 | | assert_index_lt(from, self.len()); |
651 | | let from_hash = self.entries[from].hash; |
652 | | if from != to { |
653 | | assert_index_lt(to, self.len()); |
654 | | |
655 | | // Find the bucket index first so we won't lose it among other updated indices. |
656 | | let bucket = self |
657 | | .indices |
658 | | .find_bucket_index(from_hash.get(), move |&i| i == from) |
659 | | .expect("index not found"); |
660 | | |
661 | | self.move_index_inner(from, to); |
662 | | *self.indices.get_bucket_mut(bucket).unwrap() = to; |
663 | | } |
664 | | } |
665 | | |
666 | | fn move_index_inner(&mut self, from: usize, to: usize) { |
667 | | // Update all other indices and rotate the entry positions. |
668 | | if from < to { |
669 | | self.decrement_indices(from + 1, to + 1); |
670 | | self.entries[from..=to].rotate_left(1); |
671 | | } else if to < from { |
672 | | self.increment_indices(to, from); |
673 | | self.entries[to..=from].rotate_right(1); |
674 | | } |
675 | | } |
676 | | |
677 | | #[track_caller] |
678 | | pub(crate) fn swap_indices(&mut self, a: usize, b: usize) { |
679 | | assert_index_lt(a, self.len()); |
680 | | if a == b { |
681 | | // If they're equal, there's nothing to do. |
682 | | return; |
683 | | } |
684 | | assert_index_lt(b, self.len()); |
685 | | |
686 | | // Since the indices are in-bounds, we expect to find them in the table as well. |
687 | | match self.indices.get_disjoint_mut( |
688 | | [self.entries[a].hash.get(), self.entries[b].hash.get()], |
689 | | move |i, &x| if i == 0 { x == a } else { x == b }, |
690 | | ) { |
691 | | [Some(ref_a), Some(ref_b)] => { |
692 | | mem::swap(ref_a, ref_b); |
693 | | self.entries.swap(a, b); |
694 | | } |
695 | | _ => panic!("indices not found"), |
696 | | } |
697 | | } |
698 | | } |
699 | | |
700 | | #[test] |
701 | | fn assert_send_sync() { |
702 | | fn assert_send_sync<T: Send + Sync>() {} |
703 | | assert_send_sync::<Core<i32, i32>>(); |
704 | | } |