mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-30 18:44:35 +01:00
remove old benchmarks
This commit is contained in:
parent
0ba147ef71
commit
4131786127
@ -124,19 +124,3 @@ tokio = { version = "1.24.2", features = ["net", "rt", "macros"] }
|
|||||||
[[example]]
|
[[example]]
|
||||||
name = "ws"
|
name = "ws"
|
||||||
required-features = ["ws", "rustls"]
|
required-features = ["ws", "rustls"]
|
||||||
|
|
||||||
[[bench]]
|
|
||||||
name = "write-camel-case"
|
|
||||||
harness = false
|
|
||||||
|
|
||||||
[[bench]]
|
|
||||||
name = "status-line"
|
|
||||||
harness = false
|
|
||||||
|
|
||||||
[[bench]]
|
|
||||||
name = "uninit-headers"
|
|
||||||
harness = false
|
|
||||||
|
|
||||||
[[bench]]
|
|
||||||
name = "quality-value"
|
|
||||||
harness = false
|
|
||||||
|
@ -1,97 +0,0 @@
|
|||||||
#![allow(clippy::uninlined_format_args)]
|
|
||||||
|
|
||||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
|
||||||
|
|
||||||
const CODES: &[u16] = &[0, 1000, 201, 800, 550];
|
|
||||||
|
|
||||||
fn bench_quality_display_impls(c: &mut Criterion) {
|
|
||||||
let mut group = c.benchmark_group("quality value display impls");
|
|
||||||
|
|
||||||
for i in CODES.iter() {
|
|
||||||
group.bench_with_input(BenchmarkId::new("New (fast?)", i), i, |b, &i| {
|
|
||||||
b.iter(|| _new::Quality(i).to_string())
|
|
||||||
});
|
|
||||||
|
|
||||||
group.bench_with_input(BenchmarkId::new("Naive", i), i, |b, &i| {
|
|
||||||
b.iter(|| _naive::Quality(i).to_string())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
group.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
criterion_group!(benches, bench_quality_display_impls);
|
|
||||||
criterion_main!(benches);
|
|
||||||
|
|
||||||
mod _new {
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
pub struct Quality(pub(crate) u16);
|
|
||||||
|
|
||||||
impl fmt::Display for Quality {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self.0 {
|
|
||||||
0 => f.write_str("0"),
|
|
||||||
1000 => f.write_str("1"),
|
|
||||||
|
|
||||||
// some number in the range 1–999
|
|
||||||
x => {
|
|
||||||
f.write_str("0.")?;
|
|
||||||
|
|
||||||
// this implementation avoids string allocation otherwise required
|
|
||||||
// for `.trim_end_matches('0')`
|
|
||||||
|
|
||||||
if x < 10 {
|
|
||||||
f.write_str("00")?;
|
|
||||||
// 0 is handled so it's not possible to have a trailing 0, we can just return
|
|
||||||
itoa_fmt(f, x)
|
|
||||||
} else if x < 100 {
|
|
||||||
f.write_str("0")?;
|
|
||||||
if x % 10 == 0 {
|
|
||||||
// trailing 0, divide by 10 and write
|
|
||||||
itoa_fmt(f, x / 10)
|
|
||||||
} else {
|
|
||||||
itoa_fmt(f, x)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// x is in range 101–999
|
|
||||||
|
|
||||||
if x % 100 == 0 {
|
|
||||||
// two trailing 0s, divide by 100 and write
|
|
||||||
itoa_fmt(f, x / 100)
|
|
||||||
} else if x % 10 == 0 {
|
|
||||||
// one trailing 0, divide by 10 and write
|
|
||||||
itoa_fmt(f, x / 10)
|
|
||||||
} else {
|
|
||||||
itoa_fmt(f, x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn itoa_fmt<W: fmt::Write, V: itoa::Integer>(mut wr: W, value: V) -> fmt::Result {
|
|
||||||
let mut buf = itoa::Buffer::new();
|
|
||||||
wr.write_str(buf.format(value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod _naive {
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
pub struct Quality(pub(crate) u16);
|
|
||||||
|
|
||||||
impl fmt::Display for Quality {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self.0 {
|
|
||||||
0 => f.write_str("0"),
|
|
||||||
1000 => f.write_str("1"),
|
|
||||||
|
|
||||||
x => {
|
|
||||||
write!(f, "{}", format!("{:03}", x).trim_end_matches('0'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,214 +0,0 @@
|
|||||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
|
||||||
|
|
||||||
use bytes::BytesMut;
|
|
||||||
use http::Version;
|
|
||||||
|
|
||||||
const CODES: &[u16] = &[201, 303, 404, 515];
|
|
||||||
|
|
||||||
fn bench_write_status_line_11(c: &mut Criterion) {
|
|
||||||
let mut group = c.benchmark_group("write_status_line v1.1");
|
|
||||||
|
|
||||||
let version = Version::HTTP_11;
|
|
||||||
|
|
||||||
for i in CODES.iter() {
|
|
||||||
group.bench_with_input(BenchmarkId::new("Original (unsafe)", i), i, |b, &i| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut b = BytesMut::with_capacity(35);
|
|
||||||
_original::write_status_line(version, i, &mut b);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
group.bench_with_input(BenchmarkId::new("New (safe)", i), i, |b, &i| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut b = BytesMut::with_capacity(35);
|
|
||||||
_new::write_status_line(version, i, &mut b);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
group.bench_with_input(BenchmarkId::new("Naive", i), i, |b, &i| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut b = BytesMut::with_capacity(35);
|
|
||||||
_naive::write_status_line(version, i, &mut b);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
group.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bench_write_status_line_10(c: &mut Criterion) {
|
|
||||||
let mut group = c.benchmark_group("write_status_line v1.0");
|
|
||||||
|
|
||||||
let version = Version::HTTP_10;
|
|
||||||
|
|
||||||
for i in CODES.iter() {
|
|
||||||
group.bench_with_input(BenchmarkId::new("Original (unsafe)", i), i, |b, &i| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut b = BytesMut::with_capacity(35);
|
|
||||||
_original::write_status_line(version, i, &mut b);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
group.bench_with_input(BenchmarkId::new("New (safe)", i), i, |b, &i| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut b = BytesMut::with_capacity(35);
|
|
||||||
_new::write_status_line(version, i, &mut b);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
group.bench_with_input(BenchmarkId::new("Naive", i), i, |b, &i| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut b = BytesMut::with_capacity(35);
|
|
||||||
_naive::write_status_line(version, i, &mut b);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
group.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bench_write_status_line_09(c: &mut Criterion) {
|
|
||||||
let mut group = c.benchmark_group("write_status_line v0.9");
|
|
||||||
|
|
||||||
let version = Version::HTTP_09;
|
|
||||||
|
|
||||||
for i in CODES.iter() {
|
|
||||||
group.bench_with_input(BenchmarkId::new("Original (unsafe)", i), i, |b, &i| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut b = BytesMut::with_capacity(35);
|
|
||||||
_original::write_status_line(version, i, &mut b);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
group.bench_with_input(BenchmarkId::new("New (safe)", i), i, |b, &i| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut b = BytesMut::with_capacity(35);
|
|
||||||
_new::write_status_line(version, i, &mut b);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
group.bench_with_input(BenchmarkId::new("Naive", i), i, |b, &i| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut b = BytesMut::with_capacity(35);
|
|
||||||
_naive::write_status_line(version, i, &mut b);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
group.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
criterion_group!(
|
|
||||||
benches,
|
|
||||||
bench_write_status_line_11,
|
|
||||||
bench_write_status_line_10,
|
|
||||||
bench_write_status_line_09
|
|
||||||
);
|
|
||||||
criterion_main!(benches);
|
|
||||||
|
|
||||||
mod _naive {
|
|
||||||
use bytes::{BufMut, BytesMut};
|
|
||||||
use http::Version;
|
|
||||||
|
|
||||||
pub(crate) fn write_status_line(version: Version, n: u16, bytes: &mut BytesMut) {
|
|
||||||
match version {
|
|
||||||
Version::HTTP_11 => bytes.put_slice(b"HTTP/1.1 "),
|
|
||||||
Version::HTTP_10 => bytes.put_slice(b"HTTP/1.0 "),
|
|
||||||
Version::HTTP_09 => bytes.put_slice(b"HTTP/0.9 "),
|
|
||||||
_ => {
|
|
||||||
// other HTTP version handlers do not use this method
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes.put_slice(n.to_string().as_bytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod _new {
|
|
||||||
use bytes::{BufMut, BytesMut};
|
|
||||||
use http::Version;
|
|
||||||
|
|
||||||
const DIGITS_START: u8 = b'0';
|
|
||||||
|
|
||||||
pub(crate) fn write_status_line(version: Version, n: u16, bytes: &mut BytesMut) {
|
|
||||||
match version {
|
|
||||||
Version::HTTP_11 => bytes.put_slice(b"HTTP/1.1 "),
|
|
||||||
Version::HTTP_10 => bytes.put_slice(b"HTTP/1.0 "),
|
|
||||||
Version::HTTP_09 => bytes.put_slice(b"HTTP/0.9 "),
|
|
||||||
_ => {
|
|
||||||
// other HTTP version handlers do not use this method
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
bytes.put_u8(b' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod _original {
|
|
||||||
use std::ptr;
|
|
||||||
|
|
||||||
use bytes::{BufMut, BytesMut};
|
|
||||||
use http::Version;
|
|
||||||
|
|
||||||
const DEC_DIGITS_LUT: &[u8] = b"0001020304050607080910111213141516171819\
|
|
||||||
2021222324252627282930313233343536373839\
|
|
||||||
4041424344454647484950515253545556575859\
|
|
||||||
6061626364656667686970717273747576777879\
|
|
||||||
8081828384858687888990919293949596979899";
|
|
||||||
|
|
||||||
pub(crate) const STATUS_LINE_BUF_SIZE: usize = 13;
|
|
||||||
|
|
||||||
pub(crate) fn write_status_line(version: Version, mut n: u16, bytes: &mut BytesMut) {
|
|
||||||
let mut buf: [u8; STATUS_LINE_BUF_SIZE] = *b"HTTP/1.1 ";
|
|
||||||
|
|
||||||
match version {
|
|
||||||
Version::HTTP_2 => buf[5] = b'2',
|
|
||||||
Version::HTTP_10 => buf[7] = b'0',
|
|
||||||
Version::HTTP_09 => {
|
|
||||||
buf[5] = b'0';
|
|
||||||
buf[7] = b'9';
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut curr: isize = 12;
|
|
||||||
let buf_ptr = buf.as_mut_ptr();
|
|
||||||
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
|
|
||||||
let four = n > 999;
|
|
||||||
|
|
||||||
// decode 2 more chars, if > 2 chars
|
|
||||||
let d1 = (n % 100) << 1;
|
|
||||||
n /= 100;
|
|
||||||
curr -= 2;
|
|
||||||
unsafe {
|
|
||||||
ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(curr), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode last 1 or 2 chars
|
|
||||||
if n < 10 {
|
|
||||||
curr -= 1;
|
|
||||||
unsafe {
|
|
||||||
*buf_ptr.offset(curr) = (n as u8) + b'0';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let d1 = n << 1;
|
|
||||||
curr -= 2;
|
|
||||||
unsafe {
|
|
||||||
ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(curr), 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes.put_slice(&buf);
|
|
||||||
if four {
|
|
||||||
bytes.put_u8(b' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,135 +0,0 @@
|
|||||||
use criterion::{criterion_group, criterion_main, Criterion};
|
|
||||||
|
|
||||||
use bytes::BytesMut;
|
|
||||||
|
|
||||||
// A Miri run detects UB, seen on this playground:
|
|
||||||
// https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f5d9aa166aa48df8dca05fce2b6c3915
|
|
||||||
|
|
||||||
fn bench_header_parsing(c: &mut Criterion) {
|
|
||||||
c.bench_function("Original (Unsound) [short]", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut buf = BytesMut::from(REQ_SHORT);
|
|
||||||
_original::parse_headers(&mut buf);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
c.bench_function("New (safe) [short]", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut buf = BytesMut::from(REQ_SHORT);
|
|
||||||
_new::parse_headers(&mut buf);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
c.bench_function("Original (Unsound) [realistic]", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut buf = BytesMut::from(REQ);
|
|
||||||
_original::parse_headers(&mut buf);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
c.bench_function("New (safe) [realistic]", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut buf = BytesMut::from(REQ);
|
|
||||||
_new::parse_headers(&mut buf);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
criterion_group!(benches, bench_header_parsing);
|
|
||||||
criterion_main!(benches);
|
|
||||||
|
|
||||||
const MAX_HEADERS: usize = 96;
|
|
||||||
|
|
||||||
const EMPTY_HEADER_ARRAY: [httparse::Header<'static>; MAX_HEADERS] =
|
|
||||||
[httparse::EMPTY_HEADER; MAX_HEADERS];
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
struct HeaderIndex {
|
|
||||||
name: (usize, usize),
|
|
||||||
value: (usize, usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
const EMPTY_HEADER_INDEX: HeaderIndex = HeaderIndex {
|
|
||||||
name: (0, 0),
|
|
||||||
value: (0, 0),
|
|
||||||
};
|
|
||||||
|
|
||||||
const EMPTY_HEADER_INDEX_ARRAY: [HeaderIndex; MAX_HEADERS] = [EMPTY_HEADER_INDEX; MAX_HEADERS];
|
|
||||||
|
|
||||||
impl HeaderIndex {
|
|
||||||
fn record(bytes: &[u8], headers: &[httparse::Header<'_>], indices: &mut [HeaderIndex]) {
|
|
||||||
let bytes_ptr = bytes.as_ptr() as usize;
|
|
||||||
for (header, indices) in headers.iter().zip(indices.iter_mut()) {
|
|
||||||
let name_start = header.name.as_ptr() as usize - bytes_ptr;
|
|
||||||
let name_end = name_start + header.name.len();
|
|
||||||
indices.name = (name_start, name_end);
|
|
||||||
let value_start = header.value.as_ptr() as usize - bytes_ptr;
|
|
||||||
let value_end = value_start + header.value.len();
|
|
||||||
indices.value = (value_start, value_end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// test cases taken from:
|
|
||||||
// https://github.com/seanmonstar/httparse/blob/master/benches/parse.rs
|
|
||||||
|
|
||||||
const REQ_SHORT: &[u8] = b"\
|
|
||||||
GET / HTTP/1.0\r\n\
|
|
||||||
Host: example.com\r\n\
|
|
||||||
Cookie: session=60; user_id=1\r\n\r\n";
|
|
||||||
|
|
||||||
const REQ: &[u8] = b"\
|
|
||||||
GET /wp-content/uploads/2010/03/hello-kitty-darth-vader-pink.jpg HTTP/1.1\r\n\
|
|
||||||
Host: www.kittyhell.com\r\n\
|
|
||||||
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; ja-JP-mac; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 Pathtraq/0.9\r\n\
|
|
||||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n\
|
|
||||||
Accept-Language: ja,en-us;q=0.7,en;q=0.3\r\n\
|
|
||||||
Accept-Encoding: gzip,deflate\r\n\
|
|
||||||
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7\r\n\
|
|
||||||
Keep-Alive: 115\r\n\
|
|
||||||
Connection: keep-alive\r\n\
|
|
||||||
Cookie: wp_ozh_wsa_visits=2; wp_ozh_wsa_visit_lasttime=xxxxxxxxxx; __utma=xxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.x; __utmz=xxxxxxxxx.xxxxxxxxxx.x.x.utmccn=(referral)|utmcsr=reader.livedoor.com|utmcct=/reader/|utmcmd=referral|padding=under256\r\n\r\n";
|
|
||||||
|
|
||||||
mod _new {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub fn parse_headers(src: &mut BytesMut) -> usize {
|
|
||||||
let mut headers: [HeaderIndex; MAX_HEADERS] = EMPTY_HEADER_INDEX_ARRAY;
|
|
||||||
let mut parsed: [httparse::Header<'_>; MAX_HEADERS] = EMPTY_HEADER_ARRAY;
|
|
||||||
|
|
||||||
let mut req = httparse::Request::new(&mut parsed);
|
|
||||||
match req.parse(src).unwrap() {
|
|
||||||
httparse::Status::Complete(_len) => {
|
|
||||||
HeaderIndex::record(src, req.headers, &mut headers);
|
|
||||||
req.headers.len()
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod _original {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
|
|
||||||
pub fn parse_headers(src: &mut BytesMut) -> usize {
|
|
||||||
#![allow(invalid_value, clippy::uninit_assumed_init)]
|
|
||||||
|
|
||||||
let mut headers: [HeaderIndex; MAX_HEADERS] =
|
|
||||||
unsafe { MaybeUninit::uninit().assume_init() };
|
|
||||||
|
|
||||||
#[allow(invalid_value)]
|
|
||||||
let mut parsed: [httparse::Header<'_>; MAX_HEADERS] =
|
|
||||||
unsafe { MaybeUninit::uninit().assume_init() };
|
|
||||||
|
|
||||||
let mut req = httparse::Request::new(&mut parsed);
|
|
||||||
match req.parse(src).unwrap() {
|
|
||||||
httparse::Status::Complete(_len) => {
|
|
||||||
HeaderIndex::record(src, req.headers, &mut headers);
|
|
||||||
req.headers.len()
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,93 +0,0 @@
|
|||||||
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
|
|
||||||
|
|
||||||
fn bench_write_camel_case(c: &mut Criterion) {
|
|
||||||
let mut group = c.benchmark_group("write_camel_case");
|
|
||||||
|
|
||||||
let names = ["connection", "Transfer-Encoding", "transfer-encoding"];
|
|
||||||
|
|
||||||
for &i in &names {
|
|
||||||
let bts = i.as_bytes();
|
|
||||||
|
|
||||||
group.bench_with_input(BenchmarkId::new("Original", i), bts, |b, bts| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut buf = black_box([0; 24]);
|
|
||||||
_original::write_camel_case(black_box(bts), &mut buf)
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
group.bench_with_input(BenchmarkId::new("New", i), bts, |b, bts| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut buf = black_box([0; 24]);
|
|
||||||
let len = black_box(bts.len());
|
|
||||||
_new::write_camel_case(black_box(bts), buf.as_mut_ptr(), len)
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
group.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
criterion_group!(benches, bench_write_camel_case);
|
|
||||||
criterion_main!(benches);
|
|
||||||
|
|
||||||
mod _new {
|
|
||||||
pub fn write_camel_case(value: &[u8], buf: *mut u8, len: usize) {
|
|
||||||
// first copy entire (potentially wrong) slice to output
|
|
||||||
let buffer = unsafe {
|
|
||||||
std::ptr::copy_nonoverlapping(value.as_ptr(), buf, len);
|
|
||||||
std::slice::from_raw_parts_mut(buf, len)
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut iter = value.iter();
|
|
||||||
|
|
||||||
// first character should be uppercase
|
|
||||||
if let Some(c @ b'a'..=b'z') = iter.next() {
|
|
||||||
buffer[0] = c & 0b1101_1111;
|
|
||||||
}
|
|
||||||
|
|
||||||
// track 1 ahead of the current position since that's the location being assigned to
|
|
||||||
let mut index = 2;
|
|
||||||
|
|
||||||
// remaining characters after hyphens should also be uppercase
|
|
||||||
while let Some(&c) = iter.next() {
|
|
||||||
if c == b'-' {
|
|
||||||
// advance iter by one and uppercase if needed
|
|
||||||
if let Some(c @ b'a'..=b'z') = iter.next() {
|
|
||||||
buffer[index] = c & 0b1101_1111;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod _original {
|
|
||||||
pub fn write_camel_case(value: &[u8], buffer: &mut [u8]) {
|
|
||||||
let mut index = 0;
|
|
||||||
let key = value;
|
|
||||||
let mut key_iter = key.iter();
|
|
||||||
|
|
||||||
if let Some(c) = key_iter.next() {
|
|
||||||
if *c >= b'a' && *c <= b'z' {
|
|
||||||
buffer[index] = *c ^ b' ';
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(c) = key_iter.next() {
|
|
||||||
buffer[index] = *c;
|
|
||||||
index += 1;
|
|
||||||
if *c == b'-' {
|
|
||||||
if let Some(c) = key_iter.next() {
|
|
||||||
if *c >= b'a' && *c <= b'z' {
|
|
||||||
buffer[index] = *c ^ b' ';
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user