Skip to content

Commit 511da17

Browse files
committed
io: use memchr from libc
1 parent b343767 commit 511da17

File tree

4 files changed

+79
-2
lines changed

4 files changed

+79
-2
lines changed

tokio/Cargo.toml

+1-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ full = [
4242
]
4343

4444
fs = []
45-
io-util = ["memchr", "bytes"]
45+
io-util = ["bytes"]
4646
# stdin, stdout, stderr
4747
io-std = []
4848
macros = ["tokio-macros"]
@@ -111,7 +111,6 @@ pin-project-lite = "0.2.0"
111111
# Everything else is optional...
112112
bytes = { version = "1.0.0", optional = true }
113113
once_cell = { version = "1.5.2", optional = true }
114-
memchr = { version = "2.2", optional = true }
115114
mio = { version = "0.8.1", optional = true }
116115
socket2 = { version = "0.4.4", optional = true, features = [ "all" ] }
117116
num_cpus = { version = "1.8.0", optional = true }

tokio/src/io/util/read_until.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::io::AsyncBufRead;
2+
use crate::util::memchr;
23

34
use pin_project_lite::pin_project;
45
use std::future::Future;

tokio/src/util/memchr.rs

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//! Search for a byte in a byte array using libc.
2+
//!
3+
//! When nothing pulls in libc, then just use a trivial implementation. Note
4+
//! that we only depend on libc on unix.
5+
6+
#[cfg(not(all(unix, feature = "libc")))]
7+
pub(crate) fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
8+
haystack.iter().position(|val| needle == *val)
9+
}
10+
11+
#[cfg(all(unix, feature = "libc"))]
12+
pub(crate) fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
13+
let start = haystack.as_ptr();
14+
15+
// SAFETY: `start` is valid for `haystack.len()` bytes.
16+
let ptr = unsafe { libc::memchr(start.cast(), needle as _, haystack.len()) };
17+
18+
if ptr.is_null() {
19+
None
20+
} else {
21+
Some(ptr as usize - start as usize)
22+
}
23+
}
24+
25+
#[cfg(test)]
26+
mod tests {
27+
use super::memchr;
28+
29+
#[test]
30+
fn memchr_test() {
31+
let haystack = b"123abc456\0\xffabc\n";
32+
33+
assert_eq!(memchr(b'1', haystack), Some(0));
34+
assert_eq!(memchr(b'2', haystack), Some(1));
35+
assert_eq!(memchr(b'3', haystack), Some(2));
36+
assert_eq!(memchr(b'4', haystack), Some(6));
37+
assert_eq!(memchr(b'5', haystack), Some(7));
38+
assert_eq!(memchr(b'6', haystack), Some(8));
39+
assert_eq!(memchr(b'7', haystack), None);
40+
assert_eq!(memchr(b'a', haystack), Some(3));
41+
assert_eq!(memchr(b'b', haystack), Some(4));
42+
assert_eq!(memchr(b'c', haystack), Some(5));
43+
assert_eq!(memchr(b'd', haystack), None);
44+
assert_eq!(memchr(b'A', haystack), None);
45+
assert_eq!(memchr(0, haystack), Some(9));
46+
assert_eq!(memchr(0xff, haystack), Some(10));
47+
assert_eq!(memchr(0xfe, haystack), None);
48+
assert_eq!(memchr(1, haystack), None);
49+
assert_eq!(memchr(b'\n', haystack), Some(14));
50+
assert_eq!(memchr(b'\r', haystack), None);
51+
}
52+
53+
#[test]
54+
fn memchr_all() {
55+
let mut arr = Vec::new();
56+
for b in 0..=255 {
57+
arr.push(b);
58+
}
59+
for b in 0..=255 {
60+
assert_eq!(memchr(b, &arr), Some(b as usize));
61+
}
62+
arr.reverse();
63+
for b in 0..=255 {
64+
assert_eq!(memchr(b, &arr), Some(255 - b as usize));
65+
}
66+
}
67+
68+
#[test]
69+
fn memchr_empty() {
70+
for b in 0..=255 {
71+
assert_eq!(memchr(b, b""), None);
72+
}
73+
}
74+
}

tokio/src/util/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,6 @@ pub use self::rand::thread_rng_n;
8181
all(unix, feature = "signal")
8282
))]
8383
pub(crate) mod error;
84+
85+
#[cfg(feature = "io-util")]
86+
pub(crate) mod memchr;

0 commit comments

Comments
 (0)