Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add {Entry,VacantEntry}::insert_entry #361

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 27 additions & 23 deletions src/map/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,17 @@ impl<K, V> IndexMapCore<K, V> {
self.indices.find(hash.get(), eq).copied()
}

/// Append a key-value pair to `entries`,
/// *without* checking whether it already exists.
fn push_entry(&mut self, hash: HashValue, key: K, value: V) {
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.entries.push(Bucket { hash, key, value });
}

pub(crate) fn insert_full(&mut self, hash: HashValue, key: K, value: V) -> (usize, Option<V>)
where
K: Eq,
Expand All @@ -330,7 +341,7 @@ impl<K, V> IndexMapCore<K, V> {
hash_table::Entry::Vacant(entry) => {
let i = self.entries.len();
entry.insert(i);
self.borrow_mut().push_entry(hash, key, value);
self.push_entry(hash, key, value);
debug_assert_eq!(self.indices.len(), self.entries.len());
(i, None)
}
Expand Down Expand Up @@ -362,7 +373,7 @@ impl<K, V> IndexMapCore<K, V> {
hash_table::Entry::Vacant(entry) => {
let i = self.entries.len();
entry.insert(i);
self.borrow_mut().push_entry(hash, key, value);
self.push_entry(hash, key, value);
debug_assert_eq!(self.indices.len(), self.entries.len());
(i, None)
}
Expand Down Expand Up @@ -522,37 +533,25 @@ impl<'a, K, V> RefMut<'a, K, V> {
self.entries.reserve_exact(additional);
}

/// Append a key-value pair to `entries`,
/// Insert a key-value pair in `entries`,
/// *without* checking whether it already exists.
fn push_entry(&mut self, hash: HashValue, key: K, value: V) {
fn insert_unique(mut self, hash: HashValue, key: K, value: V) -> OccupiedEntry<'a, K, V> {
if self.entries.len() == self.entries.capacity() {
// Reserve our own capacity synced to the indices,
// rather than letting `Vec::push` just double it.
self.reserve_entries(1);
}
self.entries.push(Bucket { hash, key, value });
}

/// Insert a key-value pair in `entries` at a particular index,
/// *without* checking whether it already exists.
fn insert_entry(&mut self, index: usize, hash: HashValue, key: K, value: V) {
if self.entries.len() == self.entries.capacity() {
// Reserve our own capacity synced to the indices,
// rather than letting `Vec::insert` just double it.
self.reserve_entries(1);
}
self.entries.insert(index, Bucket { hash, key, value });
}

fn insert_unique(&mut self, hash: HashValue, key: K, value: V) -> usize {
let i = self.indices.len();
self.indices
let entry = self
.indices
.insert_unique(hash.get(), i, get_hash(self.entries));
debug_assert_eq!(i, self.entries.len());
self.push_entry(hash, key, value);
i
self.entries.push(Bucket { hash, key, value });
OccupiedEntry::new(self.entries, entry)
}

/// Insert a key-value pair in `entries` at a particular index,
/// *without* checking whether it already exists.
fn shift_insert_unique(&mut self, index: usize, hash: HashValue, key: K, value: V) {
let end = self.indices.len();
assert!(index <= end);
Expand All @@ -565,7 +564,12 @@ impl<'a, K, V> RefMut<'a, K, V> {
let i = if i < index { i } else { i - 1 };
entries[i].hash.get()
});
self.insert_entry(index, hash, key, value);
if self.entries.len() == self.entries.capacity() {
// Reserve our own capacity synced to the indices,
// rather than letting `Vec::insert` just double it.
self.reserve_entries(1);
}
self.entries.insert(index, Bucket { hash, key, value });
}

/// Remove an entry by shifting all entries that follow it
Expand Down
40 changes: 37 additions & 3 deletions src/map/core/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ impl<'a, K, V> Entry<'a, K, V> {
}
}

/// Sets the value of the entry (after inserting if vacant), and returns an `OccupiedEntry`.
///
/// Computes in **O(1)** time (amortized average).
pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> {
match self {
Entry::Occupied(mut entry) => {
entry.insert(value);
entry
}
Entry::Vacant(entry) => entry.insert_entry(value),
}
}

/// Inserts the given default value in the entry if it is vacant and returns a mutable
/// reference to it. Otherwise a mutable reference to an already existent value is returned.
///
Expand Down Expand Up @@ -136,6 +149,13 @@ pub struct OccupiedEntry<'a, K, V> {
}

impl<'a, K, V> OccupiedEntry<'a, K, V> {
pub(crate) fn new(
entries: &'a mut Entries<K, V>,
index: hash_table::OccupiedEntry<'a, usize>,
) -> Self {
Self { entries, index }
}

/// Return the index of the key-value pair
#[inline]
pub fn index(&self) -> usize {
Expand Down Expand Up @@ -182,6 +202,11 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
&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()
}

/// Sets the value of the entry to `value`, and returns the entry's old value.
pub fn insert(&mut self, value: V) -> V {
mem::replace(self.get_mut(), value)
Expand Down Expand Up @@ -343,9 +368,18 @@ impl<'a, K, V> VacantEntry<'a, K, V> {

/// Inserts the entry's key and the given value into the map, and returns a mutable reference
/// to the value.
pub fn insert(mut self, value: V) -> &'a mut V {
let i = self.map.insert_unique(self.hash, self.key, value);
&mut self.map.entries[i].value
///
/// Computes in **O(1)** time (amortized average).
pub fn insert(self, value: V) -> &'a mut V {
self.insert_entry(value).into_mut()
}

/// Inserts the entry's key and the given value into the map, and returns an `OccupiedEntry`.
///
/// 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)
}

/// Inserts the entry's key and the given value into the map at its ordered
Expand Down
5 changes: 2 additions & 3 deletions src/map/core/raw_entry_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,10 +618,9 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {

/// Inserts the given key and value into the map with the provided hash,
/// and returns mutable references to them.
pub fn insert_hashed_nocheck(mut self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) {
pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) {
let hash = HashValue(hash as usize);
let i = self.map.insert_unique(hash, key, value);
self.map.entries[i].muts()
self.map.insert_unique(hash, key, value).into_muts()
}

/// Inserts the given key and value into the map at the given index,
Expand Down