Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions library/core/src/num/int_bits.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
//! Implementations for `uN::gather_bits` and `uN::scatter_bits`
//! Implementations for `uN::extract_bits` and `uN::deposit_bits`
//!
//! For the purposes of this implementation, the operations can be thought
//! of as operating on the input bits as a list, starting from the least
//! significant bit. Gathering is like `Vec::retain` that deletes bits
//! where the mask has a zero. Scattering is like doing the inverse by
//! inserting the zeros that gathering would delete.
//! significant bit. Extraction is like `Vec::retain` that deletes bits
//! where the mask has a zero. Deposition is like doing the inverse by
//! inserting the zeros that extraction would delete.
//!
//! Key observation: Each bit that is gathered/scattered needs to be
//! Key observation: Each extracted or deposited bit needs to be
//! shifted by the count of zeros up to the corresponding mask bit.
//!
//! With that in mind, the general idea is to decompose the operation into
//! a sequence of stages in `0..log2(BITS)`, where each stage shifts some
//! of the bits by `n = 1 << stage`. The masks for each stage are computed
//! via prefix counts of zeros in the mask.
//!
//! # Gathering
//! # Extraction
//!
//! Consider the input as a sequence of runs of data (bitstrings A,B,C,...),
//! split by fixed-width groups of zeros ('.'), initially at width `n = 1`.
Expand All @@ -36,9 +36,9 @@
//! ........abbbcccccddeghh
//! ```
//!
//! # Scattering
//! # Deposition
//!
//! For `scatter_bits`, the stages are reversed. We start with a single run of
//! For `deposit_bits`, the stages are reversed. We start with a single run of
//! data in the low bits. Each stage then splits each run of data in two by
//! shifting part of it left by `n`, which is halved each stage.
//! ```text
Expand Down Expand Up @@ -100,7 +100,7 @@ macro_rules! uint_impl {
}

