Created
June 19, 2012 05:18
-
-
Save BaiGang/2952423 to your computer and use it in GitHub Desktop.
cpp string builder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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