1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 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;
}
}
|