HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Fast (faster than std::) ostringstream

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
faststdthanostringstreamfaster

Problem

I tried to implement a faster ostringstream which initially uses the stack (up to 256 bytes before using the heap).

Also, unlke the standard, it provides a way to access the data and size without creating new string each time, and supports copy and move ctors.

Please review.

```
#include
#include
#include
#include
#include
#include

template
class stack_buf
{
public:
static const unsigned short stack_size = STACK_SIZE;
stack_buf() :_v(), _stack_size(0) {}
~stack_buf() = default;
stack_buf(const stack_buf& other):stack_buf(other, delegate_copy_move {})
{}

stack_buf(stack_buf&& other):stack_buf(other, delegate_copy_move {})
{
other.clear();
}
template
stack_buf& operator=(T1&& other)
{
_stack_size = other._stack_size;
if (other.vector_used())
_v = std::forward(other)._v;
else
std::copy_n(other._stack_array.begin(), other._stack_size, _stack_array.begin());
return *this;
}

void append(const char* buf, std::size_t buf_size)
{
//If we are aleady using _v, forget about the stack
if (vector_used())
{
_v.insert(_v.end(), buf, buf + buf_size);
}
//Try use the stack
else
{
if (_stack_size + buf_size
stack_buf(T1&& other, delegate_copy_move)
{
_stack_size = other._stack_size;
if (other.vector_used())
_v = std::forward(other)._v;
else
std::copy_n(other._stack_array.begin(), other._stack_size, _stack_array.begin());
}

inline bool vector_used() const
{
return !(_v.empty());
}

std::vector _v;
std::array _stack_array;
std::size_t _stack_size;
};

//
// Custom std::streambuf
//
class stack_devicebuf :public std::streambuf
{
public:
static const unsigned short stack_size = 256;
using stackbuf_t = stack_buf;

stack_devicebuf() = default;
~stack_devicebuf() = defa

Solution

Just some minor coding style issues that jump into the eye.

The ternary operator would make some of the methods shorter and sweeter:

const char* data() const
{
    return vector_used() ? _v.data() : _stack_array.data();
}

std::size_t size() const
{
    return vector_used() ? _v.size() : _stack_size;
}


The parentheses are unnecessary around _v.empty():

inline bool vector_used() const
{
    return !(_v.empty());
}


Instead of:

void swap(fast_oss& first, fast_oss& second) // nothrow
{
    using std::swap;
    swap(first._dev, second._dev);
}


Why not just:

void swap(fast_oss& first, fast_oss& second) // nothrow
{
    std::swap(first._dev, second._dev);
}


As per @loki's comment:


The reason for doing using std::swap; and then using swap() without the namespace is to force Koenig look-up of which swap to use. So the original version is correct.

Code Snippets

const char* data() const
{
    return vector_used() ? _v.data() : _stack_array.data();
}

std::size_t size() const
{
    return vector_used() ? _v.size() : _stack_size;
}
inline bool vector_used() const
{
    return !(_v.empty());
}
void swap(fast_oss& first, fast_oss& second) // nothrow
{
    using std::swap;
    swap(first._dev, second._dev);
}
void swap(fast_oss& first, fast_oss& second) // nothrow
{
    std::swap(first._dev, second._dev);
}

Context

StackExchange Code Review Q#67262, answer score: 4

Revisions (0)

No revisions yet.