1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-07-01 20:23:57 +00:00
Files
CLK/Numeric/BitStream.hpp
2025-02-19 22:04:51 -05:00

63 lines
1.5 KiB
C++

//
// BitStream.hpp
// Clock Signal
//
// Created by Thomas Harte on 18/02/2025.
// Copyright © 2025 Thomas Harte. All rights reserved.
//
#pragma once
#include "BitReverse.hpp"
#include "Sizes.hpp"
#include <functional>
namespace Numeric {
/*!
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 {
public:
using IntT = min_int_size_t<max_bits + 8>;
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>
IntT next([[maybe_unused]] const size_t rbits = 0) {
const size_t required = bits ? bits : rbits;
while(enqueued_ < required) {
uint8_t next = next_byte_();
if constexpr (lsb_first) {
next = bit_reverse(next);
}
input_ |= IntT(next) << (BitSize - 8 - enqueued_);
enqueued_ += 8;
}
const auto result = IntT(input_ >> (BitSize - required));
input_ <<= required;
enqueued_ -= required;
return result;
}
private:
std::function<uint8_t(void)> next_byte_;
size_t enqueued_{};
IntT input_{};
static constexpr size_t BitSize = sizeof(IntT) * 8;
};
}