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