5
\$\begingroup\$

In a previous question I posted a method for easy std::bitset IO on a bit-for-bit basis. This question was later followed up in another solution. Both of these solutions had limitations; the interface of my original solution was not pretty, and the second method was limited to 64 bit std::bitsets.

Here is the solution I settled on. I have benchmarked this against my original solution (with the suggested improvements), and the runtime performance characteristics are very comparable. In fact, it seems this method is even faster than the buffering approach, while obviously also having the advantage of memory savings.

bitio.h

template <std::size_t N>
class BitIO
{
public:

    std::bitset<N> data;

    BitIO() {};
    BitIO(const std::bitset<N>& data) : data(data)
    {
        bitset_to_bytes();
    }

private:

    template <std::size_t T>
    friend std::ostream& operator<<(std::ostream& os, const BitIO<T>& bio);
    template <std::size_t T>
    friend std::istream& operator>>(std::istream& is, BitIO<T>& bio);

    void bitset_to_bytes()
    {
        for (std::size_t j = 0; j < N; ++j) {
            bytes[j >> 3] |= (data[j] << (j & 7));
        }
    }

    void bytes_to_bitset()
    {
        data.reset();
        for (std::size_t j = 0; j < N; ++j) {
            data[j] = ((bytes[(j >> 3)] >> (j & 7)) & 1);
        }
    }

    std::istream& read_file(std::istream& is)
    {

        is.read(reinterpret_cast<char*>(&bytes[0]), (N + 7) >> 3);
        bytes_to_bitset();
        return is;
    }

    std::array<unsigned char, ((N + 7) >> 3)> bytes{};
};

template <std::size_t N>
std::ostream& operator<<(std::ostream& os, const BitIO<N>& bio)
{
    for (const auto& byte : bio.bytes) {
        os << byte;
    }
    return os;
}

template <std::size_t N>
std::istream& operator>>(std::istream& is, BitIO<N>& bio)
{
    bio.read_file(is);
    is.peek(); // To set eof flag.
    return is;
}

main.cpp

#include "bitio.h"
#include <iostream>

int main()
{
    std::ofstream bin_out("~/bf.bin", std::ios::out | std::ios::binary);

    std::vector<std::bitset<16>> values { std::bitset<16>(100), std::bitset<16>(200), std::bitset<16>(255) };

    std::copy(std::begin(values), std::end(values), std::ostream_iterator<BitIO<16>>(bin_out));

    bin_out.close();

    std::ifstream bin_in("~/bf.bin", std::ios::binary);

    values.clear();

    while (!bin_in.eof()) {
        BitIO<16> bio;
        bin_in >> bio;
        values.push_back(bio.data);
    }
}

Any further suggestions for improvement are welcome!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.