From 266f299f86876b76c1706888d8aaeea658e59207 Mon Sep 17 00:00:00 2001 From: Ahmet Inan Date: Thu, 20 Sep 2018 09:11:33 +0200 Subject: [PATCH] added bitwise stream container --- README.md | 4 ++ bitstream.hh | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 bitstream.hh diff --git a/README.md b/README.md index 787907a..9c62fdc 100644 --- a/README.md +++ b/README.md @@ -27,3 +27,7 @@ Sometimes we need a sequence of ["random enough"](https://en.wikipedia.org/wiki/ Here a [Pseudorandom number generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) can help by prodiving a deterministic and thus repeatable sequence of numbers. [George Marsaglia](https://en.wikipedia.org/wiki/George_Marsaglia) discovered a class of simple and fast pseudorandom number generators, which he called [Xorshift](https://en.wikipedia.org/wiki/Xorshift). +### [bitstream.hh](bitstream.hh) + +When dealing with unaligned and arbitrary-bit-sized elements in a data stream, the bitwise stream container might help avoiding some headaches. + diff --git a/bitstream.hh b/bitstream.hh new file mode 100644 index 0000000..bd579aa --- /dev/null +++ b/bitstream.hh @@ -0,0 +1,154 @@ +/* +Bitwise stream container + +Copyright 2018 Ahmet Inan +*/ + +#ifndef BITSTREAM_HH +#define BITSTREAM_HH + +namespace CODE { + +template +class Bitstream +{ +public: + static const int BITS = SIZE; + static const int BYTES = (SIZE + 7) / 8; +private: + uint8_t buf_[BYTES]; + int pos_ = 0; +public: + void seek(int pos) + { + pos_ = pos; + } + int tell() + { + return pos_; + } + uint8_t *data() + { + return buf_; + } + void reset() + { + pos_ = 0; + for (int i = 0; i < BYTES; ++i) + buf_[i] = 0; + } + void putbit(bool b) + { + int bit = pos_ % 8; + int byte = pos_ / 8; + ++pos_; + uint8_t mask = 1 << bit; + uint8_t tmp = ~mask & buf_[byte]; + buf_[byte] = tmp | b << bit; + } + bool getbit() + { + int bit = pos_ % 8; + int byte = pos_ / 8; + ++pos_; + return (buf_[byte] >> bit) & 1; + } + void putbyte(const uint8_t b) + { + int bit = pos_ % 8; + int byte = pos_ / 8; + pos_ += 8; + if (bit) { + uint8_t mask = (1 << bit) - 1; + uint8_t lsb = mask & buf_[byte]; + buf_[byte++] = lsb | b << bit; + uint8_t msb = ~mask & buf_[byte]; + buf_[byte] = msb | b >> (8 - bit); + } else { + buf_[byte] = b; + } + } + uint8_t getbyte() + { + int bit = pos_ % 8; + int byte = pos_ / 8; + pos_ += 8; + if (bit) { + uint8_t lsb = buf_[byte++] >> bit; + uint8_t msb = buf_[byte] << (8 - bit); + return msb | lsb; + } + return buf_[byte]; + } + void writebytes(const uint8_t *buf, int len) + { + int bit = pos_ % 8; + int byte = pos_ / 8; + pos_ += 8 * len; + if (bit) { + uint8_t mask = (1 << bit) - 1; + for (int i = 0; i < len; ++i) { + uint8_t lsb = mask & buf_[byte]; + buf_[byte++] = lsb | buf[i] << bit; + uint8_t msb = ~mask & buf_[byte]; + buf_[byte] = msb | buf[i] >> (8 - bit); + } + } else { + for (int i = 0; i < len; ++i) + buf_[byte++] = buf[i]; + } + } + void readbytes(uint8_t *buf, int len) + { + int bit = pos_ % 8; + int byte = pos_ / 8; + pos_ += 8 * len; + if (bit) { + for (int i = 0; i < len; ++i) { + uint8_t lsb = buf_[byte++] >> bit; + uint8_t msb = buf_[byte] << (8 - bit); + buf[i] = msb | lsb; + } + } else { + for (int i = 0; i < len; ++i) + buf[i] = buf_[byte++]; + } + } + template + void writebits(TYPE b, int num) + { + for (int sum = 0; num;) { + int bit = pos_ % 8; + int byte = pos_ / 8; + int copy = std::min(8 - bit, num); + uint8_t mask = (1 << copy) - 1; + uint8_t src = (mask & (b >> sum)) << bit; + uint8_t dst = ~(mask << bit) & buf_[byte]; + buf_[byte++] = dst | src; + pos_ += copy; + num -= copy; + sum += copy; + } + } + template + void readbits(TYPE *b, int num) + { + TYPE a = 0; + for (int sum = 0; num;) { + int bit = pos_ % 8; + int byte = pos_ / 8; + int copy = std::min(8 - bit, num); + uint8_t mask = (1 << copy) - 1; + TYPE tmp = mask & (buf_[byte++] >> bit); + a |= tmp << sum; + pos_ += copy; + num -= copy; + sum += copy; + } + *b = a; + } +}; + +} + +#endif