Skip to content

Commit b984120

Browse files
authored
Rollup merge of #149539 - quaternic:gather-scatter-bits, r=Mark-Simulacrum
Additional test for uN::{gather,scatter}_bits Feature gate: #![feature(uint_gather_scatter_bits)] Tracking issue: #149069 Accepted ACP: rust-lang/libs-team#695 (comment) Adds an additional runtime test for `uN::gather_bits` and `uN::scatter_bits` in coretests. They are each other's inverses in a sense, so a shared test can test both with relative ease. I plan to follow up with optimized implementations for these functions.
2 parents 77744ea + f49eaec commit b984120

File tree

1 file changed

+62
-0
lines changed

1 file changed

+62
-0
lines changed

library/coretests/tests/num/uint_macros.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,68 @@ macro_rules! uint_module {
387387
}
388388
}
389389

390+
#[cfg(not(miri))] // Miri is too slow
391+
#[test]
392+
fn test_lots_of_gather_scatter() {
393+
// Generate a handful of bit patterns to use as inputs
394+
let xs = {
395+
let mut xs = vec![];
396+
let mut x: $T = !0;
397+
let mut w = $T::BITS;
398+
while w > 0 {
399+
w >>= 1;
400+
xs.push(x);
401+
xs.push(!x);
402+
x ^= x << w;
403+
}
404+
xs
405+
};
406+
if $T::BITS == 8 {
407+
assert_eq!(&xs, &[0xff, 0x00, 0x0f, 0xf0, 0x33, 0xcc, 0x55, 0xaa]);
408+
}
409+
410+
// `256 * (BITS / 5)` masks
411+
let sparse_masks = (i8::MIN..=i8::MAX)
412+
.map(|i| (i as i128 as $T).rotate_right(4))
413+
.flat_map(|x| (0..$T::BITS).step_by(5).map(move |r| x.rotate_right(r)));
414+
415+
for sparse in sparse_masks {
416+
// Collect the set bits to sequential low bits
417+
let dense = sparse.gather_bits(sparse);
418+
let count = sparse.count_ones();
419+
assert_eq!(count, dense.count_ones());
420+
assert_eq!(count, dense.trailing_ones());
421+
422+
// Check that each bit is individually mapped correctly
423+
let mut t = sparse;
424+
let mut bit = 1 as $T;
425+
for _ in 0..count {
426+
let lowest_one = t.isolate_lowest_one();
427+
assert_eq!(lowest_one, bit.scatter_bits(sparse));
428+
assert_eq!(bit, lowest_one.gather_bits(sparse));
429+
t ^= lowest_one;
430+
bit <<= 1;
431+
}
432+
// Other bits are ignored
433+
assert_eq!(0, bit.wrapping_neg().scatter_bits(sparse));
434+
assert_eq!(0, (!sparse).gather_bits(sparse));
435+
436+
for &x in &xs {
437+
// Gather bits from `x & sparse` to `dense`
438+
let dx = x.gather_bits(sparse);
439+
assert_eq!(dx & !dense, 0);
440+
441+
// Scatter bits from `x & dense` to `sparse`
442+
let sx = x.scatter_bits(sparse);
443+
assert_eq!(sx & !sparse, 0);
444+
445+
// The other recovers the input (within the mask)
446+
assert_eq!(dx.scatter_bits(sparse), x & sparse);
447+
assert_eq!(sx.gather_bits(sparse), x & dense);
448+
}
449+
}
450+
}
451+
390452
test_runtime_and_compiletime! {
391453
fn test_div_floor() {
392454
assert_eq_const_safe!($T: (8 as $T).div_floor(3), 2);

0 commit comments

Comments
 (0)