ROSE 0.11.145.147
BitOps.h
1#ifndef ROSE_BitOps_H
2#define ROSE_BitOps_H
3#include <RoseFirst.h>
4
5#include <Sawyer/Assert.h>
6#include <Sawyer/Optional.h>
7
8namespace Rose {
9
14namespace BitOps {
15
19template<typename Unsigned>
20inline size_t nBits(Unsigned = Unsigned(0)) {
21 return 8*sizeof(Unsigned);
22}
23
27template<typename Unsigned>
28inline Unsigned all(bool b = true) {
29 return Unsigned(0) - Unsigned(b ? 1 : 0);
30}
31
32template<typename Unsigned> inline Unsigned lowMask(size_t n);
33
39template<typename Unsigned>
40inline Unsigned allLsb(Unsigned src, size_t w, bool b = true) {
41 ASSERT_require(w <= nBits(src));
42 if (b) {
43 return src | lowMask<Unsigned>(w);
44 } else {
45 return src & ~lowMask<Unsigned>(w);
46 }
47}
48
56template<typename Unsigned>
57inline Unsigned lowMask(size_t n) {
58 return n >= nBits<Unsigned>() ? all<Unsigned>(true) : (Unsigned(1) << n) - Unsigned(1);
59}
60
67template<typename Unsigned>
68inline Unsigned highMask(size_t n) {
69 return n >= nBits<Unsigned>() ? all<Unsigned>(true) : lowMask<Unsigned>(n) << (nBits<Unsigned>() - n);
70}
71
78template<typename Unsigned>
79inline Unsigned select(Unsigned cond, Unsigned a, Unsigned b) {
80 return (a & cond) | (b & ~cond);
81}
82
90template<typename Unsigned>
91inline Unsigned shiftLeft(Unsigned src, size_t n, bool b = false) {
92 if (n >= nBits(src)) {
93 return all<Unsigned>(b);
94 } else {
95 return Unsigned(src << n) | (all<Unsigned>(b) & lowMask<Unsigned>(n));
96 }
97}
98
107template<typename Unsigned>
108inline Unsigned shiftLeftLsb(Unsigned src, size_t w, size_t n, bool b = false) {
109 ASSERT_require(w <= nBits(src));
110 if (n >= w) {
111 return allLsb(src, w, b);
112 } else {
113 return select(lowMask<Unsigned>(w), shiftLeft(src, n, b), src);
114 }
115}
116
124template<typename Unsigned>
125inline Unsigned shiftRight(Unsigned src, size_t n, bool b = false) {
126 if (n >= nBits(src)) {
127 return all<Unsigned>(b);
128 } else {
129 return Unsigned(src >> n) | (all<Unsigned>(b) & highMask<Unsigned>(n));
130 }
131}
132
140template<typename Unsigned>
141inline Unsigned shiftRightLsb(Unsigned src, size_t w, size_t n, bool b = false) {
142 ASSERT_require(w <= nBits(src));
143 if (n >= w) {
144 return allLsb(src, w, b);
145 } else {
146 const Unsigned affectedBits = lowMask<Unsigned>(w);
147 const Unsigned toShift = select(affectedBits, src, all<Unsigned>(b));
148 return select(affectedBits, shiftRight(toShift, n, b), src);
149 }
150}
151
158template<typename Unsigned>
159inline Unsigned position(size_t i) {
160 return i < nBits<Unsigned>() ? shiftLeft(Unsigned(1), i) : Unsigned(0);
161}
162
168template<typename Unsigned>
169inline Unsigned positionLsb(Unsigned src, size_t w, size_t i) {
170 ASSERT_require(w <= nBits(src));
171 return select(lowMask<Unsigned>(w), position<Unsigned>(i), src);
172}
173
181template<typename Unsigned>
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);
186}
187
193template<typename Unsigned>
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);
197}
198
204template<typename Unsigned>
205inline bool bit(Unsigned src, size_t i) {
206 return i < nBits(src) ? (src & position<Unsigned>(i)) != 0 : false;
207}
208
215template<typename Unsigned>
216inline bool bitLsb(Unsigned src, size_t w, size_t i) {
217 return i < w ? (src & position<Unsigned>(i)) != 0 : false;
218}
219
225template<typename Unsigned>
226inline bool msb(Unsigned src) {
227 return bit(src, nBits(src) - 1);
228}
229
235template<typename Unsigned>
236inline bool msbLsb(Unsigned src, size_t w) {
237 ASSERT_require(w <= nBits(src));
238 return w > 0 ? bit(src, w-1) : false;
239}
240
249template<typename Unsigned>
250inline Unsigned shiftRightSigned(Unsigned src, size_t n) {
251 return shiftRight(src, n, msb(src));
252}
253
262template<typename Unsigned>
263inline Unsigned shiftRightSignedLsb(Unsigned src, size_t w, size_t n) {
264 return shiftRightLsb(src, w, n, msbLsb(src, w));
265}
266
273template<typename Unsigned>
274inline Unsigned bits(Unsigned src, size_t least, size_t greatest) {
275 return shiftRight(src & mask<Unsigned>(least, greatest), least);
276}
277
284template<typename Unsigned>
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);
287}
288
289
296template<typename UnsignedTarget, typename UnsignedSource>
297inline UnsignedTarget convert(UnsignedSource x, bool b = false) {
298 if (nBits(x) < nBits<UnsignedTarget>()) {
299 // extending
300 return UnsignedTarget(x) | (all<UnsignedTarget>(b) & ~lowMask<UnsignedTarget>(nBits(x)));
301 } else {
302 // truncating
303 return UnsignedTarget(x & lowMask<UnsignedSource>(nBits<UnsignedTarget>()));
304 }
305}
306
313template<typename UnsignedTarget, typename UnsignedSource>
314inline UnsignedTarget convertSigned(UnsignedSource x) {
315 return convert<UnsignedTarget>(x, msb(x));
316}
317
323template<typename Unsigned>
324inline Unsigned signExtend(Unsigned src, size_t n) {
325 if (n < nBits(src)) {
326 if (msbLsb(src, n)) {
327 src |= mask<Unsigned>(n, nBits(src)-1);
328 } else {
329 src &= ~mask<Unsigned>(n, nBits(src)-1);
330 }
331 }
332 return src;
333}
334
341template<typename Unsigned>
342inline Unsigned signExtendLsb(Unsigned src, size_t n, size_t m) {
343 ASSERT_require(n > 0);
344 ASSERT_require(m >= n);
345 ASSERT_require(m <= nBits(src));
346 if (m == n) {
347 return src;
348 } else {
349 Unsigned newBitsMask = mask<Unsigned>(n, m-1);
350 if (bit(src, n-1)) {
351 return src | newBitsMask;
352 } else {
353 return src & ~newBitsMask;
354 }
355 }
356}
357
365template<typename Unsigned>
366inline Unsigned rotateLeft(Unsigned src, size_t n) {
367 n %= nBits(src);
368 return shiftLeft(src, n) | shiftRight(src, nBits(src)-n);
369}
370
377template<typename Unsigned>
378inline Unsigned rotateLeftLsb(Unsigned src, size_t w, size_t n) {
379 ASSERT_require(w <= nBits(src));
380 n = w ? n % w : 0;
381 return select(lowMask<Unsigned>(w),
382 shiftLeftLsb(src, w, n) | shiftRightLsb(src, w, w-n),
383 src);
384}
385
393template<typename Unsigned>
394inline Unsigned rotateRight(Unsigned src, size_t n) {
395 n %= nBits(src);
396 return shiftRight(src, n) | shiftLeft(src, nBits(src)-n);
397}
398
405template<typename Unsigned>
406inline Unsigned rotateRightLsb(Unsigned src, size_t w, size_t n) {
407 ASSERT_require(w <= nBits(src));
408 n = w ? n % w : 0;
409 return select(lowMask<Unsigned>(w),
410 shiftRightLsb(src, w, n) | shiftLeftLsb(src, w, w-n),
411 src);
412}
413
422template<typename Unsigned>
423inline Unsigned replicate(Unsigned src, size_t n) {
424 ASSERT_require(n != 0);
425 if (n >= nBits(src)) {
426 return src;
427 } else {
428 size_t ngroups = (nBits(src) + n - 1) / n;
429 Unsigned retval = 0;
430 for (size_t i = 0; i < ngroups; ++i)
431 retval |= shiftLeft(src & lowMask<Unsigned>(n), i*n);
432 return retval;
433 }
434}
435
443template<typename Unsigned>
444inline Unsigned replicateLsb(Unsigned src, size_t w, size_t n) {
445 ASSERT_require(w <= nBits(src));
446 return select(lowMask<Unsigned>(w), replicate(src, n), src);
447}
448
454template<typename Unsigned>
456 if (src) {
457 for (size_t i = nBits(src); i > 0; --i) {
458 if (bit(src, i-1))
459 return i-1;
460 }
461 }
462 return Sawyer::Nothing();
463}
464
465template<typename Unsigned>
466inline size_t nSet(Unsigned src) {
467 size_t retval = 0;
468 while (src != 0) {
469 if ((src & 1) != 0)
470 ++retval;
471 src >>= 1;
472 }
473 return retval;
474}
475
479template<class T>
480typename std::enable_if<std::is_integral<T>::value, T>::type
481inline reverseBytes(const T &x) {
482 // In C++23 and later, use std::byteswap
483 using Unsigned = typename std::make_unsigned<T>::type;
484 Unsigned u = x;
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;
493
494 u &= ~(loMask | hiMask);
495 u |= lo << hiOffset;
496 u |= hi << loOffset;
497 }
498 return u;
499}
500
504inline bool
506 static const unsigned i = 1;
507 return *(unsigned char*)&i == 0;
508}
509
513inline bool
515 static const unsigned i = 1;
516 return *(unsigned char*)&i == 1;
517}
518
522template<class T>
523inline typename std::enable_if<std::is_integral<T>::value, T>::type
524toBigEndian(const T x) {
525 using U = typename std::make_unsigned<T>::type;
526 return isBigEndian() ? x : reverseBytes((U)x);
527}
528
532template<class T>
533inline typename std::enable_if<std::is_integral<T>::value, T>::type
534toLittleEndian(const T x) {
535 using U = typename std::make_unsigned<T>::type;
536 return isLittleEndian() ? x : reverseBytes((U)x);
537}
538
542template<class T>
543inline typename std::enable_if<std::is_integral<T>::value, T>::type
544fromBigEndian(const T x) {
545 using U = typename std::make_unsigned<T>::type;
546 return isBigEndian() ? x : reverseBytes((U)x);
547}
548
552template<class T>
553inline typename std::enable_if<std::is_integral<T>::value, T>::type
555 using U = typename std::make_unsigned<T>::type;
556 return isLittleEndian() ? x : reverseBytes((U)x);
557}
558
559} // namespace
560} // namespace
561#endif
562
Represents no value.
Definition Optional.h:36
Holds a value or nothing.
Definition Optional.h:56
Unsigned maskLsb(Unsigned src, size_t w, size_t least, size_t greatest)
Generate a mask without affecting other bits.
Definition BitOps.h:194
Unsigned shiftRightSignedLsb(Unsigned src, size_t w, size_t n)
Right shift low bits without affecting other bits.
Definition BitOps.h:263
Sawyer::Optional< size_t > highestSetBit(Unsigned src)
Index of the highest set bit.
Definition BitOps.h:455
Unsigned lowMask(size_t n)
Generate a value with low order bits set.
Definition BitOps.h:57
Unsigned replicateLsb(Unsigned src, size_t w, size_t n)
Replicate low-order bits to fill region without affecting other bits.
Definition BitOps.h:444
Unsigned signExtendLsb(Unsigned src, size_t n, size_t m)
Sign extend part of value without affecting other bits.
Definition BitOps.h:342
std::enable_if< std::is_integral< T >::value, T >::type reverseBytes(const T &x)
Reverse the bytes.
Definition BitOps.h:481
Unsigned select(Unsigned cond, Unsigned a, Unsigned b)
Combine two values based on a bit mask.
Definition BitOps.h:79
Unsigned shiftRight(Unsigned src, size_t n, bool b=false)
Right shift a value.
Definition BitOps.h:125
bool bitLsb(Unsigned src, size_t w, size_t i)
Extract a single bit.
Definition BitOps.h:216
UnsignedTarget convert(UnsignedSource x, bool b=false)
Extend or truncate a value.
Definition BitOps.h:297
std::enable_if< std::is_integral< T >::value, T >::type toBigEndian(const T x)
Convert integral value from host order to big endian.
Definition BitOps.h:524
std::enable_if< std::is_integral< T >::value, T >::type fromBigEndian(const T x)
Convert integral value from big endian to host order.
Definition BitOps.h:544
Unsigned shiftRightLsb(Unsigned src, size_t w, size_t n, bool b=false)
Right shift part of a value without affecting the rest.
Definition BitOps.h:141
Unsigned rotateLeft(Unsigned src, size_t n)
Rotate bits left.
Definition BitOps.h:366
bool isBigEndian()
True if host is big endian.
Definition BitOps.h:505
Unsigned position(size_t i)
Generate a single-bit mask.
Definition BitOps.h:159
bool msb(Unsigned src)
Most significant bit.
Definition BitOps.h:226
Unsigned rotateLeftLsb(Unsigned src, size_t w, size_t n)
Rotate low-order bits left without affecting others.
Definition BitOps.h:378
Unsigned signExtend(Unsigned src, size_t n)
Sign extend part of a value to the full width of the src type.
Definition BitOps.h:324
Unsigned rotateRight(Unsigned src, size_t n)
Rotate bits right.
Definition BitOps.h:394
bool msbLsb(Unsigned src, size_t w)
Most significant bit within lsb region.
Definition BitOps.h:236
std::enable_if< std::is_integral< T >::value, T >::type fromLittleEndian(const T x)
Convert integral value from little endian to host order.
Definition BitOps.h:554
Unsigned shiftRightSigned(Unsigned src, size_t n)
Right shift replicating MSB.
Definition BitOps.h:250
Unsigned positionLsb(Unsigned src, size_t w, size_t i)
Generate a single-bit mask without affecting the high-order bits.
Definition BitOps.h:169
Unsigned shiftLeftLsb(Unsigned src, size_t w, size_t n, bool b=false)
Left shift part of a value without affecting the rest.
Definition BitOps.h:108
Unsigned allLsb(Unsigned src, size_t w, bool b=true)
Set or clear the low-order w bits.
Definition BitOps.h:40
Unsigned bitsLsb(Unsigned src, size_t w, size_t least, size_t greatest)
Extract part of a value limited by width.
Definition BitOps.h:285
bool isLittleEndian()
True if host is little endian.
Definition BitOps.h:514
Unsigned replicate(Unsigned src, size_t n)
Replicate low-order bits to fill return value.
Definition BitOps.h:423
Unsigned shiftLeft(Unsigned src, size_t n, bool b=false)
Left shift a value.
Definition BitOps.h:91
std::enable_if< std::is_integral< T >::value, T >::type toLittleEndian(const T x)
Convert integral value from host order to little endian.
Definition BitOps.h:534
Unsigned highMask(size_t n)
Generate a value with high order bits set.
Definition BitOps.h:68
Unsigned mask(size_t least, size_t greatest)
Generate a mask.
Definition BitOps.h:182
Unsigned rotateRightLsb(Unsigned src, size_t w, size_t n)
Rotate low-order bits right without affecting others.
Definition BitOps.h:406
Unsigned bits(Unsigned src, size_t least, size_t greatest)
Extract part of a value.
Definition BitOps.h:274
size_t nBits(Unsigned=Unsigned(0))
Number of bits in a type or value.
Definition BitOps.h:20
bool bit(Unsigned src, size_t i)
Extract a single bit.
Definition BitOps.h:205
UnsignedTarget convertSigned(UnsignedSource x)
Sign extend or truncate a value.
Definition BitOps.h:314
Unsigned all(bool b=true)
Generate a value with all bits set or cleared.
Definition BitOps.h:28
The ROSE library.