#[inline(always)]
pub(in super::super) const fn gather_impl(mut x: $U, sparse: $U) -> $U {
pub(in super::super) const fn extract_impl(mut x: $U, sparse: $U) -> $U {
let masks = prepare(sparse);
x &= sparse;
let mut stage = 0;
Expand Down Expand Up @@ -131,7 +131,7 @@ macro_rules! uint_impl {
x
}
#[inline(always)]
pub(in super::super) const fn scatter_impl(mut x: $U, sparse: $U) -> $U {
pub(in super::super) const fn deposit_impl(mut x: $U, sparse: $U) -> $U {
let masks = prepare(sparse);
let mut stage = STAGES;
while stage > 0 {
Expand Down
16 changes: 8 additions & 8 deletions library/core/src/num/uint_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,15 +507,15 @@ macro_rules! uint_impl {
/// #![feature(uint_gather_scatter_bits)]
#[doc = concat!("let n: ", stringify!($SelfT), " = 0b1011_1100;")]
///
/// assert_eq!(n.gather_bits(0b0010_0100), 0b0000_0011);
/// assert_eq!(n.gather_bits(0xF0), 0b0000_1011);
/// assert_eq!(n.extract_bits(0b0010_0100), 0b0000_0011);
/// assert_eq!(n.extract_bits(0xF0), 0b0000_1011);
/// ```
#[unstable(feature = "uint_gather_scatter_bits", issue = "149069")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn gather_bits(self, mask: Self) -> Self {
crate::num::int_bits::$ActualT::gather_impl(self as $ActualT, mask as $ActualT) as $SelfT
pub const fn extract_bits(self, mask: Self) -> Self {
crate::num::int_bits::$ActualT::extract_impl(self as $ActualT, mask as $ActualT) as $SelfT
}

/// Returns an integer with the least significant bits of `self`
Expand All @@ -524,15 +524,15 @@ macro_rules! uint_impl {
/// #![feature(uint_gather_scatter_bits)]
#[doc = concat!("let n: ", stringify!($SelfT), " = 0b1010_1101;")]
///
/// assert_eq!(n.scatter_bits(0b0101_0101), 0b0101_0001);
/// assert_eq!(n.scatter_bits(0xF0), 0b1101_0000);
/// assert_eq!(n.deposit_bits(0b0101_0101), 0b0101_0001);
/// assert_eq!(n.deposit_bits(0xF0), 0b1101_0000);
/// ```
#[unstable(feature = "uint_gather_scatter_bits", issue = "149069")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn scatter_bits(self, mask: Self) -> Self {
crate::num::int_bits::$ActualT::scatter_impl(self as $ActualT, mask as $ActualT) as $SelfT
pub const fn deposit_bits(self, mask: Self) -> Self {
crate::num::int_bits::$ActualT::deposit_impl(self as $ActualT, mask as $ActualT) as $SelfT
}

/// Reverses the order of bits in the integer. The least significant bit becomes the most significant bit,
Expand Down
4 changes: 2 additions & 2 deletions library/coretests/benches/num/int_bits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ macro_rules! bench_mask_kind {
($mask_kind:ident, $mask:expr) => {
mod $mask_kind {
use super::{Data, ITERATIONS, U};
bench_template!(U::gather_bits, gather_bits, $mask);
bench_template!(U::scatter_bits, scatter_bits, $mask);
bench_template!(U::extract_bits, extract_bits, $mask);
bench_template!(U::deposit_bits, deposit_bits, $mask);
}
};
}
Expand Down
108 changes: 54 additions & 54 deletions library/coretests/tests/num/uint_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,50 +127,50 @@ macro_rules! uint_module {
assert_eq_const_safe!($T: _1.swap_bytes(), _1);
}

fn test_gather_bits() {
assert_eq_const_safe!($T: $T::gather_bits(0b1010_0101, 0b0000_0011), 0b_0001);
assert_eq_const_safe!($T: $T::gather_bits(0b1010_0101, 0b0000_0110), 0b_0010);
assert_eq_const_safe!($T: $T::gather_bits(0b1010_0101, 0b0000_1100), 0b_0001);
assert_eq_const_safe!($T: $T::gather_bits(0b1010_0101, 0b0001_1000), 0b_0000);
assert_eq_const_safe!($T: $T::gather_bits(0b1010_0101, 0b0011_0000), 0b_0010);
assert_eq_const_safe!($T: $T::gather_bits(0b1010_0101, 0b0110_0000), 0b_0001);
assert_eq_const_safe!($T: $T::gather_bits(0b1010_0101, 0b1100_0000), 0b_0010);

assert_eq_const_safe!($T: A.gather_bits(_0), 0);
assert_eq_const_safe!($T: B.gather_bits(_0), 0);
assert_eq_const_safe!($T: C.gather_bits(_0), 0);
assert_eq_const_safe!($T: _0.gather_bits(A), 0);
assert_eq_const_safe!($T: _0.gather_bits(B), 0);
assert_eq_const_safe!($T: _0.gather_bits(C), 0);

assert_eq_const_safe!($T: A.gather_bits(_1), A);
assert_eq_const_safe!($T: B.gather_bits(_1), B);
assert_eq_const_safe!($T: C.gather_bits(_1), C);
assert_eq_const_safe!($T: _1.gather_bits(0b0010_0001), 0b0000_0011);
assert_eq_const_safe!($T: _1.gather_bits(0b0010_1100), 0b0000_0111);
assert_eq_const_safe!($T: _1.gather_bits(0b0111_1001), 0b0001_1111);
}

fn test_scatter_bits() {
assert_eq_const_safe!($T: $T::scatter_bits(0b1111, 0b1001_0110), 0b1001_0110);
assert_eq_const_safe!($T: $T::scatter_bits(0b0001, 0b1001_0110), 0b0000_0010);
assert_eq_const_safe!($T: $T::scatter_bits(0b0010, 0b1001_0110), 0b0000_0100);
assert_eq_const_safe!($T: $T::scatter_bits(0b0100, 0b1001_0110), 0b0001_0000);
assert_eq_const_safe!($T: $T::scatter_bits(0b1000, 0b1001_0110), 0b1000_0000);

assert_eq_const_safe!($T: A.scatter_bits(_0), 0);
assert_eq_const_safe!($T: B.scatter_bits(_0), 0);
assert_eq_const_safe!($T: C.scatter_bits(_0), 0);
assert_eq_const_safe!($T: _0.scatter_bits(A), 0);
assert_eq_const_safe!($T: _0.scatter_bits(B), 0);
assert_eq_const_safe!($T: _0.scatter_bits(C), 0);

assert_eq_const_safe!($T: A.scatter_bits(_1), A);
assert_eq_const_safe!($T: B.scatter_bits(_1), B);
assert_eq_const_safe!($T: C.scatter_bits(_1), C);
assert_eq_const_safe!($T: _1.scatter_bits(A), A);
assert_eq_const_safe!($T: _1.scatter_bits(B), B);
assert_eq_const_safe!($T: _1.scatter_bits(C), C);
fn test_extract_bits() {
assert_eq_const_safe!($T: $T::extract_bits(0b1010_0101, 0b0000_0011), 0b_0001);
assert_eq_const_safe!($T: $T::extract_bits(0b1010_0101, 0b0000_0110), 0b_0010);
assert_eq_const_safe!($T: $T::extract_bits(0b1010_0101, 0b0000_1100), 0b_0001);
assert_eq_const_safe!($T: $T::extract_bits(0b1010_0101, 0b0001_1000), 0b_0000);
assert_eq_const_safe!($T: $T::extract_bits(0b1010_0101, 0b0011_0000), 0b_0010);
assert_eq_const_safe!($T: $T::extract_bits(0b1010_0101, 0b0110_0000), 0b_0001);
assert_eq_const_safe!($T: $T::extract_bits(0b1010_0101, 0b1100_0000), 0b_0010);

assert_eq_const_safe!($T: A.extract_bits(_0), 0);
assert_eq_const_safe!($T: B.extract_bits(_0), 0);
assert_eq_const_safe!($T: C.extract_bits(_0), 0);
assert_eq_const_safe!($T: _0.extract_bits(A), 0);
assert_eq_const_safe!($T: _0.extract_bits(B), 0);
assert_eq_const_safe!($T: _0.extract_bits(C), 0);

assert_eq_const_safe!($T: A.extract_bits(_1), A);
assert_eq_const_safe!($T: B.extract_bits(_1), B);
assert_eq_const_safe!($T: C.extract_bits(_1), C);
assert_eq_const_safe!($T: _1.extract_bits(0b0010_0001), 0b0000_0011);
assert_eq_const_safe!($T: _1.extract_bits(0b0010_1100), 0b0000_0111);
assert_eq_const_safe!($T: _1.extract_bits(0b0111_1001), 0b0001_1111);
}

fn test_deposit_bits() {
assert_eq_const_safe!($T: $T::deposit_bits(0b1111, 0b1001_0110), 0b1001_0110);
assert_eq_const_safe!($T: $T::deposit_bits(0b0001, 0b1001_0110), 0b0000_0010);
assert_eq_const_safe!($T: $T::deposit_bits(0b0010, 0b1001_0110), 0b0000_0100);
assert_eq_const_safe!($T: $T::deposit_bits(0b0100, 0b1001_0110), 0b0001_0000);
assert_eq_const_safe!($T: $T::deposit_bits(0b1000, 0b1001_0110), 0b1000_0000);

assert_eq_const_safe!($T: A.deposit_bits(_0), 0);
assert_eq_const_safe!($T: B.deposit_bits(_0), 0);
assert_eq_const_safe!($T: C.deposit_bits(_0), 0);
assert_eq_const_safe!($T: _0.deposit_bits(A), 0);
assert_eq_const_safe!($T: _0.deposit_bits(B), 0);
assert_eq_const_safe!($T: _0.deposit_bits(C), 0);

assert_eq_const_safe!($T: A.deposit_bits(_1), A);
assert_eq_const_safe!($T: B.deposit_bits(_1), B);
assert_eq_const_safe!($T: C.deposit_bits(_1), C);
assert_eq_const_safe!($T: _1.deposit_bits(A), A);
assert_eq_const_safe!($T: _1.deposit_bits(B), B);
assert_eq_const_safe!($T: _1.deposit_bits(C), C);
}

fn test_reverse_bits() {
Expand Down Expand Up @@ -389,7 +389,7 @@ macro_rules! uint_module {

#[cfg(not(miri))] // Miri is too slow
#[test]
fn test_lots_of_gather_scatter() {
fn test_lots_of_extract_deposit() {
// Generate a handful of bit patterns to use as inputs
let xs = {
let mut xs = vec![];
Expand All @@ -414,7 +414,7 @@ macro_rules! uint_module {

for sparse in sparse_masks {
// Collect the set bits to sequential low bits
let dense = sparse.gather_bits(sparse);
let dense = sparse.extract_bits(sparse);
let count = sparse.count_ones();
assert_eq!(count, dense.count_ones());
assert_eq!(count, dense.trailing_ones());
Expand All @@ -424,27 +424,27 @@ macro_rules! uint_module {
let mut bit = 1 as $T;
for _ in 0..count {
let lowest_one = t.isolate_lowest_one();
assert_eq!(lowest_one, bit.scatter_bits(sparse));
assert_eq!(bit, lowest_one.gather_bits(sparse));
assert_eq!(lowest_one, bit.deposit_bits(sparse));
assert_eq!(bit, lowest_one.extract_bits(sparse));
t ^= lowest_one;
bit <<= 1;
}
// Other bits are ignored
assert_eq!(0, bit.wrapping_neg().scatter_bits(sparse));
assert_eq!(0, (!sparse).gather_bits(sparse));
assert_eq!(0, bit.wrapping_neg().deposit_bits(sparse));
assert_eq!(0, (!sparse).extract_bits(sparse));

for &x in &xs {
// Gather bits from `x & sparse` to `dense`
let dx = x.gather_bits(sparse);
let dx = x.extract_bits(sparse);
assert_eq!(dx & !dense, 0);

// Scatter bits from `x & dense` to `sparse`
let sx = x.scatter_bits(sparse);
let sx = x.deposit_bits(sparse);
assert_eq!(sx & !sparse, 0);

// The other recovers the input (within the mask)
assert_eq!(dx.scatter_bits(sparse), x & sparse);
assert_eq!(sx.gather_bits(sparse), x & dense);
assert_eq!(dx.deposit_bits(sparse), x & sparse);
assert_eq!(sx.extract_bits(sparse), x & dense);
}
}
}
Expand Down
Loading