From 7d8fb631a074dc31cde9a3da4a82acb9b027563f Mon Sep 17 00:00:00 2001 From: Nick Kolpinskiy Date: Thu, 21 May 2020 22:25:34 +0300 Subject: [PATCH] Use `itoa` in the content-length helper --- actix-http/Cargo.toml | 1 + actix-http/benches/content-length.rs | 24 +++++++ actix-http/src/helpers.rs | 101 +++------------------------ 3 files changed, 33 insertions(+), 93 deletions(-) diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 573fcf1e4..deb63197a 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -64,6 +64,7 @@ h2 = "0.2.1" http = "0.2.0" httparse = "1.3" indexmap = "1.3" +itoa = "0.4" lazy_static = "1.4" language-tags = "0.2" log = "0.4" diff --git a/actix-http/benches/content-length.rs b/actix-http/benches/content-length.rs index b001b3931..18a55a33b 100644 --- a/actix-http/benches/content-length.rs +++ b/actix-http/benches/content-length.rs @@ -25,6 +25,13 @@ fn bench_write_content_length(c: &mut Criterion) { _new::write_content_length(i, &mut b) }) }); + + group.bench_with_input(BenchmarkId::new("itoa", i), i, |b, &i| { + b.iter(|| { + let mut b = BytesMut::with_capacity(35); + _itoa::write_content_length(i, &mut b) + }) + }); } group.finish(); @@ -33,6 +40,23 @@ fn bench_write_content_length(c: &mut Criterion) { criterion_group!(benches, bench_write_content_length); criterion_main!(benches); +mod _itoa { + use bytes::{BufMut, BytesMut}; + + pub fn write_content_length(n: usize, bytes: &mut BytesMut) { + if n == 0 { + bytes.put_slice(b"\r\ncontent-length: 0\r\n"); + return; + } + + let mut buf = itoa::Buffer::new(); + + bytes.put_slice(b"\r\ncontent-length: "); + bytes.put_slice(buf.format(n).as_bytes()); + bytes.put_slice(b"\r\n"); + } +} + mod _new { use bytes::{BufMut, BytesMut}; diff --git a/actix-http/src/helpers.rs b/actix-http/src/helpers.rs index 5ac6c9be5..bbf358b66 100644 --- a/actix-http/src/helpers.rs +++ b/actix-http/src/helpers.rs @@ -31,103 +31,18 @@ pub(crate) fn write_status_line(version: Version, n: u16, bytes: &mut BytesMut) /// NOTE: bytes object has to contain enough space pub fn write_content_length(n: u64, bytes: &mut BytesMut) { + if n == 0 { + bytes.put_slice(b"\r\ncontent-length: 0\r\n"); + return; + } + + let mut buf = itoa::Buffer::new(); + bytes.put_slice(b"\r\ncontent-length: "); - - if n < 10 { - bytes.put_u8(DIGITS_START + (n as u8)); - } else if n < 100 { - let n = n as u8; - - let d10 = n / 10; - let d1 = n % 10; - - bytes.put_u8(DIGITS_START + d10); - bytes.put_u8(DIGITS_START + d1); - } else if n < 1000 { - let n = n as u16; - - let d100 = (n / 100) as u8; - let d10 = ((n / 10) % 10) as u8; - let d1 = (n % 10) as u8; - - bytes.put_u8(DIGITS_START + d100); - bytes.put_u8(DIGITS_START + d10); - bytes.put_u8(DIGITS_START + d1); - } else if n < 10_000 { - let n = n as u16; - - let d1000 = (n / 1000) as u8; - let d100 = ((n / 100) % 10) as u8; - let d10 = ((n / 10) % 10) as u8; - let d1 = (n % 10) as u8; - - bytes.put_u8(DIGITS_START + d1000); - bytes.put_u8(DIGITS_START + d100); - bytes.put_u8(DIGITS_START + d10); - bytes.put_u8(DIGITS_START + d1); - } else if n < 100_000 { - let n = n as u32; - - let d10000 = (n / 10000) as u8; - let d1000 = ((n / 1000) % 10) as u8; - let d100 = ((n / 100) % 10) as u8; - let d10 = ((n / 10) % 10) as u8; - let d1 = (n % 10) as u8; - - bytes.put_u8(DIGITS_START + d10000); - bytes.put_u8(DIGITS_START + d1000); - bytes.put_u8(DIGITS_START + d100); - bytes.put_u8(DIGITS_START + d10); - bytes.put_u8(DIGITS_START + d1); - } else if n < 1_000_000 { - let n = n as u32; - - let d100000 = (n / 100_000) as u8; - let d10000 = ((n / 10000) % 10) as u8; - let d1000 = ((n / 1000) % 10) as u8; - let d100 = ((n / 100) % 10) as u8; - let d10 = ((n / 10) % 10) as u8; - let d1 = (n % 10) as u8; - - bytes.put_u8(DIGITS_START + d100000); - bytes.put_u8(DIGITS_START + d10000); - bytes.put_u8(DIGITS_START + d1000); - bytes.put_u8(DIGITS_START + d100); - bytes.put_u8(DIGITS_START + d10); - bytes.put_u8(DIGITS_START + d1); - } else { - write_u64(n, bytes); - } - + bytes.put_slice(buf.format(n).as_bytes()); bytes.put_slice(b"\r\n"); } -pub(crate) fn write_u64(n: u64, bytes: &mut BytesMut) { - let mut n = n; - - // 20 chars is max length of a u64 (2^64) - // digits will be added to the buffer from lsd to msd - let mut buf = BytesMut::with_capacity(20); - - while n > 9 { - // "pop" the least-significant digit - let lsd = (n % 10) as u8; - - // remove the lsd from n - n /= 10; - - buf.put_u8(DIGITS_START + lsd); - } - - // put msd to result buffer - bytes.put_u8(DIGITS_START + (n as u8)); - - // put, in reverse (msd to lsd), remaining digits to buffer - for i in (0..buf.len()).rev() { - bytes.put_u8(buf[i]); - } -} - pub(crate) struct Writer<'a>(pub &'a mut BytesMut); impl<'a> io::Write for Writer<'a> {