Skip to content

Instantly share code, notes, and snippets.

@BaiGang
Created June 19, 2012 05:18
Show Gist options
  • Save BaiGang/2952423 to your computer and use it in GitHub Desktop.
Save BaiGang/2952423 to your computer and use it in GitHub Desktop.
cpp string builder
There is no an efficient StringBuilder class in C++ std library. std::ostringstream could be used as StringBuilder, but it is inefficient, and it use C++ iostream interface, which was proved a bad practice than printf family in C, although it is more "flexible" than printf family. Here are 2 thin wrapper for gnu asprintf family, which maybe more efficient and more readable than ostringstream.
strbuilder.h
// strbuilder.h
#include <stdio.h>
#include <string.h>
// This class is more simple to use, but it should be used for one-time printf
class StrPrintf {
public:
char* s; // for easy access
int n;
StrPrintf(const char* format, ...);
StrPrintf(std::string& dest, const* format, ...);
~StrFormater();
operator std::string() const;
};
// This class should be used for multiple-time append by printf
class StrBuilder {
FILE* memFile;
public:
char* s; // for easy access
size_t n;
~StrBuilder();
StrBuilder();
StringBuilder& printf(const char* format, ...);
operator std::string() const;
void setEof(int offset); // assert(offset < 0)
void setEof(int offset, const char* endmark); // assert(offset < 0)
};
Sample Usage
#include <strbuilder.h>
void foo() {
{// build small string by calling StrPrintf multiple times
std::string smallstr;
StrPrintf(smallstr, "%s %d\n", "abc", 100);
StrPrintf(smallstr, "%s %d\n", "bcd", 101);
}
{ // build string in one line
std::string smallstr = StrPrintf("%s %d\n", "abc", 100);
}
{ // bare usage of gnu.asprintf, same as build string in one line
char* s;
int n = asprintf("%s %d\n", "abc", 100);
if (n < 0) {
perror("asprintf");
abort(); // faital
}
std::string smallstr(s, n);
free(s); // required
}
//-------------------------------------------------
// build string by StrBuilder
{ // build string in one line
std::string smallstr = StrBuilder().printf("%s %d\n", "abc", 100);
}
{ // for big strings, such as sql query
StrBuilder sb;
sb.printf("insert into tab(id1, id2) values ");
for (int i = 0; i < 100; ++i)
sb.printf("(%03d %03d),", i, i*i);
sb.setEof(-1); // trim last ','
sb.printf(";"); // append a ';'
// sb.setEof(-1, ";"); // trim last ',' and append a ';'
std::string bigstr = sb;
}
{
using namespace std; // for setw setfill
std::ostringstream oss;
for (int i = 0; i < 100; ++i)
oss << "(" << setw(3) << setfill('0') << i
<< " " << setw(3) << setfill('0') << i*i
<< "),";
oss.seekp(-1, oss.end); // trim last ',', oss.end is a static member: ios::end
oss << ";"; // append a ';'
std::string bigstr = oss.str();
}
}
strbuilder.cpp
// strbuilder.cpp
#include "strbuilder.h"
#include <stdlib.h>
#include <stdexcept>
StrPrintf::StrPrintf(const char* format, ...) {
va_list ap;
va_start(ap, format);
n = vasprintf(&s, format, ap);
if (n < 0) {
throw std::bad_alloc();
}
va_end(ap);
}
StrPrintf::StrPrintf(std::string& dest, const* format, ...) {
va_list ap;
va_start(ap, format);
n = vasprintf(&s, format, ap);
if (n < 0) {
throw std::bad_alloc();
}
va_end(ap);
dest.append(dest, s, n);
}
StrPrintf::~StrFormater() {
assert(NULL != s);
free(s);
}
StrPrintf::operator std::string() const {
assert(NULL != s);
assert(n >= 0);
return std::string(s, n);
}
StrBuilder::StrBuilder() {
s = NULL;
n = 0;
memFile = open_memstream(&s, &n);
if (NULL == memFile) {
throw std::runtime_error("open_memstream");
}
}
StrBuilder::~StrBuilder() {
assert(NULL != memFile);
assert(NULL != s);
close(memFile);
free(s);
}
StrBuilder& StrBuilder::printf(const char* format, ...) {
assert(NULL != memFile);
va_list ap;
va_start(ap, format);
int rv = vfprintf(&s, format, ap);
va_end(ap);
if (rv < 0) {
throw std::runtime_error("vfprintf on memstream");
}
return *this;
}
StrBuilder::operator std::string() const {
assert(NULL != memFile);
assert(NULL != s);
assert(n >= 0);
fflush(memFile);
return std::string(s, n);
}
void StrBuilder::setEof(int offset) {
assert(offset < 0);
assert(NULL != memFile);
assert(NULL != s);
assert((long)n + offset >= 0);
fseek(memFile, offset, SEEK_END);
fflush(memFile);
}
void StrBuilder::setEof(int offset, const char* endmark) {
assert(offset < 0);
assert(NULL != endmark);
assert(NULL != memFile);
assert(NULL != s);
assert((long)n + offset >= 0);
fseek(memFile, offset, SEEK_END);
fputs(endmark, memFile);
fflush(memFile);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment