diff --git a/Cargo.toml b/Cargo.toml index 6aec45c..b6b2325 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ringmap" edition = "2021" -version = "0.2.0" +version = "0.2.1" documentation = "https://docs.rs/ringmap/" repository = "https://github.com/indexmap-rs/ringmap" license = "Apache-2.0 OR MIT" @@ -15,6 +15,7 @@ bench = false [dependencies] equivalent = { version = "1.0", 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 } @@ -23,10 +24,6 @@ borsh = { version = "1.2", optional = true, default-features = false } rayon = { version = "1.9", optional = true } sval = { version = "2", optional = true, default-features = false } -[dependencies.hashbrown] -version = "0.16.0" -default-features = false - # serde v1.0.220 is the first version that released with `serde_core`. # This is required to avoid conflict with other `serde` users which may require an older version. [target.'cfg(any())'.dependencies] diff --git a/RELEASES.md b/RELEASES.md index 0474d43..fd61086 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,9 @@ # Releases +## 0.2.1 (2025-11-20) + +- Simplified a lot of internals using `hashbrown`'s new bucket API. + ## 0.2.0 (2025-10-18) - **MSRV**: Rust 1.82.0 or later is now required. diff --git a/src/map.rs b/src/map.rs index 16a3953..8d7b4bc 100644 --- a/src/map.rs +++ b/src/map.rs @@ -760,7 +760,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 @@ -1564,10 +1564,7 @@ impl RingMap { /// /// 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 a33c10c..9d4d833 100644 --- a/src/map/core.rs +++ b/src/map/core.rs @@ -58,18 +58,6 @@ pub(crate) struct RingMapCore { offset: usize, } -/// Mutable references to the parts of an `RingMapCore`. -/// -/// 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 RingMapCore`. So this type -/// is used to implement methods on the split references, and `RingMapCore` can also call those to -/// avoid duplication. -struct RefMut<'a, K, V> { - indices: &'a mut Indices, - entries: &'a mut Entries, - offset: &'a mut usize, -} - #[inline(always)] fn get_hash( entries: &Entries, @@ -177,7 +165,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); self.offset = other.offset; @@ -197,11 +185,6 @@ impl RingMapCore { } } - #[inline] - fn borrow_mut(&mut self) -> RefMut<'_, K, V> { - RefMut::new(&mut self.indices, &mut self.entries, &mut self.offset) - } - #[inline] pub(crate) fn with_capacity(n: usize) -> Self { RingMapCore { @@ -341,7 +324,7 @@ impl RingMapCore { .reserve(additional, get_hash(&self.entries, self.offset)); // 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); } } @@ -443,7 +426,7 @@ impl RingMapCore { let i = self.entries.len(); let oi = OffsetIndex::new(i, self.offset); entry.insert(oi); - self.borrow_mut().push_back_entry(hash, key, value); + self.push_back_entry(hash, key, value); debug_assert_eq!(self.indices.len(), self.entries.len()); (i, None) } @@ -464,7 +447,7 @@ impl RingMapCore { hash_table::Entry::Vacant(entry) => { let oi = OffsetIndex::new(usize::MAX, self.offset); entry.insert(oi); - self.borrow_mut().push_front_entry(hash, key, value); + self.push_front_entry(hash, key, value); debug_assert_eq!(self.indices.len(), self.entries.len()); self.offset = self.offset.wrapping_sub(1); // now MAX is 0 (0, None) @@ -498,20 +481,13 @@ impl RingMapCore { let i = self.entries.len(); let oi = OffsetIndex::new(i, self.offset); entry.insert(oi); - self.borrow_mut().push_back_entry(hash, key, value); + self.push_back_entry(hash, key, value); debug_assert_eq!(self.indices.len(), self.entries.len()); (i, None) } } } - /// 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 @@ -522,31 +498,13 @@ impl RingMapCore { Ok(entry) => { let (oi, _) = entry.remove(); let index = oi.get(self.offset); - let (key, value) = self.borrow_mut().shift_remove_finish(index); + let (key, value) = self.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); - } - /// Remove an entry by swapping it with the last pub(crate) fn swap_remove_back_full( &mut self, @@ -561,19 +519,13 @@ impl RingMapCore { Ok(entry) => { let (oi, _) = entry.remove(); let index = oi.get(self.offset); - let (key, value) = self.borrow_mut().swap_remove_back_finish(index); + let (key, value) = self.swap_remove_back_finish(index); Some((index, key, value)) } Err(_) => None, } } - /// Remove an entry by swapping it with the last - #[inline] - pub(crate) fn swap_remove_back_index(&mut self, index: usize) -> Option<(K, V)> { - self.borrow_mut().swap_remove_back_index(index) - } - /// Remove an entry by swapping it with the first pub(crate) fn swap_remove_front_full( &mut self, @@ -588,19 +540,13 @@ impl RingMapCore { Ok(entry) => { let (oi, _) = entry.remove(); let index = oi.get(self.offset); - let (key, value) = self.borrow_mut().swap_remove_front_finish(index); + let (key, value) = self.swap_remove_front_finish(index); Some((index, key, value)) } Err(_) => None, } } - /// Remove an entry by swapping it with the first - #[inline] - pub(crate) fn swap_remove_front_index(&mut self, index: usize) -> Option<(K, V)> { - self.borrow_mut().swap_remove_front_index(index) - } - /// Erase `start..end` from `indices`, and shift `end..` indices down to `start..` /// /// All of these items should still be at their original location in `entries`. @@ -724,38 +670,18 @@ impl RingMapCore { self.entries .partition_point(move |a| pred(&a.key, &a.value)) } -} - -/// 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(RingMapCore::::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, - offset: &'a mut usize, - ) -> Self { - Self { - indices, - entries, - offset, - } - } /// 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); } /// Append a key-value pair to `entries`, @@ -780,62 +706,40 @@ impl<'a, K, V> RefMut<'a, K, V> { self.entries.push_back(Bucket { hash, key, value }); } - fn push_front_unique(self, hash: HashValue, key: K, value: V) -> OccupiedEntry<'a, K, V> { - let oi = OffsetIndex::new(usize::MAX, *self.offset); - let entry = - self.indices - .insert_unique(hash.get(), oi, get_hash(self.entries, *self.offset)); - 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_front(Bucket { hash, key, value }); - *self.offset = self.offset.wrapping_sub(1); // now MAX is 0 - OccupiedEntry::new(self.entries, self.offset, entry) + fn push_front_unique(&mut self, hash: HashValue, key: K, value: V) -> &mut Bucket { + let oi = OffsetIndex::new(usize::MAX, self.offset); + self.indices + .insert_unique(hash.get(), oi, get_hash(&self.entries, self.offset)); + self.push_front_entry(hash, key, value); + self.offset = self.offset.wrapping_sub(1); // now MAX is 0 + &mut self.entries[0] } - fn push_back_unique(self, hash: HashValue, key: K, value: V) -> OccupiedEntry<'a, K, V> { + fn push_back_unique(&mut self, hash: HashValue, key: K, value: V) -> &mut Bucket { let i = self.indices.len(); debug_assert_eq!(i, self.entries.len()); - let oi = OffsetIndex::new(i, *self.offset); - let entry = - self.indices - .insert_unique(hash.get(), oi, get_hash(self.entries, *self.offset)); - 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_back(Bucket { hash, key, value }); - OccupiedEntry::new(self.entries, self.offset, entry) + let oi = OffsetIndex::new(i, self.offset); + self.indices + .insert_unique(hash.get(), oi, get_hash(&self.entries, self.offset)); + self.push_back_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. - let offset = *self.offset; + let offset = self.offset; let oi = OffsetIndex::new(index, offset); - erase_index(self.indices, offset, self.entries[index].hash, index); - let table_entry = - self.indices - .insert_unique(hash.get(), oi, get_hash(&self.entries, offset)); + erase_index(&mut self.indices, offset, self.entries[index].hash, index); + self.indices + .insert_unique(hash.get(), oi, get_hash(&self.entries, offset)); let entry = &mut self.entries[index]; entry.hash = hash; - let old_key = mem::replace(&mut entry.key, key); - let occupied = OccupiedEntry::new(self.entries, self.offset, table_entry); - (old_key, occupied) + mem::replace(&mut entry.key, key) } /// Insert a key-value pair in `entries` at a particular index, @@ -845,8 +749,8 @@ impl<'a, K, V> RefMut<'a, K, V> { assert!(index <= end); // Increment others first so we don't have duplicate indices. self.increment_indices(index, end); - let entries = &*self.entries; - let offset = *self.offset; + let entries = &self.entries; + let offset = self.offset; let oi = OffsetIndex::new(index, offset); self.indices.insert_unique(hash.get(), oi, move |&i| { // Adjust for the incremented indices to find hashes. @@ -864,10 +768,11 @@ 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)> { + #[inline] + pub(crate) fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> { match self.entries.get(index) { Some(entry) => { - erase_index(self.indices, *self.offset, entry.hash, index); + erase_index(&mut self.indices, self.offset, entry.hash, index); Some(self.shift_remove_finish(index)) } None => None, @@ -887,10 +792,11 @@ impl<'a, K, V> RefMut<'a, K, V> { } /// Remove an entry by swapping it with the last - fn swap_remove_back_index(&mut self, index: usize) -> Option<(K, V)> { + #[inline] + pub(crate) fn swap_remove_back_index(&mut self, index: usize) -> Option<(K, V)> { match self.entries.get(index) { Some(entry) => { - erase_index(self.indices, *self.offset, entry.hash, index); + erase_index(&mut self.indices, self.offset, entry.hash, index); Some(self.swap_remove_back_finish(index)) } None => None, @@ -910,17 +816,18 @@ 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, *self.offset, entry.hash, last, index); + update_index(&mut self.indices, self.offset, entry.hash, last, index); } (entry.key, entry.value) } /// Remove an entry by swapping it with the first - fn swap_remove_front_index(&mut self, index: usize) -> Option<(K, V)> { + #[inline] + pub(crate) fn swap_remove_front_index(&mut self, index: usize) -> Option<(K, V)> { match self.entries.get(index) { Some(entry) => { - erase_index(self.indices, *self.offset, entry.hash, index); + erase_index(&mut self.indices, self.offset, entry.hash, index); Some(self.swap_remove_front_finish(index)) } None => None, @@ -940,10 +847,10 @@ impl<'a, K, V> RefMut<'a, K, V> { // was not first element if let Some(entry) = self.entries.get(index - 1) { // examine new element in `index` and find it in indices - update_index(self.indices, *self.offset, entry.hash, 0, index); + update_index(&mut self.indices, self.offset, entry.hash, 0, index); } } - *self.offset = self.offset.wrapping_add(1); + self.offset = self.offset.wrapping_add(1); (entry.key, entry.value) } @@ -966,7 +873,7 @@ impl<'a, K, V> RefMut<'a, K, V> { if target_len <= start_len + end_len { // Find each entry in range to decrement its index. for (i, entry) in (start..end).zip(iter_slices(target_entries)) { - update_index(self.indices, *self.offset, entry.hash, i, i - 1); + update_index(&mut self.indices, self.offset, entry.hash, i, i - 1); } } else if start_len + end_len < half_capacity { // Find each entry outside the range and increment them instead. @@ -975,18 +882,18 @@ impl<'a, K, V> RefMut<'a, K, V> { .rev() .zip(iter_slices(end_entries).rev()) { - update_index(self.indices, *self.offset, entry.hash, i, i + 1); + update_index(&mut self.indices, self.offset, entry.hash, i, i + 1); } for (i, entry) in (0..start_len).rev().zip(iter_slices(start_entries).rev()) { - update_index(self.indices, *self.offset, entry.hash, i, i + 1); + update_index(&mut self.indices, self.offset, entry.hash, i, i + 1); } - *self.offset = self.offset.wrapping_add(1); + self.offset = self.offset.wrapping_add(1); } else { // Shift all indices in range. - for i in &mut *self.indices { - let index = i.get(*self.offset); + for i in &mut self.indices { + let index = i.get(self.offset); if start <= index && index < end { - *i = OffsetIndex::new(index - 1, *self.offset); + *i = OffsetIndex::new(index - 1, self.offset); } } } @@ -1013,90 +920,97 @@ impl<'a, K, V> RefMut<'a, K, V> { // Find each entry in range to increment its index, updated in reverse so // we never have duplicated indices that might have a hash collision. for (i, entry) in (start..end).rev().zip(iter_slices(target_entries).rev()) { - update_index(self.indices, *self.offset, entry.hash, i, i + 1); + update_index(&mut self.indices, self.offset, entry.hash, i, i + 1); } } else if start_len + end_len < half_capacity { // Find each entry outside the range and decrement them instead. - *self.offset = self.offset.wrapping_sub(1); + self.offset = self.offset.wrapping_sub(1); for (i, entry) in (0..).zip(iter_slices(start_entries)) { - update_index(self.indices, *self.offset, entry.hash, i + 1, i); + update_index(&mut self.indices, self.offset, entry.hash, i + 1, i); } for (i, entry) in (end + 1..).zip(iter_slices(end_entries)) { - update_index(self.indices, *self.offset, entry.hash, i + 1, i); + update_index(&mut self.indices, self.offset, entry.hash, i + 1, i); } } else { // Shift all indices in range. - for i in &mut *self.indices { - let index = i.get(*self.offset); + for i in &mut self.indices { + let index = i.get(self.offset); if start <= index && index < end { - *i = OffsetIndex::new(index + 1, *self.offset); + *i = OffsetIndex::new(index + 1, self.offset); } } } } + #[inline] #[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. - let orig_offset = *self.offset; - let sentinel = isize::MIN as usize; - update_index(self.indices, orig_offset, from_hash, from, sentinel); - - // 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); - if from == 0 { - let entry = self.entries.pop_front().unwrap(); - self.entries.insert(to, entry); - } else if to + 1 == self.entries.len() { - let entry = self.entries.remove(from).unwrap(); - self.entries.push_back(entry); - } else { - match sub_slices_mut(self.entries.as_mut_slices(), from, to + 1) { - (xs, []) | ([], xs) => xs.rotate_left(1), - (xs, ys) => { - mem::swap(&mut xs[0], &mut ys[0]); - xs.rotate_left(1); - ys.rotate_left(1); - } + let _ = self.entries[to]; // explicit bounds check + + // Find the bucket index first so we won't lose it among other updated indices. + let from_index = OffsetIndex::new(from, self.offset); + let bucket = self + .indices + .find_bucket_index(from_hash.get(), move |&i| i == from_index) + .expect("index not found"); + + self.move_index_inner(from, to); + + // Change the bucket index to its final position. + // (taking care if `decrement`/`increment_indices` changed the offset) + let to_index = OffsetIndex::new(to, self.offset); + *self.indices.get_bucket_mut(bucket).unwrap() = to_index; + } + } + + 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); + if from == 0 { + let entry = self.entries.pop_front().unwrap(); + self.entries.insert(to, entry); + } else if to + 1 == self.entries.len() { + let entry = self.entries.remove(from).unwrap(); + self.entries.push_back(entry); + } else { + match sub_slices_mut(self.entries.as_mut_slices(), from, to + 1) { + (xs, []) | ([], xs) => xs.rotate_left(1), + (xs, ys) => { + mem::swap(&mut xs[0], &mut ys[0]); + xs.rotate_left(1); + ys.rotate_left(1); } } - } else if to < from { - self.increment_indices(to, from); - // self.entries[to..=from].rotate_right(1); - if to == 0 { - let entry = self.entries.remove(from).unwrap(); - self.entries.push_front(entry); - } else if from + 1 == self.entries.len() { - let entry = self.entries.pop_back().unwrap(); - self.entries.insert(to, entry); - } else { - match sub_slices_mut(self.entries.as_mut_slices(), to, from + 1) { - (xs, []) | ([], xs) => xs.rotate_right(1), - (xs, ys) => { - mem::swap(&mut xs[xs.len() - 1], &mut ys[ys.len() - 1]); - xs.rotate_right(1); - ys.rotate_right(1); - } + } + } else if to < from { + self.increment_indices(to, from); + // self.entries[to..=from].rotate_right(1); + if to == 0 { + let entry = self.entries.remove(from).unwrap(); + self.entries.push_front(entry); + } else if from + 1 == self.entries.len() { + let entry = self.entries.pop_back().unwrap(); + self.entries.insert(to, entry); + } else { + match sub_slices_mut(self.entries.as_mut_slices(), to, from + 1) { + (xs, []) | ([], xs) => xs.rotate_right(1), + (xs, ys) => { + mem::swap(&mut xs[xs.len() - 1], &mut ys[ys.len() - 1]); + xs.rotate_right(1); + ys.rotate_right(1); } } } - - // Change the sentinel index to its final position. - // (taking care if `decrement`/`increment_indices` changed the offset) - let sentinel = sentinel - .wrapping_add(orig_offset) - .wrapping_sub(*self.offset); - update_index(self.indices, *self.offset, from_hash, sentinel, to); } } + #[inline] #[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; @@ -1104,9 +1018,9 @@ 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. - let oa = OffsetIndex::new(a, *self.offset); - let ob = OffsetIndex::new(b, *self.offset); - match self.indices.get_many_mut( + let oa = OffsetIndex::new(a, self.offset); + let ob = OffsetIndex::new(b, self.offset); + match self.indices.get_disjoint_mut( [self.entries[a].hash.get(), self.entries[b].hash.get()], move |i, &x| if i == 0 { x == oa } else { x == ob }, ) { @@ -1117,28 +1031,6 @@ impl<'a, K, V> RefMut<'a, K, V> { _ => panic!("indices not found"), } } - - fn binary_search_keys(&self, x: &K) -> Result - where - K: Ord, - { - self.binary_search_by(|p, _| p.cmp(x)) - } - - fn binary_search_by<'b, F>(&'b self, mut f: F) -> Result - where - F: FnMut(&'b K, &'b V) -> Ordering, - { - self.entries.binary_search_by(move |a| f(&a.key, &a.value)) - } - - fn binary_search_by_key<'b, B, F>(&'b self, b: &B, mut f: F) -> Result - where - F: FnMut(&'b K, &'b V) -> B, - B: Ord, - { - self.binary_search_by(|k, v| f(k, v).cmp(b)) - } } #[test] diff --git a/src/map/core/entry.rs b/src/map/core/entry.rs index 5e78ad7..a8a0f83 100644 --- a/src/map/core/entry.rs +++ b/src/map/core/entry.rs @@ -1,31 +1,7 @@ -use super::{equivalent, Entries, OffsetIndex, RefMut, RingMapCore}; +use super::{equivalent, get_hash, Bucket, OffsetIndex, RingMapCore}; use crate::HashValue; use core::cmp::Ordering; use core::{fmt, mem}; -use hashbrown::hash_table; - -impl RingMapCore { - pub(crate) fn entry(&mut self, hash: HashValue, key: K) -> Entry<'_, K, V> - where - K: Eq, - { - let entries = &mut self.entries; - let offset = &mut self.offset; - let eq = equivalent(&key, entries, *offset); - match self.indices.find_entry(hash.get(), eq) { - Ok(index) => Entry::Occupied(OccupiedEntry { - entries, - index, - offset, - }), - Err(absent) => Entry::Vacant(VacantEntry { - map: RefMut::new(absent.into_table(), entries, offset), - hash, - key, - }), - } - } -} /// Entry for an existing key-value pair in an [`RingMap`][crate::RingMap] /// or a vacant location to insert one. @@ -37,13 +13,30 @@ pub enum Entry<'a, K, V> { } impl<'a, K, V> Entry<'a, K, V> { + pub(crate) fn new(map: &'a mut RingMapCore, hash: HashValue, key: K) -> Self + where + K: Eq, + { + let entries = &map.entries; + let offset = map.offset; + let eq = equivalent(&key, entries, offset); + match map.indices.find_entry(hash.get(), eq) { + Ok(entry) => Entry::Occupied(OccupiedEntry { + bucket: entry.bucket_index(), + index: entry.get().get(offset), + map, + }), + Err(_) => Entry::Vacant(VacantEntry { map, hash, key }), + } + } + /// Return the index where the key-value pair exists or may be appended. /// /// Note that some methods may instead prepend new items at index 0. 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(), } } @@ -250,33 +243,52 @@ impl fmt::Debug for Entry<'_, K, V> { /// A view into an occupied entry in an [`RingMap`][crate::RingMap]. /// It is part of the [`Entry`] enum. pub struct OccupiedEntry<'a, K, V> { - entries: &'a mut Entries, - offset: &'a mut usize, - index: hash_table::OccupiedEntry<'a, OffsetIndex>, + map: &'a mut RingMapCore, + // 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(super) fn new( - entries: &'a mut Entries, - offset: &'a mut usize, - index: hash_table::OccupiedEntry<'a, OffsetIndex>, - ) -> Self { - Self { - entries, - offset, - index, + /// Constructor for `RawEntryMut::from_hash` + pub(super) fn from_hash( + map: &'a mut RingMapCore, + hash: u64, + mut is_match: F, + ) -> Result> + where + F: FnMut(&K) -> bool, + { + let entries = &map.entries; + let offset = map.offset; + let eq = move |&i: &OffsetIndex| is_match(&entries[i.get(offset)].key); + match map.indices.find_entry(hash, eq) { + Ok(entry) => Ok(OccupiedEntry { + bucket: entry.bucket_index(), + index: entry.get().get(offset), + map, + }), + Err(_) => Err(map), } } - /// Return the index of the key-value pair - #[inline] - pub fn index(&self) -> usize { - self.index.get().get(*self.offset) + 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, self.offset) + pub fn index(&self) -> usize { + self.index } /// Gets a reference to the entry's key in the map. @@ -285,17 +297,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. @@ -303,20 +310,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. @@ -342,10 +342,9 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// **This perturbs the index of all of the following elements!** /// /// Computes in **O(n)** time (average). - pub fn remove_entry(self) -> (K, V) { - let (index, entry) = self.index.remove(); - let index = index.get(*self.offset); - RefMut::new(entry.into_table(), self.entries, self.offset).shift_remove_finish(index) + pub fn remove_entry(mut self) -> (K, V) { + self.remove_index(); + self.map.shift_remove_finish(self.index) } /// Remove the key, value pair stored in the map for this entry, and return the value. @@ -366,10 +365,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_back_entry(self) -> (K, V) { - let (index, entry) = self.index.remove(); - let index = index.get(*self.offset); - RefMut::new(entry.into_table(), self.entries, self.offset).swap_remove_back_finish(index) + pub fn swap_remove_back_entry(mut self) -> (K, V) { + self.remove_index(); + self.map.swap_remove_back_finish(self.index) } /// Remove the key, value pair stored in the map for this entry, and return the value. @@ -390,10 +388,15 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// **This perturbs the position of what used to be the front element!** /// /// Computes in **O(1)** time (average). - pub fn swap_remove_front_entry(self) -> (K, V) { - let (index, entry) = self.index.remove(); - let index = index.get(*self.offset); - RefMut::new(entry.into_table(), self.entries, self.offset).swap_remove_front_finish(index) + pub fn swap_remove_front_entry(mut self) -> (K, V) { + self.remove_index(); + self.map.swap_remove_front_finish(self.index) + } + + fn remove_index(&mut self) { + let entry = self.map.indices.get_bucket_entry(self.bucket).unwrap(); + debug_assert_eq!(entry.get().get(self.map.offset), self.index); + entry.remove(); } /// Moves the position of the entry to a new index @@ -410,8 +413,16 @@ 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 + + let orig_offset = self.map.offset; + self.map.move_index_inner(self.index, to); + + let index = self.map.indices.get_bucket_mut(self.bucket).unwrap(); + debug_assert_eq!(index.get(orig_offset), self.index); + *index = OffsetIndex::new(to, self.map.offset); + } } /// Swaps the position of entry with another. @@ -424,8 +435,19 @@ 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 oi = OffsetIndex::new(other, self.map.offset); + let other_mut = self.map.indices.find_mut(hash.get(), move |&i| i == oi); + *other_mut.expect("index not found") = OffsetIndex::new(self.index, self.map.offset); + + let index = self.map.indices.get_bucket_mut(self.bucket).unwrap(); + debug_assert_eq!(index.get(self.map.offset), self.index); + *index = oi; + + self.map.entries.swap(self.index, other); + } } } @@ -440,31 +462,21 @@ 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, - offset, - }, - index, - } = other; - let hash = entries[index].hash; - let needle = OffsetIndex::new(index, *offset); - Self { - entries, - offset, - index: indices - .find_entry(hash.get(), move |&i| i == needle) - .expect("index not found"), - } + let IndexedEntry { map, index } = other; + let hash = map.entries[index].hash; + let needle = OffsetIndex::new(index, map.offset); + let bucket = map + .indices + .find_bucket_index(hash.get(), move |&i| i == needle) + .expect("index not found"); + Self { map, index, bucket } } } /// A view into a vacant entry in an [`RingMap`][crate::RingMap]. /// It is part of the [`Entry`] enum. pub struct VacantEntry<'a, K, V> { - map: RefMut<'a, K, V>, + map: &'a mut RingMapCore, hash: HashValue, key: K, } @@ -500,17 +512,15 @@ impl<'a, K, V> VacantEntry<'a, K, V> { /// Appends the entry's key and the given value onto the map, /// and returns a mutable reference to the value. pub fn push_back(self, value: V) -> &'a mut V { - self.map - .push_back_unique(self.hash, self.key, value) - .into_mut() + let Self { map, hash, key } = self; + map.push_back_unique(hash, key, value).value_mut() } /// Prepends the entry's key and the given value onto the map, /// and returns a mutable reference to the value. pub fn push_front(self, value: V) -> &'a mut V { - self.map - .push_front_unique(self.hash, self.key, value) - .into_mut() + let Self { map, hash, key } = self; + map.push_front_unique(hash, key, value).value_mut() } #[deprecated = "use `push_back_entry` or `push_front_entry` instead"] @@ -522,14 +532,32 @@ impl<'a, K, V> VacantEntry<'a, K, V> { /// /// Computes in **O(1)** time (amortized average). pub fn push_back_entry(self, value: V) -> OccupiedEntry<'a, K, V> { - self.map.push_back_unique(self.hash, self.key, value) + let Self { map, hash, key } = self; + let index = map.indices.len(); + debug_assert_eq!(index, map.entries.len()); + let oi = OffsetIndex::new(index, map.offset); + let bucket = map + .indices + .insert_unique(hash.get(), oi, get_hash(&map.entries, map.offset)) + .bucket_index(); + map.push_back_entry(hash, key, value); + OccupiedEntry { map, index, bucket } } /// Prepends the entry's key and the given value into the map, and returns an `OccupiedEntry`. /// /// Computes in **O(1)** time (amortized average). pub fn push_front_entry(self, value: V) -> OccupiedEntry<'a, K, V> { - self.map.push_front_unique(self.hash, self.key, value) + let Self { map, hash, key } = self; + let index = 0; + let oi = OffsetIndex::new(usize::MAX, map.offset); + let bucket = map + .indices + .insert_unique(hash.get(), oi, get_hash(&map.entries, map.offset)) + .bucket_index(); + map.push_front_entry(hash, key, value); + map.offset = map.offset.wrapping_sub(1); // now MAX is 0 + OccupiedEntry { map, index, bucket } } /// Inserts the entry's key and the given value into the map at its ordered @@ -594,7 +622,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 @@ -608,7 +636,27 @@ 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) + // 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; + let oi = OffsetIndex::new(index, map.offset); + map.indices + .find_entry(old_hash.get(), move |&i| i == oi) + .expect("index not found") + .remove(); + let bucket = map + .indices + .insert_unique(hash.get(), oi, get_hash(&map.entries, map.offset)) + .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 }) } } @@ -622,17 +670,18 @@ impl fmt::Debug for VacantEntry<'_, K, V> { /// /// This `struct` is created from the [`get_index_entry`][crate::RingMap::get_index_entry] method. pub struct IndexedEntry<'a, K, V> { - map: RefMut<'a, K, V>, + map: &'a mut RingMapCore, // 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 RingMapCore, index: usize) -> Self { - Self { - map: map.borrow_mut(), - index, + pub(crate) fn new(map: &'a mut RingMapCore, index: usize) -> Option { + if index < map.len() { + Some(Self { map, index }) + } else { + None } } @@ -682,7 +731,7 @@ impl<'a, K, V> IndexedEntry<'a, K, V> { /// **This perturbs the index of all of the following elements!** /// /// Computes in **O(n)** time (average). - pub fn remove_entry(mut self) -> (K, V) { + pub fn remove_entry(self) -> (K, V) { self.map.shift_remove_index(self.index).unwrap() } @@ -704,7 +753,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_back_entry(mut self) -> (K, V) { + pub fn swap_remove_back_entry(self) -> (K, V) { self.map.swap_remove_back_index(self.index).unwrap() } @@ -726,7 +775,7 @@ impl<'a, K, V> IndexedEntry<'a, K, V> { /// **This perturbs the position of what used to be the front element!** /// /// Computes in **O(1)** time (average). - pub fn swap_remove_front_entry(mut self) -> (K, V) { + pub fn swap_remove_front_entry(self) -> (K, V) { self.map.swap_remove_front_index(self.index).unwrap() } @@ -754,7 +803,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); } @@ -767,7 +816,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); } } @@ -785,8 +834,8 @@ 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(), + map: other.map, + index: other.index, } } } diff --git a/src/map/core/raw_entry_v1.rs b/src/map/core/raw_entry_v1.rs index b23d28f..a4cfcce 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 //! `RingMap` without such an opt-in trait. -use super::{Entries, OffsetIndex, RefMut}; +use super::{OccupiedEntry, OffsetIndex, RingMapCore}; use crate::{Equivalent, HashValue, RingMap}; 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. /// @@ -272,26 +271,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 offset = self.map.core.offset; - let eq = move |&i: &OffsetIndex| is_match(&ref_entries[i.get(offset)].key); - match self.map.core.indices.find_entry(hash, eq) { - Ok(index) => RawEntryMut::Occupied(RawOccupiedEntryMut { - entries: &mut self.map.core.entries, - offset: &mut self.map.core.offset, - 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, - &mut self.map.core.offset, - ), + Err(map) => RawEntryMut::Vacant(RawVacantEntryMut { + map, hash_builder: &self.map.hash_builder, }), } @@ -374,9 +364,7 @@ impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { /// A raw view into an occupied entry in an [`RingMap`]. /// It is part of the [`RawEntryMut`] enum. pub struct RawOccupiedEntryMut<'a, K, V, S> { - entries: &'a mut Entries, - offset: &'a mut usize, - index: hash_table::OccupiedEntry<'a, OffsetIndex>, + inner: OccupiedEntry<'a, K, V>, hash_builder: PhantomData<&'a S>, } @@ -393,12 +381,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().get(*self.offset) - } - - #[inline] - fn into_ref_mut(self) -> RefMut<'a, K, V> { - RefMut::new(self.index.into_table(), self.entries, self.offset) + self.inner.index() } /// Gets a reference to the entry's key in the map. @@ -407,7 +390,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. @@ -416,8 +399,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, @@ -427,13 +409,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. @@ -441,38 +422,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. @@ -488,7 +465,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// /// Computes in **O(n)** time (average). pub fn remove(self) -> V { - self.remove_entry().1 + self.inner.remove() } /// Remove and return the key, value pair stored in the map for this entry @@ -499,9 +476,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// /// Computes in **O(n)** time (average). pub fn remove_entry(self) -> (K, V) { - let (index, entry) = self.index.remove(); - let index = index.get(*self.offset); - RefMut::new(entry.into_table(), self.entries, self.offset).shift_remove_finish(index) + self.inner.remove_entry() } /// Remove the key, value pair stored in the map for this entry, and return the value. @@ -512,7 +487,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// /// Computes in **O(1)** time (average). pub fn swap_remove_back(self) -> V { - self.swap_remove_back_entry().1 + self.inner.swap_remove_back() } /// Remove and return the key, value pair stored in the map for this entry @@ -523,9 +498,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// /// Computes in **O(1)** time (average). pub fn swap_remove_back_entry(self) -> (K, V) { - let (index, entry) = self.index.remove(); - let index = index.get(*self.offset); - RefMut::new(entry.into_table(), self.entries, self.offset).swap_remove_back_finish(index) + self.inner.swap_remove_back_entry() } /// Remove the key, value pair stored in the map for this entry, and return the value. @@ -536,7 +509,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// /// Computes in **O(1)** time (average). pub fn swap_remove_front(self) -> V { - self.swap_remove_front_entry().1 + self.inner.swap_remove_front() } /// Remove and return the key, value pair stored in the map for this entry @@ -547,9 +520,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// /// Computes in **O(1)** time (average). pub fn swap_remove_front_entry(self) -> (K, V) { - let (index, entry) = self.index.remove(); - let index = index.get(*self.offset); - RefMut::new(entry.into_table(), self.entries, self.offset).swap_remove_front_finish(index) + self.inner.swap_remove_front_entry() } /// Moves the position of the entry to a new index @@ -566,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. @@ -580,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 [`RingMap`]. /// It is part of the [`RawEntryMut`] enum. pub struct RawVacantEntryMut<'a, K, V, S> { - map: RefMut<'a, K, V>, + map: &'a mut RingMapCore, hash_builder: &'a S, } @@ -601,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, @@ -619,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.push_back_unique(hash, key, value).into_muts() + self.map.push_back_unique(hash, key, value).muts() } /// Inserts the given key and value into the map at the given index, @@ -646,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 f8806f4..663f92a 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 } }