--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/mystring/rep.cc Wed Jan 16 22:39:43 2008 +0100
@@ -0,0 +1,157 @@
+#include "mystring.h"
+#include "trace.h"
+#include <ctype.h>
+#include <string.h>
+
+mystringrep nil = { 0, 1, 1, "" };
+
+static const unsigned replength = sizeof(unsigned)*3;
+
+static const unsigned sizestep = sizeof(unsigned);
+static const unsigned slackdiv = 4;
+static const unsigned slackmax = 16;
+
+#ifdef MYSTRINGREP_STATS
+
+#include "fdbuf.h"
+
+struct _rep_stats
+{
+ unsigned allocs;
+ unsigned alloc_size;
+ unsigned alloc_len;
+
+ unsigned appends;
+ unsigned appends_dup;
+
+ _rep_stats()
+ : allocs(0)
+ {
+ }
+
+ void stat(const char* name, unsigned value)
+ {
+ ferr << "mystringrep: " << name << ": " << value << '\n';
+ }
+ void pcnt(const char* name, unsigned denom, unsigned divis)
+ {
+ ferr << "mystringrep: " << name << ": "
+ << denom << '/' << divis << '=';
+ if(divis) ferr << denom * 100 / divis << '%';
+ else ferr << "N/A";
+ ferr << '\n';
+ }
+
+ ~_rep_stats()
+ {
+ stat(" size step", sizestep);
+ stat(" slack divisor", slackdiv);
+ stat(" slack maximum", slackmax);
+ stat(" allocs", allocs);
+ stat(" alloc length", alloc_len);
+ stat(" alloc size", alloc_size);
+ pcnt(" alloc slack", alloc_size-alloc_len, alloc_len);
+ stat("alloc overhead", allocs*replength);
+ pcnt(" appends->dup", appends_dup, appends);
+ }
+};
+
+static _rep_stats stats;
+
+#define ACCOUNT(NAME,VALUE) stats. NAME += VALUE
+
+#else // MYSTRINGREP_STATS
+
+#define ACCOUNT(NAME,VALUE)
+
+#endif // MYSTRINGREP_STATS
+
+///////////////////////////////////////////////////////////////////////////////
+// class mystringrep
+///////////////////////////////////////////////////////////////////////////////
+mystringrep* mystringrep::alloc(unsigned length)
+{
+ ACCOUNT(allocs, 1);
+ trace_static("length=" << length);
+ if(length == 0)
+ return &nil;
+
+ ACCOUNT(alloc_len, length);
+ unsigned slack = length / slackdiv;
+ if(slack > slackmax)
+ slack = slackmax;
+ unsigned size = length+1 + sizestep-1 + slack;
+ size = size - size % sizestep;
+ ACCOUNT(alloc_size, size);
+
+ mystringrep* ptr = (mystringrep*)new char[size+replength];
+ ptr->length = length;
+ ptr->references = 0;
+ ptr->size = size;
+ return ptr;
+}
+
+mystringrep* mystringrep::dup(const char* str, unsigned length)
+{
+ trace_static("str=" << (void*)str << " length=" << length);
+ if(length == 0)
+ return &nil;
+ mystringrep* ptr = alloc(length);
+ memcpy(ptr->buf, str, length);
+ ptr->buf[length] = 0;
+ return ptr;
+}
+
+mystringrep* mystringrep::dup(const char* str1, unsigned length1,
+ const char* str2, unsigned length2)
+{
+ trace_static("");
+ if(length1+length2 == 0)
+ return &nil;
+ mystringrep* ptr = alloc(length1+length2);
+ memcpy(ptr->buf, str1, length1);
+ memcpy(ptr->buf+length1, str2, length2);
+ ptr->buf[length1+length2] = 0;
+ return ptr;
+}
+
+mystringrep* mystringrep::append(const char* str, unsigned len)
+{
+ ACCOUNT(appends, 1);
+ unsigned newlen = length + len;
+ // If there are more than one references, always make a duplicate
+ // Also, if this does not have enough space to add the new string, dup it
+ if(references > 1 || newlen >= size) {
+ ACCOUNT(appends_dup, 1);
+ mystringrep* tmp = dup(buf, length, str, len);
+ tmp->attach();
+ detach();
+ return tmp;
+ }
+ // Otherwise, just add the new string to the end of this
+ else {
+ memcpy(buf+length, str, len);
+ buf[newlen] = 0;
+ length = newlen;
+ return this;
+ }
+}
+
+#ifdef MYSTRING_TRACE
+void mystringrep::attach()
+{
+ trace("references=" << references);
+ ++references;
+}
+#endif
+
+void mystringrep::detach()
+{
+ trace("references=" << references);
+
+ --references;
+ if(!references) {
+ trace("deleting this");
+ delete this;
+ }
+}