1 | use 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)] |
45 | pub 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. |
73 | pub 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 | |
188 | impl<T, const N: usize> Simd<T, N> |
189 | where |
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 | |
517 | impl<T, const N: usize> Mask<T, N> |
518 | where |
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 | } |
690 |
Definitions
- simd_swizzle
- Swizzle
- swizzle
- SimdShuffleIdx
- concat_swizzle
- SimdShuffleIdx
- swizzle_mask
- concat_swizzle_mask
- reverse
- Reverse
- rotate_elements_left
- Rotate
- rotate_elements_right
- Rotate
- shift_elements_left
- Shift
- shift_elements_right
- Shift
- interleave
- interleave
- Lo
- Hi
- deinterleave
- deinterleave
- Even
- Odd
- resize
- Resize
- extract
- Extract
- reverse
- rotate_elements_left
- rotate_elements_right
- shift_elements_left
- shift_elements_right
- interleave
- deinterleave
- resize
Learn Rust with the experts
Find out more