diff --git a/src/header/map.rs b/src/header/map.rs index a0bed219..58349fa8 100644 --- a/src/header/map.rs +++ b/src/header/map.rs @@ -232,7 +232,7 @@ enum Cursor { /// You may notice that `u16` may represent more than 32,768 values. This is /// true, but 32,768 should be plenty and it allows us to reserve the top bit /// for future usage. -type Size = usize; +type Size = u16; /// This limit falls out from above. const MAX_SIZE: usize = (1 << 15); @@ -252,7 +252,7 @@ struct Pos { /// bits is fine since we know that the `indices` vector will never grow beyond /// that size. #[derive(Debug, Copy, Clone, Eq, PartialEq)] -struct HashValue(usize); +struct HashValue(u16); /// Stores the data associated with a `HeaderMap` entry. Only the first value is /// included in this struct. If a header name has more than one associated @@ -465,8 +465,6 @@ impl HeaderMap { /// assert_eq!(12, map.capacity()); /// ``` pub fn with_capacity(capacity: usize) -> HeaderMap { - assert!(capacity <= MAX_SIZE, "requested capacity too large"); - if capacity == 0 { HeaderMap { mask: 0, @@ -477,6 +475,7 @@ impl HeaderMap { } } else { let raw_cap = to_raw_capacity(capacity).next_power_of_two(); + assert!(raw_cap <= MAX_SIZE, "requested capacity too large"); debug_assert!(raw_cap > 0); HeaderMap { @@ -642,11 +641,11 @@ impl HeaderMap { if cap > self.indices.len() { let cap = cap.next_power_of_two(); - assert!(cap < MAX_SIZE, "header map reserve over max capacity"); + assert!(cap <= MAX_SIZE, "header map reserve over max capacity"); assert!(cap != 0, "header map reserve overflowed"); if self.entries.len() == 0 { - self.mask = cap - 1; + self.mask = cap as Size - 1; self.indices = vec![Pos::none(); cap].into_boxed_slice(); self.entries = Vec::with_capacity(usable_capacity(cap)); } else { @@ -1543,6 +1542,7 @@ impl HeaderMap { #[inline] fn grow(&mut self, new_raw_cap: usize) { + assert!(new_raw_cap <= MAX_SIZE, "requested capacity too large"); // This path can never be reached when handling the first allocation in // the map. @@ -3109,6 +3109,7 @@ impl ops::IndexMut for RawLinks { impl Pos { #[inline] fn new(index: usize, hash: HashValue) -> Self { + debug_assert!(index < MAX_SIZE); Pos { index: index as Size, hash: hash, @@ -3136,7 +3137,7 @@ impl Pos { #[inline] fn resolve(&self) -> Option<(usize, HashValue)> { if self.is_some() { - Some((self.index, self.hash)) + Some((self.index as usize, self.hash)) } else { None } @@ -3192,13 +3193,13 @@ fn to_raw_capacity(n: usize) -> usize { #[inline] fn desired_pos(mask: Size, hash: HashValue) -> usize { - hash.0 & mask + (hash.0 & mask) as usize } /// The number of steps that `current` is forward of the desired position for hash #[inline] fn probe_distance(mask: Size, hash: HashValue, current: usize) -> usize { - current.wrapping_sub(desired_pos(mask, hash)) & mask + current.wrapping_sub(desired_pos(mask, hash)) & mask as usize } fn hash_elem_using(danger: &Danger, k: &K) -> HashValue @@ -3224,7 +3225,7 @@ where } }; - HashValue((hash & MASK) as usize) + HashValue((hash & MASK) as u16) } /* diff --git a/tests/header_map.rs b/tests/header_map.rs index 91c8f3f6..39893568 100644 --- a/tests/header_map.rs +++ b/tests/header_map.rs @@ -43,6 +43,18 @@ fn reserve_over_capacity() { headers.reserve(50_000); // over MAX_SIZE } +#[test] +fn with_capacity_max() { + // The largest capacity such that (cap + cap / 3) < MAX_SIZE. + HeaderMap::::with_capacity(24_576); +} + +#[test] +#[should_panic] +fn with_capacity_overflow() { + HeaderMap::::with_capacity(24_577); +} + #[test] #[should_panic] fn reserve_overflow() {