From 2767071cac0cc33d51349cfcf26f2d4aa3831462 Mon Sep 17 00:00:00 2001 From: Zachary Dremann Date: Sat, 28 Aug 2021 11:58:43 -0400 Subject: [PATCH] Optimize `replace_headers` to avoid copies of keys Sometimes, I'm amazed at what non lexical lifetimes allows. --- src/util.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/util.rs b/src/util.rs index 81f123a..a125ecc 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,4 +1,4 @@ -use crate::header::HeaderMap; +use crate::header::{Entry, HeaderMap, OccupiedEntry}; // xor-shift #[cfg(not(target_arch = "wasm32"))] @@ -42,21 +42,23 @@ pub(crate) fn replace_headers(dst: &mut HeaderMap, src: HeaderMap) { // The first time a name is yielded, it will be Some(name), and if // there are more values with the same name, the next yield will be // None. - // - // TODO: a complex exercise would be to optimize this to only - // require 1 hash/lookup of the key, but doing something fancy - // with header::Entry... - let mut prev_name = None; + let mut prev_entry: Option> = None; for (key, value) in src { match key { - Some(key) => { - dst.insert(key.clone(), value); - prev_name = Some(key); - } - None => match prev_name { - Some(ref key) => { - dst.append(key.clone(), value); + Some(key) => match dst.entry(key) { + Entry::Occupied(mut e) => { + e.insert(value); + prev_entry = Some(e); + } + Entry::Vacant(e) => { + let e = e.insert_entry(value); + prev_entry = Some(e); + } + }, + None => match prev_entry { + Some(ref mut entry) => { + entry.append(value); } None => unreachable!("HeaderMap::into_iter yielded None first"), },