mirror of
https://github.com/TomHarte/CLK.git
synced 2025-10-27 08:16:22 +00:00
Work in terms of the number of bits to be handled.
This commit is contained in:
@@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user