Coverage Report

Created: 2024-10-16 07:58

/rust/registry/src/index.crates.io-6f17d22bba15001f/simdutf8-0.1.4/src/implementation/algorithm.rs
Line
Count
Source (jump to first uncovered line)
1
/// Macros requires newtypes in scope:
2
/// `SimdU8Value` - implementation of SIMD primitives
3
/// `SimdInput` - which  holds 64 bytes of SIMD input
4
/// `TempSimdChunk` - correctly aligned `TempSimdChunk`, either `TempSimdChunkA16` or `TempSimdChunkA32`
5
6
macro_rules! algorithm_simd {
7
    ($feat:expr) => {
8
        use crate::{basic, compat};
9
10
        impl Utf8CheckAlgorithm<SimdU8Value> {
11
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
12
            #[inline]
13
0
            unsafe fn default() -> Self {
14
0
                Self {
15
0
                    prev: SimdU8Value::splat0(),
16
0
                    incomplete: SimdU8Value::splat0(),
17
0
                    error: SimdU8Value::splat0(),
18
0
                }
19
0
            }
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m256i>>>::default
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m128i>>>::default
20
21
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
22
            #[inline]
23
0
            unsafe fn check_incomplete_pending(&mut self) {
24
0
                self.error = self.error.or(self.incomplete);
25
0
            }
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m256i>>>::check_incomplete_pending
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m128i>>>::check_incomplete_pending
26
27
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
28
            #[inline]
29
0
            unsafe fn is_incomplete(input: SimdU8Value) -> SimdU8Value {
30
0
                input.saturating_sub(SimdU8Value::from_32_cut_off_leading(
31
0
                    0xff,
32
0
                    0xff,
33
0
                    0xff,
34
0
                    0xff,
35
0
                    0xff,
36
0
                    0xff,
37
0
                    0xff,
38
0
                    0xff,
39
0
                    0xff,
40
0
                    0xff,
41
0
                    0xff,
42
0
                    0xff,
43
0
                    0xff,
44
0
                    0xff,
45
0
                    0xff,
46
0
                    0xff,
47
0
                    0xff,
48
0
                    0xff,
49
0
                    0xff,
50
0
                    0xff,
51
0
                    0xff,
52
0
                    0xff,
53
0
                    0xff,
54
0
                    0xff,
55
0
                    0xff,
56
0
                    0xff,
57
0
                    0xff,
58
0
                    0xff,
59
0
                    0xff,
60
0
                    0b1111_0000 - 1,
61
0
                    0b1110_0000 - 1,
62
0
                    0b1100_0000 - 1,
63
0
                ))
64
0
            }
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m256i>>>::is_incomplete
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m128i>>>::is_incomplete
65
66
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
67
            #[inline]
68
            #[allow(clippy::too_many_lines)]
69
0
            unsafe fn check_special_cases(input: SimdU8Value, prev1: SimdU8Value) -> SimdU8Value {
70
0
                const TOO_SHORT: u8 = 1 << 0;
71
0
                const TOO_LONG: u8 = 1 << 1;
72
0
                const OVERLONG_3: u8 = 1 << 2;
73
0
                const SURROGATE: u8 = 1 << 4;
74
0
                const OVERLONG_2: u8 = 1 << 5;
75
0
                const TWO_CONTS: u8 = 1 << 7;
76
0
                const TOO_LARGE: u8 = 1 << 3;
77
0
                const TOO_LARGE_1000: u8 = 1 << 6;
78
0
                const OVERLONG_4: u8 = 1 << 6;
79
0
                const CARRY: u8 = TOO_SHORT | TOO_LONG | TWO_CONTS;
80
0
81
0
                let byte_1_high = prev1.shr4().lookup_16(
82
0
                    TOO_LONG,
83
0
                    TOO_LONG,
84
0
                    TOO_LONG,
85
0
                    TOO_LONG,
86
0
                    TOO_LONG,
87
0
                    TOO_LONG,
88
0
                    TOO_LONG,
89
0
                    TOO_LONG,
90
0
                    TWO_CONTS,
91
0
                    TWO_CONTS,
92
0
                    TWO_CONTS,
93
0
                    TWO_CONTS,
94
0
                    TOO_SHORT | OVERLONG_2,
95
0
                    TOO_SHORT,
96
0
                    TOO_SHORT | OVERLONG_3 | SURROGATE,
97
0
                    TOO_SHORT | TOO_LARGE | TOO_LARGE_1000 | OVERLONG_4,
98
0
                );
99
0
100
0
                let byte_1_low = prev1.and(SimdU8Value::splat(0x0F)).lookup_16(
101
0
                    CARRY | OVERLONG_3 | OVERLONG_2 | OVERLONG_4,
102
0
                    CARRY | OVERLONG_2,
103
0
                    CARRY,
104
0
                    CARRY,
105
0
                    CARRY | TOO_LARGE,
106
0
                    CARRY | TOO_LARGE | TOO_LARGE_1000,
107
0
                    CARRY | TOO_LARGE | TOO_LARGE_1000,
108
0
                    CARRY | TOO_LARGE | TOO_LARGE_1000,
109
0
                    CARRY | TOO_LARGE | TOO_LARGE_1000,
110
0
                    CARRY | TOO_LARGE | TOO_LARGE_1000,
111
0
                    CARRY | TOO_LARGE | TOO_LARGE_1000,
112
0
                    CARRY | TOO_LARGE | TOO_LARGE_1000,
113
0
                    CARRY | TOO_LARGE | TOO_LARGE_1000,
114
0
                    CARRY | TOO_LARGE | TOO_LARGE_1000 | SURROGATE,
115
0
                    CARRY | TOO_LARGE | TOO_LARGE_1000,
116
0
                    CARRY | TOO_LARGE | TOO_LARGE_1000,
117
0
                );
118
0
119
0
                let byte_2_high = input.shr4().lookup_16(
120
0
                    TOO_SHORT,
121
0
                    TOO_SHORT,
122
0
                    TOO_SHORT,
123
0
                    TOO_SHORT,
124
0
                    TOO_SHORT,
125
0
                    TOO_SHORT,
126
0
                    TOO_SHORT,
127
0
                    TOO_SHORT,
128
0
                    TOO_LONG | OVERLONG_2 | TWO_CONTS | OVERLONG_3 | TOO_LARGE_1000 | OVERLONG_4,
129
0
                    TOO_LONG | OVERLONG_2 | TWO_CONTS | OVERLONG_3 | TOO_LARGE,
130
0
                    TOO_LONG | OVERLONG_2 | TWO_CONTS | SURROGATE | TOO_LARGE,
131
0
                    TOO_LONG | OVERLONG_2 | TWO_CONTS | SURROGATE | TOO_LARGE,
132
0
                    TOO_SHORT,
133
0
                    TOO_SHORT,
134
0
                    TOO_SHORT,
135
0
                    TOO_SHORT,
136
0
                );
137
0
138
0
                byte_1_high.and(byte_1_low).and(byte_2_high)
139
0
            }
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m256i>>>::check_special_cases
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m128i>>>::check_special_cases
140
141
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
142
            #[inline]
143
0
            unsafe fn check_multibyte_lengths(
144
0
                input: SimdU8Value,
145
0
                prev: SimdU8Value,
146
0
                special_cases: SimdU8Value,
147
0
            ) -> SimdU8Value {
148
0
                let prev2 = input.prev2(prev);
149
0
                let prev3 = input.prev3(prev);
150
0
                let must23 = Self::must_be_2_3_continuation(prev2, prev3);
151
0
                let must23_80 = must23.and(SimdU8Value::splat(0x80));
152
0
                must23_80.xor(special_cases)
153
0
            }
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m256i>>>::check_multibyte_lengths
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m128i>>>::check_multibyte_lengths
154
155
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
156
            #[inline]
157
0
            unsafe fn has_error(&self) -> bool {
158
0
                self.error.any_bit_set()
159
0
            }
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m256i>>>::has_error
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m128i>>>::has_error
160
161
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
162
            #[inline]
163
0
            unsafe fn check_bytes(&mut self, input: SimdU8Value) {
164
0
                let prev1 = input.prev1(self.prev);
165
0
                let sc = Self::check_special_cases(input, prev1);
166
0
                self.error = self
167
0
                    .error
168
0
                    .or(Self::check_multibyte_lengths(input, self.prev, sc));
169
0
                self.prev = input;
170
0
            }
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m256i>>>::check_bytes
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m128i>>>::check_bytes
171
172
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
173
            #[inline]
174
0
            unsafe fn check_utf8(&mut self, input: SimdInput) {
175
0
                if input.is_ascii() {
176
0
                    self.check_incomplete_pending();
177
0
                } else {
178
0
                    self.check_block(input);
179
0
                }
180
0
            }
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m256i>>>::check_utf8
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m128i>>>::check_utf8
181
182
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
183
            #[inline]
184
            #[allow(unconditional_panic)] // does not panic because len is checked
185
            #[allow(const_err)] // the same, but for Rust 1.38.0
186
0
            unsafe fn check_block(&mut self, input: SimdInput) {
187
0
                // WORKAROUND
188
0
                // necessary because the for loop is not unrolled on ARM64
189
0
                if input.vals.len() == 2 {
190
0
                    self.check_bytes(input.vals[0]);
191
0
                    self.check_bytes(input.vals[1]);
192
0
                    self.incomplete = Self::is_incomplete(input.vals[1]);
193
0
                } else if input.vals.len() == 4 {
194
0
                    self.check_bytes(input.vals[0]);
195
0
                    self.check_bytes(input.vals[1]);
196
0
                    self.check_bytes(input.vals[2]);
197
0
                    self.check_bytes(input.vals[3]);
198
0
                    self.incomplete = Self::is_incomplete(input.vals[3]);
199
0
                } else {
200
0
                    panic!("Unsupported number of chunks");
201
                }
202
0
            }
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m256i>>>::check_block
Unexecuted instantiation: <simdutf8::implementation::helpers::Utf8CheckAlgorithm<simdutf8::implementation::helpers::SimdU8Value<core::core_arch::x86::__m128i>>>::check_block
203
        }
204
205
        /// Validation implementation for CPUs supporting the SIMD extension (see module).
206
        ///
207
        /// # Errors
208
        /// Returns the zero-sized [`basic::Utf8Error`] on failure.
209
        ///
210
        /// # Safety
211
        /// This function is inherently unsafe because it is compiled with SIMD extensions
212
        /// enabled. Make sure that the CPU supports it before calling.
213
        ///
214
        #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
215
        #[inline]
216
0
        pub unsafe fn validate_utf8_basic(
217
0
            input: &[u8],
218
0
        ) -> core::result::Result<(), basic::Utf8Error> {
219
0
            use crate::implementation::helpers::SIMD_CHUNK_SIZE;
220
0
            let len = input.len();
221
0
            let mut algorithm = Utf8CheckAlgorithm::<SimdU8Value>::default();
222
0
            let mut idx: usize = 0;
223
0
            let iter_lim = len - (len % SIMD_CHUNK_SIZE);
224
225
0
            while idx < iter_lim {
226
0
                let simd_input = SimdInput::new(input.get_unchecked(idx as usize..));
227
0
                idx += SIMD_CHUNK_SIZE;
228
0
                if !simd_input.is_ascii() {
229
0
                    algorithm.check_block(simd_input);
230
0
                    break;
231
0
                }
232
            }
233
234
0
            while idx < iter_lim {
235
0
                if PREFETCH {
236
0
                    simd_prefetch(input.as_ptr().add(idx + SIMD_CHUNK_SIZE * 2));
237
0
                }
238
0
                let input = SimdInput::new(input.get_unchecked(idx as usize..));
239
0
                algorithm.check_utf8(input);
240
0
                idx += SIMD_CHUNK_SIZE;
241
            }
242
243
0
            if idx < len {
244
0
                let mut tmpbuf = TempSimdChunk::new();
245
0
                crate::implementation::helpers::memcpy_unaligned_nonoverlapping_inline_opt_lt_64(
246
0
                    input.as_ptr().add(idx),
247
0
                    tmpbuf.0.as_mut_ptr(),
248
0
                    len - idx,
249
0
                );
250
0
                let simd_input = SimdInput::new(&tmpbuf.0);
251
0
                algorithm.check_utf8(simd_input);
252
0
            }
253
0
            algorithm.check_incomplete_pending();
254
0
            if algorithm.has_error() {
255
0
                Err(basic::Utf8Error {})
256
            } else {
257
0
                Ok(())
258
            }
259
0
        }
Unexecuted instantiation: simdutf8::implementation::x86::avx2::validate_utf8_basic
Unexecuted instantiation: simdutf8::implementation::x86::sse42::validate_utf8_basic
260
261
        /// Validation implementation for CPUs supporting the SIMD extension (see module).
262
        ///
263
        /// # Errors
264
        /// Returns [`compat::Utf8Error`] with detailed error information on failure.
265
        ///
266
        /// # Safety
267
        /// This function is inherently unsafe because it is compiled with SIMD extensions
268
        /// enabled. Make sure that the CPU supports it before calling.
269
        ///
270
        #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
271
        #[inline]
272
0
        pub unsafe fn validate_utf8_compat(
273
0
            input: &[u8],
274
0
        ) -> core::result::Result<(), compat::Utf8Error> {
275
0
            validate_utf8_compat_simd0(input)
276
0
                .map_err(|idx| crate::implementation::helpers::get_compat_error(input, idx))
Unexecuted instantiation: simdutf8::implementation::x86::avx2::validate_utf8_compat::{closure#0}
Unexecuted instantiation: simdutf8::implementation::x86::sse42::validate_utf8_compat::{closure#0}
277
0
        }
Unexecuted instantiation: simdutf8::implementation::x86::avx2::validate_utf8_compat
Unexecuted instantiation: simdutf8::implementation::x86::sse42::validate_utf8_compat
278
279
        #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
280
        #[inline]
281
0
        unsafe fn validate_utf8_compat_simd0(input: &[u8]) -> core::result::Result<(), usize> {
282
0
            use crate::implementation::helpers::SIMD_CHUNK_SIZE;
283
0
            let len = input.len();
284
0
            let mut algorithm = Utf8CheckAlgorithm::<SimdU8Value>::default();
285
0
            let mut idx: usize = 0;
286
0
            let mut only_ascii = true;
287
0
            let iter_lim = len - (len % SIMD_CHUNK_SIZE);
288
289
0
            'outer: loop {
290
0
                if only_ascii {
291
0
                    while idx < iter_lim {
292
0
                        let simd_input = SimdInput::new(input.get_unchecked(idx as usize..));
293
0
                        if !simd_input.is_ascii() {
294
0
                            algorithm.check_block(simd_input);
295
0
                            if algorithm.has_error() {
296
0
                                return Err(idx);
297
                            } else {
298
0
                                only_ascii = false;
299
0
                                idx += SIMD_CHUNK_SIZE;
300
0
                                continue 'outer;
301
                            }
302
0
                        }
303
0
                        idx += SIMD_CHUNK_SIZE;
304
                    }
305
                } else {
306
0
                    while idx < iter_lim {
307
0
                        if PREFETCH {
308
0
                            simd_prefetch(input.as_ptr().add(idx + SIMD_CHUNK_SIZE * 2));
309
0
                        }
310
0
                        let simd_input = SimdInput::new(input.get_unchecked(idx as usize..));
311
0
                        if simd_input.is_ascii() {
312
0
                            algorithm.check_incomplete_pending();
313
0
                            if algorithm.has_error() {
314
0
                                return Err(idx);
315
                            } else {
316
                                // we are in pure ASCII territory again
317
0
                                only_ascii = true;
318
0
                                idx += SIMD_CHUNK_SIZE;
319
0
                                continue 'outer;
320
                            }
321
                        } else {
322
0
                            algorithm.check_block(simd_input);
323
0
                            if algorithm.has_error() {
324
0
                                return Err(idx);
325
0
                            }
326
0
                        }
327
0
                        idx += SIMD_CHUNK_SIZE;
328
                    }
329
                }
330
0
                break;
331
0
            }
332
0
            if idx < len {
333
0
                let mut tmpbuf = TempSimdChunk::new();
334
0
                crate::implementation::helpers::memcpy_unaligned_nonoverlapping_inline_opt_lt_64(
335
0
                    input.as_ptr().add(idx),
336
0
                    tmpbuf.0.as_mut_ptr(),
337
0
                    len - idx,
338
0
                );
339
0
                let simd_input = SimdInput::new(&tmpbuf.0);
340
0
341
0
                algorithm.check_utf8(simd_input);
342
0
            }
343
0
            algorithm.check_incomplete_pending();
344
0
            if algorithm.has_error() {
345
0
                Err(idx)
346
            } else {
347
0
                Ok(())
348
            }
349
0
        }
Unexecuted instantiation: simdutf8::implementation::x86::avx2::validate_utf8_compat_simd0
Unexecuted instantiation: simdutf8::implementation::x86::sse42::validate_utf8_compat_simd0
350
351
        /// Low-level implementation of the [`basic::imp::Utf8Validator`] trait.
352
        ///
353
        /// This is implementation requires CPU SIMD features specified by the module it resides in.
354
        /// It is undefined behavior to call it if the required CPU features are not
355
        /// available.
356
        #[cfg(feature = "public_imp")]
357
        pub struct Utf8ValidatorImp {
358
            algorithm: Utf8CheckAlgorithm<SimdU8Value>,
359
            incomplete_data: [u8; 64],
360
            incomplete_len: usize,
361
        }
362
363
        #[cfg(feature = "public_imp")]
364
        impl Utf8ValidatorImp {
365
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
366
            #[inline]
367
            unsafe fn update_from_incomplete_data(&mut self) {
368
                let simd_input = SimdInput::new(&self.incomplete_data);
369
                self.algorithm.check_utf8(simd_input);
370
                self.incomplete_len = 0;
371
            }
372
        }
373
374
        #[cfg(feature = "public_imp")]
375
        impl basic::imp::Utf8Validator for Utf8ValidatorImp {
376
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
377
            #[inline]
378
            #[must_use]
379
            unsafe fn new() -> Self {
380
                Self {
381
                    algorithm: Utf8CheckAlgorithm::<SimdU8Value>::default(),
382
                    incomplete_data: [0; 64],
383
                    incomplete_len: 0,
384
                }
385
            }
386
387
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
388
            #[inline]
389
            unsafe fn update(&mut self, mut input: &[u8]) {
390
                use crate::implementation::helpers::SIMD_CHUNK_SIZE;
391
                if input.is_empty() {
392
                    return;
393
                }
394
                if self.incomplete_len != 0 {
395
                    let to_copy =
396
                        core::cmp::min(SIMD_CHUNK_SIZE - self.incomplete_len, input.len());
397
                    self.incomplete_data
398
                        .as_mut_ptr()
399
                        .add(self.incomplete_len)
400
                        .copy_from_nonoverlapping(input.as_ptr(), to_copy);
401
                    if self.incomplete_len + to_copy == SIMD_CHUNK_SIZE {
402
                        self.update_from_incomplete_data();
403
                        input = &input[to_copy..];
404
                    } else {
405
                        self.incomplete_len += to_copy;
406
                        return;
407
                    }
408
                }
409
                let len = input.len();
410
                let mut idx: usize = 0;
411
                let iter_lim = len - (len % SIMD_CHUNK_SIZE);
412
                while idx < iter_lim {
413
                    let input = SimdInput::new(input.get_unchecked(idx as usize..));
414
                    self.algorithm.check_utf8(input);
415
                    idx += SIMD_CHUNK_SIZE;
416
                }
417
                if idx < len {
418
                    let to_copy = len - idx;
419
                    self.incomplete_data
420
                        .as_mut_ptr()
421
                        .copy_from_nonoverlapping(input.as_ptr().add(idx), to_copy);
422
                    self.incomplete_len = to_copy;
423
                }
424
            }
425
426
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
427
            #[inline]
428
            unsafe fn finalize(mut self) -> core::result::Result<(), basic::Utf8Error> {
429
                if self.incomplete_len != 0 {
430
                    for i in &mut self.incomplete_data[self.incomplete_len..] {
431
                        *i = 0;
432
                    }
433
                    self.update_from_incomplete_data();
434
                }
435
                self.algorithm.check_incomplete_pending();
436
                if self.algorithm.has_error() {
437
                    Err(basic::Utf8Error {})
438
                } else {
439
                    Ok(())
440
                }
441
            }
442
        }
443
444
        /// Low-level implementation of the [`basic::imp::ChunkedUtf8Validator`] trait.
445
        ///
446
        /// This is implementation requires CPU SIMD features specified by the module it resides in.
447
        /// It is undefined behavior to call it if the required CPU features are not
448
        /// available.
449
        #[cfg(feature = "public_imp")]
450
        pub struct ChunkedUtf8ValidatorImp {
451
            algorithm: Utf8CheckAlgorithm<SimdU8Value>,
452
        }
453
454
        #[cfg(feature = "public_imp")]
455
        impl basic::imp::ChunkedUtf8Validator for ChunkedUtf8ValidatorImp {
456
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
457
            #[inline]
458
            #[must_use]
459
            unsafe fn new() -> Self {
460
                Self {
461
                    algorithm: Utf8CheckAlgorithm::<SimdU8Value>::default(),
462
                }
463
            }
464
465
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
466
            #[inline]
467
            unsafe fn update_from_chunks(&mut self, input: &[u8]) {
468
                use crate::implementation::helpers::SIMD_CHUNK_SIZE;
469
470
                assert!(
471
                    input.len() % SIMD_CHUNK_SIZE == 0,
472
                    "Input size must be a multiple of 64."
473
                );
474
                for chunk in input.chunks_exact(SIMD_CHUNK_SIZE) {
475
                    let input = SimdInput::new(chunk);
476
                    self.algorithm.check_utf8(input);
477
                }
478
            }
479
480
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
481
            #[inline]
482
            unsafe fn finalize(
483
                mut self,
484
                remaining_input: core::option::Option<&[u8]>,
485
            ) -> core::result::Result<(), basic::Utf8Error> {
486
                use crate::implementation::helpers::SIMD_CHUNK_SIZE;
487
488
                if let Some(mut remaining_input) = remaining_input {
489
                    if !remaining_input.is_empty() {
490
                        let len = remaining_input.len();
491
                        let chunks_lim = len - (len % SIMD_CHUNK_SIZE);
492
                        if chunks_lim > 0 {
493
                            self.update_from_chunks(&remaining_input[..chunks_lim]);
494
                        }
495
                        let rem = len - chunks_lim;
496
                        if rem > 0 {
497
                            remaining_input = &remaining_input[chunks_lim..];
498
                            let mut tmpbuf = TempSimdChunk::new();
499
                            tmpbuf.0.as_mut_ptr().copy_from_nonoverlapping(
500
                                remaining_input.as_ptr(),
501
                                remaining_input.len(),
502
                            );
503
                            let simd_input = SimdInput::new(&tmpbuf.0);
504
                            self.algorithm.check_utf8(simd_input);
505
                        }
506
                    }
507
                }
508
                self.algorithm.check_incomplete_pending();
509
                if self.algorithm.has_error() {
510
                    Err(basic::Utf8Error {})
511
                } else {
512
                    Ok(())
513
                }
514
            }
515
        }
516
    };
517
}
518
519
macro_rules! simd_input_128_bit {
520
    ($feat:expr) => {
521
        #[repr(C)]
522
        struct SimdInput {
523
            vals: [SimdU8Value; 4],
524
        }
525
526
        impl SimdInput {
527
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
528
            #[inline]
529
            #[allow(clippy::cast_ptr_alignment)]
530
0
            unsafe fn new(ptr: &[u8]) -> Self {
531
0
                Self {
532
0
                    vals: [
533
0
                        SimdU8Value::load_from(ptr.as_ptr()),
534
0
                        SimdU8Value::load_from(ptr.as_ptr().add(16)),
535
0
                        SimdU8Value::load_from(ptr.as_ptr().add(32)),
536
0
                        SimdU8Value::load_from(ptr.as_ptr().add(48)),
537
0
                    ],
538
0
                }
539
0
            }
540
541
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
542
            #[inline]
543
0
            unsafe fn is_ascii(&self) -> bool {
544
0
                let r1 = self.vals[0].or(self.vals[1]);
545
0
                let r2 = self.vals[2].or(self.vals[3]);
546
0
                let r = r1.or(r2);
547
0
                r.is_ascii()
548
0
            }
549
        }
550
    };
551
}
552
553
macro_rules! simd_input_256_bit {
554
    ($feat:expr) => {
555
        #[repr(C)]
556
        struct SimdInput {
557
            vals: [SimdU8Value; 2],
558
        }
559
560
        impl SimdInput {
561
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
562
            #[inline]
563
            #[allow(clippy::cast_ptr_alignment)]
564
0
            unsafe fn new(ptr: &[u8]) -> Self {
565
0
                Self {
566
0
                    vals: [
567
0
                        SimdU8Value::load_from(ptr.as_ptr()),
568
0
                        SimdU8Value::load_from(ptr.as_ptr().add(32)),
569
0
                    ],
570
0
                }
571
0
            }
572
573
            #[cfg_attr(not(target_arch="aarch64"), target_feature(enable = $feat))]
574
            #[inline]
575
0
            unsafe fn is_ascii(&self) -> bool {
576
0
                self.vals[0].or(self.vals[1]).is_ascii()
577
0
            }
578
        }
579
    };
580
}