How to Serialize Boost::Dynamic_Bitset

How to serialize boost::dynamic_bitset?

dynamic_bitset<> is not serializable, as you've found out (std::bitset<N> is different type).

Not to worry, though, you can add it without too much effort:

namespace boost { namespace serialization {

template <typename Ar, typename Block, typename Alloc>
void save(Ar& ar, dynamic_bitset<Block, Alloc> const& bs, unsigned) {
size_t num_bits = bs.size();
std::vector<Block> blocks(bs.num_blocks());
to_block_range(bs, blocks.begin());

ar & num_bits & blocks;
}

template <typename Ar, typename Block, typename Alloc>
void load(Ar& ar, dynamic_bitset<Block, Alloc>& bs, unsigned) {
size_t num_bits;
std::vector<Block> blocks;
ar & num_bits & blocks;

bs.resize(num_bits);
from_block_range(blocks.begin(), blocks.end(), bs);
bs.resize(num_bits);
}

template <typename Ar, typename Block, typename Alloc>
void serialize(Ar& ar, dynamic_bitset<Block, Alloc>& bs, unsigned version) {
split_free(ar, bs, version);
}

} }

This works e.g. Live On Coliru

int main() {
A a;
for (int i=0; i<128; ++i)
a.x.resize(11*i, i%2);

std::stringstream ss;
{
boost::archive::text_oarchive oa(ss);
oa << a;
}
std::cout << ss.str();
{
boost::archive::text_iarchive ia(ss);
A b;
ia >> b;

assert(a.x == b.x);
}
}

Note that if you can't afford to copy the blocks vector, it's equally easy to add serialization directly on the m_bits level, but that requires intrusive changes (friend access required at a minimum).

Such a thing would easily be added to boost in a pull request.

Update added that pull request

