Skip to content

Commit 42dee6c

Browse files
zakcutnermarmeladema
authored andcommitted
Tidy up in preparation for release
1 parent fca2a2b commit 42dee6c

File tree

12 files changed

+312
-198
lines changed

12 files changed

+312
-198
lines changed

Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
[package]
2-
name = "strstr"
2+
name = "sliceslice"
33
version = "0.1.0"
44
authors = ["adema"]
55
edition = "2018"
6+
description = "A fast implementation of single-pattern substring search using SIMD acceleration"
7+
readme = "README.md"
8+
repository = "https://github.com/marmeladema/sliceslice-rs"
9+
license = "MIT"
10+
keywords = ["search", "text", "string", "single", "simd"]
611

712
[lib]
813
bench = false

README.md

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,27 @@
1-
# strstr-rs
1+
# sliceslice
22

3-
Main goal of this crate is to provide fast algorithms for single pattern substring search.
4-
For multi pattern substring search, please refer to the [aho-corasick crate](https://github.com/BurntSushi/aho-corasick).
3+
[![Actions](https://github.com/marmeladema/sliceslice-rs/workflows/Check/badge.svg)](https://github.com/marmeladema/sliceslice-rs/actions)
4+
5+
A fast implementation of single-pattern substring search using SIMD acceleration, based on the work [presented by Wojciech Muła](http://0x80.pl/articles/simd-strfind.html). For a fast multi-pattern substring search algorithm, see instead the [`aho-corasick` crate](https://github.com/BurntSushi/aho-corasick).
6+
7+
## Example
8+
9+
```rust
10+
use sliceslice::x86::avx2::DynamicAvx2Searcher;
11+
12+
fn main() {
13+
let searcher = unsafe { DynamicAvx2Searcher::new(b"ipsum".to_owned().into()) };
14+
15+
assert!(unsafe {
16+
searcher.search_in(b"Lorem ipsum dolor sit amet, consectetur adipiscing elit")
17+
});
18+
19+
assert!(!unsafe {
20+
searcher.search_in(b"foo bar baz qux quux quuz corge grault garply waldo fred")
21+
});
22+
}
23+
```
24+
25+
## Licensing
26+
27+
Licensed under the MIT license. See the [LICENSE](LICENSE) file for details.

benches/i386.rs

Lines changed: 91 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
#![allow(deprecated)]
2+
13
use criterion::{black_box, criterion_group, criterion_main, Criterion};
24
use memmem::{Searcher, TwoWaySearcher};
5+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
6+
use sliceslice::x86::avx2::{deprecated::*, *};
37
use std::{
48
fs::{self, File},
59
io::{BufRead, BufReader},
610
};
7-
use strstr::avx2::*;
811

912
fn search_short_haystack(c: &mut Criterion) {
1013
let mut needles = BufReader::new(File::open("data/words.txt").unwrap())
@@ -51,59 +54,64 @@ fn search_short_haystack(c: &mut Criterion) {
5154
});
5255
});
5356

54-
group.bench_function("strstr_avx2_original", |b| {
55-
b.iter(|| {
56-
for (i, needle) in needles.iter().enumerate() {
57-
for haystack in &needles[i..] {
58-
black_box(unsafe {
59-
strstr_avx2_original(haystack.as_bytes(), needle.as_bytes())
60-
});
57+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
58+
{
59+
group.bench_function("strstr_avx2_original", |b| {
60+
b.iter(|| {
61+
for (i, needle) in needles.iter().enumerate() {
62+
for haystack in &needles[i..] {
63+
black_box(unsafe {
64+
strstr_avx2_original(haystack.as_bytes(), needle.as_bytes())
65+
});
66+
}
6167
}
62-
}
68+
});
6369
});
64-
});
6570

66-
group.bench_function("strstr_avx2_rust", |b| {
67-
b.iter(|| {
68-
for (i, needle) in needles.iter().enumerate() {
69-
for haystack in &needles[i..] {
70-
black_box(strstr_avx2_rust(haystack.as_bytes(), needle.as_bytes()));
71+
group.bench_function("strstr_avx2_rust", |b| {
72+
b.iter(|| {
73+
for (i, needle) in needles.iter().enumerate() {
74+
for haystack in &needles[i..] {
75+
black_box(unsafe {
76+
strstr_avx2_rust(haystack.as_bytes(), needle.as_bytes())
77+
});
78+
}
7179
}
72-
}
80+
});
7381
});
74-
});
7582

76-
group.bench_function("StrStrAVX2Searcher::search_in", |b| {
77-
let searchers = needles
78-
.iter()
79-
.map(|&needle| StrStrAVX2Searcher::new(needle.as_bytes()))
80-
.collect::<Vec<_>>();
81-
82-
b.iter(|| {
83-
for (i, searcher) in searchers.iter().enumerate() {
84-
for haystack in &needles[i..] {
85-
black_box(searcher.search_in(haystack.as_bytes()));
83+
group.bench_function("StrStrAVX2Searcher::search_in", |b| {
84+
let searchers = needles
85+
.iter()
86+
.map(|&needle| unsafe { StrStrAVX2Searcher::new(needle.as_bytes()) })
87+
.collect::<Vec<_>>();
88+
89+
b.iter(|| {
90+
for (i, searcher) in searchers.iter().enumerate() {
91+
for haystack in &needles[i..] {
92+
black_box(unsafe { searcher.search_in(haystack.as_bytes()) });
93+
}
8694
}
87-
}
95+
});
8896
});
89-
});
90-
91-
group.bench_function("DynamicAvx2Searcher::search_in", |b| {
92-
let searchers = needles
93-
.iter()
94-
.map(|&needle| unsafe {
95-
DynamicAvx2Searcher::new(needle.as_bytes().to_owned().into_boxed_slice())
96-
})
97-
.collect::<Vec<_>>();
9897

99-
b.iter(|| {
100-
for (i, searcher) in searchers.iter().enumerate() {
101-
for haystack in &needles[i..] {
102-
black_box(searcher.search_in(haystack.as_bytes()));
98+
group.bench_function("DynamicAvx2Searcher::search_in", |b| {
99+
let searchers = needles
100+
.iter()
101+
.map(|&needle| unsafe {
102+
DynamicAvx2Searcher::new(needle.as_bytes().to_owned().into_boxed_slice())
103+
})
104+
.collect::<Vec<_>>();
105+
106+
b.iter(|| {
107+
for (i, searcher) in searchers.iter().enumerate() {
108+
for haystack in &needles[i..] {
109+
black_box(unsafe { searcher.search_in(haystack.as_bytes()) });
110+
}
103111
}
104-
}
112+
});
105113
});
106-
});
114+
}
107115

108116
group.finish();
109117
}
@@ -148,49 +156,54 @@ fn search_long_haystack(c: &mut Criterion) {
148156
});
149157
});
150158

151-
group.bench_function("strstr_avx2_original", |b| {
152-
b.iter(|| {
153-
for needle in &needles {
154-
black_box(unsafe { strstr_avx2_original(haystack.as_bytes(), needle.as_bytes()) });
155-
}
159+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
160+
{
161+
group.bench_function("strstr_avx2_original", |b| {
162+
b.iter(|| {
163+
for needle in &needles {
164+
black_box(unsafe {
165+
strstr_avx2_original(haystack.as_bytes(), needle.as_bytes())
166+
});
167+
}
168+
});
156169
});
157-
});
158170

159-
group.bench_function("strstr_avx2_rust", |b| {
160-
b.iter(|| {
161-
for needle in &needles {
162-
black_box(strstr_avx2_rust(haystack.as_bytes(), needle.as_bytes()));
163-
}
171+
group.bench_function("strstr_avx2_rust", |b| {
172+
b.iter(|| {
173+
for needle in &needles {
174+
black_box(unsafe { strstr_avx2_rust(haystack.as_bytes(), needle.as_bytes()) });
175+
}
176+
});
164177
});
165-
});
166178

167-
group.bench_function("StrStrAVX2Searcher::search_in", |b| {
168-
let searchers = needles
169-
.iter()
170-
.map(|needle| StrStrAVX2Searcher::new(needle.as_bytes()))
171-
.collect::<Vec<_>>();
179+
group.bench_function("StrStrAVX2Searcher::search_in", |b| {
180+
let searchers = needles
181+
.iter()
182+
.map(|needle| unsafe { StrStrAVX2Searcher::new(needle.as_bytes()) })
183+
.collect::<Vec<_>>();
172184

173-
b.iter(|| {
174-
for searcher in &searchers {
175-
black_box(searcher.search_in(haystack.as_bytes()));
176-
}
185+
b.iter(|| {
186+
for searcher in &searchers {
187+
black_box(unsafe { searcher.search_in(haystack.as_bytes()) });
188+
}
189+
});
177190
});
178-
});
179-
180-
group.bench_function("DynamicAvx2Searcher::search_in", |b| {
181-
let searchers = needles
182-
.iter()
183-
.map(|needle| unsafe {
184-
DynamicAvx2Searcher::new(needle.as_bytes().to_owned().into_boxed_slice())
185-
})
186-
.collect::<Vec<_>>();
187191

188-
b.iter(|| {
189-
for searcher in &searchers {
190-
black_box(searcher.search_in(haystack.as_bytes()));
191-
}
192+
group.bench_function("DynamicAvx2Searcher::search_in", |b| {
193+
let searchers = needles
194+
.iter()
195+
.map(|needle| unsafe {
196+
DynamicAvx2Searcher::new(needle.as_bytes().to_owned().into_boxed_slice())
197+
})
198+
.collect::<Vec<_>>();
199+
200+
b.iter(|| {
201+
for searcher in &searchers {
202+
black_box(unsafe { searcher.search_in(haystack.as_bytes()) });
203+
}
204+
});
192205
});
193-
});
206+
}
194207

195208
group.finish();
196209
}

benches/random.rs

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
#![allow(deprecated)]
2+
13
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
24
use memmem::{Searcher, TwoWaySearcher};
3-
use strstr::avx2::*;
5+
use sliceslice::x86::avx2::{deprecated::*, *};
46

57
fn search(c: &mut Criterion) {
68
let haystack = include_str!("../data/haystack");
@@ -44,40 +46,44 @@ fn search(c: &mut Criterion) {
4446
},
4547
);
4648

47-
group.bench_with_input(
48-
BenchmarkId::new("strstr_avx2_original", parameter),
49-
&size,
50-
|b, _| {
51-
b.iter(|| black_box(unsafe { strstr_avx2_original(haystack, needle) }));
52-
},
53-
);
49+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
50+
{
51+
group.bench_with_input(
52+
BenchmarkId::new("strstr_avx2_original", parameter),
53+
&size,
54+
|b, _| {
55+
b.iter(|| black_box(unsafe { strstr_avx2_original(haystack, needle) }));
56+
},
57+
);
5458

55-
group.bench_with_input(
56-
BenchmarkId::new("strstr_avx2_rust", parameter),
57-
&size,
58-
|b, _| {
59-
b.iter(|| black_box(strstr_avx2_rust(haystack, needle)));
60-
},
61-
);
59+
group.bench_with_input(
60+
BenchmarkId::new("strstr_avx2_rust", parameter),
61+
&size,
62+
|b, _| {
63+
b.iter(|| black_box(unsafe { strstr_avx2_rust(haystack, needle) }));
64+
},
65+
);
6266

63-
group.bench_with_input(
64-
BenchmarkId::new("StrStrAVX2Searcher::search_in", parameter),
65-
&size,
66-
|b, _| {
67-
let searcher = StrStrAVX2Searcher::new(needle);
68-
b.iter(|| black_box(searcher.search_in(haystack)));
69-
},
70-
);
67+
group.bench_with_input(
68+
BenchmarkId::new("StrStrAVX2Searcher::search_in", parameter),
69+
&size,
70+
|b, _| {
71+
let searcher = unsafe { StrStrAVX2Searcher::new(needle) };
72+
b.iter(|| black_box(unsafe { searcher.search_in(haystack) }));
73+
},
74+
);
7175

72-
group.bench_with_input(
73-
BenchmarkId::new("DynamicAvx2Searcher::search_in", parameter),
74-
&size,
75-
|b, _| {
76-
let searcher =
77-
unsafe { DynamicAvx2Searcher::new(needle.to_owned().into_boxed_slice()) };
78-
b.iter(|| black_box(searcher.search_in(haystack)));
79-
},
80-
);
76+
group.bench_with_input(
77+
BenchmarkId::new("DynamicAvx2Searcher::search_in", parameter),
78+
&size,
79+
|b, _| {
80+
let searcher = unsafe {
81+
DynamicAvx2Searcher::new(needle.to_owned().into_boxed_slice())
82+
};
83+
b.iter(|| black_box(unsafe { searcher.search_in(haystack) }));
84+
},
85+
);
86+
}
8187
}
8288

8389
group.finish();

src/bits.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#[inline(always)]
1+
#[inline]
22
pub fn clear_leftmost_set(value: u32) -> u32 {
33
value & (value - 1)
44
}

src/lib.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
1-
pub mod avx2;
1+
//! A fast implementation of single-pattern substring search using SIMD acceleration, based on the
2+
//! work [presented by Wojciech Muła](http://0x80.pl/articles/simd-strfind.html). For a
3+
//! fast multi-pattern substring search algorithm, see instead the [`aho-corasick`
4+
//! crate](https://github.com/BurntSushi/aho-corasick).
5+
//!
6+
//! # Example
7+
//!
8+
//! ```
9+
//! use sliceslice::x86::avx2::DynamicAvx2Searcher;
10+
//!
11+
//! let searcher = unsafe { DynamicAvx2Searcher::new(b"ipsum".to_owned().into()) };
12+
//!
13+
//! assert!(unsafe {
14+
//! searcher.search_in(b"Lorem ipsum dolor sit amet, consectetur adipiscing elit")
15+
//! });
16+
//!
17+
//! assert!(!unsafe {
18+
//! searcher.search_in(b"foo bar baz qux quux quuz corge grault garply waldo fred")
19+
//! });
20+
21+
#![allow(deprecated)]
22+
#![warn(missing_docs)]
23+
24+
/// Substring search implementations using the `memchr` function.
225
pub mod memchr;
326

27+
/// Substring search implementations using x86 architecture features.
28+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
29+
pub mod x86;
30+
431
mod bits;
532
mod memcmp;

src/x86/avx2/deprecated/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
mod original;
2+
mod rust;
3+
4+
pub use original::*;
5+
pub use rust::*;

0 commit comments

Comments
 (0)