* Variable-length integer decoder using a custom encoding scheme. * * The encoding is easiest to describe using an example. Let's say minval=100 and * bit_sizes=[4,2,2,3]. In that case: * - x in [100..115]: encoded as [0] + [4-bit BE encoding of (x-100)] * - x in [116..119]: encoded as [1,0] + [2-bit BE encoding of (x-116)] * - x in [120..123]: encoded as [1,1,0] + [2-bit BE encoding of (x-1
| 83 | * - Lastly, bit_sizes[k] bits encoding in big endian the position within that class |
| 84 | */ |
| 85 | uint32_t DecodeBits(size_t& bitpos, const std::span<const std::byte> data, uint8_t minval, const std::span<const uint8_t> bit_sizes) |
| 86 | { |
| 87 | uint32_t val = minval; // Start with minimum encodable value |
| 88 | bool bit; |
| 89 | for (auto bit_sizes_it = bit_sizes.begin(); bit_sizes_it != bit_sizes.end(); ++bit_sizes_it) { |
| 90 | // Read continuation bit to determine if we're in this class |
| 91 | if (bit_sizes_it + 1 != bit_sizes.end()) { // Unless we're in the last class |
| 92 | if (bitpos >= data.size() * 8) break; |
| 93 | bit = ConsumeBitLE(bitpos, data); |
| 94 | } else { |
| 95 | bit = 0; // Last class has no continuation bit |
| 96 | } |
| 97 | if (bit) { |
| 98 | // If the value will not fit in this class, subtract its range from val, |
| 99 | // emit a "1" bit and continue with the next class |
| 100 | val += (1 << *bit_sizes_it); // Add size of this class |
| 101 | } else { |
| 102 | // Decode the position within this class in big endian |
| 103 | for (int b = 0; b < *bit_sizes_it; b++) { |
| 104 | if (bitpos >= data.size() * 8) return INVALID; // Reached EOF in mantissa |
| 105 | bit = ConsumeBitLE(bitpos, data); |
| 106 | val += bit << (*bit_sizes_it - 1 - b); // Big-endian within the class |
| 107 | } |
| 108 | return val; |
| 109 | } |
| 110 | } |
| 111 | return INVALID; // Reached EOF in exponent |
| 112 | } |
| 113 | |
| 114 | /** |
| 115 | * Instruction Set |
no test coverage detected