1 | #pragma once |
2 | #include <stdint.h> |
3 | #include <limits> |
4 | #include <type_traits> |
5 | |
6 | |
7 | inline uint16_t LO_16(uint32_t x) { return static_cast<uint16_t>(x & 0x0000FFFF); } |
8 | inline uint16_t HI_16(uint32_t x) { return static_cast<uint16_t>(x >> 16); } |
9 | |
10 | inline uint32_t LO_32(uint64_t x) { return static_cast<uint32_t>(x & 0x00000000FFFFFFFF); } |
11 | inline uint32_t HI_32(uint64_t x) { return static_cast<uint32_t>(x >> 32); } |
12 | |
13 | |
14 | /// Clang also defines __GNUC__ |
15 | #if defined(__GNUC__) |
16 | inline unsigned GetValueBitCountImpl(unsigned int value) noexcept { |
17 | // NOTE: __builtin_clz* have undefined result for zero. |
18 | return std::numeric_limits<unsigned int>::digits - __builtin_clz(value); |
19 | } |
20 | |
21 | inline unsigned GetValueBitCountImpl(unsigned long value) noexcept { |
22 | return std::numeric_limits<unsigned long>::digits - __builtin_clzl(value); |
23 | } |
24 | |
25 | inline unsigned GetValueBitCountImpl(unsigned long long value) noexcept { |
26 | return std::numeric_limits<unsigned long long>::digits - __builtin_clzll(value); |
27 | } |
28 | #else |
29 | /// Stupid implementation for non GCC-like compilers. Can use BSR from x86 instructions set. |
30 | template <typename T> |
31 | inline unsigned GetValueBitCountImpl(T value) noexcept { |
32 | unsigned result = 1; // result == 0 - impossible value, since value cannot be zero |
33 | value >>= 1; |
34 | while (value) { |
35 | value >>= 1; |
36 | ++result; |
37 | } |
38 | |
39 | return result; |
40 | } |
41 | #endif |
42 | |
43 | |
44 | /** |
45 | * Returns the number of leading 0-bits in `value`, starting at the most significant bit position. |
46 | * NOTE: value cannot be zero |
47 | */ |
48 | template <typename T> |
49 | static inline unsigned GetValueBitCount(T value) noexcept { |
50 | using TCvt = std::make_unsigned_t<std::decay_t<T>>; |
51 | return GetValueBitCountImpl(static_cast<TCvt>(value)); |
52 | } |
53 | |