Skip to content

Commit

Permalink
fix: HeaderMap::reserve allocates insufficient capacity (#741)
Browse files Browse the repository at this point in the history
This bug caused additional allocation when attempted to insert
the requested number of entries.
This commit fix that by converting capacity to raw capacity before
allocation.
  • Loading branch information
kawaemon authored Jan 10, 2025
1 parent 4e02046 commit 68845bd
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 7 deletions.
16 changes: 9 additions & 7 deletions src/header/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -707,20 +707,22 @@ impl<T> HeaderMap<T> {
.checked_add(additional)
.ok_or_else(MaxSizeReached::new)?;

if cap > self.indices.len() {
let cap = cap
let raw_cap = to_raw_capacity(cap);

if raw_cap > self.indices.len() {
let raw_cap = raw_cap
.checked_next_power_of_two()
.ok_or_else(MaxSizeReached::new)?;
if cap > MAX_SIZE {
if raw_cap > MAX_SIZE {
return Err(MaxSizeReached::new());
}

if self.entries.is_empty() {
self.mask = cap as Size - 1;
self.indices = vec![Pos::none(); cap].into_boxed_slice();
self.entries = Vec::with_capacity(usable_capacity(cap));
self.mask = raw_cap as Size - 1;
self.indices = vec![Pos::none(); raw_cap].into_boxed_slice();
self.entries = Vec::with_capacity(usable_capacity(raw_cap));
} else {
self.try_grow(cap)?;
self.try_grow(raw_cap)?;
}
}

Expand Down
24 changes: 24 additions & 0 deletions tests/header_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,30 @@ fn reserve_overflow() {
headers.reserve(std::usize::MAX); // next_power_of_two overflows
}

#[test]
fn reserve() {
let mut headers = HeaderMap::<usize>::default();
assert_eq!(headers.capacity(), 0);

let requested_cap = 8;
headers.reserve(requested_cap);

let reserved_cap = headers.capacity();
assert!(
reserved_cap >= requested_cap,
"requested {} capacity, but it reserved only {} entries",
requested_cap,
reserved_cap,
);

for i in 0..requested_cap {
let name = format!("h{i}").parse::<HeaderName>().unwrap();
headers.insert(name, i);
}

assert_eq!(headers.capacity(), reserved_cap, "unexpected reallocation");
}

#[test]
fn drain() {
let mut headers = HeaderMap::new();
Expand Down

0 comments on commit 68845bd

Please sign in to comment.