core_simd/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_simd_unchecked(Self::swizzle(mask.to_simd())) }
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 {
185 Mask::from_simd_unchecked(Self::concat_swizzle(first.to_simd(), second.to_simd()))
186 }
187 }
188}
189
190impl<T, const N: usize> Simd<T, N>
191where
192 T: SimdElement,
193 LaneCount<N>: SupportedLaneCount,
194{
195 /// Reverse the order of the elements in the vector.
196 #[inline]
197 #[must_use = "method returns a new vector and does not mutate the original inputs"]
198 pub fn reverse(self) -> Self {
199 struct Reverse;
200
201 impl<const N: usize> Swizzle<N> for Reverse {
202 const INDEX: [usize; N] = const {
203 let mut index = [0; N];
204 let mut i = 0;
205 while i < N {
206 index[i] = N - i - 1;
207 i += 1;
208 }
209 index
210 };
211 }
212
213 Reverse::swizzle(self)
214 }
215
216 /// Rotates the vector such that the first `OFFSET` elements of the slice move to the end
217 /// while the last `self.len() - OFFSET` elements move to the front. After calling `rotate_elements_left`,
218 /// the element previously at index `OFFSET` will become the first element in the slice.
219 /// ```
220 /// # #![feature(portable_simd)]
221 /// # #[cfg(feature = "as_crate")] use core_simd::simd::Simd;
222 /// # #[cfg(not(feature = "as_crate"))] use core::simd::Simd;
223 /// let a = Simd::from_array([0, 1, 2, 3]);
224 /// let x = a.rotate_elements_left::<3>();
225 /// assert_eq!(x.to_array(), [3, 0, 1, 2]);
226 ///
227 /// let y = a.rotate_elements_left::<7>();
228 /// assert_eq!(y.to_array(), [3, 0, 1, 2]);
229 /// ```
230 #[inline]
231 #[must_use = "method returns a new vector and does not mutate the original inputs"]
232 pub fn rotate_elements_left<const OFFSET: usize>(self) -> Self {
233 struct Rotate<const OFFSET: usize>;
234
235 impl<const OFFSET: usize, const N: usize> Swizzle<N> for Rotate<OFFSET> {
236 const INDEX: [usize; N] = const {
237 let offset = OFFSET % N;
238 let mut index = [0; N];
239 let mut i = 0;
240 while i < N {
241 index[i] = (i + offset) % N;
242 i += 1;
243 }
244 index
245 };
246 }
247
248 Rotate::<OFFSET>::swizzle(self)
249 }
250
251 /// Rotates the vector such that the first `self.len() - OFFSET` elements of the vector move to
252 /// the end while the last `OFFSET` elements move to the front. After calling `rotate_elements_right`,
253 /// the element previously at index `self.len() - OFFSET` will become the first element in the slice.
254 /// ```
255 /// # #![feature(portable_simd)]
256 /// # #[cfg(feature = "as_crate")] use core_simd::simd::Simd;
257 /// # #[cfg(not(feature = "as_crate"))] use core::simd::Simd;
258 /// let a = Simd::from_array([0, 1, 2, 3]);
259 /// let x = a.rotate_elements_right::<3>();
260 /// assert_eq!(x.to_array(), [1, 2, 3, 0]);
261 ///
262 /// let y = a.rotate_elements_right::<7>();
263 /// assert_eq!(y.to_array(), [1, 2, 3, 0]);
264 /// ```
265 #[inline]
266 #[must_use = "method returns a new vector and does not mutate the original inputs"]
267 pub fn rotate_elements_right<const OFFSET: usize>(self) -> Self {
268 struct Rotate<const OFFSET: usize>;
269
270 impl<const OFFSET: usize, const N: usize> Swizzle<N> for Rotate<OFFSET> {
271 const INDEX: [usize; N] = const {
272 let offset = N - OFFSET % N;
273 let mut index = [0; N];
274 let mut i = 0;
275 while i < N {
276 index[i] = (i + offset) % N;
277 i += 1;
278 }
279 index
280 };
281 }
282
283 Rotate::<OFFSET>::swizzle(self)
284 }
285
286 /// Shifts the vector elements to the left by `OFFSET`, filling in with
287 /// `padding` from the right.
288 /// ```
289 /// # #![feature(portable_simd)]
290 /// # #[cfg(feature = "as_crate")] use core_simd::simd::Simd;
291 /// # #[cfg(not(feature = "as_crate"))] use core::simd::Simd;
292 /// let a = Simd::from_array([0, 1, 2, 3]);
293 /// let x = a.shift_elements_left::<3>(255);
294 /// assert_eq!(x.to_array(), [3, 255, 255, 255]);
295 ///
296 /// let y = a.shift_elements_left::<7>(255);
297 /// assert_eq!(y.to_array(), [255, 255, 255, 255]);
298 /// ```
299 #[inline]
300 #[must_use = "method returns a new vector and does not mutate the original inputs"]
301 pub fn shift_elements_left<const OFFSET: usize>(self, padding: T) -> Self {
302 struct Shift<const OFFSET: usize>;
303
304 impl<const OFFSET: usize, const N: usize> Swizzle<N> for Shift<OFFSET> {
305 const INDEX: [usize; N] = const {
306 let mut index = [N; N];
307 let mut i = 0;
308 while i + OFFSET < N {
309 index[i] = i + OFFSET;
310 i += 1;
311 }
312 index
313 };
314 }
315
316 Shift::<OFFSET>::concat_swizzle(self, Simd::splat(padding))
317 }
318
319 /// Shifts the vector elements to the right by `OFFSET`, filling in with
320 /// `padding` from the left.
321 /// ```
322 /// # #![feature(portable_simd)]
323 /// # #[cfg(feature = "as_crate")] use core_simd::simd::Simd;
324 /// # #[cfg(not(feature = "as_crate"))] use core::simd::Simd;
325 /// let a = Simd::from_array([0, 1, 2, 3]);
326 /// let x = a.shift_elements_right::<3>(255);
327 /// assert_eq!(x.to_array(), [255, 255, 255, 0]);
328 ///
329 /// let y = a.shift_elements_right::<7>(255);
330 /// assert_eq!(y.to_array(), [255, 255, 255, 255]);
331 /// ```
332 #[inline]
333 #[must_use = "method returns a new vector and does not mutate the original inputs"]
334 pub fn shift_elements_right<const OFFSET: usize>(self, padding: T) -> Self {
335 struct Shift<const OFFSET: usize>;
336
337 impl<const OFFSET: usize, const N: usize> Swizzle<N> for Shift<OFFSET> {
338 const INDEX: [usize; N] = const {
339 let mut index = [N; N];
340 let mut i = OFFSET;
341 while i < N {
342 index[i] = i - OFFSET;
343 i += 1;
344 }
345 index
346 };
347 }
348
349 Shift::<OFFSET>::concat_swizzle(self, Simd::splat(padding))
350 }
351
352 /// Interleave two vectors.
353 ///
354 /// The resulting vectors contain elements taken alternatively from `self` and `other`, first
355 /// filling the first result, and then the second.
356 ///
357 /// The reverse of this operation is [`Simd::deinterleave`].
358 ///
359 /// ```
360 /// # #![feature(portable_simd)]
361 /// # use core::simd::Simd;
362 /// let a = Simd::from_array([0, 1, 2, 3]);
363 /// let b = Simd::from_array([4, 5, 6, 7]);
364 /// let (x, y) = a.interleave(b);
365 /// assert_eq!(x.to_array(), [0, 4, 1, 5]);
366 /// assert_eq!(y.to_array(), [2, 6, 3, 7]);
367 /// ```
368 #[inline]
369 #[must_use = "method returns a new vector and does not mutate the original inputs"]
370 pub fn interleave(self, other: Self) -> (Self, Self) {
371 const fn interleave<const N: usize>(high: bool) -> [usize; N] {
372 let mut idx = [0; N];
373 let mut i = 0;
374 while i < N {
375 let dst_index = if high { i + N } else { i };
376 let src_index = dst_index / 2 + (dst_index % 2) * N;
377 idx[i] = src_index;
378 i += 1;
379 }
380 idx
381 }
382
383 struct Lo;
384 struct Hi;
385
386 impl<const N: usize> Swizzle<N> for Lo {
387 const INDEX: [usize; N] = interleave::<N>(false);
388 }
389
390 impl<const N: usize> Swizzle<N> for Hi {
391 const INDEX: [usize; N] = interleave::<N>(true);
392 }
393
394 (
395 Lo::concat_swizzle(self, other),
396 Hi::concat_swizzle(self, other),
397 )
398 }
399
400 /// Deinterleave two vectors.
401 ///
402 /// The first result takes every other element of `self` and then `other`, starting with
403 /// the first element.
404 ///
405 /// The second result takes every other element of `self` and then `other`, starting with
406 /// the second element.
407 ///
408 /// The reverse of this operation is [`Simd::interleave`].
409 ///
410 /// ```
411 /// # #![feature(portable_simd)]
412 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
413 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
414 /// # use simd::Simd;
415 /// let a = Simd::from_array([0, 4, 1, 5]);
416 /// let b = Simd::from_array([2, 6, 3, 7]);
417 /// let (x, y) = a.deinterleave(b);
418 /// assert_eq!(x.to_array(), [0, 1, 2, 3]);
419 /// assert_eq!(y.to_array(), [4, 5, 6, 7]);
420 /// ```
421 #[inline]
422 #[must_use = "method returns a new vector and does not mutate the original inputs"]
423 pub fn deinterleave(self, other: Self) -> (Self, Self) {
424 const fn deinterleave<const N: usize>(second: bool) -> [usize; N] {
425 let mut idx = [0; N];
426 let mut i = 0;
427 while i < N {
428 idx[i] = i * 2 + second as usize;
429 i += 1;
430 }
431 idx
432 }
433
434 struct Even;
435 struct Odd;
436
437 impl<const N: usize> Swizzle<N> for Even {
438 const INDEX: [usize; N] = deinterleave::<N>(false);
439 }
440
441 impl<const N: usize> Swizzle<N> for Odd {
442 const INDEX: [usize; N] = deinterleave::<N>(true);
443 }
444
445 (
446 Even::concat_swizzle(self, other),
447 Odd::concat_swizzle(self, other),
448 )
449 }
450
451 /// Resize a vector.
452 ///
453 /// If `M` > `N`, extends the length of a vector, setting the new elements to `value`.
454 /// If `M` < `N`, truncates the vector to the first `M` elements.
455 ///
456 /// ```
457 /// # #![feature(portable_simd)]
458 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
459 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
460 /// # use simd::u32x4;
461 /// let x = u32x4::from_array([0, 1, 2, 3]);
462 /// assert_eq!(x.resize::<8>(9).to_array(), [0, 1, 2, 3, 9, 9, 9, 9]);
463 /// assert_eq!(x.resize::<2>(9).to_array(), [0, 1]);
464 /// ```
465 #[inline]
466 #[must_use = "method returns a new vector and does not mutate the original inputs"]
467 pub fn resize<const M: usize>(self, value: T) -> Simd<T, M>
468 where
469 LaneCount<M>: SupportedLaneCount,
470 {
471 struct Resize<const N: usize>;
472 impl<const N: usize, const M: usize> Swizzle<M> for Resize<N> {
473 const INDEX: [usize; M] = const {
474 let mut index = [0; M];
475 let mut i = 0;
476 while i < M {
477 index[i] = if i < N { i } else { N };
478 i += 1;
479 }
480 index
481 };
482 }
483 Resize::<N>::concat_swizzle(self, Simd::splat(value))
484 }
485
486 /// Extract a vector from another vector.
487 ///
488 /// ```
489 /// # #![feature(portable_simd)]
490 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
491 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
492 /// # use simd::u32x4;
493 /// let x = u32x4::from_array([0, 1, 2, 3]);
494 /// assert_eq!(x.extract::<1, 2>().to_array(), [1, 2]);
495 /// ```
496 #[inline]
497 #[must_use = "method returns a new vector and does not mutate the original inputs"]
498 pub fn extract<const START: usize, const LEN: usize>(self) -> Simd<T, LEN>
499 where
500 LaneCount<LEN>: SupportedLaneCount,
501 {
502 struct Extract<const N: usize, const START: usize>;
503 impl<const N: usize, const START: usize, const LEN: usize> Swizzle<LEN> for Extract<N, START> {
504 const INDEX: [usize; LEN] = const {
505 assert!(START + LEN <= N, "index out of bounds");
506 let mut index = [0; LEN];
507 let mut i = 0;
508 while i < LEN {
509 index[i] = START + i;
510 i += 1;
511 }
512 index
513 };
514 }
515 Extract::<N, START>::swizzle(self)
516 }
517}
518
519impl<T, const N: usize> Mask<T, N>
520where
521 T: MaskElement,
522 LaneCount<N>: SupportedLaneCount,
523{
524 /// Reverse the order of the elements in the mask.
525 #[inline]
526 #[must_use = "method returns a new vector and does not mutate the original inputs"]
527 pub fn reverse(self) -> Self {
528 // Safety: swizzles are safe for masks
529 unsafe { Self::from_simd_unchecked(self.to_simd().reverse()) }
530 }
531
532 /// Rotates the mask such that the first `OFFSET` elements of the slice move to the end
533 /// while the last `self.len() - OFFSET` elements move to the front. After calling `rotate_elements_left`,
534 /// the element previously at index `OFFSET` will become the first element in the slice.
535 #[inline]
536 #[must_use = "method returns a new vector and does not mutate the original inputs"]
537 pub fn rotate_elements_left<const OFFSET: usize>(self) -> Self {
538 // Safety: swizzles are safe for masks
539 unsafe { Self::from_simd_unchecked(self.to_simd().rotate_elements_left::<OFFSET>()) }
540 }
541
542 /// Rotates the mask such that the first `self.len() - OFFSET` elements of the mask move to
543 /// the end while the last `OFFSET` elements move to the front. After calling `rotate_elements_right`,
544 /// the element previously at index `self.len() - OFFSET` will become the first element in the slice.
545 #[inline]
546 #[must_use = "method returns a new vector and does not mutate the original inputs"]
547 pub fn rotate_elements_right<const OFFSET: usize>(self) -> Self {
548 // Safety: swizzles are safe for masks
549 unsafe { Self::from_simd_unchecked(self.to_simd().rotate_elements_right::<OFFSET>()) }
550 }
551
552 /// Shifts the mask elements to the left by `OFFSET`, filling in with
553 /// `padding` from the right.
554 #[inline]
555 #[must_use = "method returns a new mask and does not mutate the original inputs"]
556 pub fn shift_elements_left<const OFFSET: usize>(self, padding: bool) -> Self {
557 // Safety: swizzles are safe for masks
558 unsafe {
559 Self::from_simd_unchecked(self.to_simd().shift_elements_left::<OFFSET>(if padding {
560 T::TRUE
561 } else {
562 T::FALSE
563 }))
564 }
565 }
566
567 /// Shifts the mask elements to the right by `OFFSET`, filling in with
568 /// `padding` from the left.
569 #[inline]
570 #[must_use = "method returns a new mask and does not mutate the original inputs"]
571 pub fn shift_elements_right<const OFFSET: usize>(self, padding: bool) -> Self {
572 // Safety: swizzles are safe for masks
573 unsafe {
574 Self::from_simd_unchecked(self.to_simd().shift_elements_right::<OFFSET>(if padding {
575 T::TRUE
576 } else {
577 T::FALSE
578 }))
579 }
580 }
581
582 /// Interleave two masks.
583 ///
584 /// The resulting masks contain elements taken alternatively from `self` and `other`, first
585 /// filling the first result, and then the second.
586 ///
587 /// The reverse of this operation is [`Mask::deinterleave`].
588 ///
589 /// ```
590 /// # #![feature(portable_simd)]
591 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
592 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
593 /// # use simd::mask32x4;
594 /// let a = mask32x4::from_array([false, true, false, true]);
595 /// let b = mask32x4::from_array([false, false, true, true]);
596 /// let (x, y) = a.interleave(b);
597 /// assert_eq!(x.to_array(), [false, false, true, false]);
598 /// assert_eq!(y.to_array(), [false, true, true, true]);
599 /// ```
600 #[inline]
601 #[must_use = "method returns a new vector and does not mutate the original inputs"]
602 pub fn interleave(self, other: Self) -> (Self, Self) {
603 let (lo, hi) = self.to_simd().interleave(other.to_simd());
604 // Safety: swizzles are safe for masks
605 unsafe { (Self::from_simd_unchecked(lo), Self::from_simd_unchecked(hi)) }
606 }
607
608 /// Deinterleave two masks.
609 ///
610 /// The first result takes every other element of `self` and then `other`, starting with
611 /// the first element.
612 ///
613 /// The second result takes every other element of `self` and then `other`, starting with
614 /// the second element.
615 ///
616 /// The reverse of this operation is [`Mask::interleave`].
617 ///
618 /// ```
619 /// # #![feature(portable_simd)]
620 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
621 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
622 /// # use simd::mask32x4;
623 /// let a = mask32x4::from_array([false, true, false, true]);
624 /// let b = mask32x4::from_array([false, false, true, true]);
625 /// let (x, y) = a.deinterleave(b);
626 /// assert_eq!(x.to_array(), [false, false, false, true]);
627 /// assert_eq!(y.to_array(), [true, true, false, true]);
628 /// ```
629 #[inline]
630 #[must_use = "method returns a new vector and does not mutate the original inputs"]
631 pub fn deinterleave(self, other: Self) -> (Self, Self) {
632 let (even, odd) = self.to_simd().deinterleave(other.to_simd());
633 // Safety: swizzles are safe for masks
634 unsafe {
635 (
636 Self::from_simd_unchecked(even),
637 Self::from_simd_unchecked(odd),
638 )
639 }
640 }
641
642 /// Resize a mask.
643 ///
644 /// If `M` > `N`, extends the length of a mask, setting the new elements to `value`.
645 /// If `M` < `N`, truncates the mask to the first `M` elements.
646 ///
647 /// ```
648 /// # #![feature(portable_simd)]
649 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
650 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
651 /// # use simd::mask32x4;
652 /// let x = mask32x4::from_array([false, true, true, false]);
653 /// assert_eq!(x.resize::<8>(true).to_array(), [false, true, true, false, true, true, true, true]);
654 /// assert_eq!(x.resize::<2>(true).to_array(), [false, true]);
655 /// ```
656 #[inline]
657 #[must_use = "method returns a new vector and does not mutate the original inputs"]
658 pub fn resize<const M: usize>(self, value: bool) -> Mask<T, M>
659 where
660 LaneCount<M>: SupportedLaneCount,
661 {
662 // Safety: swizzles are safe for masks
663 unsafe {
664 Mask::<T, M>::from_simd_unchecked(self.to_simd().resize::<M>(if value {
665 T::TRUE
666 } else {
667 T::FALSE
668 }))
669 }
670 }
671
672 /// Extract a vector from another vector.
673 ///
674 /// ```
675 /// # #![feature(portable_simd)]
676 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
677 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
678 /// # use simd::mask32x4;
679 /// let x = mask32x4::from_array([false, true, true, false]);
680 /// assert_eq!(x.extract::<1, 2>().to_array(), [true, true]);
681 /// ```
682 #[inline]
683 #[must_use = "method returns a new vector and does not mutate the original inputs"]
684 pub fn extract<const START: usize, const LEN: usize>(self) -> Mask<T, LEN>
685 where
686 LaneCount<LEN>: SupportedLaneCount,
687 {
688 // Safety: swizzles are safe for masks
689 unsafe { Mask::<T, LEN>::from_simd_unchecked(self.to_simd().extract::<START, LEN>()) }
690 }
691}