CCSDS 124.0-B-1 C++ 1.0.0
CCSDS 124.0-B-1 Lossless Compression
Loading...
Searching...
No Matches
encoder.hpp
Go to the documentation of this file.
1
27#ifndef CCSDS124_ENCODER_HPP
28#define CCSDS124_ENCODER_HPP
29
30#include "bitbuffer.hpp"
31#include "bitvector.hpp"
32#include "config.hpp"
33#include "error.hpp"
34
35namespace ccsds124 {
36
40namespace detail {
41inline constexpr std::uint8_t COUNT_VALUES[34] = {
42 0U, 0U, // 0: unused, 1: '0'
43 0xC0U, 0xC1U, 0xC2U, 0xC3U, 0xC4U, 0xC5U, 0xC6U, 0xC7U, // 2-9
44 0xC8U, 0xC9U, 0xCAU, 0xCBU, 0xCCU, 0xCDU, 0xCEU, 0xCFU, // 10-17
45 0xD0U, 0xD1U, 0xD2U, 0xD3U, 0xD4U, 0xD5U, 0xD6U, 0xD7U, // 18-25
46 0xD8U, 0xD9U, 0xDAU, 0xDBU, 0xDCU, 0xDDU, 0xDEU, 0xDFU // 26-33
47};
48inline constexpr std::uint8_t COUNT_BITS[34] = {
49 0U, 1U, // 0: unused, 1: 1 bit
50 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, // 2-9: 8 bits each
51 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, // 10-17
52 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, // 18-25
53 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U // 26-33
54};
55} // namespace detail
56
70template <std::size_t MaxBytes>
71Error count_encode(BitBuffer<MaxBytes>& output, std::uint32_t A) noexcept {
72 if (A == 0 || A > 65535) [[unlikely]] {
73 return Error::InvalidArg;
74 }
75
76 // Fast path: Most values are in 2-33 range
77 if (A <= 33) [[likely]] {
78 if (A == 1) {
79 // Case 1: A = 1 → '0'
80 return output.append_bit(0);
81 }
82 // Case 2: use lookup table for A=2-33
83 return output.append_value(static_cast<std::uint32_t>(detail::COUNT_VALUES[A]),
84 static_cast<std::size_t>(detail::COUNT_BITS[A]));
85 }
86
87 // Case 3: A ≥ 34 → '111' ∥ BIT_E(A-2)
88 // Append '111' prefix as single value
89 auto result = output.append_value(0b111U, 3);
90 if (result != Error::Ok)
91 return result;
92
93 // Calculate E = 2⌊log₂(A-2)+1⌋ - 6
94 std::uint32_t value = A - 2;
95 int highest_bit = 31 - __builtin_clz(value);
96 int E = (2 * (highest_bit + 1)) - 6;
97
98 // Append BIT_E(A-2) MSB-first as single value
99 return output.append_value(value, static_cast<std::size_t>(E));
100}
101
113template <std::size_t MaxBytes, std::size_t N>
114Error rle_encode(BitBuffer<MaxBytes>& output, const BitVector<N>& input) noexcept {
115 // Start from the end of the vector
116 int old_bit_position = static_cast<int>(N);
117
118 // Process words in reverse order (from high to low)
119 for (int word = static_cast<int>(BitVector<N>::NUM_WORDS) - 1; word >= 0; --word) {
120 std::uint32_t word_data = input.data()[word];
121
122 // Process all set bits in this word
123 while (word_data != 0) {
124 // Find LSB position using __builtin_ctz (avoids UB with signed negation)
125 int trailing_zeros = __builtin_ctz(word_data);
126 std::uint32_t lsb = 1U << static_cast<unsigned>(trailing_zeros);
127
128 // Convert to bit position from MSB (big-endian ordering)
129 int bit_position_in_word = 31 - trailing_zeros;
130
131 // Calculate global bit position
132 int new_bit_position = (word * 32) + bit_position_in_word;
133
134 // Calculate delta (number of zeros + 1)
135 int delta = old_bit_position - new_bit_position;
136
137 // Encode the count
138 auto result = count_encode(output, static_cast<std::uint32_t>(delta));
139 if (result != Error::Ok)
140 return result;
141
142 // Update old position for next iteration
143 old_bit_position = new_bit_position;
144
145 // Clear the processed bit
146 word_data ^= lsb;
147 }
148 }
149
150 // Append terminator '10' as single value
151 return output.append_value(0b10U, 2);
152}
153
166template <std::size_t MaxBytes, std::size_t N>
168 const BitVector<N>& mask) noexcept {
169 // Batch accumulator for append_value (max 24 bits)
170 std::uint32_t batch_value = 0;
171 std::size_t batch_count = 0;
172
173 // Process words in REVERSE order (high to low)
174 for (int word = static_cast<int>(BitVector<N>::NUM_WORDS) - 1; word >= 0; --word) {
175 std::uint32_t mask_word = mask.data()[word];
176 std::uint32_t data_word = data.data()[word];
177
178 // Loop bounded by popcount - guarantees termination
179 for (int bits_remaining = __builtin_popcount(mask_word); bits_remaining > 0;
180 --bits_remaining) {
181 // Find LSB position using __builtin_ctz (avoids UB with signed negation)
182 int trailing_zeros = __builtin_ctz(mask_word);
183 std::uint32_t lsb = 1U << static_cast<unsigned>(trailing_zeros);
184
185 // Convert to bit position from MSB (big-endian ordering)
186 int bit_pos_in_word = 31 - trailing_zeros;
187
188 // Check if this bit is within the valid length
189 int global_pos = (word * 32) + bit_pos_in_word;
190 if (static_cast<std::size_t>(global_pos) < N) {
191 // Extract data bit and accumulate in batch
192 int bit = (data_word & lsb) != 0 ? 1 : 0;
193 batch_value = (batch_value << 1) | static_cast<std::uint32_t>(bit);
194 ++batch_count;
195
196 // Flush when batch is full (24 bits max for append_value)
197 if (batch_count == 24) {
198 auto result = output.append_value(batch_value, 24);
199 if (result != Error::Ok)
200 return result;
201 batch_value = 0;
202 batch_count = 0;
203 }
204 }
205
206 // Clear processed bit
207 mask_word &= mask_word - 1;
208 }
209 }
210
211 // Flush remaining bits in batch
212 if (batch_count > 0) {
213 auto result = output.append_value(batch_value, batch_count);
214 if (result != Error::Ok)
215 return result;
216 }
217
218 return Error::Ok;
219}
220
233template <std::size_t MaxBytes, std::size_t N>
235 const BitVector<N>& mask) noexcept {
236 // Batch accumulator for append_value (max 24 bits)
237 std::uint32_t batch_value = 0;
238 std::size_t batch_count = 0;
239
240 // Process words in FORWARD order (low to high)
241 for (std::size_t word = 0; word < BitVector<N>::NUM_WORDS; ++word) {
242 std::uint32_t mask_word = mask.data()[word];
243 std::uint32_t data_word = data.data()[word];
244
245 // Loop bounded by popcount - guarantees termination
246 for (int bits_remaining = __builtin_popcount(mask_word); bits_remaining > 0;
247 --bits_remaining) {
248 // Find MSB position using extract_msb helper
249 int clz = detail::extract_msb(mask_word);
250
251 std::size_t global_pos = (word * 32) + static_cast<std::size_t>(clz);
252
253 if (global_pos < N) {
254 // Extract data bit and accumulate in batch
255 std::uint32_t bit_mask = 1U << (31U - static_cast<std::uint32_t>(clz));
256 int bit = (data_word & bit_mask) != 0 ? 1 : 0;
257 batch_value = (batch_value << 1) | static_cast<std::uint32_t>(bit);
258 ++batch_count;
259
260 // Flush when batch is full (24 bits max for append_value)
261 if (batch_count == 24) {
262 auto result = output.append_value(batch_value, 24);
263 if (result != Error::Ok)
264 return result;
265 batch_value = 0;
266 batch_count = 0;
267 }
268 }
269 }
270 }
271
272 // Flush remaining bits in batch
273 if (batch_count > 0) {
274 auto result = output.append_value(batch_value, batch_count);
275 if (result != Error::Ok)
276 return result;
277 }
278
279 return Error::Ok;
280}
281
285template <std::size_t MaxBytes, std::size_t N1, std::size_t N2>
287 const BitVector<N2>& mask) noexcept {
288 if constexpr (N1 != N2) {
289 return Error::InvalidArg;
290 } else {
291 return bit_extract<MaxBytes, N1>(output, data, mask);
292 }
293}
294
295} // namespace ccsds124
296
297#endif // CCSDS124_ENCODER_HPP
Variable-length bit buffer for building compressed output.
Fixed-length bit vector with static allocation.
Variable-length bit buffer with static allocation.
Definition bitbuffer.hpp:51
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.
constexpr std::uint8_t COUNT_VALUES[34]
Definition encoder.hpp:41
int extract_msb(std::uint32_t &word) noexcept
Extract and clear the most significant set bit from a word.
Definition bitvector.hpp:56
constexpr std::uint8_t COUNT_BITS[34]
Definition encoder.hpp:48
Error count_encode(BitBuffer< MaxBytes > &output, std::uint32_t A) noexcept
Counter encoding (CCSDS Section 5.2.2, Equation 9).
Definition encoder.hpp:71
Error bit_extract(BitBuffer< MaxBytes > &output, const BitVector< N > &data, const BitVector< N > &mask) noexcept
Bit extraction in reverse order (CCSDS Section 5.2.4, Equation 11).
Definition encoder.hpp:167
Error
Error codes for error-code-based error handling.
Definition error.hpp:29
@ InvalidArg
Invalid argument.
Error bit_extract_forward(BitBuffer< MaxBytes > &output, const BitVector< N > &data, const BitVector< N > &mask) noexcept
Bit extraction in forward order.
Definition encoder.hpp:234
Error rle_encode(BitBuffer< MaxBytes > &output, const BitVector< N > &input) noexcept
Run-length encoding (CCSDS Section 5.2.3, Equation 10).
Definition encoder.hpp:114