summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2015-08-28 20:36:52 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2015-08-28 20:36:52 +0100
commitf182efe2ac0ab58b2af4c503ea7b49988f307b5a (patch)
treed58c66e2e4e68d31e7ab19d4e8e81d73ff1040ef
parentAdd ScopeExit (was ScopeObject) (diff)
downloadlibadhocutil-f182efe2ac0ab58b2af4c503ea7b49988f307b5a.tar.bz2
libadhocutil-f182efe2ac0ab58b2af4c503ea7b49988f307b5a.tar.xz
libadhocutil-f182efe2ac0ab58b2af4c503ea7b49988f307b5a.zip
Support std::string fragment storage, reduce copy overheads, better control
-rw-r--r--libadhocutil/buffer.cpp180
-rw-r--r--libadhocutil/buffer.h66
-rw-r--r--libadhocutil/unittests/testBuffer.cpp36
3 files changed, 195 insertions, 87 deletions
diff --git a/libadhocutil/buffer.cpp b/libadhocutil/buffer.cpp
index daf5be6..3468f27 100644
--- a/libadhocutil/buffer.cpp
+++ b/libadhocutil/buffer.cpp
@@ -2,52 +2,123 @@
#include <string.h>
#include <stdio.h>
-Buffer::Fragment::Fragment(const char * b) :
- len(strlen(b))
+//
+// CString Fragment
+//
+
+Buffer::CStringFragment::CStringFragment(const char * b, CStringHandling h) :
+ len(strlen(b)),
+ buf(b),
+ handling(h)
{
- buf = (char*)malloc(len + 1);
- memcpy(buf, b, len + 1);
- *(buf + len) = '\0';
}
-Buffer::Fragment::Fragment(const char * b, size_t l) :
- len(l)
+Buffer::CStringFragment::CStringFragment(const char * b, CStringHandling h, size_t l) :
+ len(l),
+ buf(b),
+ handling(h)
{
- buf = (char*)malloc(l + 1);
- memcpy(buf, b, l + 1);
- *(buf + len) = '\0';
}
-Buffer::Fragment::Fragment(char * b, size_t l, bool copy) :
- len(l)
+Buffer::CStringFragment::CStringFragment(char * b, CStringHandling h) :
+ len(strlen(b)),
+ buf(b),
+ handling(h)
{
- if (copy) {
- buf = (char*)malloc(l + 1);
- memcpy(buf, b, l + 1);
- }
- else {
- buf = b;
+}
+
+Buffer::CStringFragment::CStringFragment(char * b, CStringHandling h, size_t l) :
+ len(l),
+ buf(b),
+ handling(h)
+{
+}
+
+Buffer::CStringFragment::~CStringFragment()
+{
+ if (handling != Use) { // Copy or Free
+ free(const_cast<char *>(buf));
}
- *(buf + len) = '\0';
}
-Buffer::Fragment::~Fragment()
+char
+Buffer::CStringFragment::operator[](size_t x) const
+{
+ return buf[x];
+}
+
+size_t
+Buffer::CStringFragment::length() const
+{
+ return len;
+}
+
+const char *
+Buffer::CStringFragment::c_str() const
+{
+ return buf;
+}
+
+std::string
+Buffer::CStringFragment::str() const
+{
+ return buf;
+}
+
+//
+// Std::String Fragment
+//
+
+Buffer::StringFragment::StringFragment(const std::string & str) :
+ buf(str)
+{
+}
+
+size_t
+Buffer::StringFragment::length() const
+{
+ return buf.length();
+}
+
+const char *
+Buffer::StringFragment::c_str() const
+{
+ return buf.c_str();
+}
+
+std::string
+Buffer::StringFragment::str() const
{
- free(buf);
+ return buf;
}
+char
+Buffer::StringFragment::operator[](size_t x) const
+{
+ return buf[x];
+}
+
+//
+// Buffer :)
+//
+
Buffer::Buffer()
{
}
-Buffer::Buffer(const char * src)
+Buffer::Buffer(const char * src, CStringHandling h)
+{
+ append(src, h);
+}
+
+Buffer::Buffer(char * src, CStringHandling h)
{
- content.push_back(new Fragment(src));
+ append(src, h);
}
-Buffer::Buffer(char * src, bool copy)
+Buffer::Buffer(const std::string & str)
{
- content.push_back(new Fragment(src, strlen(src), copy));
+ append(str);
}
Buffer::~Buffer()
@@ -55,19 +126,29 @@ Buffer::~Buffer()
}
Buffer &
-Buffer::append(const char * str)
+Buffer::append(const char * str, CStringHandling h)
{
if (str && *str) {
- content.push_back(new Fragment(str));
+ if (h == Copy) {
+ content.push_back(new StringFragment(str));
+ }
+ else {
+ content.push_back(new CStringFragment(str, h));
+ }
}
return *this;
}
Buffer &
-Buffer::append(char * str, bool copy)
+Buffer::append(char * str, CStringHandling h)
{
if (str && *str) {
- content.push_back(new Fragment(str, strlen(str), copy));
+ if (h == Copy) {
+ content.push_back(new StringFragment(str));
+ }
+ else {
+ content.push_back(new CStringFragment(str, h));
+ }
}
return *this;
}
@@ -76,7 +157,7 @@ Buffer &
Buffer::append(const std::string & str)
{
if (!str.empty()) {
- content.push_back(new Fragment(str.c_str(), str.length()));
+ content.push_back(new StringFragment(str));
}
return *this;
}
@@ -97,7 +178,7 @@ Buffer::vappendf(const char * fmt, va_list args)
char * frag;
size_t len = vasprintf(&frag, fmt, args);
if (len > 0) {
- content.push_back(new Fragment(frag, len, false));
+ content.push_back(new CStringFragment(frag, Free, len));
}
else {
free(frag);
@@ -129,13 +210,13 @@ void
Buffer::writeto(char * buf, size_t bufSize, size_t off) const
{
Content::const_iterator f = content.begin();
- while (f != content.end() && (*f)->len < off) {
- off -= (*f)->len;
+ while (f != content.end() && (*f)->length() < off) {
+ off -= (*f)->length();
++f;
}
while (f != content.end() && bufSize) {
- for (size_t c = 0; bufSize && c < (*f)->len; bufSize--) {
- *buf++ = (*f)->buf[c++];
+ for (size_t c = 0; bufSize && c < (*f)->length(); bufSize--) {
+ *buf++ = (**f)[c++];
}
++f;
off = 0;
@@ -148,13 +229,13 @@ Buffer::operator std::string() const
if (content.size() > 1) {
std::string res;
res.reserve(length());
- for (const Fragment::Ptr & f : content) {
- res.append(f->buf, f->len);
+ for (const auto & f : content) {
+ res.append(f->str());
}
return res;
}
else if (content.size() == 1) {
- return std::string(content.front()->buf, content.front()->len);
+ return std::string(content.front()->str());
}
return std::string();
}
@@ -165,23 +246,16 @@ Buffer::operator const char *() const
return "";
}
flatten();
- return content.front()->buf;
+ return content.front()->c_str();
}
void
Buffer::flatten() const
{
if (content.size() > 1) {
- auto len = length();
- auto buf = (char*)malloc(len + 1);
- auto f = new Fragment(buf, len, false);
- for (const Fragment::Ptr & f : content) {
- memcpy(buf, f->buf, f->len);
- buf += f->len;
- }
- *buf = '\0';
- content.clear();
- content.push_back(f);
+ auto f = new StringFragment(str());
+ content.resize(1);
+ content.front() = f;
}
}
@@ -196,7 +270,7 @@ Buffer::length() const
{
size_t len = 0;
for (const Content::value_type & c : content) {
- len += c->len;
+ len += c->length();
}
return len;
}
@@ -205,7 +279,7 @@ Buffer &
Buffer::operator=(const char * str)
{
content.resize(1);
- content[0] = new Fragment(str);
+ content.front() = new StringFragment(str);
return *this;
}
@@ -213,7 +287,7 @@ Buffer &
Buffer::operator=(const std::string & str)
{
content.resize(1);
- content[0] = new Fragment(str.c_str(), str.length());
+ content.front() = new StringFragment(str);
return *this;
}
@@ -239,7 +313,7 @@ std::ostream &
std::operator<<(std::ostream & os, const Buffer & b)
{
for (const auto & f : b.content) {
- os.write(f->buf, f->len);
+ os.write(f->c_str(), f->length());
}
return os;
}
diff --git a/libadhocutil/buffer.h b/libadhocutil/buffer.h
index c435574..aa1560a 100644
--- a/libadhocutil/buffer.h
+++ b/libadhocutil/buffer.h
@@ -12,17 +12,20 @@
class DLL_PUBLIC Buffer;
namespace std {
- DLL_PUBLIC std::ostream & operator<<(std::ostream &, const Buffer &);
+ DLL_PUBLIC std::ostream & operator<<(std::ostream &, const Buffer &);
}
class DLL_PUBLIC Buffer : public virtual IntrusivePtrBase {
public:
+ enum CStringHandling { Use, Copy, Free };
+
typedef boost::intrusive_ptr<Buffer> Ptr;
typedef boost::intrusive_ptr<const Buffer> CPtr;
Buffer();
- Buffer(const char * src);
- Buffer(char * src, bool copy);
+ Buffer(const char * src, CStringHandling);
+ Buffer(char * src, CStringHandling);
+ Buffer(const std::string &);
~Buffer();
Buffer & operator+=(const char * str);
@@ -39,8 +42,8 @@ class DLL_PUBLIC Buffer : public virtual IntrusivePtrBase {
void writeto(char * buf, size_t bufSize, size_t off) const;
friend std::ostream & std::operator<<(std::ostream &, const Buffer &);
- Buffer & append(const char * str);
- Buffer & append(char * str, bool copy);
+ Buffer & append(const char * str, CStringHandling h);
+ Buffer & append(char * str, CStringHandling h);
Buffer & append(const std::string & str);
Buffer & appendf(const char * fmt, ...) __attribute__((format (printf, 2, 3)));
Buffer & vappendf(const char * fmt, va_list args);
@@ -55,7 +58,6 @@ class DLL_PUBLIC Buffer : public virtual IntrusivePtrBase {
fmt % param;
return appendbf(fmt, params...);
}
- Buffer & appendbf(boost::format & fmt);
Buffer & clear();
size_t length() const;
@@ -64,24 +66,56 @@ class DLL_PUBLIC Buffer : public virtual IntrusivePtrBase {
static boost::shared_ptr<boost::format> getFormat(const std::string & msgfmt);
private:
+ Buffer & appendbf(boost::format & fmt);
void DLL_PRIVATE flatten() const;
- class DLL_PRIVATE Fragment : public virtual IntrusivePtrBase {
+ class DLL_PRIVATE FragmentBase : public virtual IntrusivePtrBase {
public:
- typedef boost::intrusive_ptr<Fragment> Ptr;
- typedef boost::intrusive_ptr<const Fragment> CPtr;
+ virtual ~FragmentBase() = 0;
- Fragment(const char *, size_t);
- Fragment(const char *);
- Fragment(char *, size_t, bool);
- ~Fragment();
+ virtual size_t length() const = 0;
+ virtual char operator[](size_t) const = 0;
+ virtual const char * c_str() const = 0;
+ virtual std::string str() const = 0;
+ };
- size_t len; // Excluding NULL term
- char * buf;
+ class DLL_PRIVATE CStringFragment : public FragmentBase {
+ public:
+ CStringFragment(const char *, CStringHandling);
+ CStringFragment(const char *, CStringHandling, size_t);
+ CStringFragment(char *, CStringHandling);
+ CStringFragment(char *, CStringHandling, size_t);
+ ~CStringFragment();
+
+ size_t length() const;
+ char operator[](size_t) const;
+ const char * c_str() const;
+ std::string str() const;
+
+ private:
+ const size_t len; // Excluding NULL term
+ const char * buf;
+ const CStringHandling handling;
};
- typedef std::vector<Fragment::Ptr> Content;
+
+ class DLL_PRIVATE StringFragment : public FragmentBase {
+ public:
+ StringFragment(const std::string &);
+
+ size_t length() const;
+ char operator[](size_t) const;
+ const char * c_str() const;
+ std::string str() const;
+
+ private:
+ const std::string buf;
+ };
+
+ typedef boost::intrusive_ptr<FragmentBase> FragmentPtr;
+ typedef std::vector<FragmentPtr> Content;
mutable Content content;
};
+Buffer::FragmentBase::~FragmentBase() = default;
#endif
diff --git a/libadhocutil/unittests/testBuffer.cpp b/libadhocutil/unittests/testBuffer.cpp
index 5d64642..9c1c956 100644
--- a/libadhocutil/unittests/testBuffer.cpp
+++ b/libadhocutil/unittests/testBuffer.cpp
@@ -5,32 +5,32 @@
BOOST_AUTO_TEST_CASE ( create )
{
- Buffer a;
- Buffer b("const");
+ Buffer empty;
+ Buffer copy("const", Buffer::Copy);
auto nonconst = (char*)malloc(9);
strcpy(nonconst, "nonconst");
- Buffer c(nonconst, true);
- Buffer d(nonconst, false);
+ Buffer use(nonconst, Buffer::Use);
+ Buffer fre(nonconst, Buffer::Free);
- BOOST_REQUIRE_EQUAL(false, a);
- BOOST_REQUIRE_EQUAL(true, !a);
- BOOST_REQUIRE_EQUAL(0, a.length());
- BOOST_REQUIRE_EQUAL("", a.str());
+ BOOST_REQUIRE_EQUAL(false, empty);
+ BOOST_REQUIRE_EQUAL(true, !empty);
+ BOOST_REQUIRE_EQUAL(0, empty.length());
+ BOOST_REQUIRE_EQUAL("", empty.str());
- BOOST_REQUIRE_EQUAL(true, b);
- BOOST_REQUIRE_EQUAL(false, !b);
- BOOST_REQUIRE_EQUAL(5, b.length());
- BOOST_REQUIRE_EQUAL("const", b.str());
+ BOOST_REQUIRE_EQUAL(true, copy);
+ BOOST_REQUIRE_EQUAL(false, !copy);
+ BOOST_REQUIRE_EQUAL(5, copy.length());
+ BOOST_REQUIRE_EQUAL("const", copy.str());
- BOOST_REQUIRE_EQUAL(8, c.length());
- BOOST_REQUIRE_EQUAL("nonconst", c.str());
+ BOOST_REQUIRE_EQUAL(8, use.length());
+ BOOST_REQUIRE_EQUAL("nonconst", use.str());
- BOOST_REQUIRE_EQUAL(8, d.length());
- BOOST_REQUIRE_EQUAL("nonconst", d.str());
+ BOOST_REQUIRE_EQUAL(8, fre.length());
+ BOOST_REQUIRE_EQUAL("nonconst", fre.str());
nonconst[0] = 'N';
- BOOST_REQUIRE_EQUAL("nonconst", c.str());
- BOOST_REQUIRE_EQUAL("Nonconst", d.str());
+ BOOST_REQUIRE_EQUAL("Nonconst", use.str());
+ BOOST_REQUIRE_EQUAL("Nonconst", fre.str());
}
BOOST_AUTO_TEST_CASE( writestream )