patterncppMinor
Implementing binary output to a file in C++11
Viewed 0 times
fileimplementingbinaryoutput
Problem
I would like to have a class which supports outputting bits into a file. This is what I came up with but I fear there are many poor decisions. Should I inherit from a
std::ofstream instead of keeping it as a data member?class OFBitStream final
{
static const std::size_t bitset_size = 8 * sizeof(unsigned long);
std::bitset bitset;
std::size_t current_bit;
std::ofstream &_stream;
void flush() {
for (auto i = current_bit; i (&buffer), 1);
buffer >>= 8;
}
}
public:
OFBitStream(std::ofstream &stream)
: bitset(0), current_bit(0), _stream(stream) {}
~OFBitStream() {
flush();
_stream.close();
}
friend OFBitStream &operator<<(OFBitStream &dst, const bool &data)
{
dst.bitset[dst.current_bit++] = data;
if (dst.current_bit == dst.bitset_size) {
dst.flush();
dst.current_bit = 0;
}
return dst;
}
};Solution
I would not write an adapter for a stream.
But rather a stream manipulator.
Try this:
Example:
But rather a stream manipulator.
Try this:
#include
// The object that does all the work.
class BBoolWrapper
{
std::ostream& str;
mutable std::size_t position;
mutable std::bitset data;
public:
BBoolWrapper(std::ostream& str)
: str(str)
, position(0)
{}
~BBoolWrapper()
{
// If there is data to be flushed when we destroy the
// object then make sure it goes on the stream.
flush();
}
// Testing state.
bool empty() const { return position == 0;}
bool full() const { return position == data.size();}
// Just the way I do it.
// You can add bits any way you like one at a time.
void addBit(bool nextbit) const
{
data (&value), sizeof(unsigned long));
position = 0;
}
}
// The interesting part.
// If we have an object like this and a bool using the `
friend std::ostream& operator<<(BBoolWrapper const& stream, T const& val)
{
stream.flush();
return stream.str << val;
}
};
// A simple empty class to start the streaming of bits
// via the above wrapper class.
struct BBool
{
friend BBoolWrapper operator<<(std::ostream& stream, BBool const&)
{
return BBoolWrapper(stream);
}
};Example:
#include
#include
int main()
{
// Use the BBool() object on a stream to turn binary mode on.
// It stays on until you add a non boolean object to the chain. (like "\n")
std::ofstream log("log");
log << BBool() << false << true << false << false << false << false << false << true << "\n";
std::cout << BBool() << false << true << false << false << false << false << false << true << "\n";
}Code Snippets
#include <ostream>
// The object that does all the work.
class BBoolWrapper
{
std::ostream& str;
mutable std::size_t position;
mutable std::bitset<sizeof(unsigned long) * CHAR_BIT> data;
public:
BBoolWrapper(std::ostream& str)
: str(str)
, position(0)
{}
~BBoolWrapper()
{
// If there is data to be flushed when we destroy the
// object then make sure it goes on the stream.
flush();
}
// Testing state.
bool empty() const { return position == 0;}
bool full() const { return position == data.size();}
// Just the way I do it.
// You can add bits any way you like one at a time.
void addBit(bool nextbit) const
{
data <<= 1;
data[0] = nextbit;
++position;
if (full())
{
flush();
}
}
// Simple Flush to the stream (if there is any data).
void flush() const
{
if (!empty())
{
unsigned long value = data.to_ulong();
str.write(reinterpret_cast<char*>(&value), sizeof(unsigned long));
position = 0;
}
}
// The interesting part.
// If we have an object like this and a bool using the `<<` operator
// Then add the bit and return this object so we are chaining the
// `<<` operations.
friend BBoolWrapper const& operator<<(BBoolWrapper const& stream, bool nextbit)
{
stream.addBit(nextbit);
return stream;
}
// If we use any other type with `<<` operator then flush this object.
// Return the underlying stream object to get back to normal stream
// operations.
template<typename T>
friend std::ostream& operator<<(BBoolWrapper const& stream, T const& val)
{
stream.flush();
return stream.str << val;
}
};
// A simple empty class to start the streaming of bits
// via the above wrapper class.
struct BBool
{
friend BBoolWrapper operator<<(std::ostream& stream, BBool const&)
{
return BBoolWrapper(stream);
}
};#include <iostream>
#include <ifstream>
int main()
{
// Use the BBool() object on a stream to turn binary mode on.
// It stays on until you add a non boolean object to the chain. (like "\n")
std::ofstream log("log");
log << BBool() << false << true << false << false << false << false << false << true << "\n";
std::cout << BBool() << false << true << false << false << false << false << false << true << "\n";
}Context
StackExchange Code Review Q#69007, answer score: 2
Revisions (0)
No revisions yet.