Last active
May 26, 2023 22:15
-
-
Save Broxzier/ad18cd71cf9701de7f1c7a7540dc2f16 to your computer and use it in GitHub Desktop.
Compact int reader and writer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdint> | |
#include <iostream> | |
#include <limits> | |
#include <type_traits> | |
int GetBitValue(const std::uint8_t* data, int offset) | |
{ | |
constexpr auto BitsPerByte = std::numeric_limits<std::decay_t<decltype(*data)>>::digits; | |
static_assert(BitsPerByte != 0, "Unknown bit size for type"); | |
auto byteIndex = offset / BitsPerByte; | |
auto bitIndex = offset % BitsPerByte; | |
auto byte = data[byteIndex]; | |
return byte >> (BitsPerByte - 1 - bitIndex) & 1; | |
} | |
int SeekBitPattern(const std::uint8_t* data, int startPosition, std::uint8_t pattern, std::uint_fast8_t numBits) | |
{ | |
constexpr auto BitsPerByte = std::numeric_limits<std::decay_t<decltype(*data)>>::digits; | |
static_assert(BitsPerByte != 0, "Unknown bit size for type"); | |
// In the current implementation, numBits may not be higher than 8 | |
if (numBits == 0 || numBits > BitsPerByte) | |
return -1; | |
const auto mask = (1u << numBits) - 1; | |
// Start off by reading the first numBits bits | |
int value; | |
if (startPosition % BitsPerByte + numBits <= BitsPerByte) | |
{ // initial bits are all within the first byte | |
auto byte = data[startPosition / BitsPerByte]; | |
value = (byte >> (BitsPerByte - (startPosition % BitsPerByte) - numBits)) & mask; | |
} | |
else | |
{ // A portion of the bits are in the next byte | |
// TODO: Size check | |
auto byte1 = data[startPosition / BitsPerByte]; | |
auto byte2 = data[startPosition / BitsPerByte + 1]; | |
auto shiftL = startPosition % BitsPerByte + numBits - BitsPerByte; | |
value = byte1 << shiftL | byte2 >> (BitsPerByte - shiftL) & mask; | |
} | |
// Iterate over the following bits to try find the pattern | |
auto bitIndex = 0; | |
while (value != pattern) | |
{ | |
// TODO: Size check | |
const auto nextBitIndex = startPosition + bitIndex + numBits; | |
value <<= 1; | |
value &= mask; | |
value |= GetBitValue(data, nextBitIndex); | |
bitIndex++; | |
} | |
return startPosition + bitIndex; | |
} | |
int main() | |
{ | |
// The first byte tells us how many numbers are in the rest of the array starting from the second byte | |
std::uint8_t input[] = { | |
//4, 0b11010101, 0b01010000, 0b01101000, 0b11101010, 0b11010010, 0b01100001, 0b10010000, // 289000, 100, 0, 10 | |
//6, 0b10100010, 0b01110100, 0b00001111, 0b01000110, 0b10101001, 0b01110100, 0b10011100, 0b00000000, // 39, 65, 88, 53, 23, 6 | |
8, 0b10100000, 0b00010010, 0b11101000, 0b11011010, 0b01111011, 0b01000110, 0b01110100, 0b01110111, 0b00110110, 0b10000110, 0b00000000, // 30, 25, 43, 60, 87, 91, 12, 74 | |
}; | |
const auto numberCount = input[0]; | |
auto* data = &input[1]; | |
// Seek the first "00" occurrence | |
auto position = 0; | |
for (int i = 0; i < numberCount; i++) // TODO: Loop while "00" bits are found, or simply while there is data | |
{ | |
auto end = SeekBitPattern(data, position, 0b00, 2); | |
// Parse the bits up to this position into a number | |
// Each 1 adds 1, each 0 adds 2 | |
int numBits = 1; // The "00" part itself counts as 1, so we start with 1 | |
for (int i = position; i < end; i++) | |
{ | |
numBits += GetBitValue(data, i) ? 1 : 2; | |
} | |
// Set the range (position and end) for the next part to read | |
// Skip the "00" part we sought before | |
position = end + 2; | |
end = position + numBits; | |
// Read and parse the number of bits right after the "00" to an integer | |
// The most significant bit is always 1, otherwise it wouldn't have been saved anyway | |
int num = 1; | |
while (position < end) | |
{ | |
num <<= 1; | |
num |= GetBitValue(data, position); | |
position++; | |
} | |
// Subtract two from the parsed number to get the actual value stored. This is necessary, because the numbers 0 and 1 couldn't be stored otherwise. | |
num -= 2; | |
std::cout << num << std::endl; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment