Skip to content

Commit cb520a7

Browse files
authored
Merge pull request #368 from cuviper/reserve_entries
Improve memory reservation for `insert_entry`
2 parents f0ec924 + 1f12721 commit cb520a7

File tree

1 file changed

+22
-18
lines changed

1 file changed

+22
-18
lines changed

src/map/core.rs

+22-18
Original file line numberDiff line numberDiff line change
@@ -522,40 +522,44 @@ impl<K, V> IndexMapCore<K, V> {
522522
}
523523
}
524524

525+
/// Reserve entries capacity, rounded up to match the indices (via `try_capacity`).
526+
fn reserve_entries<K, V>(entries: &mut Entries<K, V>, additional: usize, try_capacity: usize) {
527+
// Use a soft-limit on the maximum capacity, but if the caller explicitly
528+
// requested more, do it and let them have the resulting panic.
529+
let try_capacity = try_capacity.min(IndexMapCore::<K, V>::MAX_ENTRIES_CAPACITY);
530+
let try_add = try_capacity - entries.len();
531+
if try_add > additional && entries.try_reserve_exact(try_add).is_ok() {
532+
return;
533+
}
534+
entries.reserve_exact(additional);
535+
}
536+
525537
impl<'a, K, V> RefMut<'a, K, V> {
526538
#[inline]
527539
fn new(indices: &'a mut Indices, entries: &'a mut Entries<K, V>) -> Self {
528540
Self { indices, entries }
529541
}
530542

531543
/// Reserve entries capacity, rounded up to match the indices
544+
#[inline]
532545
fn reserve_entries(&mut self, additional: usize) {
533-
// Use a soft-limit on the maximum capacity, but if the caller explicitly
534-
// requested more, do it and let them have the resulting panic.
535-
let new_capacity = Ord::min(
536-
self.indices.capacity(),
537-
IndexMapCore::<K, V>::MAX_ENTRIES_CAPACITY,
538-
);
539-
let try_add = new_capacity - self.entries.len();
540-
if try_add > additional && self.entries.try_reserve_exact(try_add).is_ok() {
541-
return;
542-
}
543-
self.entries.reserve_exact(additional);
546+
reserve_entries(self.entries, additional, self.indices.capacity());
544547
}
545548

546549
/// Insert a key-value pair in `entries`,
547550
/// *without* checking whether it already exists.
548-
fn insert_unique(mut self, hash: HashValue, key: K, value: V) -> OccupiedEntry<'a, K, V> {
549-
if self.entries.len() == self.entries.capacity() {
550-
// Reserve our own capacity synced to the indices,
551-
// rather than letting `Vec::push` just double it.
552-
self.reserve_entries(1);
553-
}
551+
fn insert_unique(self, hash: HashValue, key: K, value: V) -> OccupiedEntry<'a, K, V> {
554552
let i = self.indices.len();
553+
debug_assert_eq!(i, self.entries.len());
555554
let entry = self
556555
.indices
557556
.insert_unique(hash.get(), i, get_hash(self.entries));
558-
debug_assert_eq!(i, self.entries.len());
557+
if self.entries.len() == self.entries.capacity() {
558+
// We can't call `indices.capacity()` while this `entry` has borrowed it, so we'll have
559+
// to amortize growth on our own. It's still an improvement over the basic `Vec::push`
560+
// doubling though, since we also consider `MAX_ENTRIES_CAPACITY`.
561+
reserve_entries(self.entries, 1, 2 * self.entries.capacity());
562+
}
559563
self.entries.push(Bucket { hash, key, value });
560564
OccupiedEntry::new(self.entries, entry)
561565
}

0 commit comments

Comments
 (0)