I had a requirement for building strings for logging, but the std::ostringstream was
less than optimum. Firstly, it required more than one line of code to build the string and
secondly, it uses the heap for buffering. The code here describes a simple, stack based, string builder class that
that uses a fixed array as the workspace for a string stream.
How the String Builder Works
The string builder works by creating a class derived from streambuf (Stream_Buffer) that has its
buffer set to a fixed internal array, and using that as the buffer for the ostream derived object (Stream).
The Stream_Buffer discards any characters that would cause the buffer to overflow. An overloaded << operator
in the String_Builder class adds objects to the internal stream. A conversion operator to
std::string is provided as well as two functions ‘str’ and ‘c_str’ to convert to std::string
and const char*.
The default size for the buffer is set to 256 characters. Larger buffers can be
accommodated by using a larger template parameter.
Example of the String Builder
void Log(const std::string &text)
{
// Log the text somewhere...
}
int value = 10;
Log(String_Builder<>() << "The value is " << value << "n");
Log(String_Builder<1000>() << "A really long string up to 1000 characters");
The String Builder Code
Following is the code for thie String_Builder class:
#include <ostream>
#include <streambuf>
template <const int MAX_CHARACTERS = 256>
class String_Builder
{
private:
//*****************************************************************
// Special stream buffer
//*****************************************************************
class Stream_Buffer : public std::streambuf
{
public:
//**************************************************************
// Constructor
//**************************************************************
Stream_Buffer()
{
// Set the pointer to the internal buffer.
setp(buffer, buffer + MAX_CHARACTERS);
}
//**************************************************************
// Returns a null terminated string.
//**************************************************************
const char *c_str() const
{
*pptr() = 0;
return (pbase());
}
protected:
//**************************************************************
// Overridden Overflow()
//**************************************************************
int_type overflow(int_type c = 0)
{
// Don't do anything if we have no more room.
return (0);
}
private:
// The buffer that accumulates the characters.
// Leave room for a terminating zero.
char buffer[MAX_CHARACTERS + 1];
};
//*****************************************************************
// Special stream
//*****************************************************************
class Stream : public std::ostream
{
public:
//**************************************************************
// Constructor
//**************************************************************
Stream()
: std::ostream(&stream_buffer)
{
}
//**************************************************************
// Returns a null terminated string.
//**************************************************************
const char *c_str() const
{
return (stream_buffer.c_str());
}
private:
Stream_Buffer stream_buffer; // The stream that builds the string.
};
public:
//*********************************************************************
// Output stream operator.
//*********************************************************************
template<typename T>
String_Builder &operator <<(const T &value)
{
builder << value;
return (*this);
}
//*********************************************************************
// Conversion operator to std::string
//*********************************************************************
operator std::string() const
{
return (std::string(builder.c_str()));
}
//*********************************************************************
// Conversion to std::string
//*********************************************************************
std::string str() const
{
return (std::string(builder.c_str()));
}
//*********************************************************************
// Pointer to the internal C string.
//*********************************************************************
const char *c_str() const
{
return (builder.c_str());
}
private:
Stream builder; // The stream used to accumulate text.
};
//*********************************************************************
// Operator to stream to a std::ostream.
//*********************************************************************
template <const int MAX_CHARACTERS>
inline std::ostream &operator <<(std::ostream &os, const String_Builder<MAX_CHARACTERS> &sb)
{
os << std::string(sb);
return (os);
}