BufferWriter¶
Synopsis¶
#include <tsutil/ts_bw_format.h> // Above plus Formatting support.
Description¶
BufferWriter
is intended to increase code reliability and reduce complexity in the common
circumstance of generating formatted output strings in fixed buffers. Current usage is a mixture of
snprintf
and memcpy
which provides a large scope for errors and verbose code to
check for buffer overruns. The goal is to provide a wrapper over buffer size tracking to make such
code simpler and less vulnerable to implementation error.
BufferWriter
itself is an abstract class to describe the base interface to wrappers for
various types of output buffers. As a common example, FixedBufferWriter
is a subclass
designed to wrap a fixed size buffer. FixedBufferWriter
is constructed by passing it a
buffer and a size, which it then tracks as data is written. Writing past the end of the buffer is
clipped to prevent overruns.
Consider current code that looks like this.
char buff[1024];
char * ptr = buff;
size_t len = sizeof(buff);
//...
if (len > 0) {
auto n = std::min(len, thing1_len);
memcpy(ptr, thing1, n);
len -= n;
}
if (len > 0) {
auto n = std::min(len, thing2_len);
memcpy(ptr, thing2, n);
len -= n;
}
if (len > 0) {
auto n = std::min(len, thing3_len);
memcpy(ptr, thing3, n);
len -= n;
}
This is changed to
char buff[1024];
swoc::FixedBufferWriter bw(buff, sizeof(buff));
//...
bw.write(thing1, thing1_len);
bw.write(thing2, thing2_len);
bw.write(thing3, thing3_len);
The remaining length is updated every time and checked every time. A series of checks, calls to
memcpy
, and size updates become a simple series of calls to BufferWriter::write
.
More in depth documentation is in the libswoc documentation.
Which header to include depends on usage.
- “ts_bw.h”
Contains on the basic buffer manipulation.
- “ts_bw_format.h”
Basic buffer manipulation and formatting. This does not include IP address support, which is pulled in with the “ts_ip.h” header.
Usage¶
BufferWriter
is an abstract base class, in the style of std::ostream
. There are
several subclasses for various use cases. When passing around this is the common type.
FixedBufferWriter
writes to an externally provided buffer of a fixed length. The buffer must
be provided to the constructor. This will generally be used in a function where the target buffer is
external to the function or already exists.
LocalBufferWriter
is a templated class whose template argument is the size of an internal
buffer. This is useful when the buffer is local to a function and the results will be transferred
from the buffer to other storage after the output is assembled. Rather than having code like:
char buff[1024];
swoc::FixedBufferWriter bw(buff, sizeof(buff));
it can be written more compactly as:
swoc::LocalBufferWriter<1024> bw;
In many cases, when using LocalBufferWriter
this is the only place the size of the buffer
needs to be specified and therefore can simply be a constant without the overhead of defining a size
to maintain consistency. The choice between LocalBufferWriter
and FixedBufferWriter
comes down to the owner of the buffer - the former has its own buffer while the latter operates on
a buffer owned by some other object. Therefore if the buffer is declared locally, use
LocalBufferWriter
and if the buffer is received from an external source (such as via a
function parameter) use FixedBufferWriter
.
For convenience and performance there is a thread local string, ts::bw_dbg
which can be used as
an expanding buffer for BufferWriter
. If the output is too large for the string storage, that storage
is increased to be sufficient to hold the output which is generated again. Because the storage is never
decreased over time the string becomes large enough that no further allocation is needed.