String Builder: Building Strings with Streams on the Stack

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);
}


About the Author

John Wellbelove

John has been in the electronics business for 30 years, gradually moving over the years from pure hardware design to mostly software with hardware interface elements in a real-time environment. Over the years he has programmed in Assembler (6502, 6809, 68000), BASIC, Pascal, C & C++. He has dabbled a little in PHP/MySQL as he runs run a climbing club website and forum. http://www.southamptonrats.org. Projects have included DCT based image compression (pre-jpeg), remote imaging security systems, CCTV cameras, images analysis, real-time conveyor control. He is currently working on a template library based on the STL for images and image algorithms.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • The explosion in mobile devices and applications has generated a great deal of interest in APIs. Today's businesses are under increased pressure to make it easy to build apps, supply tools to help developers work more quickly, and deploy operational analytics so they can track users, developers, application performance, and more. Apigee Edge provides comprehensive API delivery tools and both operational and business-level analytics in an integrated platform. It is available as on-premise software or through …

  • As mobile devices have pushed their way into the enterprise, they have brought cloud apps along with them. This app explosion means account passwords are multiplying, which exposes corporate data and leads to help desk calls from frustrated users. This paper will discover how IT can improve user productivity, gain visibility and control over SaaS and mobile apps, and stop password sprawl. Download this white paper to learn: How you can leverage your existing AD to manage app access. Key capabilities to …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds