Skip to content
Merged
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
12 changes: 10 additions & 2 deletions src/header/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2133,12 +2133,16 @@ impl<T> Extend<(Option<HeaderName>, T)> for HeaderMap<T> {
// Reserve the entire hint lower bound if the map is empty.
// Otherwise reserve half the hint (rounded up), so the map
// will only resize twice in the worst case.
let reserve = if self.is_empty() {
let hint = if self.is_empty() {
iter.size_hint().0
} else {
(iter.size_hint().0 + 1) / 2
};

// Clamp the hint so an over-estimate cannot overflow `reserve`.
let max_reserve = usable_capacity(MAX_SIZE).saturating_sub(self.entries.len());
let reserve = hint.min(max_reserve);

self.reserve(reserve);

// The structure of this is a bit weird, but it is mostly to make the
Expand Down Expand Up @@ -2189,12 +2193,16 @@ impl<T> Extend<(HeaderName, T)> for HeaderMap<T> {
// will only resize twice in the worst case.
let iter = iter.into_iter();

let reserve = if self.is_empty() {
let hint = if self.is_empty() {
iter.size_hint().0
} else {
(iter.size_hint().0 + 1) / 2
};

// Clamp the hint so an over-estimate cannot overflow `reserve`.
let max_reserve = usable_capacity(MAX_SIZE).saturating_sub(self.entries.len());
let reserve = hint.min(max_reserve);

self.reserve(reserve);

for (k, v) in iter {
Expand Down
17 changes: 17 additions & 0 deletions tests/header_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,23 @@ fn with_capacity_overflow() {
HeaderMap::<u32>::with_capacity(24_577);
}

#[test]
fn extend_size_hint_above_capacity() {
// A `HeaderMap` may hold more values than the table can index when many
// values are appended under one name, so an exact size hint can exceed the
// largest `reserve` request. Extending must not panic in that case.
let name = HeaderName::from_static("h");
let value = HeaderValue::from_static("0");
let pairs: Vec<(HeaderName, HeaderValue)> =
std::iter::repeat_with(|| (name.clone(), value.clone()))
.take(24_577)
.collect();

let map = HeaderMap::from_iter(pairs);
assert_eq!(map.len(), 24_577);
assert_eq!(map.keys_len(), 1);
}

#[test]
#[should_panic]
fn reserve_overflow() {
Expand Down