Coverage Report

Created: 2026-09-14 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}