/rust/registry/src/index.crates.io-1949cf8c6b5b557f/bytecount-0.6.9/src/lib.rs
Line | Count | Source |
1 | | //! count occurrences of a given byte, or the number of UTF-8 code points, in a |
2 | | //! byte slice, fast. |
3 | | //! |
4 | | //! This crate has the [`count`](fn.count.html) method to count byte |
5 | | //! occurrences (for example newlines) in a larger `&[u8]` slice. |
6 | | //! |
7 | | //! For example: |
8 | | //! |
9 | | //! ```rust |
10 | | //! assert_eq!(5, bytecount::count(b"Hello, this is the bytecount crate!", b' ')); |
11 | | //! ``` |
12 | | //! |
13 | | //! Also there is a [`num_chars`](fn.num_chars.html) method to count |
14 | | //! the number of UTF8 characters in a slice. It will work the same as |
15 | | //! `str::chars().count()` for byte slices of correct UTF-8 character |
16 | | //! sequences. The result will likely be off for invalid sequences, |
17 | | //! although the result is guaranteed to be between `0` and |
18 | | //! `[_]::len()`, inclusive. |
19 | | //! |
20 | | //! Example: |
21 | | //! |
22 | | //! ```rust |
23 | | //! let sequence = "Wenn ich ein Vöglein wär, flög ich zu Dir!"; |
24 | | //! assert_eq!(sequence.chars().count(), |
25 | | //! bytecount::num_chars(sequence.as_bytes())); |
26 | | //! ``` |
27 | | //! |
28 | | //! For completeness and easy comparison, the "naive" versions of both |
29 | | //! count and num_chars are provided. Those are also faster if used on |
30 | | //! predominantly small strings. The |
31 | | //! [`naive_count_32`](fn.naive_count_32.html) method can be faster |
32 | | //! still on small strings. |
33 | | |
34 | | #![cfg_attr(feature = "generic-simd", feature(portable_simd))] |
35 | | #![deny(missing_docs)] |
36 | | #![cfg_attr(not(feature = "runtime-dispatch-simd"), no_std)] |
37 | | |
38 | | #[cfg(not(feature = "runtime-dispatch-simd"))] |
39 | | use core::mem; |
40 | | #[cfg(feature = "runtime-dispatch-simd")] |
41 | | use std::mem; |
42 | | |
43 | | mod naive; |
44 | | pub use naive::*; |
45 | | mod integer_simd; |
46 | | |
47 | | #[cfg(any( |
48 | | all( |
49 | | feature = "runtime-dispatch-simd", |
50 | | any(target_arch = "x86", target_arch = "x86_64") |
51 | | ), |
52 | | all(target_arch = "aarch64", target_endian = "little"), |
53 | | target_arch = "wasm32", |
54 | | feature = "generic-simd" |
55 | | ))] |
56 | | mod simd; |
57 | | |
58 | | /// Count occurrences of a byte in a slice of bytes, fast |
59 | | /// |
60 | | /// # Examples |
61 | | /// |
62 | | /// ``` |
63 | | /// let s = b"This is a Text with spaces"; |
64 | | /// let number_of_spaces = bytecount::count(s, b' '); |
65 | | /// assert_eq!(number_of_spaces, 5); |
66 | | /// ``` |
67 | 97.6k | pub fn count(haystack: &[u8], needle: u8) -> usize { |
68 | 97.6k | if haystack.len() >= 32 { |
69 | 54.2k | #[cfg(all(feature = "runtime-dispatch-simd", target_arch = "x86_64"))] |
70 | 54.2k | { |
71 | 54.2k | if is_x86_feature_detected!("avx2") { |
72 | 54.2k | unsafe { |
73 | 54.2k | return simd::x86_avx2::chunk_count(haystack, needle); |
74 | 54.2k | } |
75 | 54.2k | } |
76 | 54.2k | } |
77 | 54.2k | |
78 | 54.2k | #[cfg(feature = "generic-simd")] |
79 | 54.2k | return simd::generic::chunk_count(haystack, needle); |
80 | 54.2k | } |
81 | | |
82 | 97.6k | if haystack.len() >= 16 { |
83 | 64.5k | #[cfg(all( |
84 | 64.5k | feature = "runtime-dispatch-simd", |
85 | 64.5k | any(target_arch = "x86", target_arch = "x86_64"), |
86 | 64.5k | not(feature = "generic-simd") |
87 | 64.5k | ))] |
88 | 64.5k | { |
89 | 64.5k | if is_x86_feature_detected!("sse2") { |
90 | 64.5k | unsafe { |
91 | 64.5k | return simd::x86_sse2::chunk_count(haystack, needle); |
92 | 64.5k | } |
93 | 64.5k | } |
94 | 64.5k | } |
95 | 64.5k | #[cfg(all( |
96 | 64.5k | target_arch = "aarch64", |
97 | 64.5k | target_endian = "little", |
98 | 64.5k | not(feature = "generic-simd") |
99 | 64.5k | ))] |
100 | 64.5k | { |
101 | 64.5k | unsafe { |
102 | 64.5k | return simd::aarch64::chunk_count(haystack, needle); |
103 | 64.5k | } |
104 | 64.5k | } |
105 | 64.5k | |
106 | 64.5k | #[cfg(target_arch = "wasm32")] |
107 | 64.5k | { |
108 | 64.5k | unsafe { |
109 | 64.5k | return simd::wasm::chunk_count(haystack, needle); |
110 | 64.5k | } |
111 | 64.5k | } |
112 | 64.5k | } |
113 | | |
114 | 97.6k | if haystack.len() >= mem::size_of::<usize>() { |
115 | 86.3k | return integer_simd::chunk_count(haystack, needle); |
116 | 11.2k | } |
117 | | |
118 | 11.2k | naive_count(haystack, needle) |
119 | 97.6k | } |
120 | | |
121 | | /// Count the number of UTF-8 encoded Unicode codepoints in a slice of bytes, fast |
122 | | /// |
123 | | /// This function is safe to use on any byte array, valid UTF-8 or not, |
124 | | /// but the output is only meaningful for well-formed UTF-8. |
125 | | /// |
126 | | /// # Example |
127 | | /// |
128 | | /// ``` |
129 | | /// let swordfish = "メカジキ"; |
130 | | /// let char_count = bytecount::num_chars(swordfish.as_bytes()); |
131 | | /// assert_eq!(char_count, 4); |
132 | | /// ``` |
133 | 0 | pub fn num_chars(utf8_chars: &[u8]) -> usize { |
134 | 0 | if utf8_chars.len() >= 32 { |
135 | 0 | #[cfg(all(feature = "runtime-dispatch-simd", target_arch = "x86_64"))] |
136 | 0 | { |
137 | 0 | if is_x86_feature_detected!("avx2") { |
138 | 0 | unsafe { |
139 | 0 | return simd::x86_avx2::chunk_num_chars(utf8_chars); |
140 | 0 | } |
141 | 0 | } |
142 | 0 | } |
143 | 0 |
|
144 | 0 | #[cfg(feature = "generic-simd")] |
145 | 0 | return simd::generic::chunk_num_chars(utf8_chars); |
146 | 0 | } |
147 | | |
148 | 0 | if utf8_chars.len() >= 16 { |
149 | 0 | #[cfg(all( |
150 | 0 | feature = "runtime-dispatch-simd", |
151 | 0 | any(target_arch = "x86", target_arch = "x86_64"), |
152 | 0 | not(feature = "generic-simd") |
153 | 0 | ))] |
154 | 0 | { |
155 | 0 | if is_x86_feature_detected!("sse2") { |
156 | 0 | unsafe { |
157 | 0 | return simd::x86_sse2::chunk_num_chars(utf8_chars); |
158 | 0 | } |
159 | 0 | } |
160 | 0 | } |
161 | 0 | #[cfg(all( |
162 | 0 | target_arch = "aarch64", |
163 | 0 | target_endian = "little", |
164 | 0 | not(feature = "generic-simd") |
165 | 0 | ))] |
166 | 0 | { |
167 | 0 | unsafe { |
168 | 0 | return simd::aarch64::chunk_num_chars(utf8_chars); |
169 | 0 | } |
170 | 0 | } |
171 | 0 |
|
172 | 0 | #[cfg(target_arch = "wasm32")] |
173 | 0 | { |
174 | 0 | unsafe { |
175 | 0 | return simd::wasm::chunk_num_chars(utf8_chars); |
176 | 0 | } |
177 | 0 | } |
178 | 0 | } |
179 | | |
180 | 0 | if utf8_chars.len() >= mem::size_of::<usize>() { |
181 | 0 | return integer_simd::chunk_num_chars(utf8_chars); |
182 | 0 | } |
183 | | |
184 | 0 | naive_num_chars(utf8_chars) |
185 | 0 | } |