1use super::*;
2
3pick! {
4 if #[cfg(target_feature="avx2")] {
5 #[derive(Default, Clone, Copy, PartialEq, Eq)]
6 #[repr(C, align(32))]
7 pub struct u8x32 { pub(crate) avx: m256i }
8 } else {
9 #[derive(Default, Clone, Copy, PartialEq, Eq)]
10 #[repr(C, align(32))]
11 pub struct u8x32 { pub(crate) a : u8x16, pub(crate) b : u8x16 }
12 }
13}
14
15int_uint_consts!(u8, 32, u8x32, 256);
16
17unsafe impl Zeroable for u8x32 {}
18unsafe impl Pod for u8x32 {}
19
20impl AlignTo for u8x32 {
21 type Elem = u8;
22}
23
24impl Add for u8x32 {
25 type Output = Self;
26 #[inline]
27 fn add(self, rhs: Self) -> Self::Output {
28 pick! {
29 if #[cfg(target_feature="avx2")] {
30 Self { avx: add_i8_m256i(self.avx,rhs.avx) }
31 } else {
32 Self {
33 a : self.a.add(rhs.a),
34 b : self.b.add(rhs.b),
35 }
36 }
37 }
38 }
39}
40
41impl Sub for u8x32 {
42 type Output = Self;
43 #[inline]
44 fn sub(self, rhs: Self) -> Self::Output {
45 pick! {
46 if #[cfg(target_feature="avx2")] {
47 Self { avx: sub_i8_m256i(self.avx,rhs.avx) }
48 } else {
49 Self {
50 a : self.a.sub(rhs.a),
51 b : self.b.sub(rhs.b),
52 }
53 }
54 }
55 }
56}
57
58impl Mul for u8x32 {
59 type Output = Self;
60
61 #[inline]
62 fn mul(self, rhs: Self) -> Self::Output {
63 let [self_a, self_b]: [u8x16; 2] = cast(self);
67 let [rhs_a, rhs_b]: [u8x16; 2] = cast(rhs);
68 cast([self_a * rhs_a, self_b * rhs_b])
69 }
70}
71
72integer_impl_div_rem!(
73 u8,
74 u8x32,
75 [
76 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
77 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
78 ],
79);
80
81impl Shl for u8x32 {
82 type Output = Self;
83
84 #[inline]
90 fn shl(self, rhs: Self) -> Self::Output {
91 let [self_a, self_b]: [u8x16; 2] = cast(self);
95 let [rhs_a, rhs_b]: [u8x16; 2] = cast(rhs);
96 cast([self_a << rhs_a, self_b << rhs_b])
97 }
98}
99
100impl Shr for u8x32 {
101 type Output = Self;
102
103 #[inline]
109 fn shr(self, rhs: Self) -> Self::Output {
110 let [self_a, self_b]: [u8x16; 2] = cast(self);
114 let [rhs_a, rhs_b]: [u8x16; 2] = cast(rhs);
115 cast([self_a >> rhs_a, self_b >> rhs_b])
116 }
117}
118
119impl Add<u8> for u8x32 {
120 type Output = Self;
121 #[inline]
122 fn add(self, rhs: u8) -> Self::Output {
123 self.add(Self::splat(rhs))
124 }
125}
126
127impl Sub<u8> for u8x32 {
128 type Output = Self;
129 #[inline]
130 fn sub(self, rhs: u8) -> Self::Output {
131 self.sub(Self::splat(rhs))
132 }
133}
134
135impl Mul<u8> for u8x32 {
136 type Output = Self;
137
138 #[inline]
139 fn mul(self, rhs: u8) -> Self::Output {
140 self * Self::splat(rhs)
141 }
142}
143
144macro_rules! impl_shl_scalar {
145 ($Rhs:ident) => {
146 impl Shl<$Rhs> for u8x32 {
147 type Output = Self;
148
149 #[inline]
155 fn shl(self, rhs: $Rhs) -> Self::Output {
156 let [self_a, self_b]: [u8x16; 2] = cast(self);
160 cast([self_a << rhs, self_b << rhs])
161 }
162 }
163 };
164}
165impl_shl_scalar!(i8);
166impl_shl_scalar!(u8);
167impl_shl_scalar!(i16);
168impl_shl_scalar!(u16);
169impl_shl_scalar!(i32);
170impl_shl_scalar!(u32);
171impl_shl_scalar!(i64);
172impl_shl_scalar!(u64);
173impl_shl_scalar!(i128);
174impl_shl_scalar!(u128);
175
176macro_rules! impl_shr_scalar {
177 ($Rhs:ident) => {
178 impl Shr<$Rhs> for u8x32 {
179 type Output = Self;
180
181 #[inline]
187 fn shr(self, rhs: $Rhs) -> Self::Output {
188 let [self_a, self_b]: [u8x16; 2] = cast(self);
192 cast([self_a >> rhs, self_b >> rhs])
193 }
194 }
195 };
196}
197impl_shr_scalar!(i8);
198impl_shr_scalar!(u8);
199impl_shr_scalar!(i16);
200impl_shr_scalar!(u16);
201impl_shr_scalar!(i32);
202impl_shr_scalar!(u32);
203impl_shr_scalar!(i64);
204impl_shr_scalar!(u64);
205impl_shr_scalar!(i128);
206impl_shr_scalar!(u128);
207
208impl Add<u8x32> for u8 {
209 type Output = u8x32;
210 #[inline]
211 fn add(self, rhs: u8x32) -> Self::Output {
212 u8x32::splat(self).add(rhs)
213 }
214}
215
216impl Sub<u8x32> for u8 {
217 type Output = u8x32;
218 #[inline]
219 fn sub(self, rhs: u8x32) -> Self::Output {
220 u8x32::splat(self).sub(rhs)
221 }
222}
223
224impl Mul<u8x32> for u8 {
225 type Output = u8x32;
226
227 #[inline]
228 fn mul(self, rhs: u8x32) -> Self::Output {
229 u8x32::splat(self) * rhs
230 }
231}
232
233impl BitAnd for u8x32 {
234 type Output = Self;
235 #[inline]
236 fn bitand(self, rhs: Self) -> Self::Output {
237 pick! {
238 if #[cfg(target_feature="avx2")] {
239 Self { avx : bitand_m256i(self.avx,rhs.avx) }
240 } else {
241 Self {
242 a : self.a.bitand(rhs.a),
243 b : self.b.bitand(rhs.b),
244 }
245 }
246 }
247 }
248}
249
250impl BitOr for u8x32 {
251 type Output = Self;
252 #[inline]
253 fn bitor(self, rhs: Self) -> Self::Output {
254 pick! {
255 if #[cfg(target_feature="avx2")] {
256 Self { avx : bitor_m256i(self.avx,rhs.avx) }
257 } else {
258 Self {
259 a : self.a.bitor(rhs.a),
260 b : self.b.bitor(rhs.b),
261 }
262 }
263 }
264 }
265}
266
267impl BitXor for u8x32 {
268 type Output = Self;
269 #[inline]
270 fn bitxor(self, rhs: Self) -> Self::Output {
271 pick! {
272 if #[cfg(target_feature="avx2")] {
273 Self { avx : bitxor_m256i(self.avx,rhs.avx) }
274 } else {
275 Self {
276 a : self.a.bitxor(rhs.a),
277 b : self.b.bitxor(rhs.b),
278 }
279 }
280 }
281 }
282}
283
284#[expect(deprecated)]
285impl CmpEq for u8x32 {
286 type Output = Self;
287 #[inline]
288 fn simd_eq(self, rhs: Self) -> Self::Output {
289 pick! {
290 if #[cfg(target_feature="avx2")] {
291 Self { avx : cmp_eq_mask_i8_m256i(self.avx,rhs.avx) }
292 } else {
293 Self {
294 a : self.a.simd_eq(rhs.a),
295 b : self.b.simd_eq(rhs.b),
296 }
297 }
298 }
299 }
300}
301
302#[expect(deprecated)]
303impl CmpNe for u8x32 {
304 type Output = Self;
305 #[inline]
306 fn simd_ne(self, rhs: Self) -> Self::Output {
307 pick! {
308 if #[cfg(target_feature="avx2")] {
309 !self.simd_eq(rhs)
310 } else {
311 Self {
312 a : self.a.simd_ne(rhs.a),
313 b : self.b.simd_ne(rhs.b),
314 }
315 }
316 }
317 }
318}
319
320#[expect(deprecated)]
321impl CmpLt for u8x32 {
322 type Output = Self;
323 #[inline]
324 fn simd_lt(self, rhs: Self) -> Self::Output {
325 pick! {
326 if #[cfg(target_feature="avx2")] {
327 let offset = Self::splat(0x80);
329 let self_i8 = self.bitxor(offset).avx;
330 let rhs_i8 = rhs.bitxor(offset).avx;
331 Self { avx: cmp_gt_mask_i8_m256i(rhs_i8, self_i8)}
332 } else {
333 Self { a: self.a.simd_lt(rhs.a), b: self.b.simd_lt(rhs.b) }
334 }
335 }
336 }
337}
338
339#[expect(deprecated)]
340impl CmpLe for u8x32 {
341 type Output = Self;
342 #[inline]
343 fn simd_le(self, rhs: Self) -> Self::Output {
344 pick! {
345 if #[cfg(target_feature="avx2")] {
346 let offset = Self::splat(0x80);
348 let self_i8 = self.bitxor(offset).avx;
349 let rhs_i8 = rhs.bitxor(offset).avx;
350 let gt_mask = Self { avx : cmp_gt_mask_i8_m256i(self_i8,rhs_i8) };
351 Self { avx: gt_mask.bitxor(Self::splat(0xFF)).avx }
352 } else {
353 Self { a: self.a.simd_le(rhs.a), b: self.b.simd_le(rhs.b) }
354 }
355 }
356 }
357}
358
359#[expect(deprecated)]
360impl CmpGe for u8x32 {
361 type Output = Self;
362 #[inline]
363 fn simd_ge(self, rhs: Self) -> Self::Output {
364 pick! {
365 if #[cfg(target_feature="avx2")] {
366 let offset = Self::splat(0x80);
368 let self_i8 = self.bitxor(offset).avx;
369 let rhs_i8 = rhs.bitxor(offset).avx;
370 let lt_mask = Self { avx: cmp_gt_mask_i8_m256i(rhs_i8, self_i8)};
371 Self { avx: lt_mask.bitxor(Self::splat(0xFF)).avx }
372 } else {
373 Self { a: self.a.simd_ge(rhs.a), b: self.b.simd_ge(rhs.b) }
374 }
375 }
376 }
377}
378
379#[expect(deprecated)]
380impl CmpGt for u8x32 {
381 type Output = Self;
382 #[inline]
383 fn simd_gt(self, rhs: Self) -> Self::Output {
384 pick! {
385 if #[cfg(target_feature="avx2")] {
386 let offset = Self::splat(0x80);
388 let self_i8 = self.bitxor(offset).avx;
389 let rhs_i8 = rhs.bitxor(offset).avx;
390 Self { avx : cmp_gt_mask_i8_m256i(self_i8,rhs_i8) }
391 } else {
392 Self { a: self.a.simd_gt(rhs.a), b: self.b.simd_gt(rhs.b) }
393 }
394 }
395 }
396}
397
398impl Not for u8x32 {
399 type Output = Self;
400 #[inline]
401 fn not(self) -> Self {
402 pick! {
403 if #[cfg(target_feature="avx2")] {
404 Self { avx: self.avx.not() }
405 } else {
406 Self {
407 a : self.a.not(),
408 b : self.b.not(),
409 }
410 }
411 }
412 }
413}
414
415impl u8x32 {
416 #[inline]
417 #[must_use]
418 pub const fn new(array: [u8; 32]) -> Self {
419 unsafe { core::mem::transmute(array) }
420 }
421
422 simd_comparison_fns!();
423
424 #[inline]
425 #[must_use]
426 pub fn blend(self, t: Self, f: Self) -> Self {
427 pick! {
428 if #[cfg(target_feature="avx2")] {
429 Self { avx: blend_varying_i8_m256i(f.avx, t.avx, self.avx) }
430 } else {
431 Self {
432 a : self.a.blend(t.a, f.a),
433 b : self.b.blend(t.b, f.b),
434 }
435 }
436 }
437 }
438
439 #[inline]
440 #[must_use]
441 pub fn reduce_add(self) -> u8 {
442 cast(i8x32::reduce_add(cast(self)))
443 }
444
445 #[inline]
446 #[must_use]
447 pub fn reduce_max(self) -> u8 {
448 let array: [u8x16; 2] = cast(self);
449 array[0].max(array[1]).reduce_max()
450 }
451
452 #[inline]
453 #[must_use]
454 pub fn reduce_min(self) -> u8 {
455 let array: [u8x16; 2] = cast(self);
456 array[0].min(array[1]).reduce_min()
457 }
458
459 #[inline]
460 #[must_use]
461 pub fn max(self, rhs: Self) -> Self {
462 pick! {
463 if #[cfg(target_feature="avx2")] {
464 Self { avx: max_u8_m256i(self.avx,rhs.avx) }
465 } else {
466 Self {
467 a : self.a.max(rhs.a),
468 b : self.b.max(rhs.b),
469 }
470 }
471 }
472 }
473 #[inline]
474 #[must_use]
475 pub fn min(self, rhs: Self) -> Self {
476 pick! {
477 if #[cfg(target_feature="avx2")] {
478 Self { avx: min_u8_m256i(self.avx,rhs.avx) }
479 } else {
480 Self {
481 a : self.a.min(rhs.a),
482 b : self.b.min(rhs.b),
483 }
484 }
485 }
486 }
487
488 integer_fn_clamp!();
489
490 #[inline]
491 #[must_use]
492 pub fn saturating_add(self, rhs: Self) -> Self {
493 pick! {
494 if #[cfg(target_feature="avx2")] {
495 Self { avx: add_saturating_u8_m256i(self.avx, rhs.avx) }
496 } else {
497 Self {
498 a : self.a.saturating_add(rhs.a),
499 b : self.b.saturating_add(rhs.b),
500 }
501 }
502 }
503 }
504 #[inline]
505 #[must_use]
506 pub fn saturating_sub(self, rhs: Self) -> Self {
507 pick! {
508 if #[cfg(target_feature="avx2")] {
509 Self { avx: sub_saturating_u8_m256i(self.avx, rhs.avx) }
510 } else {
511 Self {
512 a : self.a.saturating_sub(rhs.a),
513 b : self.b.saturating_sub(rhs.b),
514 }
515 }
516 }
517 }
518
519 #[inline]
521 #[must_use]
522 pub fn saturating_mul(self, rhs: Self) -> Self {
523 let [self_a, self_b]: [u8x16; 2] = cast(self);
524 let [rhs_a, rhs_b]: [u8x16; 2] = cast(rhs);
525 cast([self_a.saturating_mul(rhs_a), self_b.saturating_mul(rhs_b)])
526 }
527
528 integer_fn_saturating_div!([
529 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
530 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
531 ]);
532
533 #[inline]
534 #[must_use]
535 #[doc(alias("movemask", "move_mask"))]
536 pub fn to_bitmask(self) -> u32 {
537 i8x32::to_bitmask(cast(self)) as u32
538 }
539
540 #[inline]
541 #[must_use]
542 pub fn any(self) -> bool {
543 i8x32::any(cast(self))
544 }
545
546 #[inline]
547 #[must_use]
548 pub fn all(self) -> bool {
549 i8x32::all(cast(self))
550 }
551
552 #[inline]
561 pub fn swizzle_half(self, rhs: i8x32) -> i8x32 {
562 cast(i8x32::swizzle_half(cast(self), cast(rhs)))
563 }
564
565 #[inline]
575 pub fn swizzle_half_relaxed(self, rhs: u8x32) -> u8x32 {
576 cast(i8x32::swizzle_half_relaxed(cast(self), cast(rhs)))
577 }
578
579 #[inline]
580 #[must_use]
581 pub fn none(self) -> bool {
582 !self.any()
583 }
584
585 #[must_use]
587 #[inline]
588 pub fn transpose(data: [u8x32; 32]) -> [u8x32; 32] {
589 cast(i8x32::transpose(cast(data)))
590 }
591
592 #[inline]
593 pub fn to_array(self) -> [u8; 32] {
594 cast(self)
595 }
596
597 #[inline]
598 pub fn as_array(&self) -> &[u8; 32] {
599 cast_ref(self)
600 }
601
602 #[inline]
603 pub fn as_mut_array(&mut self) -> &mut [u8; 32] {
604 cast_mut(self)
605 }
606}