3#include <pixie/storage/aligned.h>
25 std::size_t size_ = 0;
28 static std::size_t bits_for_words(std::size_t words) {
29 if (words > std::numeric_limits<std::size_t>::max() / 64) {
30 throw std::length_error(
"Packed bit sequence is too large");
35 void ensure_word_capacity(std::size_t required_words) {
36 const std::size_t current_words =
38 if (required_words <= current_words) {
41 if (current_words == 0) {
43 bits_for_words(std::max(required_words, kAlignedStorageLineWords64)));
46 const std::size_t doubled_words =
47 current_words > std::numeric_limits<std::size_t>::max() / 2
50 const std::size_t grown_words = std::max(required_words, doubled_words);
51 data_.resize(bits_for_words(grown_words));
59 if (size_ % 64 == 0) {
60 const std::size_t word = size_ / 64;
61 ensure_word_capacity(word + 1);
62 data_.writable_words64()[word] =
static_cast<std::uint64_t
>(bit);
64 data_.writable_words64()[size_ / 64] |= 1ull << (size_ % 64);
77 throw std::invalid_argument(
"Packed bit width is greater than 64");
82 if (size_ > std::numeric_limits<std::size_t>::max() - width) {
83 throw std::length_error(
"Packed bit sequence is too large");
86 const std::size_t offset = size_ % 64;
88 const std::size_t word = size_ / 64;
89 ensure_word_capacity(word + 1);
90 data_.writable_words64()[word] =
91 width == 64 ? bits : bits & ((1ull << width) - 1);
93 const std::size_t prefix = std::min(width, 64 - offset);
94 const std::uint64_t prefix_mask =
95 prefix == 64 ? ~std::uint64_t{0} : (1ull << prefix) - 1;
96 auto words = data_.writable_words64();
97 words[size_ / 64] |= (bits & prefix_mask) << offset;
99 const std::size_t word = size_ / 64 + 1;
100 ensure_word_capacity(word + 1);
101 data_.writable_words64()[word] = bits >> prefix;
108 std::size_t
size_bits() const noexcept {
return size_; }
114 const std::size_t words =
116 ensure_word_capacity(words);
123 const std::size_t words =
124 size_ / 64 +
static_cast<std::size_t
>(size_ % 64 != 0);
125 const auto source = data_.as_words64().first(words);
126 std::vector<std::uint64_t> result(source.begin(), source.end());
136 const std::size_t words =
137 size_ / 64 +
static_cast<std::size_t
>(size_ % 64 != 0);
138 data_.
resize(bits_for_words(words));
140 return std::exchange(data_, {});
Owning storage with a logical byte size and 64-byte-aligned backing.
Definition aligned.h:41
Builder for a packed LSB-first bit sequence.
Definition packed_bit_builder.h:23
AlignedStorage take_storage()
Transfer the packed words in aligned storage and reset this builder.
Definition packed_bit_builder.h:135
void write_bit(bool bit)
Append one bit.
Definition packed_bit_builder.h:58
std::vector< std::uint64_t > take_words()
Materialize the packed words and reset this builder.
Definition packed_bit_builder.h:122
std::size_t size_bits() const noexcept
Return the number of appended bits.
Definition packed_bit_builder.h:108
void reserve_bits(std::size_t size_bits)
Reserve storage for at least size_bits bits.
Definition packed_bit_builder.h:113
void write_bits(std::uint64_t bits, std::size_t width)
Append the low width bits of bits, least-significant bit first.
Definition packed_bit_builder.h:75
std::size_t size_bytes() const
Return the logical exposed storage size in bytes.
Definition storage.h:75
void resize(std::size_t size_bits)
Resize mutable storage to hold at least size_bits bits.
Definition storage.h:221