I have the following snippets somewhere in my current code base:
// uint32_t id; defined somewhere
bool msb_set = id & 0x80000000
And would like to change this to something more flexible:
using id_t = uint64_t;
id_t id;
bool msb_set = id & 0x80000000 // uh-oh, semantic change for any other differently sized inttype
How can I most easily generate the appropriate literal depending on the concrete inttype I'm using? I'm looking for sth along the lines of
numeric_constants<id_t>::int_with_msb_set();
You can leverage a std::bitset
to check if the most significant bit is set. You can convert the number to a std::bitset
and then return the most significant bit like
template<typename T>
constexpr bool mb_set(T value)
{
constexpr auto size = sizeof(T) * CHAR_BIT;
return std::bitset<size>(value)[size - 1];
}
testing this on clang with -O2
or -O3
optimizes the function away to a shr
instruction.
Here is a function that returns the masks you want:
template<typename T>
constexpr T getMsbMask()
{
if constexpr (std::is_unsigned_v<T>)
return T(-1) - T(-1) / 2;
else
return std::numeric_limits<T>::min();
// Unsigned branch computes 0b11111... - 0b01111...
// Signed branch assumes two's complement, which will soon be the standard:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0907r0.html
}
The compiler can evidently figure out these constant values at compile-time, so there is no speed penalty whatsoever.
The other obvious solution would just be a struct with specializations for each type (akin to std::numeric_limits
).
User contributions licensed under CC BY-SA 3.0