<xstd/ints/bit/bit_expand.hpp>¶
xstd::bit_expand¶
#ifdef XSTD_HAS_STD_BIT_COMPRESS
// (1)
template<class T>
requires ints::detail::std_compresses_bits<T>
constexpr auto bit_expand(T src, T mask) noexcept -> T;
#endif
// (2)
template<unsigned_integer T>
requires (not ints::detail::std_compresses_bits<T>)
constexpr auto bit_expand(T src, T mask) noexcept(nothrow_const_operators<T>) -> T;
Deposits the low bits of an unsigned integer on the positions a mask selects.
- The forwarding overload, which calls
std::bit_expand. - The template, for every other
unsigned_integer.
Parameters¶
| Parameter | Meaning |
|---|---|
src |
the value whose low bits are deposited |
mask |
the positions to deposit them on |
Constraints: As for bit_reverse.
Return value¶
Returns: expand(src, mask), P3104R5's sum of
mask[n]·src[mask[0] + … + mask[n-1]]·2^n over n in [0, N): the low bits of src deposited, in their order, on
the positions of mask's ones.
Exceptions¶
The exception specification is nothrow_const_operators<T>, so the call is noexcept for every built-in type and not
for absl::uint128.
Remarks¶
- Where
__cpp_lib_bitopsis at least202607Landstd::bit_compress,std::bit_expand,std::bit_repeatandstd::bit_reverseall takeT, the call isstd::bit_expand(src, mask), unconditionallynoexcept, and the template does not takeT. On libstdc++ whereXSTD_INTS_HAS_FAST_BMI2is defined it is not, since that<bit>emits noPEXTorPDEP, and the template takes everyunsigned_integer. - The template expands each block of
maskon its own, drawing on the bits ofsrcthe lower blocks left unconsumed, so the bits of a mask on either side of bit 64 receive adjacent bits ofsrc. - Outside a constant expression, where
XSTD_INTS_HAS_FAST_BMI2is defined, as forbit_compress, a block is onePDEP. Everywhere else, and in every constant expression, a block takes the portable kernel, which walks the mask's ones from the lowest and deposits the next bit ofsrcon each by a mask rather than a branch. - A 64-bit call is one
pdepwith no branch or call under-mbmi2and-march=x86-64-v3, and has nopextorpdepunder-march=x86-64,-mgfni,bdver4,znver1orznver2.
Notes¶
- [bit.permute]'s example, as
P3104R6 words it, holds:
bit_expand(0bABCD, 0b0101)is0b0C0Dfor any bitsA,B,CandD. - The paper's equivalences hold: a mask of contiguous ones is an and and a shift, and expanding
2^nthroughxgivesx's one of rankn, and2^n - 1itsnlowest ones. - The paper's interleaving holds:
bit_expand(x, bit_repeat(0b10u, 2)) | bit_expand(y, bit_repeat(0b01u, 2))is the Z-order index ofxandy. - An empty mask gives zero, a full one
src, and one through the top bit gives the top bit. - It undoes
bit_compressthrough the same mask, and is undone by it, as far as the mask's population lets it. - A call is a constant expression for every type it takes.
- The result has type
T, not theintthat integral promotion makes of a narrowT.
See also¶
| Entity | Relation |
|---|---|
bit_compress |
the inverse, through the same mask |
bit_reverse, bit_repeat |
the other permutations |
bit_select |
the position of the one of a given rank, where expanding 2^k deposits |
| Notation | what N, x[n] and a block mean here |
| P3104R6 | the paper that proposes std::bit_expand |