Fix HeaderMap seq -> hash map transition (#15)

The function that rebuilds the map with a new hasher did not correctly
update the hash table. Also, fix mask values.
This commit is contained in:
Carl Lerche
2017-04-30 09:19:38 -07:00
committed by GitHub
parent cc0c2a04b9
commit 0912e4ac26
2 changed files with 139 additions and 6 deletions
+13 -6
View File
@@ -1594,6 +1594,8 @@ impl<T> HeaderMap<T> {
// Initialze the indices
self.indices = vec![Pos::none(); cap];
self.mask = cap.wrapping_sub(1) as Size;
// Rebuild the table
self.rebuild();
}
@@ -1604,32 +1606,37 @@ impl<T> HeaderMap<T> {
debug_assert!(!self.is_scan());
// Loop over all entries and re-insert them into the map
for entry in &mut self.entries {
'outer:
for (index, entry) in self.entries.iter_mut().enumerate() {
let hash = hash_elem_using(&self.danger, &entry.key);
let mut probe = desired_pos(self.mask, hash);
let mut dist = 0;
// Update the entry's hash code
entry.hash = hash;
probe_loop!(probe < self.indices.len() as Size, {
if let Some((_, entry_hash)) = self.indices[probe as usize].resolve() {
// if existing element probed less than us, swap
let their_dist = probe_distance(self.mask, entry_hash, probe);
if their_dist < dist {
// Robinhood
break;
}
} else {
break;
// Vaccant slot
self.indices[probe as usize] = Pos::new(index as Size, hash);
continue 'outer;
}
dist += 1;
});
entry.hash = hash;
do_insert_phase_two(
&mut self.indices,
probe as Size,
Pos::new(probe as Size, hash));
Pos::new(index as Size, hash));
}
}
@@ -3015,7 +3022,7 @@ fn probe_distance(mask: Size, hash: HashValue, current: Size) -> Size {
fn hash_elem_using<K: ?Sized>(danger: &Danger, k: &K) -> HashValue
where K: FastHash
{
const MASK: u64 = MAX_SIZE as u64;
const MASK: u64 = (MAX_SIZE as u64) - 1;
let hash = match *danger {
// Safe hash
+126
View File
@@ -131,3 +131,129 @@ fn eq() {
assert_ne!(a, b);
}
#[test]
fn insert_all_std_headers() {
let mut m = HeaderMap::new();
for (i, hdr) in STD.iter().enumerate() {
m.insert(hdr.clone(), hdr.as_str().to_string());
for j in 0..(i+1) {
assert_eq!(m[&STD[j]], STD[j].as_str());
}
if i != 0 {
for j in (i+1)..STD.len() {
assert!(m.get(&STD[j]).is_none(), "contained {}; j={}", STD[j].as_str(), j);
}
}
}
}
#[test]
fn insert_79_custom_std_headers() {
let mut h = HeaderMap::new();
let hdrs = custom_std(79);
for (i, hdr) in hdrs.iter().enumerate() {
h.insert(hdr.clone(), hdr.as_str().to_string());
for j in 0..(i+1) {
assert_eq!(h[&hdrs[j]], hdrs[j].as_str());
}
for j in (i+1)..hdrs.len() {
assert!(h.get(&hdrs[j]).is_none());
}
}
}
fn custom_std(n: usize) -> Vec<HeaderName> {
(0..n).map(|i| {
let s = format!("{}-{}", STD[i % STD.len()].as_str(), i);
s.parse().unwrap()
}).collect()
}
const STD: [HeaderName; 79] = [
ACCEPT,
ACCEPT_CHARSET,
ACCEPT_ENCODING,
ACCEPT_LANGUAGE,
ACCEPT_PATCH,
ACCEPT_RANGES,
ACCESS_CONTROL_ALLOW_CREDENTIALS,
ACCESS_CONTROL_ALLOW_HEADERS,
ACCESS_CONTROL_ALLOW_METHODS,
ACCESS_CONTROL_ALLOW_ORIGIN,
ACCESS_CONTROL_EXPOSE_HEADERS,
ACCESS_CONTROL_MAX_AGE,
ACCESS_CONTROL_REQUEST_HEADERS,
ACCESS_CONTROL_REQUEST_METHOD,
AGE,
ALLOW,
ALT_SVC,
AUTHORIZATION,
CACHE_CONTROL,
CONNECTION,
CONTENT_DISPOSITION,
CONTENT_ENCODING,
CONTENT_LANGUAGE,
CONTENT_LENGTH,
CONTENT_LOCATION,
CONTENT_MD5,
CONTENT_RANGE,
CONTENT_SECURITY_POLICY,
CONTENT_SECURITY_POLICY_REPORT_ONLY,
CONTENT_TYPE,
COOKIE,
DNT,
DATE,
ETAG,
EXPECT,
EXPIRES,
FORWARDED,
FROM,
HOST,
IF_MATCH,
IF_MODIFIED_SINCE,
IF_NONE_MATCH,
IF_RANGE,
IF_UNMODIFIED_SINCE,
LAST_MODIFIED,
KEEP_ALIVE,
LINK,
LOCATION,
MAX_FORWARDS,
ORIGIN,
PRAGMA,
PROXY_AUTHENTICATE,
PROXY_AUTHORIZATION,
PUBLIC_KEY_PINS,
PUBLIC_KEY_PINS_REPORT_ONLY,
RANGE,
REFERER,
REFERRER_POLICY,
REFRESH,
RETRY_AFTER,
SERVER,
SET_COOKIE,
STRICT_TRANSPORT_SECURITY,
TE,
TK,
TRAILER,
TRANSFER_ENCODING,
TSV,
USER_AGENT,
UPGRADE,
UPGRADE_INSECURE_REQUESTS,
VARY,
VIA,
WARNING,
WWW_AUTHENTICATE,
X_CONTENT_TYPE_OPTIONS,
X_DNS_PREFETCH_CONTROL,
X_FRAME_OPTIONS,
X_XSS_PROTECTION,
];