1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-10-26 17:17:58 +00:00

Work in terms of the number of bits to be handled.

This commit is contained in:
Thomas Harte
2025-02-19 22:04:51 -05:00
parent 6aff0b74cd
commit 88ffcbc62b
4 changed files with 51 additions and 13 deletions

View File

@@ -14,13 +14,25 @@
namespace Numeric { namespace Numeric {
template <typename MaxIntT, bool lsb_first> /*!
Given a means to fetch the next byte from a byte stream, serialises those bytes into a bit stream.
@c max_bits is the largest number of bits that'll be read at once.
@c lsb_first if true then the LSB of each byte from the byte stream is the first bit read. Otherwise it's the MSB.
*/
template <int max_bits, bool lsb_first>
class BitStream { class BitStream {
public: public:
using IntT = min_int_size_t<max_bits + 8>;
BitStream(std::function<uint8_t(void)> next_byte) : next_byte_(next_byte) {} BitStream(std::function<uint8_t(void)> next_byte) : next_byte_(next_byte) {}
/// @returns An integer composed of the next n bits of the bitstream where n is:
/// * the template parameter `bits` if it is non-zero; or
/// * the function argument `rbits` otherwise.
/// `rbits` is ignored if `bits` is non-zero.
template <size_t bits = 0> template <size_t bits = 0>
MaxIntT next(size_t rbits = 0) { IntT next([[maybe_unused]] const size_t rbits = 0) {
const size_t required = bits ? bits : rbits; const size_t required = bits ? bits : rbits;
while(enqueued_ < required) { while(enqueued_ < required) {
uint8_t next = next_byte_(); uint8_t next = next_byte_();
@@ -28,11 +40,11 @@ public:
next = bit_reverse(next); next = bit_reverse(next);
} }
input_ |= ShiftT(next) << (BitSize - 8 - enqueued_); input_ |= IntT(next) << (BitSize - 8 - enqueued_);
enqueued_ += 8; enqueued_ += 8;
} }
const auto result = MaxIntT(input_ >> (BitSize - required)); const auto result = IntT(input_ >> (BitSize - required));
input_ <<= required; input_ <<= required;
enqueued_ -= required; enqueued_ -= required;
return result; return result;
@@ -43,9 +55,8 @@ private:
size_t enqueued_{}; size_t enqueued_{};
using ShiftT = uint_t<sizeof(MaxIntT) * 8 * 2>; IntT input_{};
ShiftT input_{}; static constexpr size_t BitSize = sizeof(IntT) * 8;
static constexpr size_t BitSize = sizeof(ShiftT) * 8;
}; };
} }

View File

@@ -22,14 +22,15 @@ template <> struct uint_t_impl<64> { using type = uint64_t; };
template <int size> using uint_t = typename uint_t_impl<size>::type; template <int size> using uint_t = typename uint_t_impl<size>::type;
/*! /*!
Maps to the smallest integral type that can contain max_value, from the following options: Maps to the smallest integral type that can contain `max_value`, from the following options:
* uint8_t; * uint8_t;
* uint16_t; * uint16_t;
* uint32_t; or * uint32_t; or
* uint64_t. * uint64_t.
*/ */
template <uint64_t max_value> struct MinIntTypeValue { template <uint64_t max_value>
struct MinIntTypeValue {
using type = using type =
std::conditional_t< std::conditional_t<
max_value <= std::numeric_limits<uint8_t>::max(), uint8_t, max_value <= std::numeric_limits<uint8_t>::max(), uint8_t,
@@ -42,3 +43,29 @@ template <uint64_t max_value> struct MinIntTypeValue {
> >
>; >;
}; };
template <uint64_t max_value> using min_int_value_t = typename MinIntTypeValue<max_value>::type;
/*!
Maps to the smallest integral type that can hold at least `max_bits` bits, from the following options:
* uint8_t;
* uint16_t;
* uint32_t; or
* uint64_t.
*/
template <int max_bits>
struct MinIntTypeSize {
static_assert(max_bits <= 64, "Only integers up to 64 bits are supported");
using type =
std::conditional_t<
max_bits <= 8, uint8_t,
std::conditional_t<
max_bits <= 16, uint16_t,
std::conditional_t<
max_bits <= 32, uint32_t,
uint64_t
>
>
>;
};
template <uint64_t max_value> using min_int_size_t = typename MinIntTypeValue<max_value>::type;

View File

@@ -139,9 +139,9 @@ public:
/*! /*!
Obtains a BitStream for reading from the file from the current reading cursor. Obtains a BitStream for reading from the file from the current reading cursor.
*/ */
template <typename MaxIntT, bool lsb_first> template <int max_bits, bool lsb_first>
Numeric::BitStream<MaxIntT, lsb_first> bitstream() { Numeric::BitStream<max_bits, lsb_first> bitstream() {
return Numeric::BitStream<MaxIntT, lsb_first>([&] { return Numeric::BitStream<max_bits, lsb_first>([&] {
return get8(); return get8();
}); });
} }

View File

@@ -178,7 +178,7 @@ void TZX::Serialiser::get_generalised_segment(
} }
// Hence produce the output. // Hence produce the output.
auto stream = file_.bitstream<uint8_t, false>(); auto stream = file_.bitstream<8, false>();
int base = 2; int base = 2;
size_t bits = 1; size_t bits = 1;
while(base < number_of_symbols) { while(base < number_of_symbols) {