perf(header): optimize when inserting a new type header

This commit is contained in:
Sean McArthur
2017-06-23 18:49:18 -07:00
parent 7369fe649f
commit 7d122bd15f
3 changed files with 59 additions and 8 deletions

View File

@@ -58,6 +58,11 @@ impl<V: ?Sized + Any + 'static> PtrMapCell<V> {
PtrMapCell(UnsafeCell::new(PtrMap::Empty))
}
#[inline]
pub fn with_one(key: TypeId, val: Box<V>) -> PtrMapCell<V> {
PtrMapCell(UnsafeCell::new(PtrMap::One(key, val)))
}
#[inline]
pub fn get(&self, key: TypeId) -> Option<&V> {
let map = unsafe { &*self.0.get() };

View File

@@ -23,12 +23,11 @@ impl Item {
}
#[inline]
pub fn new_typed(ty: Box<Header + Send + Sync>) -> Item {
let map = PtrMapCell::new();
unsafe { map.insert((*ty).get_type(), ty); }
pub fn new_typed<H: Header>(val: H) -> Item {
Item {
raw: OptCell::new(None),
typed: map,
typed: PtrMapCell::with_one(TypeId::of::<H>(), Box::new(val)),
}
}

View File

@@ -344,6 +344,7 @@ macro_rules! literals {
_ => ()
}
trace!("maybe_literal not found, copying {:?}", s);
Cow::Owned(s.to_owned())
}
@@ -397,7 +398,7 @@ impl Headers {
pub fn set<H: Header>(&mut self, value: H) {
trace!("Headers.set( {:?}, {:?} )", header_name::<H>(), HeaderValueString(&value));
self.data.insert(HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))),
Item::new_typed(Box::new(value)));
Item::new_typed(value));
}
/// Get a reference to the header field's value, if it exists.
@@ -682,10 +683,11 @@ impl AsRef<str> for HeaderName {
}
impl PartialEq for HeaderName {
#[inline]
fn eq(&self, other: &HeaderName) -> bool {
let s = self.as_ref();
let k = other.as_ref();
if s.len() == k.len() && s.as_ptr() == k.as_ptr() {
if s.as_ptr() == k.as_ptr() && s.len() == k.len() {
true
} else {
self.0 == other.0
@@ -696,7 +698,7 @@ impl PartialEq for HeaderName {
impl PartialEq<HeaderName> for str {
fn eq(&self, other: &HeaderName) -> bool {
let k = other.as_ref();
if self.len() == k.len() && self.as_ptr() == k.as_ptr() {
if self.as_ptr() == k.as_ptr() && self.len() == k.len() {
true
} else {
other.0 == self
@@ -975,6 +977,16 @@ mod tests {
b.iter(|| assert!(headers.get::<ContentLength>().is_none()))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_get_miss_previous_10(b: &mut Bencher) {
let mut headers = Headers::new();
for i in 0..10 {
headers.set_raw(format!("non-standard-{}", i), "hi");
}
b.iter(|| assert!(headers.get::<ContentLength>().is_none()))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_set(b: &mut Bencher) {
@@ -982,6 +994,33 @@ mod tests {
b.iter(|| headers.set(ContentLength(12)))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_set_previous_10(b: &mut Bencher) {
let mut headers = Headers::new();
for i in 0..10 {
headers.set_raw(format!("non-standard-{}", i), "hi");
}
b.iter(|| headers.set(ContentLength(12)))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_set_raw(b: &mut Bencher) {
let mut headers = Headers::new();
b.iter(|| headers.set_raw("non-standard", "hello"))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_set_raw_previous_10(b: &mut Bencher) {
let mut headers = Headers::new();
for i in 0..10 {
headers.set_raw(format!("non-standard-{}", i), "hi");
}
b.iter(|| headers.set_raw("non-standard", "hello"))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_has(b: &mut Bencher) {
@@ -1003,8 +1042,16 @@ mod tests {
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_fmt(b: &mut Bencher) {
use std::fmt::Write;
let mut buf = String::with_capacity(64);
let mut headers = Headers::new();
headers.set(ContentLength(11));
b.iter(|| headers.to_string())
headers.set(ContentType::json());
b.bytes = headers.to_string().len() as u64;
b.iter(|| {
let _ = write!(buf, "{}", headers);
::test::black_box(&buf);
unsafe { buf.as_mut_vec().set_len(0); }
})
}
}