diff --git a/Cargo.toml b/Cargo.toml index c5463603..6148087b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "indexmap" edition = "2021" -version = "2.12.0" +version = "2.12.1" documentation = "https://docs.rs/indexmap/" repository = "https://github.com/indexmap-rs/indexmap" license = "Apache-2.0 OR MIT" @@ -15,7 +15,7 @@ bench = false [dependencies] equivalent = { version = "1.0", default-features = false } -hashbrown = { version = "0.16", default-features = false } +hashbrown = { version = "0.16.1", default-features = false } arbitrary = { version = "1.0", optional = true, default-features = false } quickcheck = { version = "1.0", optional = true, default-features = false } diff --git a/RELEASES.md b/RELEASES.md index 2a8a99a0..64ad9196 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,9 @@ # Releases +## 2.12.1 (2025-11-20) + +- Simplified a lot of internals using `hashbrown`'s new bucket API. + ## 2.12.0 (2025-10-17) - **MSRV**: Rust 1.82.0 or later is now required. diff --git a/src/map.rs b/src/map.rs index 6ea7cb9a..7e9b8f94 100644 --- a/src/map.rs +++ b/src/map.rs @@ -736,7 +736,7 @@ where /// Computes in **O(1)** time (amortized average). pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { let hash = self.hash(&key); - self.core.entry(hash, key) + Entry::new(&mut self.core, hash, key) } /// Creates a splicing iterator that replaces the specified range in the map @@ -1452,10 +1452,7 @@ impl IndexMap { /// /// Computes in **O(1)** time. pub fn get_index_entry(&mut self, index: usize) -> Option> { - if index >= self.len() { - return None; - } - Some(IndexedEntry::new(&mut self.core, index)) + IndexedEntry::new(&mut self.core, index) } /// Get an array of `N` key-value pairs by `N` indices diff --git a/src/map/core.rs b/src/map/core.rs index d4acadb0..1dcf2b76 100644 --- a/src/map/core.rs +++ b/src/map/core.rs @@ -35,17 +35,6 @@ pub(crate) struct IndexMapCore { entries: Entries, } -/// Mutable references to the parts of an `IndexMapCore`. -/// -/// When using `HashTable::find_entry`, that takes hold of `&mut indices`, so we have to borrow our -/// `&mut entries` separately, and there's no way to go back to a `&mut IndexMapCore`. So this type -/// is used to implement methods on the split references, and `IndexMapCore` can also call those to -/// avoid duplication. -struct RefMut<'a, K, V> { - indices: &'a mut Indices, - entries: &'a mut Entries, -} - #[inline(always)] fn get_hash(entries: &[Bucket]) -> impl Fn(&usize) -> u64 + use<'_, K, V> { move |&i| entries[i].hash.get() @@ -103,7 +92,7 @@ where if self.entries.capacity() < other.entries.len() { // If we must resize, match the indices capacity. let additional = other.entries.len() - self.entries.len(); - self.borrow_mut().reserve_entries(additional); + self.reserve_entries(additional); } self.entries.clone_from(&other.entries); } @@ -121,11 +110,6 @@ impl IndexMapCore { } } - #[inline] - fn borrow_mut(&mut self) -> RefMut<'_, K, V> { - RefMut::new(&mut self.indices, &mut self.entries) - } - #[inline] pub(crate) fn with_capacity(n: usize) -> Self { IndexMapCore { @@ -247,7 +231,7 @@ impl IndexMapCore { self.indices.reserve(additional, get_hash(&self.entries)); // Only grow entries if necessary, since we also round up capacity. if additional > self.entries.capacity() - self.entries.len() { - self.borrow_mut().reserve_entries(additional); + self.reserve_entries(additional); } } @@ -327,7 +311,7 @@ impl IndexMapCore { if self.entries.len() == self.entries.capacity() { // Reserve our own capacity synced to the indices, // rather than letting `Vec::push` just double it. - self.borrow_mut().reserve_entries(1); + self.reserve_entries(1); } self.entries.push(Bucket { hash, key, value }); } @@ -385,45 +369,15 @@ impl IndexMapCore { } } - /// Replaces the key at the given index, - /// *without* checking whether it already exists. - #[track_caller] - pub(crate) fn replace_index_unique(&mut self, index: usize, hash: HashValue, key: K) -> K { - self.borrow_mut().replace_index_unique(index, hash, key).0 - } - /// Remove an entry by shifting all entries that follow it pub(crate) fn shift_remove_full(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)> where Q: ?Sized + Equivalent, { let eq = equivalent(key, &self.entries); - match self.indices.find_entry(hash.get(), eq) { - Ok(entry) => { - let (index, _) = entry.remove(); - let (key, value) = self.borrow_mut().shift_remove_finish(index); - Some((index, key, value)) - } - Err(_) => None, - } - } - - /// Remove an entry by shifting all entries that follow it - #[inline] - pub(crate) fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> { - self.borrow_mut().shift_remove_index(index) - } - - #[inline] - #[track_caller] - pub(super) fn move_index(&mut self, from: usize, to: usize) { - self.borrow_mut().move_index(from, to); - } - - #[inline] - #[track_caller] - pub(crate) fn swap_indices(&mut self, a: usize, b: usize) { - self.borrow_mut().swap_indices(a, b); + let (index, _) = self.indices.find_entry(hash.get(), eq).ok()?.remove(); + let (key, value) = self.shift_remove_finish(index); + Some((index, key, value)) } /// Remove an entry by swapping it with the last @@ -432,20 +386,9 @@ impl IndexMapCore { Q: ?Sized + Equivalent, { let eq = equivalent(key, &self.entries); - match self.indices.find_entry(hash.get(), eq) { - Ok(entry) => { - let (index, _) = entry.remove(); - let (key, value) = self.borrow_mut().swap_remove_finish(index); - Some((index, key, value)) - } - Err(_) => None, - } - } - - /// Remove an entry by swapping it with the last - #[inline] - pub(crate) fn swap_remove_index(&mut self, index: usize) -> Option<(K, V)> { - self.borrow_mut().swap_remove_index(index) + let (index, _) = self.indices.find_entry(hash.get(), eq).ok()?.remove(); + let (key, value) = self.swap_remove_finish(index); + Some((index, key, value)) } /// Erase `start..end` from `indices`, and shift `end..` indices down to `start..` @@ -524,70 +467,44 @@ impl IndexMapCore { *i = len - *i - 1; } } -} - -/// Reserve entries capacity, rounded up to match the indices (via `try_capacity`). -fn reserve_entries(entries: &mut Entries, additional: usize, try_capacity: usize) { - // Use a soft-limit on the maximum capacity, but if the caller explicitly - // requested more, do it and let them have the resulting panic. - let try_capacity = try_capacity.min(IndexMapCore::::MAX_ENTRIES_CAPACITY); - let try_add = try_capacity - entries.len(); - if try_add > additional && entries.try_reserve_exact(try_add).is_ok() { - return; - } - entries.reserve_exact(additional); -} - -impl<'a, K, V> RefMut<'a, K, V> { - #[inline] - fn new(indices: &'a mut Indices, entries: &'a mut Entries) -> Self { - Self { indices, entries } - } /// Reserve entries capacity, rounded up to match the indices #[inline] fn reserve_entries(&mut self, additional: usize) { - reserve_entries(self.entries, additional, self.indices.capacity()); + // Use a soft-limit on the maximum capacity, but if the caller explicitly + // requested more, do it and let them have the resulting panic. + let try_capacity = Ord::min(self.indices.capacity(), Self::MAX_ENTRIES_CAPACITY); + let try_add = try_capacity - self.entries.len(); + if try_add > additional && self.entries.try_reserve_exact(try_add).is_ok() { + return; + } + self.entries.reserve_exact(additional); } /// Insert a key-value pair in `entries`, /// *without* checking whether it already exists. - fn insert_unique(self, hash: HashValue, key: K, value: V) -> OccupiedEntry<'a, K, V> { + pub(super) fn insert_unique(&mut self, hash: HashValue, key: K, value: V) -> &mut Bucket { let i = self.indices.len(); debug_assert_eq!(i, self.entries.len()); - let entry = self - .indices - .insert_unique(hash.get(), i, get_hash(self.entries)); - if self.entries.len() == self.entries.capacity() { - // We can't call `indices.capacity()` while this `entry` has borrowed it, so we'll have - // to amortize growth on our own. It's still an improvement over the basic `Vec::push` - // doubling though, since we also consider `MAX_ENTRIES_CAPACITY`. - reserve_entries(self.entries, 1, 2 * self.entries.capacity()); - } - self.entries.push(Bucket { hash, key, value }); - OccupiedEntry::new(self.entries, entry) + self.indices + .insert_unique(hash.get(), i, get_hash(&self.entries)); + self.push_entry(hash, key, value); + &mut self.entries[i] } /// Replaces the key at the given index, /// *without* checking whether it already exists. #[track_caller] - fn replace_index_unique( - self, - index: usize, - hash: HashValue, - key: K, - ) -> (K, OccupiedEntry<'a, K, V>) { + pub(crate) fn replace_index_unique(&mut self, index: usize, hash: HashValue, key: K) -> K { // NB: This removal and insertion isn't "no grow" (with unreachable hasher) // because hashbrown's tombstones might force a resize anyway. - erase_index(self.indices, self.entries[index].hash, index); - let table_entry = self - .indices + erase_index(&mut self.indices, self.entries[index].hash, index); + self.indices .insert_unique(hash.get(), index, get_hash(&self.entries)); let entry = &mut self.entries[index]; entry.hash = hash; - let old_key = mem::replace(&mut entry.key, key); - (old_key, OccupiedEntry::new(self.entries, table_entry)) + mem::replace(&mut entry.key, key) } /// Insert a key-value pair in `entries` at a particular index, @@ -613,10 +530,10 @@ impl<'a, K, V> RefMut<'a, K, V> { } /// Remove an entry by shifting all entries that follow it - fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> { + pub(crate) fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> { match self.entries.get(index) { Some(entry) => { - erase_index(self.indices, entry.hash, index); + erase_index(&mut self.indices, entry.hash, index); Some(self.shift_remove_finish(index)) } None => None, @@ -636,10 +553,10 @@ impl<'a, K, V> RefMut<'a, K, V> { } /// Remove an entry by swapping it with the last - fn swap_remove_index(&mut self, index: usize) -> Option<(K, V)> { + pub(crate) fn swap_remove_index(&mut self, index: usize) -> Option<(K, V)> { match self.entries.get(index) { Some(entry) => { - erase_index(self.indices, entry.hash, index); + erase_index(&mut self.indices, entry.hash, index); Some(self.swap_remove_finish(index)) } None => None, @@ -659,7 +576,7 @@ impl<'a, K, V> RefMut<'a, K, V> { // was not last element // examine new element in `index` and find it in indices let last = self.entries.len(); - update_index(self.indices, entry.hash, last, index); + update_index(&mut self.indices, entry.hash, last, index); } (entry.key, entry.value) @@ -674,7 +591,7 @@ impl<'a, K, V> RefMut<'a, K, V> { let shifted_entries = &self.entries[start..end]; if shifted_entries.len() > self.indices.capacity() / 2 { // Shift all indices in range. - for i in &mut *self.indices { + for i in &mut self.indices { if start <= *i && *i < end { *i -= 1; } @@ -682,7 +599,7 @@ impl<'a, K, V> RefMut<'a, K, V> { } else { // Find each entry in range to shift its index. for (i, entry) in (start..end).zip(shifted_entries) { - update_index(self.indices, entry.hash, i, i - 1); + update_index(&mut self.indices, entry.hash, i, i - 1); } } } @@ -696,7 +613,7 @@ impl<'a, K, V> RefMut<'a, K, V> { let shifted_entries = &self.entries[start..end]; if shifted_entries.len() > self.indices.capacity() / 2 { // Shift all indices in range. - for i in &mut *self.indices { + for i in &mut self.indices { if start <= *i && *i < end { *i += 1; } @@ -705,35 +622,41 @@ impl<'a, K, V> RefMut<'a, K, V> { // Find each entry in range to shift its index, updated in reverse so // we never have duplicated indices that might have a hash collision. for (i, entry) in (start..end).zip(shifted_entries).rev() { - update_index(self.indices, entry.hash, i, i + 1); + update_index(&mut self.indices, entry.hash, i, i + 1); } } } #[track_caller] - fn move_index(&mut self, from: usize, to: usize) { + pub(super) fn move_index(&mut self, from: usize, to: usize) { let from_hash = self.entries[from].hash; - let _ = self.entries[to]; // explicit bounds check if from != to { - // Use a sentinel index so other indices don't collide. - update_index(self.indices, from_hash, from, usize::MAX); - - // Update all other indices and rotate the entry positions. - if from < to { - self.decrement_indices(from + 1, to + 1); - self.entries[from..=to].rotate_left(1); - } else if to < from { - self.increment_indices(to, from); - self.entries[to..=from].rotate_right(1); - } + let _ = self.entries[to]; // explicit bounds check + + // Find the bucket index first so we won't lose it among other updated indices. + let bucket = self + .indices + .find_bucket_index(from_hash.get(), move |&i| i == from) + .expect("index not found"); - // Change the sentinel index to its final position. - update_index(self.indices, from_hash, usize::MAX, to); + self.move_index_inner(from, to); + *self.indices.get_bucket_mut(bucket).unwrap() = to; + } + } + + fn move_index_inner(&mut self, from: usize, to: usize) { + // Update all other indices and rotate the entry positions. + if from < to { + self.decrement_indices(from + 1, to + 1); + self.entries[from..=to].rotate_left(1); + } else if to < from { + self.increment_indices(to, from); + self.entries[to..=from].rotate_right(1); } } #[track_caller] - fn swap_indices(&mut self, a: usize, b: usize) { + pub(crate) fn swap_indices(&mut self, a: usize, b: usize) { // If they're equal and in-bounds, there's nothing to do. if a == b && a < self.entries.len() { return; @@ -741,7 +664,7 @@ impl<'a, K, V> RefMut<'a, K, V> { // We'll get a "nice" bounds-check from indexing `entries`, // and then we expect to find it in the table as well. - match self.indices.get_many_mut( + match self.indices.get_disjoint_mut( [self.entries[a].hash.get(), self.entries[b].hash.get()], move |i, &x| if i == 0 { x == a } else { x == b }, ) { diff --git a/src/map/core/entry.rs b/src/map/core/entry.rs index 9dafb536..87a7d955 100644 --- a/src/map/core/entry.rs +++ b/src/map/core/entry.rs @@ -1,26 +1,7 @@ -use super::{equivalent, Entries, IndexMapCore, RefMut}; +use super::{equivalent, get_hash, Bucket, IndexMapCore}; use crate::HashValue; use core::cmp::Ordering; use core::{fmt, mem}; -use hashbrown::hash_table; - -impl IndexMapCore { - pub(crate) fn entry(&mut self, hash: HashValue, key: K) -> Entry<'_, K, V> - where - K: Eq, - { - let entries = &mut self.entries; - let eq = equivalent(&key, entries); - match self.indices.find_entry(hash.get(), eq) { - Ok(index) => Entry::Occupied(OccupiedEntry { entries, index }), - Err(absent) => Entry::Vacant(VacantEntry { - map: RefMut::new(absent.into_table(), entries), - hash, - key, - }), - } - } -} /// Entry for an existing key-value pair in an [`IndexMap`][crate::IndexMap] /// or a vacant location to insert one. @@ -32,11 +13,26 @@ pub enum Entry<'a, K, V> { } impl<'a, K, V> Entry<'a, K, V> { + pub(crate) fn new(map: &'a mut IndexMapCore, hash: HashValue, key: K) -> Self + where + K: Eq, + { + let eq = equivalent(&key, &map.entries); + match map.indices.find_entry(hash.get(), eq) { + Ok(entry) => Entry::Occupied(OccupiedEntry { + bucket: entry.bucket_index(), + index: *entry.get(), + map, + }), + Err(_) => Entry::Vacant(VacantEntry { map, hash, key }), + } + } + /// Return the index where the key-value pair exists or will be inserted. pub fn index(&self) -> usize { - match *self { - Entry::Occupied(ref entry) => entry.index(), - Entry::Vacant(ref entry) => entry.index(), + match self { + Entry::Occupied(entry) => entry.index, + Entry::Vacant(entry) => entry.index(), } } @@ -145,27 +141,51 @@ impl fmt::Debug for Entry<'_, K, V> { /// A view into an occupied entry in an [`IndexMap`][crate::IndexMap]. /// It is part of the [`Entry`] enum. pub struct OccupiedEntry<'a, K, V> { - entries: &'a mut Entries, - index: hash_table::OccupiedEntry<'a, usize>, + map: &'a mut IndexMapCore, + // We have a mutable reference to the map, which keeps these two + // indices valid and pointing to the correct entry. + index: usize, + bucket: usize, } impl<'a, K, V> OccupiedEntry<'a, K, V> { - pub(crate) fn new( - entries: &'a mut Entries, - index: hash_table::OccupiedEntry<'a, usize>, - ) -> Self { - Self { entries, index } + /// Constructor for `RawEntryMut::from_hash` + pub(super) fn from_hash( + map: &'a mut IndexMapCore, + hash: u64, + mut is_match: F, + ) -> Result> + where + F: FnMut(&K) -> bool, + { + let entries = &*map.entries; + let eq = move |&i: &usize| is_match(&entries[i].key); + match map.indices.find_entry(hash, eq) { + Ok(entry) => Ok(OccupiedEntry { + bucket: entry.bucket_index(), + index: *entry.get(), + map, + }), + Err(_) => Err(map), + } } - /// Return the index of the key-value pair - #[inline] - pub fn index(&self) -> usize { - *self.index.get() + pub(crate) fn get_bucket(&self) -> &Bucket { + &self.map.entries[self.index] + } + + pub(crate) fn get_bucket_mut(&mut self) -> &mut Bucket { + &mut self.map.entries[self.index] + } + + pub(crate) fn into_bucket(self) -> &'a mut Bucket { + &mut self.map.entries[self.index] } + /// Return the index of the key-value pair #[inline] - fn into_ref_mut(self) -> RefMut<'a, K, V> { - RefMut::new(self.index.into_table(), self.entries) + pub fn index(&self) -> usize { + self.index } /// Gets a reference to the entry's key in the map. @@ -174,17 +194,12 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like /// extra fields or the memory address of an allocation. pub fn key(&self) -> &K { - &self.entries[self.index()].key - } - - pub(crate) fn key_mut(&mut self) -> &mut K { - let index = self.index(); - &mut self.entries[index].key + &self.map.entries[self.index].key } /// Gets a reference to the entry's value in the map. pub fn get(&self) -> &V { - &self.entries[self.index()].value + &self.map.entries[self.index].value } /// Gets a mutable reference to the entry's value in the map. @@ -192,20 +207,13 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// If you need a reference which may outlive the destruction of the /// [`Entry`] value, see [`into_mut`][Self::into_mut]. pub fn get_mut(&mut self) -> &mut V { - let index = self.index(); - &mut self.entries[index].value + &mut self.map.entries[self.index].value } /// Converts into a mutable reference to the entry's value in the map, /// with a lifetime bound to the map itself. pub fn into_mut(self) -> &'a mut V { - let index = self.index(); - &mut self.entries[index].value - } - - pub(super) fn into_muts(self) -> (&'a mut K, &'a mut V) { - let index = self.index(); - self.entries[index].muts() + &mut self.map.entries[self.index].value } /// Sets the value of the entry to `value`, and returns the entry's old value. @@ -266,9 +274,9 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// **This perturbs the position of what used to be the last element!** /// /// Computes in **O(1)** time (average). - pub fn swap_remove_entry(self) -> (K, V) { - let (index, entry) = self.index.remove(); - RefMut::new(entry.into_table(), self.entries).swap_remove_finish(index) + pub fn swap_remove_entry(mut self) -> (K, V) { + self.remove_index(); + self.map.swap_remove_finish(self.index) } /// Remove and return the key, value pair stored in the map for this entry @@ -278,9 +286,15 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// **This perturbs the index of all of those elements!** /// /// Computes in **O(n)** time (average). - pub fn shift_remove_entry(self) -> (K, V) { - let (index, entry) = self.index.remove(); - RefMut::new(entry.into_table(), self.entries).shift_remove_finish(index) + pub fn shift_remove_entry(mut self) -> (K, V) { + self.remove_index(); + self.map.shift_remove_finish(self.index) + } + + fn remove_index(&mut self) { + let entry = self.map.indices.get_bucket_entry(self.bucket).unwrap(); + debug_assert_eq!(*entry.get(), self.index); + entry.remove(); } /// Moves the position of the entry to a new index @@ -297,8 +311,11 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Computes in **O(n)** time (average). #[track_caller] pub fn move_index(self, to: usize) { - let index = self.index(); - self.into_ref_mut().move_index(index, to); + if self.index != to { + let _ = self.map.entries[to]; // explicit bounds check + self.map.move_index_inner(self.index, to); + self.update_index(to); + } } /// Swaps the position of entry with another. @@ -311,8 +328,21 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Computes in **O(1)** time (average). #[track_caller] pub fn swap_indices(self, other: usize) { - let index = self.index(); - self.into_ref_mut().swap_indices(index, other); + if self.index != other { + // Since we already know where our bucket is, we only need to find the other. + let hash = self.map.entries[other].hash; + let other_mut = self.map.indices.find_mut(hash.get(), move |&i| i == other); + *other_mut.expect("index not found") = self.index; + + self.map.entries.swap(self.index, other); + self.update_index(other); + } + } + + fn update_index(self, to: usize) { + let index = self.map.indices.get_bucket_mut(self.bucket).unwrap(); + debug_assert_eq!(*index, self.index); + *index = to; } } @@ -327,24 +357,20 @@ impl fmt::Debug for OccupiedEntry<'_, K, V> { impl<'a, K, V> From> for OccupiedEntry<'a, K, V> { fn from(other: IndexedEntry<'a, K, V>) -> Self { - let IndexedEntry { - map: RefMut { indices, entries }, - index, - } = other; - let hash = entries[index].hash; - Self { - entries, - index: indices - .find_entry(hash.get(), move |&i| i == index) - .expect("index not found"), - } + let IndexedEntry { map, index } = other; + let hash = map.entries[index].hash; + let bucket = map + .indices + .find_bucket_index(hash.get(), move |&i| i == index) + .expect("index not found"); + Self { map, index, bucket } } } /// A view into a vacant entry in an [`IndexMap`][crate::IndexMap]. /// It is part of the [`Entry`] enum. pub struct VacantEntry<'a, K, V> { - map: RefMut<'a, K, V>, + map: &'a mut IndexMapCore, hash: HashValue, key: K, } @@ -374,7 +400,8 @@ impl<'a, K, V> VacantEntry<'a, K, V> { /// /// Computes in **O(1)** time (amortized average). pub fn insert(self, value: V) -> &'a mut V { - self.insert_entry(value).into_mut() + let Self { map, hash, key } = self; + map.insert_unique(hash, key, value).value_mut() } /// Inserts the entry's key and the given value into the map, and returns an `OccupiedEntry`. @@ -382,7 +409,14 @@ impl<'a, K, V> VacantEntry<'a, K, V> { /// Computes in **O(1)** time (amortized average). pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { let Self { map, hash, key } = self; - map.insert_unique(hash, key, value) + let index = map.indices.len(); + debug_assert_eq!(index, map.entries.len()); + let bucket = map + .indices + .insert_unique(hash.get(), index, get_hash(&map.entries)) + .bucket_index(); + map.push_entry(hash, key, value); + OccupiedEntry { map, index, bucket } } /// Inserts the entry's key and the given value into the map at its ordered @@ -398,7 +432,7 @@ impl<'a, K, V> VacantEntry<'a, K, V> { where K: Ord, { - let slice = crate::map::Slice::from_slice(self.map.entries); + let slice = crate::map::Slice::from_slice(&self.map.entries); let i = slice.binary_search_keys(&self.key).unwrap_err(); (i, self.shift_insert(i, value)) } @@ -416,7 +450,7 @@ impl<'a, K, V> VacantEntry<'a, K, V> { where F: FnMut(&K, &V, &K, &V) -> Ordering, { - let slice = crate::map::Slice::from_slice(self.map.entries); + let slice = crate::map::Slice::from_slice(&self.map.entries); let (Ok(i) | Err(i)) = slice.binary_search_by(|k, v| cmp(k, v, &self.key, &value)); (i, self.shift_insert(i, value)) } @@ -436,7 +470,7 @@ impl<'a, K, V> VacantEntry<'a, K, V> { F: FnMut(&K, &V) -> B, { let search_key = sort_key(&self.key, &value); - let slice = crate::map::Slice::from_slice(self.map.entries); + let slice = crate::map::Slice::from_slice(&self.map.entries); let (Ok(i) | Err(i)) = slice.binary_search_by_key(&search_key, sort_key); (i, self.shift_insert(i, value)) } @@ -448,7 +482,7 @@ impl<'a, K, V> VacantEntry<'a, K, V> { /// /// Computes in **O(n)** time (average). #[track_caller] - pub fn shift_insert(mut self, index: usize, value: V) -> &'a mut V { + pub fn shift_insert(self, index: usize, value: V) -> &'a mut V { self.map .shift_insert_unique(index, self.hash, self.key, value); &mut self.map.entries[index].value @@ -462,7 +496,25 @@ impl<'a, K, V> VacantEntry<'a, K, V> { /// Computes in **O(1)** time (average). #[track_caller] pub fn replace_index(self, index: usize) -> (K, OccupiedEntry<'a, K, V>) { - self.map.replace_index_unique(index, self.hash, self.key) + let Self { map, hash, key } = self; + + // NB: This removal and insertion isn't "no grow" (with unreachable hasher) + // because hashbrown's tombstones might force a resize anyway. + let old_hash = map.entries[index].hash; + map.indices + .find_entry(old_hash.get(), move |&i| i == index) + .expect("index not found") + .remove(); + let bucket = map + .indices + .insert_unique(hash.get(), index, get_hash(&map.entries)) + .bucket_index(); + + let entry = &mut map.entries[index]; + entry.hash = hash; + let old_key = mem::replace(&mut entry.key, key); + + (old_key, OccupiedEntry { map, index, bucket }) } } @@ -476,17 +528,18 @@ impl fmt::Debug for VacantEntry<'_, K, V> { /// /// This `struct` is created from the [`get_index_entry`][crate::IndexMap::get_index_entry] method. pub struct IndexedEntry<'a, K, V> { - map: RefMut<'a, K, V>, + map: &'a mut IndexMapCore, // We have a mutable reference to the map, which keeps the index // valid and pointing to the correct entry. index: usize, } impl<'a, K, V> IndexedEntry<'a, K, V> { - pub(crate) fn new(map: &'a mut IndexMapCore, index: usize) -> Self { - Self { - map: map.borrow_mut(), - index, + pub(crate) fn new(map: &'a mut IndexMapCore, index: usize) -> Option { + if index < map.len() { + Some(Self { map, index }) + } else { + None } } @@ -536,7 +589,7 @@ impl<'a, K, V> IndexedEntry<'a, K, V> { /// **This perturbs the position of what used to be the last element!** /// /// Computes in **O(1)** time (average). - pub fn swap_remove_entry(mut self) -> (K, V) { + pub fn swap_remove_entry(self) -> (K, V) { self.map.swap_remove_index(self.index).unwrap() } @@ -547,7 +600,7 @@ impl<'a, K, V> IndexedEntry<'a, K, V> { /// **This perturbs the index of all of those elements!** /// /// Computes in **O(n)** time (average). - pub fn shift_remove_entry(mut self) -> (K, V) { + pub fn shift_remove_entry(self) -> (K, V) { self.map.shift_remove_index(self.index).unwrap() } @@ -586,7 +639,7 @@ impl<'a, K, V> IndexedEntry<'a, K, V> { /// /// Computes in **O(n)** time (average). #[track_caller] - pub fn move_index(mut self, to: usize) { + pub fn move_index(self, to: usize) { self.map.move_index(self.index, to); } @@ -599,7 +652,7 @@ impl<'a, K, V> IndexedEntry<'a, K, V> { /// /// Computes in **O(1)** time (average). #[track_caller] - pub fn swap_indices(mut self, other: usize) { + pub fn swap_indices(self, other: usize) { self.map.swap_indices(self.index, other); } } @@ -616,9 +669,7 @@ impl fmt::Debug for IndexedEntry<'_, K, V> { impl<'a, K, V> From> for IndexedEntry<'a, K, V> { fn from(other: OccupiedEntry<'a, K, V>) -> Self { - Self { - index: other.index(), - map: other.into_ref_mut(), - } + let OccupiedEntry { map, index, .. } = other; + Self { map, index } } } diff --git a/src/map/core/raw_entry_v1.rs b/src/map/core/raw_entry_v1.rs index 15abd8ad..ed8bf72c 100644 --- a/src/map/core/raw_entry_v1.rs +++ b/src/map/core/raw_entry_v1.rs @@ -9,13 +9,12 @@ //! `hash_raw_entry` feature (or some replacement), matching *inherent* methods will be added to //! `IndexMap` without such an opt-in trait. -use super::{Entries, RefMut}; +use super::{IndexMapCore, OccupiedEntry}; use crate::{Equivalent, HashValue, IndexMap}; use core::fmt; use core::hash::{BuildHasher, Hash}; use core::marker::PhantomData; use core::mem; -use hashbrown::hash_table; /// Opt-in access to the experimental raw entry API. /// @@ -270,20 +269,17 @@ impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> { } /// Access an entry by hash. - pub fn from_hash(self, hash: u64, mut is_match: F) -> RawEntryMut<'a, K, V, S> + pub fn from_hash(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S> where F: FnMut(&K) -> bool, { - let ref_entries = &*self.map.core.entries; - let eq = move |&i: &usize| is_match(&ref_entries[i].key); - match self.map.core.indices.find_entry(hash, eq) { - Ok(index) => RawEntryMut::Occupied(RawOccupiedEntryMut { - entries: &mut self.map.core.entries, - index, + match OccupiedEntry::from_hash(&mut self.map.core, hash, is_match) { + Ok(inner) => RawEntryMut::Occupied(RawOccupiedEntryMut { + inner, hash_builder: PhantomData, }), - Err(absent) => RawEntryMut::Vacant(RawVacantEntryMut { - map: RefMut::new(absent.into_table(), &mut self.map.core.entries), + Err(map) => RawEntryMut::Vacant(RawVacantEntryMut { + map, hash_builder: &self.map.hash_builder, }), } @@ -366,8 +362,7 @@ impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { /// A raw view into an occupied entry in an [`IndexMap`]. /// It is part of the [`RawEntryMut`] enum. pub struct RawOccupiedEntryMut<'a, K, V, S> { - entries: &'a mut Entries, - index: hash_table::OccupiedEntry<'a, usize>, + inner: OccupiedEntry<'a, K, V>, hash_builder: PhantomData<&'a S>, } @@ -384,12 +379,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// Return the index of the key-value pair #[inline] pub fn index(&self) -> usize { - *self.index.get() - } - - #[inline] - fn into_ref_mut(self) -> RefMut<'a, K, V> { - RefMut::new(self.index.into_table(), self.entries) + self.inner.index() } /// Gets a reference to the entry's key in the map. @@ -398,7 +388,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like /// extra fields or the memory address of an allocation. pub fn key(&self) -> &K { - &self.entries[self.index()].key + self.inner.key() } /// Gets a mutable reference to the entry's key in the map. @@ -407,8 +397,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like /// extra fields or the memory address of an allocation. pub fn key_mut(&mut self) -> &mut K { - let index = self.index(); - &mut self.entries[index].key + &mut self.inner.get_bucket_mut().key } /// Converts into a mutable reference to the entry's key in the map, @@ -418,13 +407,12 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like /// extra fields or the memory address of an allocation. pub fn into_key(self) -> &'a mut K { - let index = self.index(); - &mut self.entries[index].key + &mut self.inner.into_bucket().key } /// Gets a reference to the entry's value in the map. pub fn get(&self) -> &V { - &self.entries[self.index()].value + self.inner.get() } /// Gets a mutable reference to the entry's value in the map. @@ -432,38 +420,34 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// If you need a reference which may outlive the destruction of the /// [`RawEntryMut`] value, see [`into_mut`][Self::into_mut]. pub fn get_mut(&mut self) -> &mut V { - let index = self.index(); - &mut self.entries[index].value + self.inner.get_mut() } /// Converts into a mutable reference to the entry's value in the map, /// with a lifetime bound to the map itself. pub fn into_mut(self) -> &'a mut V { - let index = self.index(); - &mut self.entries[index].value + self.inner.into_mut() } /// Gets a reference to the entry's key and value in the map. pub fn get_key_value(&self) -> (&K, &V) { - self.entries[self.index()].refs() + self.inner.get_bucket().refs() } /// Gets a reference to the entry's key and value in the map. pub fn get_key_value_mut(&mut self) -> (&mut K, &mut V) { - let index = self.index(); - self.entries[index].muts() + self.inner.get_bucket_mut().muts() } /// Converts into a mutable reference to the entry's key and value in the map, /// with a lifetime bound to the map itself. pub fn into_key_value_mut(self) -> (&'a mut K, &'a mut V) { - let index = self.index(); - self.entries[index].muts() + self.inner.into_bucket().muts() } /// Sets the value of the entry, and returns the entry's old value. pub fn insert(&mut self, value: V) -> V { - mem::replace(self.get_mut(), value) + self.inner.insert(value) } /// Sets the key of the entry, and returns the entry's old key. @@ -491,7 +475,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// /// Computes in **O(1)** time (average). pub fn swap_remove(self) -> V { - self.swap_remove_entry().1 + self.inner.swap_remove() } /// Remove the key, value pair stored in the map for this entry, and return the value. @@ -502,7 +486,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// /// Computes in **O(n)** time (average). pub fn shift_remove(self) -> V { - self.shift_remove_entry().1 + self.inner.shift_remove() } /// Remove and return the key, value pair stored in the map for this entry @@ -525,8 +509,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// /// Computes in **O(1)** time (average). pub fn swap_remove_entry(self) -> (K, V) { - let (index, entry) = self.index.remove(); - RefMut::new(entry.into_table(), self.entries).swap_remove_finish(index) + self.inner.swap_remove_entry() } /// Remove and return the key, value pair stored in the map for this entry @@ -537,8 +520,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// /// Computes in **O(n)** time (average). pub fn shift_remove_entry(self) -> (K, V) { - let (index, entry) = self.index.remove(); - RefMut::new(entry.into_table(), self.entries).shift_remove_finish(index) + self.inner.shift_remove_entry() } /// Moves the position of the entry to a new index @@ -555,8 +537,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// Computes in **O(n)** time (average). #[track_caller] pub fn move_index(self, to: usize) { - let index = self.index(); - self.into_ref_mut().move_index(index, to); + self.inner.move_index(to); } /// Swaps the position of entry with another. @@ -569,15 +550,14 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// Computes in **O(1)** time (average). #[track_caller] pub fn swap_indices(self, other: usize) { - let index = self.index(); - self.into_ref_mut().swap_indices(index, other); + self.inner.swap_indices(other); } } /// A view into a vacant raw entry in an [`IndexMap`]. /// It is part of the [`RawEntryMut`] enum. pub struct RawVacantEntryMut<'a, K, V, S> { - map: RefMut<'a, K, V>, + map: &'a mut IndexMapCore, hash_builder: &'a S, } @@ -590,7 +570,7 @@ impl fmt::Debug for RawVacantEntryMut<'_, K, V, S> { impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { /// Return the index where a key-value pair may be inserted. pub fn index(&self) -> usize { - self.map.indices.len() + self.map.len() } /// Inserts the given key and value into the map, @@ -608,7 +588,7 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { /// and returns mutable references to them. pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) { let hash = HashValue(hash as usize); - self.map.insert_unique(hash, key, value).into_muts() + self.map.insert_unique(hash, key, value).muts() } /// Inserts the given key and value into the map at the given index, @@ -635,7 +615,7 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { /// Computes in **O(n)** time (average). #[track_caller] pub fn shift_insert_hashed_nocheck( - mut self, + self, index: usize, hash: u64, key: K, diff --git a/src/map/mutable.rs b/src/map/mutable.rs index 3977bbea..b0ecf344 100644 --- a/src/map/mutable.rs +++ b/src/map/mutable.rs @@ -132,7 +132,7 @@ impl MutableEntryKey for Entry<'_, K, V> { impl MutableEntryKey for OccupiedEntry<'_, K, V> { type Key = K; fn key_mut(&mut self) -> &mut Self::Key { - self.key_mut() + &mut self.get_bucket_mut().key } }