5#include <Sawyer/Assert.h>
6#include <Sawyer/Optional.h>
19template<
typename Un
signed>
20inline size_t nBits(Unsigned = Unsigned(0)) {
21 return 8*
sizeof(Unsigned);
27template<
typename Un
signed>
28inline Unsigned
all(
bool b =
true) {
29 return Unsigned(0) - Unsigned(b ? 1 : 0);
32template<
typename Un
signed>
inline Unsigned
lowMask(
size_t n);
39template<
typename Un
signed>
40inline Unsigned
allLsb(Unsigned src,
size_t w,
bool b =
true) {
41 ASSERT_require(w <=
nBits(src));
43 return src | lowMask<Unsigned>(w);
45 return src & ~lowMask<Unsigned>(w);
56template<
typename Un
signed>
58 return n >= nBits<Unsigned>() ? all<Unsigned>(
true) : (Unsigned(1) << n) - Unsigned(1);
67template<
typename Un
signed>
69 return n >= nBits<Unsigned>() ? all<Unsigned>(
true) : lowMask<Unsigned>(n) << (nBits<Unsigned>() - n);
78template<
typename Un
signed>
79inline Unsigned
select(Unsigned cond, Unsigned a, Unsigned b) {
80 return (a & cond) | (b & ~cond);
90template<
typename Un
signed>
91inline Unsigned
shiftLeft(Unsigned src,
size_t n,
bool b =
false) {
92 if (n >=
nBits(src)) {
93 return all<Unsigned>(b);
95 return Unsigned(src << n) | (all<Unsigned>(b) & lowMask<Unsigned>(n));
107template<
typename Un
signed>
108inline Unsigned
shiftLeftLsb(Unsigned src,
size_t w,
size_t n,
bool b =
false) {
109 ASSERT_require(w <=
nBits(src));
124template<
typename Un
signed>
125inline Unsigned
shiftRight(Unsigned src,
size_t n,
bool b =
false) {
126 if (n >=
nBits(src)) {
127 return all<Unsigned>(b);
129 return Unsigned(src >> n) | (all<Unsigned>(b) & highMask<Unsigned>(n));
140template<
typename Un
signed>
141inline Unsigned
shiftRightLsb(Unsigned src,
size_t w,
size_t n,
bool b =
false) {
142 ASSERT_require(w <=
nBits(src));
146 const Unsigned affectedBits = lowMask<Unsigned>(w);
147 const Unsigned toShift =
select(affectedBits, src, all<Unsigned>(b));
158template<
typename Un
signed>
160 return i < nBits<Unsigned>() ?
shiftLeft(Unsigned(1), i) : Unsigned(0);
168template<
typename Un
signed>
170 ASSERT_require(w <=
nBits(src));
171 return select(lowMask<Unsigned>(w), position<Unsigned>(i), src);
181template<
typename Un
signed>
182inline Unsigned
mask(
size_t least,
size_t greatest) {
183 ASSERT_require(greatest < nBits<Unsigned>());
184 ASSERT_require(greatest >= least);
185 return shiftLeft(lowMask<Unsigned>(greatest - least + 1), least);
193template<
typename Un
signed>
194inline Unsigned
maskLsb(Unsigned src,
size_t w,
size_t least,
size_t greatest) {
195 ASSERT_require(w <=
nBits(src));
196 return select(lowMask<Unsigned>(w), mask<Unsigned>(least, greatest), src);
204template<
typename Un
signed>
205inline bool bit(Unsigned src,
size_t i) {
206 return i < nBits(src) ? (src & position<Unsigned>(i)) != 0 :
false;
215template<
typename Un
signed>
216inline bool bitLsb(Unsigned src,
size_t w,
size_t i) {
217 return i < w ? (src & position<Unsigned>(i)) != 0 :
false;
225template<
typename Un
signed>
226inline bool msb(Unsigned src) {
235template<
typename Un
signed>
236inline bool msbLsb(Unsigned src,
size_t w) {
237 ASSERT_require(w <=
nBits(src));
238 return w > 0 ?
bit(src, w-1) :
false;
249template<
typename Un
signed>
262template<
typename Un
signed>
273template<
typename Un
signed>
274inline Unsigned
bits(Unsigned src,
size_t least,
size_t greatest) {
275 return shiftRight(src & mask<Unsigned>(least, greatest), least);
284template<
typename Un
signed>
285inline Unsigned
bitsLsb(Unsigned src,
size_t w,
size_t least,
size_t greatest) {
286 return shiftRight(src & mask<Unsigned>(least, greatest) & lowMask<Unsigned>(w), least);
296template<
typename Un
signedTarget,
typename Un
signedSource>
297inline UnsignedTarget
convert(UnsignedSource x,
bool b =
false) {
298 if (
nBits(x) < nBits<UnsignedTarget>()) {
300 return UnsignedTarget(x) | (all<UnsignedTarget>(b) & ~lowMask<UnsignedTarget>(
nBits(x)));
303 return UnsignedTarget(x & lowMask<UnsignedSource>(nBits<UnsignedTarget>()));
313template<
typename Un
signedTarget,
typename Un
signedSource>
315 return convert<UnsignedTarget>(x,
msb(x));
323template<
typename Un
signed>
325 if (n <
nBits(src)) {
327 src |= mask<Unsigned>(n,
nBits(src)-1);
329 src &= ~mask<Unsigned>(n,
nBits(src)-1);
341template<
typename Un
signed>
343 ASSERT_require(n > 0);
344 ASSERT_require(m >= n);
345 ASSERT_require(m <=
nBits(src));
349 Unsigned newBitsMask = mask<Unsigned>(n, m-1);
351 return src | newBitsMask;
353 return src & ~newBitsMask;
365template<
typename Un
signed>
377template<
typename Un
signed>
379 ASSERT_require(w <=
nBits(src));
381 return select(lowMask<Unsigned>(w),
393template<
typename Un
signed>
405template<
typename Un
signed>
407 ASSERT_require(w <=
nBits(src));
409 return select(lowMask<Unsigned>(w),
422template<
typename Un
signed>
424 ASSERT_require(n != 0);
425 if (n >=
nBits(src)) {
428 size_t ngroups = (
nBits(src) + n - 1) / n;
430 for (
size_t i = 0; i < ngroups; ++i)
431 retval |=
shiftLeft(src & lowMask<Unsigned>(n), i*n);
443template<
typename Un
signed>
445 ASSERT_require(w <=
nBits(src));
454template<
typename Un
signed>
457 for (
size_t i =
nBits(src); i > 0; --i) {
465template<
typename Un
signed>
466inline size_t nSet(Unsigned src) {
480typename std::enable_if<std::is_integral<T>::value, T>::type
483 using Unsigned =
typename std::make_unsigned<T>::type;
485 const size_t n =
sizeof(Unsigned);
486 for (
size_t i = 0; i < n/2; ++i) {
487 const size_t loOffset = i*8;
488 const size_t hiOffset = nBits<Unsigned>() - i*8 - 8;
489 const auto loMask = mask<Unsigned>(loOffset, loOffset+7);
490 const auto hiMask = mask<Unsigned>(hiOffset, hiOffset+7);
491 const Unsigned lo = (u >> loOffset) & 0xff;
492 const Unsigned hi = (u >> hiOffset) & 0xff;
494 u &= ~(loMask | hiMask);
506 static const unsigned i = 1;
507 return *(
unsigned char*)&i == 0;
515 static const unsigned i = 1;
516 return *(
unsigned char*)&i == 1;
523inline typename std::enable_if<std::is_integral<T>::value, T>::type
525 using U =
typename std::make_unsigned<T>::type;
533inline typename std::enable_if<std::is_integral<T>::value, T>::type
535 using U =
typename std::make_unsigned<T>::type;
543inline typename std::enable_if<std::is_integral<T>::value, T>::type
545 using U =
typename std::make_unsigned<T>::type;
553inline typename std::enable_if<std::is_integral<T>::value, T>::type
555 using U =
typename std::make_unsigned<T>::type;
Holds a value or nothing.
Unsigned maskLsb(Unsigned src, size_t w, size_t least, size_t greatest)
Generate a mask without affecting other bits.
Unsigned shiftRightSignedLsb(Unsigned src, size_t w, size_t n)
Right shift low bits without affecting other bits.
Sawyer::Optional< size_t > highestSetBit(Unsigned src)
Index of the highest set bit.
Unsigned lowMask(size_t n)
Generate a value with low order bits set.
Unsigned replicateLsb(Unsigned src, size_t w, size_t n)
Replicate low-order bits to fill region without affecting other bits.
Unsigned signExtendLsb(Unsigned src, size_t n, size_t m)
Sign extend part of value without affecting other bits.
std::enable_if< std::is_integral< T >::value, T >::type reverseBytes(const T &x)
Reverse the bytes.
Unsigned select(Unsigned cond, Unsigned a, Unsigned b)
Combine two values based on a bit mask.
Unsigned shiftRight(Unsigned src, size_t n, bool b=false)
Right shift a value.
bool bitLsb(Unsigned src, size_t w, size_t i)
Extract a single bit.
UnsignedTarget convert(UnsignedSource x, bool b=false)
Extend or truncate a value.
std::enable_if< std::is_integral< T >::value, T >::type toBigEndian(const T x)
Convert integral value from host order to big endian.
std::enable_if< std::is_integral< T >::value, T >::type fromBigEndian(const T x)
Convert integral value from big endian to host order.
Unsigned shiftRightLsb(Unsigned src, size_t w, size_t n, bool b=false)
Right shift part of a value without affecting the rest.
Unsigned rotateLeft(Unsigned src, size_t n)
Rotate bits left.
bool isBigEndian()
True if host is big endian.
Unsigned position(size_t i)
Generate a single-bit mask.
bool msb(Unsigned src)
Most significant bit.
Unsigned rotateLeftLsb(Unsigned src, size_t w, size_t n)
Rotate low-order bits left without affecting others.
Unsigned signExtend(Unsigned src, size_t n)
Sign extend part of a value to the full width of the src type.
Unsigned rotateRight(Unsigned src, size_t n)
Rotate bits right.
bool msbLsb(Unsigned src, size_t w)
Most significant bit within lsb region.
std::enable_if< std::is_integral< T >::value, T >::type fromLittleEndian(const T x)
Convert integral value from little endian to host order.
Unsigned shiftRightSigned(Unsigned src, size_t n)
Right shift replicating MSB.
Unsigned positionLsb(Unsigned src, size_t w, size_t i)
Generate a single-bit mask without affecting the high-order bits.
Unsigned shiftLeftLsb(Unsigned src, size_t w, size_t n, bool b=false)
Left shift part of a value without affecting the rest.
Unsigned allLsb(Unsigned src, size_t w, bool b=true)
Set or clear the low-order w bits.
Unsigned bitsLsb(Unsigned src, size_t w, size_t least, size_t greatest)
Extract part of a value limited by width.
bool isLittleEndian()
True if host is little endian.
Unsigned replicate(Unsigned src, size_t n)
Replicate low-order bits to fill return value.
Unsigned shiftLeft(Unsigned src, size_t n, bool b=false)
Left shift a value.
std::enable_if< std::is_integral< T >::value, T >::type toLittleEndian(const T x)
Convert integral value from host order to little endian.
Unsigned highMask(size_t n)
Generate a value with high order bits set.
Unsigned mask(size_t least, size_t greatest)
Generate a mask.
Unsigned rotateRightLsb(Unsigned src, size_t w, size_t n)
Rotate low-order bits right without affecting others.
Unsigned bits(Unsigned src, size_t least, size_t greatest)
Extract part of a value.
size_t nBits(Unsigned=Unsigned(0))
Number of bits in a type or value.
bool bit(Unsigned src, size_t i)
Extract a single bit.
UnsignedTarget convertSigned(UnsignedSource x)
Sign extend or truncate a value.
Unsigned all(bool b=true)
Generate a value with all bits set or cleared.