core/portable-simd/crates/core_simd/src/swizzle.rs
1use crate::simd::{LaneCount, Mask, MaskElement, Simd, SimdElement, SupportedLaneCount};
2
3/// Constructs a new SIMD vector by copying elements from selected elements in other vectors.
4///
5/// When swizzling one vector, elements are selected like [`Swizzle::swizzle`].
6///
7/// When swizzling two vectors, elements are selected like [`Swizzle::concat_swizzle`].
8///
9/// # Examples
10///
11/// With a single SIMD vector, the const array specifies element indices in that vector:
12/// ```
13/// # #![feature(portable_simd)]
14/// # use core::simd::{u32x2, u32x4, simd_swizzle};
15/// let v = u32x4::from_array([10, 11, 12, 13]);
16///
17/// // Keeping the same size
18/// let r: u32x4 = simd_swizzle!(v, [3, 0, 1, 2]);
19/// assert_eq!(r.to_array(), [13, 10, 11, 12]);
20///
21/// // Changing the number of elements
22/// let r: u32x2 = simd_swizzle!(v, [3, 1]);
23/// assert_eq!(r.to_array(), [13, 11]);
24/// ```
25///
26/// With two input SIMD vectors, the const array specifies element indices in the concatenation of
27/// those vectors:
28/// ```
29/// # #![feature(portable_simd)]
30/// # #[cfg(feature = "as_crate")] use core_simd::simd;
31/// # #[cfg(not(feature = "as_crate"))] use core::simd;
32/// # use simd::{u32x2, u32x4, simd_swizzle};
33/// let a = u32x4::from_array([0, 1, 2, 3]);
34/// let b = u32x4::from_array([4, 5, 6, 7]);
35///
36/// // Keeping the same size
37/// let r: u32x4 = simd_swizzle!(a, b, [0, 1, 6, 7]);
38/// assert_eq!(r.to_array(), [0, 1, 6, 7]);
39///
40/// // Changing the number of elements
41/// let r: u32x2 = simd_swizzle!(a, b, [0, 4]);
42/// assert_eq!(r.to_array(), [0, 4]);
43/// ```
44#[allow(unused_macros)]
45pub macro simd_swizzle {
46 (
47 $vector:expr, $index:expr $(,)?
48 ) => {
49 {
50 use $crate::simd::Swizzle;
51 struct Impl;
52 impl Swizzle<{$index.len()}> for Impl {
53 const INDEX: [usize; {$index.len()}] = $index;
54 }
55 Impl::swizzle($vector)
56 }
57 },
58 (
59 $first:expr, $second:expr, $index:expr $(,)?
60 ) => {
61 {
62 use $crate::simd::Swizzle;
63 struct Impl;
64 impl Swizzle<{$index.len()}> for Impl {
65 const INDEX: [usize; {$index.len()}] = $index;
66 }
67 Impl::concat_swizzle($first, $second)
68 }
69 }
70}
71
72/// Creates a vector from the elements of another vector.
73pub trait Swizzle<const N: usize> {
74 /// Map from the elements of the input vector to the output vector.
75 const INDEX: [usize; N];
76
77 /// Creates a new vector from the elements of `vector`.
78 ///
79 /// Lane `i` of the output is `vector[Self::INDEX[i]]`.
80 #[inline]
81 #[must_use = "method returns a new vector and does not mutate the original inputs"]
82 fn swizzle<T, const M: usize>(vector: Simd<T, M>) -> Simd<T, N>
83 where
84 T: SimdElement,
85 LaneCount<N>: SupportedLaneCount,
86 LaneCount<M>: SupportedLaneCount,
87 {
88 // Safety: `vector` is a vector, and the index is a const vector of u32.
89 unsafe {
90 core::intrinsics::simd::simd_shuffle(
91 vector,
92 vector,
93 const {
94 let mut output = [0; N];
95 let mut i = 0;
96 while i < N {
97 let index = Self::INDEX[i];
98 assert!(index as u32 as usize == index);
99 assert!(
100 index < M,
101 "source element index exceeds input vector length"
102 );
103 output[i] = index as u32;
104 i += 1;
105 }
106
107 // The index list needs to be returned as a vector.
108 #[repr(simd)]
109 struct SimdShuffleIdx<const LEN: usize>([u32; LEN]);
110 SimdShuffleIdx(output)
111 },
112 )
113 }
114 }
115
116 /// Creates a new vector from the elements of `first` and `second`.
117 ///
118 /// Lane `i` of the output is `concat[Self::INDEX[i]]`, where `concat` is the concatenation of
119 /// `first` and `second`.
120 #[inline]
121 #[must_use = "method returns a new vector and does not mutate the original inputs"]
122 fn concat_swizzle<T, const M: usize>(first: Simd<T, M>, second: Simd<T, M>) -> Simd<T, N>
123 where
124 T: SimdElement,
125 LaneCount<N>: SupportedLaneCount,
126 LaneCount<M>: SupportedLaneCount,
127 {
128 // Safety: `first` and `second` are vectors, and the index is a const vector of u32.
129 unsafe {
130 core::intrinsics::simd::simd_shuffle(
131 first,
132 second,
133 const {
134 let mut output = [0; N];
135 let mut i = 0;
136 while i < N {
137 let index = Self::INDEX[i];
138 assert!(index as u32 as usize == index);
139 assert!(
140 index < 2 * M,
141 "source element index exceeds input vector length"
142 );
143 output[i] = index as u32;
144 i += 1;
145 }
146
147 // The index list needs to be returned as a vector.
148 #[repr(simd)]
149 struct SimdShuffleIdx<const LEN: usize>([u32; LEN]);
150 SimdShuffleIdx(output)
151 },
152 )
153 }
154 }
155
156 /// Creates a new mask from the elements of `mask`.
157 ///
158 /// Element `i` of the output is `mask[Self::INDEX[i]]`.
159 #[inline]
160 #[must_use = "method returns a new mask and does not mutate the original inputs"]
161 fn swizzle_mask<T, const M: usize>(mask: Mask<T, M>) -> Mask<T, N>
162 where
163 T: MaskElement,
164 LaneCount<N>: SupportedLaneCount,
165 LaneCount<M>: SupportedLaneCount,
166 {
167 // SAFETY: all elements of this mask come from another mask
168 unsafe { Mask::from_int_unchecked(Self::swizzle(mask.to_int())) }
169 }
170
171 /// Creates a new mask from the elements of `first` and `second`.
172 ///
173 /// Element `i` of the output is `concat[Self::INDEX[i]]`, where `concat` is the concatenation of
174 /// `first` and `second`.
175 #[inline]
176 #[must_use = "method returns a new mask and does not mutate the original inputs"]
177 fn concat_swizzle_mask<T, const M: usize>(first: Mask<T, M>, second: Mask<T, M>) -> Mask<T, N>
178 where
179 T: MaskElement,
180 LaneCount<N>: SupportedLaneCount,
181 LaneCount<M>: SupportedLaneCount,
182 {
183 // SAFETY: all elements of this mask come from another mask
184 unsafe { Mask::from_int_unchecked(Self::concat_swizzle(first.to_int(), second.to_int())) }
185 }
186}
187
188impl<T, const N: usize> Simd<T, N>
189where
190 T: SimdElement,
191 LaneCount<N>: SupportedLaneCount,
192{
193 /// Reverse the order of the elements in the vector.
194 #[inline]
195 #[must_use = "method returns a new vector and does not mutate the original inputs"]
196 pub fn reverse(self) -> Self {
197 struct Reverse;
198
199 impl<const N: usize> Swizzle<N> for Reverse {
200 const INDEX: [usize; N] = const {
201 let mut index = [0; N];
202 let mut i = 0;
203 while i < N {
204 index[i] = N - i - 1;
205 i += 1;
206 }
207 index
208 };
209 }
210
211 Reverse::swizzle(self)
212 }
213
214 /// Rotates the vector such that the first `OFFSET` elements of the slice move to the end
215 /// while the last `self.len() - OFFSET` elements move to the front. After calling `rotate_elements_left`,
216 /// the element previously at index `OFFSET` will become the first element in the slice.
217 /// ```
218 /// # #![feature(portable_simd)]
219 /// # #[cfg(feature = "as_crate")] use core_simd::simd::Simd;
220 /// # #[cfg(not(feature = "as_crate"))] use core::simd::Simd;
221 /// let a = Simd::from_array([0, 1, 2, 3]);
222 /// let x = a.rotate_elements_left::<3>();
223 /// assert_eq!(x.to_array(), [3, 0, 1, 2]);
224 ///
225 /// let y = a.rotate_elements_left::<7>();
226 /// assert_eq!(y.to_array(), [3, 0, 1, 2]);
227 /// ```
228 #[inline]
229 #[must_use = "method returns a new vector and does not mutate the original inputs"]
230 pub fn rotate_elements_left<const OFFSET: usize>(self) -> Self {
231 struct Rotate<const OFFSET: usize>;
232
233 impl<const OFFSET: usize, const N: usize> Swizzle<N> for Rotate<OFFSET> {
234 const INDEX: [usize; N] = const {
235 let offset = OFFSET % N;
236 let mut index = [0; N];
237 let mut i = 0;
238 while i < N {
239 index[i] = (i + offset) % N;
240 i += 1;
241 }
242 index
243 };
244 }
245
246 Rotate::<OFFSET>::swizzle(self)
247 }
248
249 /// Rotates the vector such that the first `self.len() - OFFSET` elements of the vector move to
250 /// the end while the last `OFFSET` elements move to the front. After calling `rotate_elements_right`,
251 /// the element previously at index `self.len() - OFFSET` will become the first element in the slice.
252 /// ```
253 /// # #![feature(portable_simd)]
254 /// # #[cfg(feature = "as_crate")] use core_simd::simd::Simd;
255 /// # #[cfg(not(feature = "as_crate"))] use core::simd::Simd;
256 /// let a = Simd::from_array([0, 1, 2, 3]);
257 /// let x = a.rotate_elements_right::<3>();
258 /// assert_eq!(x.to_array(), [1, 2, 3, 0]);
259 ///
260 /// let y = a.rotate_elements_right::<7>();
261 /// assert_eq!(y.to_array(), [1, 2, 3, 0]);
262 /// ```
263 #[inline]
264 #[must_use = "method returns a new vector and does not mutate the original inputs"]
265 pub fn rotate_elements_right<const OFFSET: usize>(self) -> Self {
266 struct Rotate<const OFFSET: usize>;
267
268 impl<const OFFSET: usize, const N: usize> Swizzle<N> for Rotate<OFFSET> {
269 const INDEX: [usize; N] = const {
270 let offset = N - OFFSET % N;
271 let mut index = [0; N];
272 let mut i = 0;
273 while i < N {
274 index[i] = (i + offset) % N;
275 i += 1;
276 }
277 index
278 };
279 }
280
281 Rotate::<OFFSET>::swizzle(self)
282 }
283
284 /// Shifts the vector elements to the left by `OFFSET`, filling in with
285 /// `padding` from the right.
286 /// ```
287 /// # #![feature(portable_simd)]
288 /// # #[cfg(feature = "as_crate")] use core_simd::simd::Simd;
289 /// # #[cfg(not(feature = "as_crate"))] use core::simd::Simd;
290 /// let a = Simd::from_array([0, 1, 2, 3]);
291 /// let x = a.shift_elements_left::<3>(255);
292 /// assert_eq!(x.to_array(), [3, 255, 255, 255]);
293 ///
294 /// let y = a.shift_elements_left::<7>(255);
295 /// assert_eq!(y.to_array(), [255, 255, 255, 255]);
296 /// ```
297 #[inline]
298 #[must_use = "method returns a new vector and does not mutate the original inputs"]
299 pub fn shift_elements_left<const OFFSET: usize>(self, padding: T) -> Self {
300 struct Shift<const OFFSET: usize>;
301
302 impl<const OFFSET: usize, const N: usize> Swizzle<N> for Shift<OFFSET> {
303 const INDEX: [usize; N] = const {
304 let mut index = [N; N];
305 let mut i = 0;
306 while i + OFFSET < N {
307 index[i] = i + OFFSET;
308 i += 1;
309 }
310 index
311 };
312 }
313
314 Shift::<OFFSET>::concat_swizzle(self, Simd::splat(padding))
315 }
316
317 /// Shifts the vector elements to the right by `OFFSET`, filling in with
318 /// `padding` from the left.
319 /// ```
320 /// # #![feature(portable_simd)]
321 /// # #[cfg(feature = "as_crate")] use core_simd::simd::Simd;
322 /// # #[cfg(not(feature = "as_crate"))] use core::simd::Simd;
323 /// let a = Simd::from_array([0, 1, 2, 3]);
324 /// let x = a.shift_elements_right::<3>(255);
325 /// assert_eq!(x.to_array(), [255, 255, 255, 0]);
326 ///
327 /// let y = a.shift_elements_right::<7>(255);
328 /// assert_eq!(y.to_array(), [255, 255, 255, 255]);
329 /// ```
330 #[inline]
331 #[must_use = "method returns a new vector and does not mutate the original inputs"]
332 pub fn shift_elements_right<const OFFSET: usize>(self, padding: T) -> Self {
333 struct Shift<const OFFSET: usize>;
334
335 impl<const OFFSET: usize, const N: usize> Swizzle<N> for Shift<OFFSET> {
336 const INDEX: [usize; N] = const {
337 let mut index = [N; N];
338 let mut i = OFFSET;
339 while i < N {
340 index[i] = i - OFFSET;
341 i += 1;
342 }
343 index
344 };
345 }
346
347 Shift::<OFFSET>::concat_swizzle(self, Simd::splat(padding))
348 }
349
350 /// Interleave two vectors.
351 ///
352 /// The resulting vectors contain elements taken alternatively from `self` and `other`, first
353 /// filling the first result, and then the second.
354 ///
355 /// The reverse of this operation is [`Simd::deinterleave`].
356 ///
357 /// ```
358 /// # #![feature(portable_simd)]
359 /// # use core::simd::Simd;
360 /// let a = Simd::from_array([0, 1, 2, 3]);
361 /// let b = Simd::from_array([4, 5, 6, 7]);
362 /// let (x, y) = a.interleave(b);
363 /// assert_eq!(x.to_array(), [0, 4, 1, 5]);
364 /// assert_eq!(y.to_array(), [2, 6, 3, 7]);
365 /// ```
366 #[inline]
367 #[must_use = "method returns a new vector and does not mutate the original inputs"]
368 pub fn interleave(self, other: Self) -> (Self, Self) {
369 const fn interleave<const N: usize>(high: bool) -> [usize; N] {
370 let mut idx = [0; N];
371 let mut i = 0;
372 while i < N {
373 let dst_index = if high { i + N } else { i };
374 let src_index = dst_index / 2 + (dst_index % 2) * N;
375 idx[i] = src_index;
376 i += 1;
377 }
378 idx
379 }
380
381 struct Lo;
382 struct Hi;
383
384 impl<const N: usize> Swizzle<N> for Lo {
385 const INDEX: [usize; N] = interleave::<N>(false);
386 }
387
388 impl<const N: usize> Swizzle<N> for Hi {
389 const INDEX: [usize; N] = interleave::<N>(true);
390 }
391
392 (
393 Lo::concat_swizzle(self, other),
394 Hi::concat_swizzle(self, other),
395 )
396 }
397
398 /// Deinterleave two vectors.
399 ///
400 /// The first result takes every other element of `self` and then `other`, starting with
401 /// the first element.
402 ///
403 /// The second result takes every other element of `self` and then `other`, starting with
404 /// the second element.
405 ///
406 /// The reverse of this operation is [`Simd::interleave`].
407 ///
408 /// ```
409 /// # #![feature(portable_simd)]
410 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
411 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
412 /// # use simd::Simd;
413 /// let a = Simd::from_array([0, 4, 1, 5]);
414 /// let b = Simd::from_array([2, 6, 3, 7]);
415 /// let (x, y) = a.deinterleave(b);
416 /// assert_eq!(x.to_array(), [0, 1, 2, 3]);
417 /// assert_eq!(y.to_array(), [4, 5, 6, 7]);
418 /// ```
419 #[inline]
420 #[must_use = "method returns a new vector and does not mutate the original inputs"]
421 pub fn deinterleave(self, other: Self) -> (Self, Self) {
422 const fn deinterleave<const N: usize>(second: bool) -> [usize; N] {
423 let mut idx = [0; N];
424 let mut i = 0;
425 while i < N {
426 idx[i] = i * 2 + second as usize;
427 i += 1;
428 }
429 idx
430 }
431
432 struct Even;
433 struct Odd;
434
435 impl<const N: usize> Swizzle<N> for Even {
436 const INDEX: [usize; N] = deinterleave::<N>(false);
437 }
438
439 impl<const N: usize> Swizzle<N> for Odd {
440 const INDEX: [usize; N] = deinterleave::<N>(true);
441 }
442
443 (
444 Even::concat_swizzle(self, other),
445 Odd::concat_swizzle(self, other),
446 )
447 }
448
449 /// Resize a vector.
450 ///
451 /// If `M` > `N`, extends the length of a vector, setting the new elements to `value`.
452 /// If `M` < `N`, truncates the vector to the first `M` elements.
453 ///
454 /// ```
455 /// # #![feature(portable_simd)]
456 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
457 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
458 /// # use simd::u32x4;
459 /// let x = u32x4::from_array([0, 1, 2, 3]);
460 /// assert_eq!(x.resize::<8>(9).to_array(), [0, 1, 2, 3, 9, 9, 9, 9]);
461 /// assert_eq!(x.resize::<2>(9).to_array(), [0, 1]);
462 /// ```
463 #[inline]
464 #[must_use = "method returns a new vector and does not mutate the original inputs"]
465 pub fn resize<const M: usize>(self, value: T) -> Simd<T, M>
466 where
467 LaneCount<M>: SupportedLaneCount,
468 {
469 struct Resize<const N: usize>;
470 impl<const N: usize, const M: usize> Swizzle<M> for Resize<N> {
471 const INDEX: [usize; M] = const {
472 let mut index = [0; M];
473 let mut i = 0;
474 while i < M {
475 index[i] = if i < N { i } else { N };
476 i += 1;
477 }
478 index
479 };
480 }
481 Resize::<N>::concat_swizzle(self, Simd::splat(value))
482 }
483
484 /// Extract a vector from another vector.
485 ///
486 /// ```
487 /// # #![feature(portable_simd)]
488 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
489 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
490 /// # use simd::u32x4;
491 /// let x = u32x4::from_array([0, 1, 2, 3]);
492 /// assert_eq!(x.extract::<1, 2>().to_array(), [1, 2]);
493 /// ```
494 #[inline]
495 #[must_use = "method returns a new vector and does not mutate the original inputs"]
496 pub fn extract<const START: usize, const LEN: usize>(self) -> Simd<T, LEN>
497 where
498 LaneCount<LEN>: SupportedLaneCount,
499 {
500 struct Extract<const N: usize, const START: usize>;
501 impl<const N: usize, const START: usize, const LEN: usize> Swizzle<LEN> for Extract<N, START> {
502 const INDEX: [usize; LEN] = const {
503 assert!(START + LEN <= N, "index out of bounds");
504 let mut index = [0; LEN];
505 let mut i = 0;
506 while i < LEN {
507 index[i] = START + i;
508 i += 1;
509 }
510 index
511 };
512 }
513 Extract::<N, START>::swizzle(self)
514 }
515}
516
517impl<T, const N: usize> Mask<T, N>
518where
519 T: MaskElement,
520 LaneCount<N>: SupportedLaneCount,
521{
522 /// Reverse the order of the elements in the mask.
523 #[inline]
524 #[must_use = "method returns a new vector and does not mutate the original inputs"]
525 pub fn reverse(self) -> Self {
526 // Safety: swizzles are safe for masks
527 unsafe { Self::from_int_unchecked(self.to_int().reverse()) }
528 }
529
530 /// Rotates the mask such that the first `OFFSET` elements of the slice move to the end
531 /// while the last `self.len() - OFFSET` elements move to the front. After calling `rotate_elements_left`,
532 /// the element previously at index `OFFSET` will become the first element in the slice.
533 #[inline]
534 #[must_use = "method returns a new vector and does not mutate the original inputs"]
535 pub fn rotate_elements_left<const OFFSET: usize>(self) -> Self {
536 // Safety: swizzles are safe for masks
537 unsafe { Self::from_int_unchecked(self.to_int().rotate_elements_left::<OFFSET>()) }
538 }
539
540 /// Rotates the mask such that the first `self.len() - OFFSET` elements of the mask move to
541 /// the end while the last `OFFSET` elements move to the front. After calling `rotate_elements_right`,
542 /// the element previously at index `self.len() - OFFSET` will become the first element in the slice.
543 #[inline]
544 #[must_use = "method returns a new vector and does not mutate the original inputs"]
545 pub fn rotate_elements_right<const OFFSET: usize>(self) -> Self {
546 // Safety: swizzles are safe for masks
547 unsafe { Self::from_int_unchecked(self.to_int().rotate_elements_right::<OFFSET>()) }
548 }
549
550 /// Shifts the mask elements to the left by `OFFSET`, filling in with
551 /// `padding` from the right.
552 #[inline]
553 #[must_use = "method returns a new mask and does not mutate the original inputs"]
554 pub fn shift_elements_left<const OFFSET: usize>(self, padding: bool) -> Self {
555 // Safety: swizzles are safe for masks
556 unsafe {
557 Self::from_int_unchecked(self.to_int().shift_elements_left::<OFFSET>(if padding {
558 T::TRUE
559 } else {
560 T::FALSE
561 }))
562 }
563 }
564
565 /// Shifts the mask elements to the right by `OFFSET`, filling in with
566 /// `padding` from the left.
567 #[inline]
568 #[must_use = "method returns a new mask and does not mutate the original inputs"]
569 pub fn shift_elements_right<const OFFSET: usize>(self, padding: bool) -> Self {
570 // Safety: swizzles are safe for masks
571 unsafe {
572 Self::from_int_unchecked(self.to_int().shift_elements_right::<OFFSET>(if padding {
573 T::TRUE
574 } else {
575 T::FALSE
576 }))
577 }
578 }
579
580 /// Interleave two masks.
581 ///
582 /// The resulting masks contain elements taken alternatively from `self` and `other`, first
583 /// filling the first result, and then the second.
584 ///
585 /// The reverse of this operation is [`Mask::deinterleave`].
586 ///
587 /// ```
588 /// # #![feature(portable_simd)]
589 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
590 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
591 /// # use simd::mask32x4;
592 /// let a = mask32x4::from_array([false, true, false, true]);
593 /// let b = mask32x4::from_array([false, false, true, true]);
594 /// let (x, y) = a.interleave(b);
595 /// assert_eq!(x.to_array(), [false, false, true, false]);
596 /// assert_eq!(y.to_array(), [false, true, true, true]);
597 /// ```
598 #[inline]
599 #[must_use = "method returns a new vector and does not mutate the original inputs"]
600 pub fn interleave(self, other: Self) -> (Self, Self) {
601 let (lo, hi) = self.to_int().interleave(other.to_int());
602 // Safety: swizzles are safe for masks
603 unsafe { (Self::from_int_unchecked(lo), Self::from_int_unchecked(hi)) }
604 }
605
606 /// Deinterleave two masks.
607 ///
608 /// The first result takes every other element of `self` and then `other`, starting with
609 /// the first element.
610 ///
611 /// The second result takes every other element of `self` and then `other`, starting with
612 /// the second element.
613 ///
614 /// The reverse of this operation is [`Mask::interleave`].
615 ///
616 /// ```
617 /// # #![feature(portable_simd)]
618 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
619 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
620 /// # use simd::mask32x4;
621 /// let a = mask32x4::from_array([false, true, false, true]);
622 /// let b = mask32x4::from_array([false, false, true, true]);
623 /// let (x, y) = a.deinterleave(b);
624 /// assert_eq!(x.to_array(), [false, false, false, true]);
625 /// assert_eq!(y.to_array(), [true, true, false, true]);
626 /// ```
627 #[inline]
628 #[must_use = "method returns a new vector and does not mutate the original inputs"]
629 pub fn deinterleave(self, other: Self) -> (Self, Self) {
630 let (even, odd) = self.to_int().deinterleave(other.to_int());
631 // Safety: swizzles are safe for masks
632 unsafe {
633 (
634 Self::from_int_unchecked(even),
635 Self::from_int_unchecked(odd),
636 )
637 }
638 }
639
640 /// Resize a mask.
641 ///
642 /// If `M` > `N`, extends the length of a mask, setting the new elements to `value`.
643 /// If `M` < `N`, truncates the mask to the first `M` elements.
644 ///
645 /// ```
646 /// # #![feature(portable_simd)]
647 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
648 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
649 /// # use simd::mask32x4;
650 /// let x = mask32x4::from_array([false, true, true, false]);
651 /// assert_eq!(x.resize::<8>(true).to_array(), [false, true, true, false, true, true, true, true]);
652 /// assert_eq!(x.resize::<2>(true).to_array(), [false, true]);
653 /// ```
654 #[inline]
655 #[must_use = "method returns a new vector and does not mutate the original inputs"]
656 pub fn resize<const M: usize>(self, value: bool) -> Mask<T, M>
657 where
658 LaneCount<M>: SupportedLaneCount,
659 {
660 // Safety: swizzles are safe for masks
661 unsafe {
662 Mask::<T, M>::from_int_unchecked(self.to_int().resize::<M>(if value {
663 T::TRUE
664 } else {
665 T::FALSE
666 }))
667 }
668 }
669
670 /// Extract a vector from another vector.
671 ///
672 /// ```
673 /// # #![feature(portable_simd)]
674 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
675 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
676 /// # use simd::mask32x4;
677 /// let x = mask32x4::from_array([false, true, true, false]);
678 /// assert_eq!(x.extract::<1, 2>().to_array(), [true, true]);
679 /// ```
680 #[inline]
681 #[must_use = "method returns a new vector and does not mutate the original inputs"]
682 pub fn extract<const START: usize, const LEN: usize>(self) -> Mask<T, LEN>
683 where
684 LaneCount<LEN>: SupportedLaneCount,
685 {
686 // Safety: swizzles are safe for masks
687 unsafe { Mask::<T, LEN>::from_int_unchecked(self.to_int().extract::<START, LEN>()) }
688 }
689}