Skip to main content

indexmap/
inner.rs

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
10mod entry;
11mod extract;
12
13use alloc::vec::{self, Vec};
14use core::mem;
15use core::ops::RangeBounds;
16use hashbrown::hash_table;
17
18use crate::util::{assert_index_le, assert_index_lt, simplify_range};
19use crate::{Bucket, Equivalent, HashValue, TryReserveError};
20
21type Indices = hash_table::HashTable<usize>;
22type Entries<K, V> = Vec<Bucket<K, V>>;
23
24pub use entry::{OccupiedEntry, VacantEntry};
25pub(crate) use extract::ExtractCore;
26
27/// Core of the map that does not depend on S
28#[cfg_attr(feature = "test_debug", derive(Debug))]
29pub(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)]
37fn get_hash<K, V>(entries: &[Bucket<K, V>]) -> impl Fn(&usize) -> u64 + use<'_, K, V> {
38    move |&i| entries[i].hash.get()
39}
40
41#[inline]
42fn equal<'a, K: Eq, V>(
43    key: &'a K,
44    entries: &'a [Bucket<K, V>],
45) -> impl Fn(&usize) -> bool + use<'a, K, V> {
46    move |&i| K::eq(key, &entries[i].key)
47}
48
49#[inline]
50fn 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]
58fn 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]
67fn 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.
78fn 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
85impl<K, V> Clone for Core<K, V>
86where
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
107impl<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    pub(crate) const fn new() -> Self {
113        Core {
114            indices: Indices::new(),
115            entries: Vec::new(),
116        }
117    }
118
119    #[inline]
120    pub(crate) fn with_capacity(n: usize) -> Self {
121        Core {
122            indices: Indices::with_capacity(n),
123            entries: Vec::with_capacity(n),
124        }
125    }
126
127    #[inline]
128    pub(crate) fn into_entries(self) -> Entries<K, V> {
129        self.entries
130    }
131
132    #[inline]
133    pub(crate) fn as_entries(&self) -> &[Bucket<K, V>] {
134        &self.entries
135    }
136
137    #[inline]
138    pub(crate) fn as_entries_mut(&mut self) -> &mut [Bucket<K, V>] {
139        &mut self.entries
140    }
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    pub(crate) fn len(&self) -> usize {
152        debug_assert_eq!(self.entries.len(), self.indices.len());
153        self.indices.len()
154    }
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    fn push_entry(&mut self, hash: HashValue, key: K, value: V) {
322        if self.entries.len() == self.entries.capacity() {
323            // Reserve our own capacity synced to the indices,
324            // rather than letting `Vec::push` just double it.
325            self.reserve_entries(1);
326        }
327        self.entries.push(Bucket { hash, key, value });
328    }
329
330    pub(crate) fn insert_full(&mut self, hash: HashValue, key: K, value: V) -> (usize, Option<V>)
331    where
332        K: Eq,
333    {
334        let eq = equal(&key, &self.entries);
335        let hasher = get_hash(&self.entries);
336        match self.indices.entry(hash.get(), eq, hasher) {
337            hash_table::Entry::Occupied(entry) => {
338                let i = *entry.get();
339                (i, Some(mem::replace(&mut self.entries[i].value, value)))
340            }
341            hash_table::Entry::Vacant(entry) => {
342                let i = self.entries.len();
343                entry.insert(i);
344                self.push_entry(hash, key, value);
345                debug_assert_eq!(self.indices.len(), self.entries.len());
346                (i, None)
347            }
348        }
349    }
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    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        let try_capacity = Ord::min(self.indices.capacity(), Self::MAX_ENTRIES_CAPACITY);
488        let try_add = try_capacity - self.entries.len();
489        if try_add > additional && self.entries.try_reserve_exact(try_add).is_ok() {
490            return;
491        }
492        self.entries.reserve_exact(additional);
493    }
494
495    /// Insert a key-value pair in `entries`,
496    /// *without* checking whether it already exists.
497    pub(super) fn insert_unique(&mut self, hash: HashValue, key: K, value: V) -> &mut Bucket<K, V> {
498        let i = self.indices.len();
499        debug_assert_eq!(i, self.entries.len());
500        self.indices
501            .insert_unique(hash.get(), i, get_hash(&self.entries));
502        self.push_entry(hash, key, value);
503        &mut self.entries[i]
504    }
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]
701fn assert_send_sync() {
702    fn assert_send_sync<T: Send + Sync>() {}
703    assert_send_sync::<Core<i32, i32>>();
704}