CCSDS 124.0-B-1 C++ 1.0.0
CCSDS 124.0-B-1 Lossless Compression
Loading...
Searching...
No Matches
bitvector.hpp
Go to the documentation of this file.
1
35#ifndef CCSDS124_BITVECTOR_HPP
36#define CCSDS124_BITVECTOR_HPP
37
38#include <array>
39#include <cstring>
40
41#include "config.hpp"
42
43namespace ccsds124 {
44
45namespace detail {
46
56inline int extract_msb(std::uint32_t& word) noexcept {
57 if (word == 0) {
58 return -1;
59 }
60 int clz = __builtin_clz(word);
61 word &= ~(1U << (31U - static_cast<std::uint32_t>(clz)));
62 return clz;
63}
64
71inline int extract_lsb(std::uint32_t& word) noexcept {
72 if (word == 0) {
73 return -1;
74 }
75 int ctz = __builtin_ctz(word);
76 word &= word - 1; // Clear LSB (standard idiom)
77 return 31 - ctz; // Convert to position from MSB
78}
79
80} // namespace detail
81
90template <std::size_t N> class BitVector {
91public:
93 static constexpr std::size_t NUM_WORDS = (N + 31) / 32;
94
96 static constexpr std::size_t NUM_BYTES = (N + 7) / 8;
97
101 constexpr BitVector() noexcept : data_{} {}
102
107 [[nodiscard]] constexpr std::size_t length() const noexcept {
108 return N;
109 }
110
115 [[nodiscard]] constexpr std::size_t num_words() const noexcept {
116 return NUM_WORDS;
117 }
118
122 void zero() noexcept {
123 data_.fill(0);
124 }
125
132 [[nodiscard]] inline int get_bit(std::size_t pos) const noexcept {
133 if (pos >= N) [[unlikely]]
134 return 0;
135 return get_bit_unchecked(pos);
136 }
137
145 [[nodiscard]] inline int get_bit_unchecked(std::size_t pos) const noexcept {
146 std::size_t word_idx = pos >> 5;
147 std::size_t bit_in_word = 31U - (pos & 31U);
148 return static_cast<int>((data_[word_idx] >> bit_in_word) & 1U);
149 }
150
157 inline void set_bit(std::size_t pos, int value) noexcept {
158 if (pos >= N) [[unlikely]]
159 return;
160 set_bit_unchecked(pos, value);
161 }
162
170 inline void set_bit_unchecked(std::size_t pos, int value) noexcept {
171 std::size_t word_idx = pos >> 5;
172 std::size_t bit_in_word = 31U - (pos & 31U);
173
174 if (value) {
175 data_[word_idx] |= (1U << bit_in_word);
176 } else {
177 data_[word_idx] &= ~(1U << bit_in_word);
178 }
179 }
180
185 void copy_from(const BitVector& src) noexcept {
186 data_ = src.data_;
187 }
188
194 void xor_of(const BitVector& a, const BitVector& b) noexcept {
195 for (std::size_t i = 0; i < NUM_WORDS; ++i) {
196 data_[i] = a.data_[i] ^ b.data_[i];
197 }
198 }
199
205 void or_of(const BitVector& a, const BitVector& b) noexcept {
206 for (std::size_t i = 0; i < NUM_WORDS; ++i) {
207 data_[i] = a.data_[i] | b.data_[i];
208 }
209 }
210
216 void and_of(const BitVector& a, const BitVector& b) noexcept {
217 for (std::size_t i = 0; i < NUM_WORDS; ++i) {
218 data_[i] = a.data_[i] & b.data_[i];
219 }
220 }
221
226 void not_of(const BitVector& a) noexcept {
227 for (std::size_t i = 0; i < NUM_WORDS; ++i) {
228 data_[i] = ~a.data_[i];
229 }
230 mask_unused_bits();
231 }
232
237 void left_shift_of(const BitVector& a) noexcept {
238 if constexpr (NUM_WORDS > 0) {
239 for (std::size_t i = 0; i < NUM_WORDS - 1; ++i) {
240 data_[i] = (a.data_[i] << 1) | (a.data_[i + 1] >> 31);
241 }
242 data_[NUM_WORDS - 1] = a.data_[NUM_WORDS - 1] << 1;
243 }
244 }
245
250 void reverse_of(const BitVector& a) noexcept {
251 // Reverse word order and reverse bits within each word
252 for (std::size_t i = 0; i < NUM_WORDS; ++i) {
253 std::uint32_t word = a.data_[NUM_WORDS - 1 - i];
254 // Reverse bits within word using efficient swaps
255 word = ((word & 0x55555555U) << 1) | ((word >> 1) & 0x55555555U);
256 word = ((word & 0x33333333U) << 2) | ((word >> 2) & 0x33333333U);
257 word = ((word & 0x0F0F0F0FU) << 4) | ((word >> 4) & 0x0F0F0F0FU);
258 word = __builtin_bswap32(word); // Reverse bytes
259 data_[i] = word;
260 }
261
262 // Handle non-32-bit-aligned size: shift to account for unused bits
263 constexpr std::size_t extra_bits = (NUM_WORDS * 32) - N;
264 if constexpr (extra_bits > 0) {
265 // Shift entire array left by extra_bits to align
266 for (std::size_t i = 0; i < NUM_WORDS - 1; ++i) {
267 data_[i] = (data_[i] << extra_bits) | (data_[i + 1] >> (32 - extra_bits));
268 }
269 data_[NUM_WORDS - 1] <<= extra_bits;
270 }
271 }
272
277 void xor_with(const BitVector& other) noexcept {
278 for (std::size_t i = 0; i < NUM_WORDS; ++i) {
279 data_[i] ^= other.data_[i];
280 }
281 }
282
288 void xor_with(const BitVector& a, const BitVector& b) noexcept {
289 xor_of(a, b);
290 }
291
296 void or_with(const BitVector& other) noexcept {
297 for (std::size_t i = 0; i < NUM_WORDS; ++i) {
298 data_[i] |= other.data_[i];
299 }
300 }
301
307 void or_with(const BitVector& a, const BitVector& b) noexcept {
308 or_of(a, b);
309 }
310
315 void or_in_place(const BitVector& other) noexcept {
316 or_with(other);
317 }
318
323 void and_with(const BitVector& other) noexcept {
324 for (std::size_t i = 0; i < NUM_WORDS; ++i) {
325 data_[i] &= other.data_[i];
326 }
327 }
328
332 void invert() noexcept {
333 for (std::size_t i = 0; i < NUM_WORDS; ++i) {
334 data_[i] = ~data_[i];
335 }
336 mask_unused_bits();
337 }
338
342 void left_shift() noexcept {
343 if constexpr (NUM_WORDS > 0) {
344 for (std::size_t i = 0; i < NUM_WORDS - 1; ++i) {
345 data_[i] = (data_[i] << 1) | (data_[i + 1] >> 31);
346 }
347 data_[NUM_WORDS - 1] <<= 1;
348 }
349 }
350
355 void left_shift(const BitVector& src) noexcept {
356 left_shift_of(src);
357 }
358
363 [[nodiscard]] std::size_t hamming_weight() const noexcept {
364 std::size_t count = 0;
365 for (std::size_t i = 0; i < NUM_WORDS; ++i) {
366 count += static_cast<std::size_t>(__builtin_popcount(data_[i]));
367 }
368
369 // Adjust for unused bits in last word
370 constexpr std::size_t extra_bits = (NUM_WORDS * 32) - N;
371 if constexpr (extra_bits > 0) {
372 word_t last_word = data_[NUM_WORDS - 1];
373 word_t mask = (1U << extra_bits) - 1U;
374 count -= static_cast<std::size_t>(__builtin_popcount(last_word & mask));
375 }
376
377 return count;
378 }
379
385 [[nodiscard]] bool operator==(const BitVector& other) const noexcept {
386 return data_ == other.data_;
387 }
388
394 [[nodiscard]] bool operator!=(const BitVector& other) const noexcept {
395 return data_ != other.data_;
396 }
397
404 void from_bytes(const std::uint8_t* bytes, std::size_t num_bytes) noexcept {
405 zero();
406
407 std::size_t max_bytes = (num_bytes < NUM_BYTES) ? num_bytes : NUM_BYTES;
408 std::size_t word_idx = 0;
409 int byte_in_word = 4;
410 word_t word_acc = 0;
411
412 for (std::size_t i = 0; i < max_bytes; ++i) {
413 --byte_in_word;
414 word_acc |= static_cast<word_t>(bytes[i]) << (byte_in_word * 8);
415
416 if (byte_in_word == 0) {
417 data_[word_idx] = word_acc;
418 ++word_idx;
419 word_acc = 0;
420 byte_in_word = 4;
421 }
422 }
423
424 // Handle incomplete final word
425 if (byte_in_word < 4) {
426 data_[word_idx] = word_acc;
427 }
428 }
429
436 void to_bytes(std::uint8_t* bytes, std::size_t num_bytes) const noexcept {
437 std::size_t max_bytes = (num_bytes < NUM_BYTES) ? num_bytes : NUM_BYTES;
438 std::size_t byte_idx = 0;
439
440 for (std::size_t word_idx = 0; word_idx < NUM_WORDS && byte_idx < max_bytes; ++word_idx) {
441 word_t word = data_[word_idx];
442
443 for (int j = 3; j >= 0 && byte_idx < max_bytes; --j) {
444 bytes[byte_idx] = static_cast<std::uint8_t>((word >> (j * 8)) & 0xFFU);
445 ++byte_idx;
446 }
447 }
448 }
449
454 [[nodiscard]] word_t* data() noexcept {
455 return data_.data();
456 }
457
462 [[nodiscard]] const word_t* data() const noexcept {
463 return data_.data();
464 }
465
466private:
467 std::array<word_t, NUM_WORDS> data_;
468
472 void mask_unused_bits() noexcept {
473 constexpr std::size_t extra_bits = (NUM_WORDS * 32) - N;
474 if constexpr (extra_bits > 0 && NUM_WORDS > 0) {
475 word_t mask = ~((1U << extra_bits) - 1U);
476 data_[NUM_WORDS - 1] &= mask;
477 }
478 }
479};
480
481} // namespace ccsds124
482
483#endif // CCSDS124_BITVECTOR_HPP
Fixed-length bit vector with compile-time size.
Definition bitvector.hpp:90
static constexpr std::size_t NUM_WORDS
Number of 32-bit words needed.
Definition bitvector.hpp:93
void copy_from(const BitVector &src) noexcept
Copy from another BitVector.
void or_with(const BitVector &a, const BitVector &b) noexcept
Compute OR of two vectors (result = a | b).
constexpr std::size_t length() const noexcept
Get the number of bits.
void reverse_of(const BitVector &a) noexcept
Compute bit reversal of a vector.
void xor_of(const BitVector &a, const BitVector &b) noexcept
Compute XOR of two vectors.
int get_bit(std::size_t pos) const noexcept
Get bit value at position.
int get_bit_unchecked(std::size_t pos) const noexcept
Get bit value at position without bounds checking.
void set_bit(std::size_t pos, int value) noexcept
Set bit value at position.
void left_shift_of(const BitVector &a) noexcept
Compute left shift by 1 of a vector.
bool operator!=(const BitVector &other) const noexcept
Compare for inequality.
std::size_t hamming_weight() const noexcept
Count number of set bits (Hamming weight).
void and_of(const BitVector &a, const BitVector &b) noexcept
Compute AND of two vectors.
void xor_with(const BitVector &other) noexcept
XOR in-place with another vector.
bool operator==(const BitVector &other) const noexcept
Compare for equality.
void set_bit_unchecked(std::size_t pos, int value) noexcept
Set bit value at position without bounds checking.
void xor_with(const BitVector &a, const BitVector &b) noexcept
Compute XOR of two vectors (result = a ^ b).
static constexpr std::size_t NUM_BYTES
Number of bytes needed.
Definition bitvector.hpp:96
void left_shift(const BitVector &src) noexcept
Compute left shift of another vector (result = src << 1).
void left_shift() noexcept
Left shift by 1 in-place.
void or_in_place(const BitVector &other) noexcept
OR in-place with another vector (alias for or_with).
void or_of(const BitVector &a, const BitVector &b) noexcept
Compute OR of two vectors.
void from_bytes(const std::uint8_t *bytes, std::size_t num_bytes) noexcept
Load from byte array (big-endian).
void or_with(const BitVector &other) noexcept
OR in-place with another vector.
const word_t * data() const noexcept
Get raw data pointer (const version).
constexpr BitVector() noexcept
Default constructor - initializes all bits to zero.
constexpr std::size_t num_words() const noexcept
Get the number of 32-bit words.
void to_bytes(std::uint8_t *bytes, std::size_t num_bytes) const noexcept
Store to byte array (big-endian).
void zero() noexcept
Set all bits to zero.
void invert() noexcept
Invert all bits in-place.
word_t * data() noexcept
Get raw data pointer (for advanced use).
void and_with(const BitVector &other) noexcept
AND in-place with another vector.
void not_of(const BitVector &a) noexcept
Compute NOT of a vector.
CCSDS 124.0-B-1 compile-time configuration.
std::uint32_t word_t
32-bit word type for bit vector storage (matches C implementation)
Definition config.hpp:59
int extract_msb(std::uint32_t &word) noexcept
Extract and clear the most significant set bit from a word.
Definition bitvector.hpp:56
int extract_lsb(std::uint32_t &word) noexcept
Extract and clear the least significant set bit from a word.
Definition bitvector.hpp:71