diff --git a/benches/bench.rs b/benches/bench.rs index 92367fc..e7a0594 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -5,13 +5,16 @@ extern crate bytecount; use rand::Rng; -use bytecount::{count, naive_count, naive_count_32}; +use bytecount::{ + count, naive_count, naive_count_32, + num_chars, naive_num_chars, +}; fn random_bytes(len: usize) -> Vec { rand::thread_rng().gen_iter::().take(len).collect::>() } -macro_rules! bench { +macro_rules! bench_count { ($i: expr, $name_naive: ident, $name_32: ident, $name_hyper: ident) => { fn $name_naive(b: &mut bencher::Bencher) { let haystack = random_bytes($i); @@ -30,105 +33,206 @@ macro_rules! bench { }; } -bench!(0, bench_00000_naive, bench_00000_32, bench_00000_hyper); -bench!(10, bench_00010_naive, bench_00010_32, bench_00010_hyper); -bench!(20, bench_00020_naive, bench_00020_32, bench_00020_hyper); -bench!(30, bench_00030_naive, bench_00030_32, bench_00030_hyper); - -bench!(40, bench_00040_naive, bench_00040_32, bench_00040_hyper); -bench!(50, bench_00050_naive, bench_00050_32, bench_00050_hyper); -bench!(60, bench_00060_naive, bench_00060_32, bench_00060_hyper); -bench!(70, bench_00070_naive, bench_00070_32, bench_00070_hyper); -bench!(80, bench_00080_naive, bench_00080_32, bench_00080_hyper); -bench!(90, bench_00090_naive, bench_00090_32, bench_00090_hyper); -bench!(100, bench_00100_naive, bench_00100_32, bench_00100_hyper); -bench!(120, bench_00120_naive, bench_00120_32, bench_00120_hyper); -bench!(140, bench_00140_naive, bench_00140_32, bench_00140_hyper); -bench!(170, bench_00170_naive, bench_00170_32, bench_00170_hyper); -bench!(210, bench_00210_naive, bench_00210_32, bench_00210_hyper); -bench!(250, bench_00250_naive, bench_00250_32, bench_00250_hyper); -bench!(300, bench_00300_naive, bench_00300_32, bench_00300_hyper); - -bench!(400, bench_00400_naive, bench_00400_32, bench_00400_hyper); -bench!(500, bench_00500_naive, bench_00500_32, bench_00500_hyper); -bench!(600, bench_00600_naive, bench_00600_32, bench_00600_hyper); -bench!(700, bench_00700_naive, bench_00700_32, bench_00700_hyper); -bench!(800, bench_00800_naive, bench_00800_32, bench_00800_hyper); -bench!(900, bench_00900_naive, bench_00900_32, bench_00900_hyper); -bench!(1_000, bench_01000_naive, bench_01000_32, bench_01000_hyper); -bench!(1_200, bench_01200_naive, bench_01200_32, bench_01200_hyper); -bench!(1_400, bench_01400_naive, bench_01400_32, bench_01400_hyper); -bench!(1_700, bench_01700_naive, bench_01700_32, bench_01700_hyper); -bench!(2_100, bench_02100_naive, bench_02100_32, bench_02100_hyper); -bench!(2_500, bench_02500_naive, bench_02500_32, bench_02500_hyper); -bench!(3_000, bench_03000_naive, bench_03000_32, bench_03000_hyper); - -bench!(4_000, bench_04000_naive, bench_04000_32, bench_04000_hyper); -bench!(5_000, bench_05000_naive, bench_05000_32, bench_05000_hyper); -bench!(6_000, bench_06000_naive, bench_06000_32, bench_06000_hyper); -bench!(7_000, bench_07000_naive, bench_07000_32, bench_07000_hyper); -bench!(8_000, bench_08000_naive, bench_08000_32, bench_08000_hyper); -bench!(9_000, bench_09000_naive, bench_09000_32, bench_09000_hyper); -bench!(10_000, bench_10000_naive, bench_10000_32, bench_10000_hyper); -bench!(12_000, bench_12000_naive, bench_12000_32, bench_12000_hyper); -bench!(14_000, bench_14000_naive, bench_14000_32, bench_14000_hyper); -bench!(17_000, bench_17000_naive, bench_17000_32, bench_17000_hyper); -bench!(21_000, bench_21000_naive, bench_21000_32, bench_21000_hyper); -bench!(25_000, bench_25000_naive, bench_25000_32, bench_25000_hyper); -bench!(30_000, bench_30000_naive, bench_30000_32, bench_30000_hyper); - -bench!(100_000, bench_big_0100000_naive, bench_big_0100000_32, bench_big_0100000_hyper); -bench!(1_000_000, bench_big_1000000_naive, bench_big_1000000_32, bench_big_1000000_hyper); - -benchmark_group!(bench, - bench_00000_naive, bench_00000_32, bench_00000_hyper, - bench_00010_naive, bench_00010_32, bench_00010_hyper, - bench_00020_naive, bench_00020_32, bench_00020_hyper, - bench_00030_naive, bench_00030_32, bench_00030_hyper, - - bench_00040_naive, bench_00040_32, bench_00040_hyper, - bench_00050_naive, bench_00050_32, bench_00050_hyper, - bench_00060_naive, bench_00060_32, bench_00060_hyper, - bench_00070_naive, bench_00070_32, bench_00070_hyper, - bench_00080_naive, bench_00080_32, bench_00080_hyper, - bench_00090_naive, bench_00090_32, bench_00090_hyper, - bench_00100_naive, bench_00100_32, bench_00100_hyper, - bench_00120_naive, bench_00120_32, bench_00120_hyper, - bench_00140_naive, bench_00140_32, bench_00140_hyper, - bench_00170_naive, bench_00170_32, bench_00170_hyper, - bench_00210_naive, bench_00210_32, bench_00210_hyper, - bench_00250_naive, bench_00250_32, bench_00250_hyper, - bench_00300_naive, bench_00300_32, bench_00300_hyper, - - bench_00400_naive, bench_00400_32, bench_00400_hyper, - bench_00500_naive, bench_00500_32, bench_00500_hyper, - bench_00600_naive, bench_00600_32, bench_00600_hyper, - bench_00700_naive, bench_00700_32, bench_00700_hyper, - bench_00800_naive, bench_00800_32, bench_00800_hyper, - bench_00900_naive, bench_00900_32, bench_00900_hyper, - bench_01000_naive, bench_01000_32, bench_01000_hyper, - bench_01200_naive, bench_01200_32, bench_01200_hyper, - bench_01400_naive, bench_01400_32, bench_01400_hyper, - bench_01700_naive, bench_01700_32, bench_01700_hyper, - bench_02100_naive, bench_02100_32, bench_02100_hyper, - bench_02500_naive, bench_02500_32, bench_02500_hyper, - bench_03000_naive, bench_03000_32, bench_03000_hyper, - - bench_04000_naive, bench_04000_32, bench_04000_hyper, - bench_05000_naive, bench_05000_32, bench_05000_hyper, - bench_06000_naive, bench_06000_32, bench_06000_hyper, - bench_07000_naive, bench_07000_32, bench_07000_hyper, - bench_08000_naive, bench_08000_32, bench_08000_hyper, - bench_09000_naive, bench_09000_32, bench_09000_hyper, - bench_10000_naive, bench_10000_32, bench_10000_hyper, - bench_12000_naive, bench_12000_32, bench_12000_hyper, - bench_14000_naive, bench_14000_32, bench_14000_hyper, - bench_17000_naive, bench_17000_32, bench_17000_hyper, - bench_21000_naive, bench_21000_32, bench_21000_hyper, - bench_25000_naive, bench_25000_32, bench_25000_hyper, - bench_30000_naive, bench_30000_32, bench_30000_hyper, - - bench_big_0100000_naive, bench_big_0100000_32, bench_big_0100000_hyper, - bench_big_1000000_naive, bench_big_1000000_32, bench_big_1000000_hyper); - -benchmark_main!(bench); +macro_rules! bench_num_chars { + ($i: expr, $name_naive: ident, $name_hyper: ident) => { + fn $name_naive(b: &mut bencher::Bencher) { + let haystack = random_bytes($i); + b.iter(|| naive_num_chars(&haystack)); + } + + fn $name_hyper(b: &mut bencher::Bencher) { + let haystack = random_bytes($i); + b.iter(|| num_chars(&haystack)); + } + }; +} + +bench_count!(0, bench_count_00000_naive, bench_count_00000_32, bench_count_00000_hyper); +bench_count!(10, bench_count_00010_naive, bench_count_00010_32, bench_count_00010_hyper); +bench_count!(20, bench_count_00020_naive, bench_count_00020_32, bench_count_00020_hyper); +bench_count!(30, bench_count_00030_naive, bench_count_00030_32, bench_count_00030_hyper); + +bench_count!(40, bench_count_00040_naive, bench_count_00040_32, bench_count_00040_hyper); +bench_count!(50, bench_count_00050_naive, bench_count_00050_32, bench_count_00050_hyper); +bench_count!(60, bench_count_00060_naive, bench_count_00060_32, bench_count_00060_hyper); +bench_count!(70, bench_count_00070_naive, bench_count_00070_32, bench_count_00070_hyper); +bench_count!(80, bench_count_00080_naive, bench_count_00080_32, bench_count_00080_hyper); +bench_count!(90, bench_count_00090_naive, bench_count_00090_32, bench_count_00090_hyper); +bench_count!(100, bench_count_00100_naive, bench_count_00100_32, bench_count_00100_hyper); +bench_count!(120, bench_count_00120_naive, bench_count_00120_32, bench_count_00120_hyper); +bench_count!(140, bench_count_00140_naive, bench_count_00140_32, bench_count_00140_hyper); +bench_count!(170, bench_count_00170_naive, bench_count_00170_32, bench_count_00170_hyper); +bench_count!(210, bench_count_00210_naive, bench_count_00210_32, bench_count_00210_hyper); +bench_count!(250, bench_count_00250_naive, bench_count_00250_32, bench_count_00250_hyper); +bench_count!(300, bench_count_00300_naive, bench_count_00300_32, bench_count_00300_hyper); + +bench_count!(400, bench_count_00400_naive, bench_count_00400_32, bench_count_00400_hyper); +bench_count!(500, bench_count_00500_naive, bench_count_00500_32, bench_count_00500_hyper); +bench_count!(600, bench_count_00600_naive, bench_count_00600_32, bench_count_00600_hyper); +bench_count!(700, bench_count_00700_naive, bench_count_00700_32, bench_count_00700_hyper); +bench_count!(800, bench_count_00800_naive, bench_count_00800_32, bench_count_00800_hyper); +bench_count!(900, bench_count_00900_naive, bench_count_00900_32, bench_count_00900_hyper); +bench_count!(1_000, bench_count_01000_naive, bench_count_01000_32, bench_count_01000_hyper); +bench_count!(1_200, bench_count_01200_naive, bench_count_01200_32, bench_count_01200_hyper); +bench_count!(1_400, bench_count_01400_naive, bench_count_01400_32, bench_count_01400_hyper); +bench_count!(1_700, bench_count_01700_naive, bench_count_01700_32, bench_count_01700_hyper); +bench_count!(2_100, bench_count_02100_naive, bench_count_02100_32, bench_count_02100_hyper); +bench_count!(2_500, bench_count_02500_naive, bench_count_02500_32, bench_count_02500_hyper); +bench_count!(3_000, bench_count_03000_naive, bench_count_03000_32, bench_count_03000_hyper); + +bench_count!(4_000, bench_count_04000_naive, bench_count_04000_32, bench_count_04000_hyper); +bench_count!(5_000, bench_count_05000_naive, bench_count_05000_32, bench_count_05000_hyper); +bench_count!(6_000, bench_count_06000_naive, bench_count_06000_32, bench_count_06000_hyper); +bench_count!(7_000, bench_count_07000_naive, bench_count_07000_32, bench_count_07000_hyper); +bench_count!(8_000, bench_count_08000_naive, bench_count_08000_32, bench_count_08000_hyper); +bench_count!(9_000, bench_count_09000_naive, bench_count_09000_32, bench_count_09000_hyper); +bench_count!(10_000, bench_count_10000_naive, bench_count_10000_32, bench_count_10000_hyper); +bench_count!(12_000, bench_count_12000_naive, bench_count_12000_32, bench_count_12000_hyper); +bench_count!(14_000, bench_count_14000_naive, bench_count_14000_32, bench_count_14000_hyper); +bench_count!(17_000, bench_count_17000_naive, bench_count_17000_32, bench_count_17000_hyper); +bench_count!(21_000, bench_count_21000_naive, bench_count_21000_32, bench_count_21000_hyper); +bench_count!(25_000, bench_count_25000_naive, bench_count_25000_32, bench_count_25000_hyper); +bench_count!(30_000, bench_count_30000_naive, bench_count_30000_32, bench_count_30000_hyper); + +bench_count!(100_000, bench_count_big_0100000_naive, bench_count_big_0100000_32, bench_count_big_0100000_hyper); +bench_count!(1_000_000, bench_count_big_1000000_naive, bench_count_big_1000000_32, bench_count_big_1000000_hyper); + +benchmark_group!(bench_count_naive, + bench_count_00000_naive, bench_count_00010_naive, bench_count_00020_naive, + bench_count_00030_naive, bench_count_00040_naive, bench_count_00050_naive, + bench_count_00060_naive, bench_count_00070_naive, bench_count_00080_naive, + bench_count_00090_naive, bench_count_00100_naive, bench_count_00120_naive, + bench_count_00140_naive, bench_count_00170_naive, bench_count_00210_naive, + bench_count_00250_naive, bench_count_00300_naive, bench_count_00400_naive, + bench_count_00500_naive, bench_count_00600_naive, bench_count_00700_naive, + bench_count_00800_naive, bench_count_00900_naive, bench_count_01000_naive, + bench_count_01200_naive, bench_count_01400_naive, bench_count_01700_naive, + bench_count_02100_naive, bench_count_02500_naive, bench_count_03000_naive, + bench_count_04000_naive, bench_count_05000_naive, bench_count_06000_naive, + bench_count_07000_naive, bench_count_08000_naive, bench_count_09000_naive, + bench_count_10000_naive, bench_count_12000_naive, bench_count_14000_naive, + bench_count_17000_naive, bench_count_21000_naive, bench_count_25000_naive, + bench_count_30000_naive, bench_count_big_0100000_naive, bench_count_big_1000000_naive); + +benchmark_group!(bench_count_32, + bench_count_00000_32, bench_count_00010_32, bench_count_00020_32, + bench_count_00030_32, bench_count_00040_32, bench_count_00050_32, + bench_count_00060_32, bench_count_00070_32, bench_count_00080_32, + bench_count_00090_32, bench_count_00100_32, bench_count_00120_32, + bench_count_00140_32, bench_count_00170_32, bench_count_00210_32, + bench_count_00250_32, bench_count_00300_32, bench_count_00400_32, + bench_count_00500_32, bench_count_00600_32, bench_count_00700_32, + bench_count_00800_32, bench_count_00900_32, bench_count_01000_32, + bench_count_01200_32, bench_count_01400_32, bench_count_01700_32, + bench_count_02100_32, bench_count_02500_32, bench_count_03000_32, + bench_count_04000_32, bench_count_05000_32, bench_count_06000_32, + bench_count_07000_32, bench_count_08000_32, bench_count_09000_32, + bench_count_10000_32, bench_count_12000_32, bench_count_14000_32, + bench_count_17000_32, bench_count_21000_32, bench_count_25000_32, + bench_count_30000_32, bench_count_big_0100000_32, bench_count_big_1000000_32); + +benchmark_group!(bench_count_hyper, + bench_count_00000_hyper, bench_count_00010_hyper, bench_count_00020_hyper, + bench_count_00030_hyper, bench_count_00040_hyper, bench_count_00050_hyper, + bench_count_00060_hyper, bench_count_00070_hyper, bench_count_00080_hyper, + bench_count_00090_hyper, bench_count_00100_hyper, bench_count_00120_hyper, + bench_count_00140_hyper, bench_count_00170_hyper, bench_count_00210_hyper, + bench_count_00250_hyper, bench_count_00300_hyper, bench_count_00400_hyper, + bench_count_00500_hyper, bench_count_00600_hyper, bench_count_00700_hyper, + bench_count_00800_hyper, bench_count_00900_hyper, bench_count_01000_hyper, + bench_count_01200_hyper, bench_count_01400_hyper, bench_count_01700_hyper, + bench_count_02100_hyper, bench_count_02500_hyper, bench_count_03000_hyper, + bench_count_04000_hyper, bench_count_05000_hyper, bench_count_06000_hyper, + bench_count_07000_hyper, bench_count_08000_hyper, bench_count_09000_hyper, + bench_count_10000_hyper, bench_count_12000_hyper, bench_count_14000_hyper, + bench_count_17000_hyper, bench_count_21000_hyper, bench_count_25000_hyper, + bench_count_30000_hyper, bench_count_big_0100000_hyper, bench_count_big_1000000_hyper); + +bench_num_chars!(0, bench_num_chars_00000_naive, bench_num_chars_00000_hyper); +bench_num_chars!(10, bench_num_chars_00010_naive, bench_num_chars_00010_hyper); +bench_num_chars!(20, bench_num_chars_00020_naive, bench_num_chars_00020_hyper); +bench_num_chars!(30, bench_num_chars_00030_naive, bench_num_chars_00030_hyper); + +bench_num_chars!(40, bench_num_chars_00040_naive, bench_num_chars_00040_hyper); +bench_num_chars!(50, bench_num_chars_00050_naive, bench_num_chars_00050_hyper); +bench_num_chars!(60, bench_num_chars_00060_naive, bench_num_chars_00060_hyper); +bench_num_chars!(70, bench_num_chars_00070_naive, bench_num_chars_00070_hyper); +bench_num_chars!(80, bench_num_chars_00080_naive, bench_num_chars_00080_hyper); +bench_num_chars!(90, bench_num_chars_00090_naive, bench_num_chars_00090_hyper); +bench_num_chars!(100, bench_num_chars_00100_naive, bench_num_chars_00100_hyper); +bench_num_chars!(120, bench_num_chars_00120_naive, bench_num_chars_00120_hyper); +bench_num_chars!(140, bench_num_chars_00140_naive, bench_num_chars_00140_hyper); +bench_num_chars!(170, bench_num_chars_00170_naive, bench_num_chars_00170_hyper); +bench_num_chars!(210, bench_num_chars_00210_naive, bench_num_chars_00210_hyper); +bench_num_chars!(250, bench_num_chars_00250_naive, bench_num_chars_00250_hyper); +bench_num_chars!(300, bench_num_chars_00300_naive, bench_num_chars_00300_hyper); + +bench_num_chars!(400, bench_num_chars_00400_naive, bench_num_chars_00400_hyper); +bench_num_chars!(500, bench_num_chars_00500_naive, bench_num_chars_00500_hyper); +bench_num_chars!(600, bench_num_chars_00600_naive, bench_num_chars_00600_hyper); +bench_num_chars!(700, bench_num_chars_00700_naive, bench_num_chars_00700_hyper); +bench_num_chars!(800, bench_num_chars_00800_naive, bench_num_chars_00800_hyper); +bench_num_chars!(900, bench_num_chars_00900_naive, bench_num_chars_00900_hyper); +bench_num_chars!(1_000, bench_num_chars_01000_naive, bench_num_chars_01000_hyper); +bench_num_chars!(1_200, bench_num_chars_01200_naive, bench_num_chars_01200_hyper); +bench_num_chars!(1_400, bench_num_chars_01400_naive, bench_num_chars_01400_hyper); +bench_num_chars!(1_700, bench_num_chars_01700_naive, bench_num_chars_01700_hyper); +bench_num_chars!(2_100, bench_num_chars_02100_naive, bench_num_chars_02100_hyper); +bench_num_chars!(2_500, bench_num_chars_02500_naive, bench_num_chars_02500_hyper); +bench_num_chars!(3_000, bench_num_chars_03000_naive, bench_num_chars_03000_hyper); + +bench_num_chars!(4_000, bench_num_chars_04000_naive, bench_num_chars_04000_hyper); +bench_num_chars!(5_000, bench_num_chars_05000_naive, bench_num_chars_05000_hyper); +bench_num_chars!(6_000, bench_num_chars_06000_naive, bench_num_chars_06000_hyper); +bench_num_chars!(7_000, bench_num_chars_07000_naive, bench_num_chars_07000_hyper); +bench_num_chars!(8_000, bench_num_chars_08000_naive, bench_num_chars_08000_hyper); +bench_num_chars!(9_000, bench_num_chars_09000_naive, bench_num_chars_09000_hyper); +bench_num_chars!(10_000, bench_num_chars_10000_naive, bench_num_chars_10000_hyper); +bench_num_chars!(12_000, bench_num_chars_12000_naive, bench_num_chars_12000_hyper); +bench_num_chars!(14_000, bench_num_chars_14000_naive, bench_num_chars_14000_hyper); +bench_num_chars!(17_000, bench_num_chars_17000_naive, bench_num_chars_17000_hyper); +bench_num_chars!(21_000, bench_num_chars_21000_naive, bench_num_chars_21000_hyper); +bench_num_chars!(25_000, bench_num_chars_25000_naive, bench_num_chars_25000_hyper); +bench_num_chars!(30_000, bench_num_chars_30000_naive, bench_num_chars_30000_hyper); + +bench_num_chars!(100_000, bench_num_chars_big_0100000_naive, bench_num_chars_big_0100000_hyper); +bench_num_chars!(1_000_000, bench_num_chars_big_1000000_naive, bench_num_chars_big_1000000_hyper); + +benchmark_group!(bench_num_chars_naive, + bench_num_chars_00000_naive, bench_num_chars_00010_naive, bench_num_chars_00020_naive, + bench_num_chars_00030_naive, bench_num_chars_00040_naive, bench_num_chars_00050_naive, + bench_num_chars_00060_naive, bench_num_chars_00070_naive, bench_num_chars_00080_naive, + bench_num_chars_00090_naive, bench_num_chars_00100_naive, bench_num_chars_00120_naive, + bench_num_chars_00140_naive, bench_num_chars_00170_naive, bench_num_chars_00210_naive, + bench_num_chars_00250_naive, bench_num_chars_00300_naive, bench_num_chars_00400_naive, + bench_num_chars_00500_naive, bench_num_chars_00600_naive, bench_num_chars_00700_naive, + bench_num_chars_00800_naive, bench_num_chars_00900_naive, bench_num_chars_01000_naive, + bench_num_chars_01200_naive, bench_num_chars_01400_naive, bench_num_chars_01700_naive, + bench_num_chars_02100_naive, bench_num_chars_02500_naive, bench_num_chars_03000_naive, + bench_num_chars_04000_naive, bench_num_chars_05000_naive, bench_num_chars_06000_naive, + bench_num_chars_07000_naive, bench_num_chars_08000_naive, bench_num_chars_09000_naive, + bench_num_chars_10000_naive, bench_num_chars_12000_naive, bench_num_chars_14000_naive, + bench_num_chars_17000_naive, bench_num_chars_21000_naive, bench_num_chars_25000_naive, + bench_num_chars_30000_naive, bench_num_chars_big_0100000_naive, bench_num_chars_big_1000000_naive); + +benchmark_group!(bench_num_chars_hyper, + bench_num_chars_00000_hyper, bench_num_chars_00010_hyper, bench_num_chars_00020_hyper, + bench_num_chars_00030_hyper, bench_num_chars_00040_hyper, bench_num_chars_00050_hyper, + bench_num_chars_00060_hyper, bench_num_chars_00070_hyper, bench_num_chars_00080_hyper, + bench_num_chars_00090_hyper, bench_num_chars_00100_hyper, bench_num_chars_00120_hyper, + bench_num_chars_00140_hyper, bench_num_chars_00170_hyper, bench_num_chars_00210_hyper, + bench_num_chars_00250_hyper, bench_num_chars_00300_hyper, bench_num_chars_00400_hyper, + bench_num_chars_00500_hyper, bench_num_chars_00600_hyper, bench_num_chars_00700_hyper, + bench_num_chars_00800_hyper, bench_num_chars_00900_hyper, bench_num_chars_01000_hyper, + bench_num_chars_01200_hyper, bench_num_chars_01400_hyper, bench_num_chars_01700_hyper, + bench_num_chars_02100_hyper, bench_num_chars_02500_hyper, bench_num_chars_03000_hyper, + bench_num_chars_04000_hyper, bench_num_chars_05000_hyper, bench_num_chars_06000_hyper, + bench_num_chars_07000_hyper, bench_num_chars_08000_hyper, bench_num_chars_09000_hyper, + bench_num_chars_10000_hyper, bench_num_chars_12000_hyper, bench_num_chars_14000_hyper, + bench_num_chars_17000_hyper, bench_num_chars_21000_hyper, bench_num_chars_25000_hyper, + bench_num_chars_30000_hyper, bench_num_chars_big_0100000_hyper, bench_num_chars_big_1000000_hyper); + +benchmark_main!( + bench_count_naive, bench_count_32, bench_count_hyper, + bench_num_chars_naive, bench_num_chars_hyper +); diff --git a/src/lib.rs b/src/lib.rs index d11b8fc..96fdb45 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ trait ByteChunk: Copy { fn splat(byte: u8) -> Self::Splat; fn from_splat(splat: Self::Splat) -> Self; fn bytewise_equal(self, other: Self::Splat) -> Self; + fn mask(self, other: Self::Splat) -> Self; fn increment(self, incr: Self) -> Self; fn sum(&self) -> usize; } @@ -36,6 +37,10 @@ impl ByteChunk for usize { splat } + fn mask(self, other: Self) -> Self { + self & other + } + fn bytewise_equal(self, other: Self) -> Self { let lo = usize::MAX / 0xFF; let hi = lo << 7; @@ -72,6 +77,10 @@ impl ByteChunk for u8x16 { splat } + fn mask(self, other: Self) -> Self { + self & other + } + fn bytewise_equal(self, other: Self) -> Self { self.eq(other).to_repr().to_u8() } @@ -102,6 +111,10 @@ impl ByteChunk for u8x32 { splat } + fn mask(self, other: Self) -> Self { + self & other + } + fn bytewise_equal(self, other: Self) -> Self { self.eq(other).to_repr().to_u8() } @@ -136,6 +149,13 @@ impl ByteChunk for [T; 4] [splat, splat, splat, splat] } + fn mask(mut self, other: Self::Splat) -> Self { + for t in self[..].iter_mut() { + *t = t.mask(other); + } + self + } + fn bytewise_equal(mut self, needles: Self::Splat) -> Self { for t in self[..].iter_mut() { *t = t.bytewise_equal(needles); @@ -274,3 +294,99 @@ pub fn naive_count_32(haystack: &[u8], needle: u8) -> usize { pub fn naive_count(haystack: &[u8], needle: u8) -> usize { haystack.iter().fold(0, |n, c| n + (*c == needle) as usize) } + + +fn chunk_num_chars(haystack: &[Chunk]) -> usize { + let zero = Chunk::splat(0); + let needles = Chunk::splat(0b10_000000); + let mask = Chunk::splat(0b11_000000); + let mut count = 0; + let mut i = 0; + + while i < haystack.len() { + let mut counts = Chunk::from_splat(zero); + + let end = cmp::min(i + 255, haystack.len()); + for &chunk in &haystack[i..end] { + counts = counts.increment(chunk.mask(mask).bytewise_equal(needles)); + } + i = end; + + count += counts.sum(); + } + + count +} + +fn num_chars_generic>(naive_below: usize, + group_above: usize, + haystack: &[u8]) + -> usize { + // Extract pre/post so naive_count is only inlined once. + let len = haystack.len(); + let mut count = len; + let unchunked = if len < naive_below { + [haystack, &haystack[0..0]] + } else if len > group_above { + let (pre, mid, post) = chunk_align::<[Chunk; 4]>(haystack); + count -= chunk_num_chars(mid); + [pre, post] + } else { + let (pre, mid, post) = chunk_align::(haystack); + count -= chunk_num_chars(mid); + [pre, post] + }; + + for &slice in &unchunked { + count -= slice.len(); + count += naive_num_chars(slice); + } + + count +} + + +/// Count the number of UTF-8 encoded unicode codepoints in a slice of bytes, fast +/// +/// This function is safe to use on any byte array, valid UTF-8 or not, +/// but the output is only meaningful for well-formed UTF-8. +/// +/// # Example +/// +/// ``` +/// let swordfish = "メカジキ"; +/// let char_count = bytecount::naive_num_chars(swordfish.as_bytes()); +/// assert_eq!(char_count, 4); +/// ``` +#[cfg(not(feature = "simd-accel"))] +pub fn num_chars(haystack: &[u8]) -> usize { + // Never use [usize; 4] + num_chars_generic::(32, usize::MAX, haystack) +} + +#[cfg(all(feature = "simd-accel", not(feature = "avx-accel")))] +pub fn num_chars(haystack: &[u8]) -> usize { + num_chars_generic::(32, 4096, haystack) +} + +#[cfg(feature = "avx-accel")] +pub fn num_chars(haystack: &[u8]) -> usize { + num_chars_generic::(64, 4096, haystack) +} + +/// Count the number of UTF-8 encoded unicode codepoints in a slice of bytes, simple +/// +/// This function is safe to use on any byte array, valid UTF-8 or not, +/// but the output is only meaningful for well-formed UTF-8. +/// +/// # Example +/// +/// ``` +/// let swordfish = "メカジキ"; +/// let char_count = bytecount::naive_num_chars(swordfish.as_bytes()); +/// assert_eq!(char_count, 4); +/// ``` +pub fn naive_num_chars(haystack: &[u8]) -> usize { + haystack.iter().filter(|&&byte| (byte >> 6) != 0b10).count() +} + diff --git a/tests/check.rs b/tests/check.rs index aff8d68..819a530 100644 --- a/tests/check.rs +++ b/tests/check.rs @@ -4,7 +4,10 @@ extern crate quickcheck; extern crate rand; use std::iter; -use bytecount::{count, naive_count}; +use bytecount::{ + count, naive_count, + num_chars, naive_num_chars, +}; use rand::Rng; fn random_bytes(len: usize) -> Vec { @@ -12,21 +15,21 @@ fn random_bytes(len: usize) -> Vec { } quickcheck! { - fn check_counts_correctly(x: (Vec, u8)) -> bool { + fn check_count_correct(x: (Vec, u8)) -> bool { let (haystack, needle) = x; - count(&haystack.clone(), needle) == naive_count(&haystack, needle) + count(&haystack, needle) == naive_count(&haystack, needle) } } #[test] -fn check_large() { +fn check_count_large() { let haystack = vec![0u8; 10_000_000]; assert_eq!(naive_count(&haystack, 0), count(&haystack, 0)); assert_eq!(naive_count(&haystack, 1), count(&haystack, 1)); } #[test] -fn check_large_rand() { +fn check_count_large_rand() { let haystack = random_bytes(100_000); for i in (0..255).chain(iter::once(255)) { assert_eq!(naive_count(&haystack, i), count(&haystack, i)); @@ -34,16 +37,40 @@ fn check_large_rand() { } #[test] -fn check_some() { +fn check_count_some() { let haystack = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68]; let needle = 68; assert_eq!(count(&haystack, needle), naive_count(&haystack, needle)); } #[test] -fn check_overflow() { +fn check_count_overflow() { let haystack = vec![0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; let needle = 2; - assert_eq!(count(&haystack[0..], needle), - naive_count(&haystack[0..], needle)); + assert_eq!(count(&haystack, needle), naive_count(&haystack, needle)); +} + +quickcheck! { + fn check_num_chars_correct(haystack: Vec) -> bool { + num_chars(&haystack) == naive_num_chars(&haystack) + } +} + +#[test] +fn check_num_chars_large() { + let haystack = vec![0u8; 10_000_000]; + assert_eq!(naive_num_chars(&haystack), num_chars(&haystack)); + assert_eq!(naive_num_chars(&haystack), num_chars(&haystack)); +} + +#[test] +fn check_num_chars_some() { + let haystack = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68]; + assert_eq!(num_chars(&haystack), naive_num_chars(&haystack)); +} + +#[test] +fn check_num_chars_overflow() { + let haystack = vec![0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + assert_eq!(num_chars(&haystack), naive_num_chars(&haystack)); }