CCSDS 124.0-B-1 C++ 1.0.0
CCSDS 124.0-B-1 Lossless Compression
Loading...
Searching...
No Matches
bitbuffer.hpp
Go to the documentation of this file.
1
31#ifndef CCSDS124_BITBUFFER_HPP
32#define CCSDS124_BITBUFFER_HPP
33
34#include <array>
35#include <cstring>
36
37#include "bitvector.hpp"
38#include "config.hpp"
39#include "error.hpp"
40
41namespace ccsds124 {
42
51template <std::size_t MaxBytes = MAX_OUTPUT_BYTES> class BitBuffer {
52public:
56 constexpr BitBuffer() noexcept : data_{}, num_bits_(0), acc_(0), acc_len_(0) {}
57
61 void clear() noexcept {
62 num_bits_ = 0;
63 acc_ = 0;
64 acc_len_ = 0;
65 data_.fill(0);
66 }
67
72 [[nodiscard]] std::size_t size() const noexcept {
73 return num_bits_;
74 }
75
82 Error append_bit(int bit) noexcept {
83 constexpr std::size_t max_bits = MaxBytes * 8;
84 if (num_bits_ >= max_bits) {
85 return Error::Overflow;
86 }
87
88 // Accumulate bit in MSB-first order
89 acc_ = (acc_ << 1) | (static_cast<std::uint32_t>(bit) & 1U);
90 ++acc_len_;
91 ++num_bits_;
92
93 // Flush when accumulator has 8+ bits
94 if (acc_len_ >= 8) {
95 flush_acc();
96 }
97
98 return Error::Ok;
99 }
100
108 Error append_bits(const std::uint8_t* bytes, std::size_t num_bits) noexcept {
109 constexpr std::size_t max_bits = MaxBytes * 8;
110 if (num_bits_ + num_bits > max_bits) {
111 return Error::Overflow;
112 }
113
114 // Process complete bytes efficiently
115 std::size_t full_bytes = num_bits >> 3; // num_bits / 8
116 for (std::size_t i = 0; i < full_bytes; ++i) {
117 auto result = append_value(bytes[i], 8);
118 if (result != Error::Ok) {
119 return result;
120 }
121 }
122
123 // Process remaining bits (0-7)
124 std::size_t remaining_bits = num_bits & 7; // num_bits % 8
125 if (remaining_bits > 0) {
126 // Extract MSB-aligned bits from last byte
127 std::uint32_t value = bytes[full_bytes] >> (8 - remaining_bits);
128 auto result = append_value(value, remaining_bits);
129 if (result != Error::Ok) {
130 return result;
131 }
132 }
133
134 return Error::Ok;
135 }
136
144 Error append_value(std::uint32_t value, std::size_t num_bits) noexcept {
145 if (num_bits == 0 || num_bits > 24) {
146 return Error::InvalidArg;
147 }
148
149 constexpr std::size_t max_bits = MaxBytes * 8;
150 if (num_bits_ + num_bits > max_bits) {
151 return Error::Overflow;
152 }
153
154 // Mask to get only the relevant bits
155 std::uint32_t mask = (1U << num_bits) - 1U;
156 std::uint32_t masked_value = value & mask;
157
158 acc_ = (acc_ << num_bits) | masked_value;
159 acc_len_ += num_bits;
160 num_bits_ += num_bits;
161
162 // Flush complete bytes
163 flush_acc();
164
165 return Error::Ok;
166 }
167
176 template <std::size_t N>
177 Error append_bitvector(const BitVector<N>& bv, std::size_t num_bits) noexcept {
178 constexpr std::size_t max_bits = MaxBytes * 8;
179 if (num_bits_ + num_bits > max_bits) {
180 return Error::Overflow;
181 }
182
183 std::size_t bits_to_append = (num_bits < N) ? num_bits : N;
184 std::size_t bit_pos = 0;
185
186 // Process 24 bits at a time using direct word access
187 while (bit_pos + 24 <= bits_to_append) {
188 std::size_t word_idx = bit_pos >> 5; // bit_pos / 32
189 std::size_t bit_in_word = bit_pos & 31; // bit_pos % 32
190
191 std::uint32_t value;
192 if (bit_in_word <= 8) {
193 // All 24 bits fit in current word (bit_in_word 0-8)
194 std::uint32_t word = bv.data()[word_idx];
195 value = (word >> (8 - bit_in_word)) & 0xFFFFFFU;
196 } else if (bit_in_word + 24 <= 32) {
197 // 24 bits fit in current word but not at convenient boundary
198 std::uint32_t word = bv.data()[word_idx];
199 value = (word >> (32 - bit_in_word - 24)) & 0xFFFFFFU;
200 } else {
201 // Span two words - extract bit-by-bit for correctness
202 value = 0;
203 for (std::size_t i = 0; i < 24; ++i) {
204 value = (value << 1) | static_cast<std::uint32_t>(bv.get_bit(bit_pos + i));
205 }
206 }
207
208 auto result = append_value(value, 24);
209 if (result != Error::Ok) {
210 return result;
211 }
212 bit_pos += 24;
213 }
214
215 // Process remaining bits
216 std::size_t remaining = bits_to_append - bit_pos;
217 if (remaining > 0) {
218 std::uint32_t value = 0;
219 for (std::size_t i = 0; i < remaining; ++i) {
220 value = (value << 1) | static_cast<std::uint32_t>(bv.get_bit(bit_pos + i));
221 }
222 auto result = append_value(value, remaining);
223 if (result != Error::Ok) {
224 return result;
225 }
226 }
227
228 return Error::Ok;
229 }
230
238 template <std::size_t N> Error append_bitvector(const BitVector<N>& bv) noexcept {
239 return append_bitvector(bv, N);
240 }
241
251 std::size_t to_bytes(std::uint8_t* bytes, std::size_t max_bytes) const noexcept {
252 // Calculate number of bytes needed
253 std::size_t num_bytes = (num_bits_ + 7) / 8;
254 if (num_bytes > max_bytes) {
255 num_bytes = max_bytes;
256 }
257
258 // Copy flushed bytes from data buffer
259 std::size_t flushed_bytes = (num_bits_ - acc_len_) / 8;
260 if (flushed_bytes > num_bytes) {
261 flushed_bytes = num_bytes;
262 }
263 if (flushed_bytes > 0) {
264 std::memcpy(bytes, data_.data(), flushed_bytes);
265 }
266
267 // Handle remaining bits in accumulator
268 if (acc_len_ > 0 && flushed_bytes < num_bytes) {
269 // Shift accumulator bits to MSB position
270 bytes[flushed_bytes] = static_cast<std::uint8_t>(acc_ << (8 - acc_len_));
271 }
272
273 return num_bytes;
274 }
275
276private:
277 std::array<std::uint8_t, MaxBytes> data_;
278 std::size_t num_bits_;
279 std::uint32_t acc_;
280 std::size_t acc_len_;
281
285 void flush_acc() noexcept {
286 while (acc_len_ >= 8) {
287 // Extract top 8 bits
288 acc_len_ -= 8;
289 std::size_t byte_index = (num_bits_ - acc_len_ - 8) / 8;
290 data_[byte_index] = static_cast<std::uint8_t>(acc_ >> acc_len_);
291 // Only mask if there are remaining bits (avoid unnecessary op when acc_len_ == 0)
292 if (acc_len_ > 0) {
293 acc_ &= (1U << acc_len_) - 1U;
294 }
295 }
296 }
297};
298
299} // namespace ccsds124
300
301#endif // CCSDS124_BITBUFFER_HPP
Fixed-length bit vector with static allocation.
Variable-length bit buffer with static allocation.
Definition bitbuffer.hpp:51
Error append_bitvector(const BitVector< N > &bv) noexcept
Append all bits from a BitVector.
void clear() noexcept
Clear buffer to empty state.
Definition bitbuffer.hpp:61
Error append_bit(int bit) noexcept
Append a single bit.
Definition bitbuffer.hpp:82
Error append_bitvector(const BitVector< N > &bv, std::size_t num_bits) noexcept
Append bits from a BitVector.
std::size_t size() const noexcept
Get number of bits in buffer.
Definition bitbuffer.hpp:72
Error append_value(std::uint32_t value, std::size_t num_bits) noexcept
Append multiple bits from a value.
std::size_t to_bytes(std::uint8_t *bytes, std::size_t max_bytes) const noexcept
Convert bit buffer to byte array.
constexpr BitBuffer() noexcept
Default constructor - initializes to empty state.
Definition bitbuffer.hpp:56
Error append_bits(const std::uint8_t *bytes, std::size_t num_bits) noexcept
Append multiple bits from byte array.
Fixed-length bit vector with compile-time size.
Definition bitvector.hpp:90
CCSDS 124.0-B-1 compile-time configuration.
CCSDS 124.0-B-1 error handling.
Error
Error codes for error-code-based error handling.
Definition error.hpp:29
@ Overflow
Buffer overflow.
@ InvalidArg
Invalid argument.