Serialize boost::bimap with boost::dynamic_bitset as key value pair

  1. Wow. You're not aiming for performance with that hash function.

    • you're copying all the blocks on every key/value hash (e.g. on lookup, on insert)
    • you better never wish to use co-routines because that thread-local static will make your life miserable

    See my BONUS section below

  2. Why this awkward dance (simplified code):

    auto iter = index.begin();

    // first left element of bimap
    BS first_left = iter->left;
    Index::left_iterator left_iter = index.left.find(first_left);

    What is wrong with

    auto left_iter = index.left.begin();
  3. What do you think is the validity of an iterator when serialized? (See Iterator invalidation rules)

    oa << left_iter;

    I think loading a new datastructure from storage counts as "reallocation". Iterators or references to another datastructure are obviously meaningless here.

  4. Erm. Now it's really getting confusing.

    //  first right element of bimap
    auto pos = index.left.find(first_left);
    Index::right_iterator right_iter = index.right.find(pos->second);

    You call it the "first right element", but you do something ELSE: you find the iterator corresponding to the first_left key (which may well be the last element on the right. Also note that since the right hand side of the bimap is multiset_of, there might be multiple matches and you random use the first.

    (Side note: pos is a useless duplication of left_iter's value)

  5. See 3.

    oa << right_iter;
  6. Varia:

    • make sure you open the files as binary

      std::ofstream ofs("binaryfile", std::ios::binary);
      std::ifstream ifs("binaryfile", std::ios::binary);
    • why do you name a container with value-semantics index_reference? That's just unnecessarily confusing

    • SerializableType is unused
    • BOOST_SERIALIZATION_NVP is meaningless for binary archives (nodes have no names in those)

The Real Question

I suppose, the real question might have been "how do I serialize the Bitsets?". I'm happy to inform you I wrote the required bits in 2015: How to serialize boost::dynamic_bitset? and the pull request has been accepted into Boost starting with version 1.64.

So, you can sit back, sip your tea and include:

#include <boost/dynamic_bitset/serialization.hpp>

All done.

The BONUS Section

Since that serialization achieves a minimal-copy serialization, why not use it to power the hash function? The serialization mechanism will provide you the required private access.

I've abused serialization plumbing for hash<> specializations before: Hash an arbitrary precision value (boost::multiprecision::cpp_int)

Putting It All Together

Live On Coliru

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/bimap.hpp>
#include <boost/bimap/unordered_multiset_of.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <boost/dynamic_bitset/serialization.hpp>
#include <fstream>
#include <iostream>
#include <string>

#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/stream.hpp>

#include <boost/functional/hash.hpp>

namespace serial_hashing { // see https://stackoverflow.com/questions/30097385/hash-an-arbitrary-precision-value-boostmultiprecisioncpp-int
namespace io = boost::iostreams;

struct hash_sink {
hash_sink(size_t& seed_ref) : _ptr(&seed_ref) {}

typedef char char_type;
typedef io::sink_tag category;

std::streamsize write(const char* s, std::streamsize n) {
boost::hash_combine(*_ptr, boost::hash_range(s, s+n));
return n;
}
private:
size_t* _ptr;
};

template <typename T> struct hash_impl {
size_t operator()(T const& v) const {
using namespace boost;
size_t seed = 0;
{
iostreams::stream<hash_sink> os(seed);
archive::binary_oarchive oa(os, archive::no_header | archive::no_codecvt);
oa << v;
}
return seed;
}
};
}

namespace std {
template <typename Block, typename Alloc> struct hash<boost::dynamic_bitset<Block, Alloc> >
: serial_hashing::hash_impl<boost::dynamic_bitset<Block, Alloc> >
{};
} // namespace std

namespace bimaps = boost::bimaps;
using Bitset = boost::dynamic_bitset<>;

typedef boost::bimap<
bimaps::unordered_set_of<Bitset, std::hash<Bitset> >,
bimaps::unordered_multiset_of<Bitset, std::hash<Bitset> > > Index;

int main() {
using namespace std::string_literals;

{
std::cout << "# Writing binary file ... " << std::endl;
Index index;
index.insert({Bitset("10010"s), Bitset("1010110110101010101"s)});

std::ofstream ofs("binaryfile", std::ios::binary);
boost::archive::binary_oarchive oa(ofs);
oa << index;
}

{
std::cout << "# Loading binary file ... " << std::endl;
std::ifstream ifs("binaryfile", std::ios::binary); // name of loading file

boost::archive::binary_iarchive ia(ifs);

Index index;
ia >> index;
}
}

Prints

# Writing binary file ... 
# Loading binary file ...

No problem.

POST SCRIPTUM

Really, save yourself trouble. Since your usage clearly indicates you do not want unordered semantics, just make it ordered:

Live On Coliru

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/bimap.hpp>
#include <boost/bimap/multiset_of.hpp>
#include <boost/dynamic_bitset/serialization.hpp>
#include <fstream>
#include <iostream>

namespace bimaps = boost::bimaps;
using Bitset = boost::dynamic_bitset<>;

typedef boost::bimap<bimaps::set_of<Bitset>, bimaps::multiset_of<Bitset>> Index;

int main() {
using namespace std::string_literals;

{
std::cout << "# Writing binary file ... " << std::endl;
Index index;
index.insert({Bitset("10010"s), Bitset("1010110110101010101"s)});

std::ofstream ofs("binaryfile", std::ios::binary);
boost::archive::binary_oarchive oa(ofs);
oa << index;
}

{
std::cout << "# Loading binary file ... " << std::endl;
std::ifstream ifs("binaryfile", std::ios::binary); // name of loading file

boost::archive::binary_iarchive ia(ifs);

Index index;
ia >> index;
}
}

Down to 36 lines, less than half the code left.

Generate hash for boost::dynamic_bitset and convert hash back to boost::dynamic_bitset

Ok, I'm detecting much confusion about the essence of "hashing", so a few friendly pointers to get started:

Q. 2. How to convert the hash back to orignial bitset.

That's impossible. A hash is lossy digest. You can only do this if the hash is a Perfect Hash which, due to the laws of entropy, cannot happen if the bitset capacity exceeds the size of size_t on your platform (typically 32 or 64 bits).

Q. I also tried creating a hash by ...

 std::bitset<142> seq (str);
....

I hope you realize that std::bitset<> is an entirely different type, so it's not really related to the task. And, since it's not dynamic, it's rather unhelpful for the task, even as a workaround.

But Most Importantly:

Hashes are used by hash-tables (like unordered_*<>) but they are not stored. Hashes are lossy digests, only used to get a good distribution over the internal buckets¹. For actual element equality, std::equal<T> is still used.

In other words:

typedef boost::bimap<bimaps::unordered_set_of<unsigned long long int>,
bimaps::unordered_multiset_of<size_t> > bimap_reference;

is unsuited for creating a map of anything other than size_t or unsigned long long². If you store hashes of things there:

reference_index_vector.insert(position(10000000000, hash1));

, you lose the original information. There's no way to get the bitset from hash1.

The compiler error

Your hash_value implementation mistakenly uses private members of dynamic_bitset<>. You can't because it's not accessible.

Here's a simple implementation of std::hash<> using the public interface:

Live On Coliru

#include <boost/dynamic_bitset.hpp>
#include <boost/functional/hash.hpp>
#include <unordered_map>
#include <sstream>

namespace std {

template <typename Block, typename Alloc> struct hash<boost::dynamic_bitset<Block, Alloc> > {
size_t operator()(boost::dynamic_bitset<Block, Alloc> const& bs) const {
size_t seed = boost::hash_value(bs.size());

std::vector<Block> blocks(bs.num_blocks());
boost::hash_range(seed, blocks.begin(), blocks.end());

return seed;
}
};

}

int main() {
boost::dynamic_bitset<> x, y;
x.resize(rand()%100, 1);
y.resize(rand()%100, 0);

std::unordered_map<boost::dynamic_bitset<>, std::string> m;
m[x] = "x";
m[y] = "y";
}

You can use this std::hash<> specialization instead and use boost::bimap with it.

NOTE, that using the public interface is not optimal, because it copies the Blocks (you also did that with the std::bitset<> hack). You might be interested in the Boost Serialization implementation I did for boost::dynamic_bitset<> before:

  • How to serialize boost::dynamic_bitset?
  • And here's code to show how to use the Serialization implementation to implement the hash efficiently Hash an arbitrary precision value (boost::multiprecision::cpp_int)

¹ Assuming, for simplicity, buckets instead of "open addressing" style. The same logic applies there, but somewhat more complicated

² (by the way, please just say uintmax_t or uint64_t)

Reverse order of boost::dynamic_bitset

boost::dynamic_bitset doesn't have iterators, so a long range of comfy STL solutions like, off the top of my head, std::reverse or std::swap or their boost counterparts are not available, I reckon that a good way would be to make your own trivial reverse method:

#include <iostream>
#include <boost/dynamic_bitset.hpp>

void reverse(boost::dynamic_bitset<> &bs)
{
for (size_t begin = 0, end = bs.size() - 1; begin < end; begin++, end--)
{
bool b = bs[end];
bs[end] = bs[begin];
bs[begin] = b;
}
}

int main()
{
size_t size = 8;
boost::dynamic_bitset<> bs(size, 50);

std::cout << "Normal: " << bs << std::endl;
reverse(bs);
std::cout << "Reverse: " << bs << std::endl;
}

Output:

Normal:  00110010
Reverse: 01001100

Live demo

Is boost dynamic_bitset header-only

From the docs:

It should be noted that in practice bcp can produce a rather "fat" list of dependencies, reasons for this include:

  • It searches for library names first, so using "regex" as a name will give you everything in the libs/regex directory and everything that depends on. This can be a long list as all the regex test and example programs will get scanned for their dependencies. If you want a more minimal list, then try using the names of the headers you are actually including, or use the --scan option to scan your source code.

  • ...

So, you are getting a fat list of dependencies because the search includes the tests and examples which are themselves not header-only, and have further non-header-only dependencies.

Is Boost dynamic_bitset really header-only

I see no reason to doubt that.

if so, how do I include only the relevant headers in my project?

As per the quoted suggestion, you might attempt instead: bcp --list boost/dynamic_bitset.hpp for a leaner list.

C++ send boost::dynamic_bitset with Winsock2 sendto function

I've implemented serialization for dynamic_bitset before: How to serialize boost::dynamic_bitset?

You can use that or a similar technique based on the same interfaces:

template <typename Block, typename Alloc>
std::string to_binary_string(boost::dynamic_bitset<Block, Alloc> const& bs) {
uint32_t const num_bits = bs.size();
auto const num_blocks = div_roundup(num_bits, sizeof(Block)*CHAR_BIT);

// prepare zeroed output buffer
std::string buf(sizeof(num_bits) + num_blocks * sizeof(Block), '\0');

// write size prefix
std::memcpy(buf.data(), &num_bits, sizeof(num_bits));

// write block data
if (num_bits > 0) { // mustn't pass nullptr to src argument of memcpy
auto b = reinterpret_cast<Block*>(buf.data() + sizeof(num_bits));
to_block_range(bs, b);
}
return buf;
}

Which you could send like:

std::string buf = to_binary_string(my_bitset);

int ret = sendto(sock, buf.data(), buf.size(), flags, reinterpret_cast<SOCKADDR*>(&address), sizeof(address));

The analogous deserialization code:

template <typename Block, typename Alloc>
void from_bytes(std::string_view buf, boost::dynamic_bitset<Block, Alloc>& bs) {
// read the size prefix
uint32_t num_bits;
if (buf.size() < sizeof(num_bits)) {
throw std::length_error("from_bytes");
}
std::memcpy(&num_bits, buf.data(), sizeof(num_bits));

// shift buf to only cover the actual bit data
buf = buf.substr(sizeof(num_bits));

// read the bits as blocks
bs.resize(num_bits);
if (buf.size() % sizeof(Block) != 0) {
throw std::length_error("from_bytes");
}
auto b = reinterpret_cast<Block const*>(buf.data());
auto e = reinterpret_cast<Block const*>(buf.data() + buf.size());
size_t const num_blocks = std::distance(b, e);

// sanity checks block count vs num_bits
if (num_blocks != div_roundup(num_bits, sizeof(Block)*CHAR_BIT)) {
throw std::length_error("from_bytes"); // num_blocks doesn't match num_bits
}

from_block_range(b, e, bs);
bs.resize(num_bits);
}

Live Demo

Disclaimer:

  • Portability is NOT addressed here. If you send data across systems using different native byte orderings, the behaviour is unspecified,
    even though care has been taken to not BLOW UP, the data would be
    wrong even in the extremely unlikely event that the sizes would add
    up.
  • Similarly, no guarantees are made when the deserialized type doesn't exactly match the serialized type in terms of Block type.

That aside, the program tests edge cases and runs clean under
ASAN/UBSAN.

Live On Coliru

#include <boost/dynamic_bitset.hpp>
#include <climits> // CHAR_BIT
#include <string>
#include <string_view>
// demo output
#include <iostream>

static inline size_t div_roundup(size_t p, size_t q) {
// quick&dirty, see https://stackoverflow.com/a/926806/85371
return (p+q-1)/q;
}

template <typename Block, typename Alloc>
std::string to_binary_string(boost::dynamic_bitset<Block, Alloc> const& bs) {
uint32_t const num_bits = bs.size();
auto const num_blocks = div_roundup(num_bits, sizeof(Block)*CHAR_BIT);

// prepare zeroed output buffer
std::string buf(sizeof(num_bits) + num_blocks * sizeof(Block), '\0');

// write size prefix
std::memcpy(buf.data(), &num_bits, sizeof(num_bits));

// write block data
if (num_bits > 0) { // mustn't pass nullptr to src argument of memcpy
auto b = reinterpret_cast<Block*>(buf.data() + sizeof(num_bits));
to_block_range(bs, b);
}
return buf;
}

template <typename Block, typename Alloc>
void from_bytes(std::string_view buf, boost::dynamic_bitset<Block, Alloc>& bs) {
// read the size prefix
uint32_t num_bits;
if (buf.size() < sizeof(num_bits)) {
throw std::length_error("from_bytes");
}
std::memcpy(&num_bits, buf.data(), sizeof(num_bits));

// shift buf to only cover the actual bit data
buf = buf.substr(sizeof(num_bits));

// read the bits as blocks
bs.resize(num_bits);
if (buf.size() % sizeof(Block) != 0) {
throw std::length_error("from_bytes");
}
auto b = reinterpret_cast<Block const*>(buf.data());
auto e = reinterpret_cast<Block const*>(buf.data() + buf.size());
size_t const num_blocks = std::distance(b, e);

// sanity checks block count vs num_bits
if (num_blocks != div_roundup(num_bits, sizeof(Block)*CHAR_BIT)) {
throw std::length_error("from_bytes"); // num_blocks doesn't match num_bits
}

from_block_range(b, e, bs);
bs.resize(num_bits);
}

int main() {
::srand(::time(0)); // extremely lazy bad random, sue me

for (auto bits = 0; bits < 128; ++bits) {
boost::dynamic_bitset<> my_bitset(bits), roundtrip;

for (size_t bit = 0; bit < my_bitset.size(); ++bit)
my_bitset.set(bit, rand()%2);

from_bytes(to_binary_string(my_bitset), roundtrip);

std::cout << "{" << roundtrip << "} " << (roundtrip == my_bitset? "OK":"ERROR") << std::endl;
}
}

Printing:

{} OK
{0} OK
{11} OK
{001} OK
{0010} OK
{01000} OK
{110011} OK
{0101011} OK
{01101101} OK
{101011011} OK
{1011100010} OK
{11100100110} OK
{110010010000} OK
{0011100110110} OK
{11100110110001} OK
{111101110011011} OK
{1011101100011011} OK
{10101000000110111} OK
{000000110100111111} OK
{0110001110100001011} OK
{11111111010010010110} OK
{010011100110111000011} OK
{0110011101111000111000} OK
{10011100110001001110101} OK
{011001001100011111010011} OK
{1101010010110100000100101} OK
{01101111001100100010111110} OK
{010101111001011111100011000} OK
{0101111001111001000001011011} OK
{10011101100111110110110001010} OK
{000001110000100011000011101000} OK
{1101010001101101111001001110000} OK
{11111010100111110010101111110010} OK
{110010101001101110000001011101110} OK
{1010100100010000011011011010000111} OK
{11101101111011011010110101101010000} OK
{110000101010100111010111011110100010} OK
{1000111110000001111010110000001111010} OK
{00010010011001111101101110101111000000} OK
{000000011000001100101000111110000111101} OK
{1000111111000000000111101110111101100010} OK
{01001110000011011100111110100100010111011} OK
{001000011101111001110111110000110100011001} OK
{0011010001000110100101000010110000101101001} OK
{01110111010111101000011110110011011110110101} OK
{111001000011011110001100000111001000001101010} OK
{1110001101010100101110100111001010100111111001} OK
{00110110011111110001110111110101101010100000110} OK
{101000100110100111001000110111010101101011000011} OK
{0011111001111000011010110110111110111011001101000} OK
{00011100110101100011000001010000111001011001111111} OK
{100101100001101111011001000101110100111110000100001} OK
{1110101000000100001111100111101101111100100011111111} OK
{00001010100111101001000100010111101101100101000001110} OK
{110101000110000011000100000001100100111101001100110011} OK
{1001111110001011100010011110001011010111101010101100100} OK
{00101001010011101000100110011011110101100110000110100010} OK
{010101000111011001001010011001010110111110101011001100100} OK
{0101100010000001010001110011001100000001011101101010110000} OK
{01000111001101100011000010010010111010010010111101101001010} OK
{000111101101111000011101101101101101100001011110111000001000} OK
{0111101011101011101000011001010000011001010111001001111000011} OK
{01000100010000000110001110110010110100001000001011110000010011} OK
{110100101010111101010010011100110000110100001010110100110001011} OK
{0111110001111011011001110000101100111011010000000101111010000111} OK
{01101000000101000000010010010100010101000110100011001010011011011} OK
{110111111011010011011001001011000100010000100001001000000111110011} OK
{0000111000100111101000000001111000011100000101010100001101111101111} OK
{11100101011110110110101100100100110110110110000000000101000000000011} OK
{111011000011111101100101001010010010101110001001100110111100101011101} OK
{1001110011100111010010110011010111111001100110010011010100101000010010} OK
{01011111001100011100000000011100000111010111001111100001100110001111110} OK
{010010111000101000111100000000010011111110010110011110000000000000001100} OK
{1101010011010110010100000100100110100100100110011100011010000001000001011} OK
{10100101001110110001011010010101100100110100011011001000010110100001101010} OK
{101010100011101100111000111001011011010111000101101011111011000001010111110} OK
{1011011101011011000101101101000110011001001001110101010010001010111000101011} OK
{01100101111100011110101000001010111101011011100101111000101110011011110011100} OK
{111100111010011100010111101010110101110000100111011001001111001100001011111110} OK
{0000010110001101001001110010011011010111100010100001111010100000100000101010010} OK
{10010100010000110101000000101001011011001001000110110110110001000001001000011011} OK
{011011101100001101001110111110000111010111010011001100100010011111110000101101000} OK
{0011001100110110111111101010011111010001000001110001010000101110111100100010111101} OK
{10001101001110001000001110110011111010010111100101011100111110010100010111100001010} OK
{111100011111110011011001001111101111110001010100010000001101000000101001111110011000} OK
{1001100110101000000110001000101010100101110100011100100010111111010101101001110000011} OK
{11000111100001000001001010010011010101100100101100001100101110010100000000000111100000} OK
{011011101010011001000000101101100011010110001000111010100001111000111001101011110111110} OK
{1011100111101110001111011101111010011100111111111110011010010000111101100000110111110000} OK
{11010010100011011010011111101011100101010100110100101001010011100011100001001000010001100} OK
{101100101110110110010010010001000010101100101010000110000100101111110100010111010111010000} OK
{1001100111111100000101011010100111101010000110010100100111011001010101111010100000000110011} OK
{11001000001101011000100011101111000001110011000100010011011011110010110001111001000101000010} OK
{010101110110011011001001111010100001101010110101001101010100110111011101001110111011111111001} OK
{0000001100010100101010000011000000100110011001011111101110100111011110100011011101001011001111} OK
{11101001010111000101001110011001010000000110010110011010100001000010011010010010010110110110100} OK
{100001001010100100000100111100101100000111111010110010101101000110010110010110011111110010111010} OK
{0110011101101011110011100101100110111110011110110001100101011000101110110001011110100000001010101} OK
{11111011101101010010010000101110000111011011001010001000000111101110110001000101110100110101001100} OK
{101001001001010101110010000100001000001101111111010000000110100111110001111010100100001001100100100} OK
{1010011111100001100101101110111001110011110100000100100100110011101110001000010000100001011101001101} OK
{10101011111010101101011101110010101111010001100011111000110011111011101110101110011011010111110011010} OK
{101001011011011011111101011110110000010001000011001011111100011000001100111100001000101111101000110100} OK
{1100001111000101010001010010000110011001111111011101100011111010100011110011011001001110010100111101010} OK
{01110111101110010010110110011011100101001010011010110010000011100111111101010110110001000111101011001011} OK
{111110001010000011111101001011100010111001001110001101001011100010111001011001111110001110111000010001010} OK
{1000110001111101001001100010011101011011000000001010111001111001100001001000101111001011010000011100100110} OK
{01101100101011110001001001101001110100111100111101000100010111101011000101101110101011010100011111110101111} OK
{100011010110010100001100010011111100101010011010110101001010000100011100011110000110111101000011011110010111} OK
{0001110100111110010010100101000111111101101110010011100110111101111001111111100101100000101110011011000001101} OK
{10000101011100100101100111111000010100011100010101111000001101010011111010011011011000110011000100110100101000} OK
{100110110011000000010000100011100010010101110000111010010101011000110101111101110011011101001011001101010001010} OK
{1001010100011011000111111111111001011010000001110100011100001101000001000010101000111110110010100101101111111111} OK
{00111000110111101110100111000110101111111101101100011111111110101010101001000000110000111101101111010011100011011} OK
{111100000100010001011010111001111111010111001101000100010011010110100111011010111101001110010001001111100110110010} OK
{1111110110110111110000001110010010100011000101001001111010001001111101111100000011000101001001001101000110000001100} OK
{11110101001111001100101001010100101110100011000101110001101101101110111101010101111011010100000110100011111011010101} OK
{100111000001000011100001011000001100100010101011110110001100010100001011111011000011100110011001101110011111101000101} OK
{1110110110010100001000101001001110100000110010110011110001111111110011111010000010111101001000110010011111001111101000} OK
{00000101100100000111110000100101010100101000011000111010110110111100111101111110110101100011101101011000000001001110111} OK
{010111011011000010001010010100010110001001101101101101001011010001000010010000000111011100100110101011001000001011011000} OK
{0011011110010110010111101101111100111110000010111101010001101111101101101001001000101101101001110000110000000110100010010} OK
{00001001010011101011011010010000000011000110011100000101111000100101111110101111100100011110100101011101101111100011100101} OK
{001011011110110000011010101000001001100100011001000100110100100111100101100010111101001010101100100100011010111010000101100} OK
{1111110110100111101011110100111011000001001111111010100011110001100100010010110110111110111100001011101000000100100000100100} OK
{01110000101110010101010110100001010010101010001111110100010111000011101000111010101111001011100111000011111011110011101011100} OK
{001100001010111010111001111011011000100100110010110001010000001110000001000110010101101000111110010101001010101100010111100011} OK
{1100011010110110001110101000110011110110010011010101110001010111110010000110011111110101111010110001010100110010000101001110011} OK

How does boost::dynamic_bitset store bits

boost::dynamic_bitset<> internally stores bits in unsigned integers, which are stored in a std::vector<>. The internal storage is not exposed though, so you cannot access it directly.

You can use to_block_range to copy a boost::dynamic_bitset<> into an array of integers. And a constructor to convert that array of integers back to a boost::dynamic_bitset<>.



Related Topics



Leave a reply



Submit