Coverage Report

Created: 2026-09-01 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}