File: rep.cc

package info (click to toggle)
nullmailer 1%3A1.03-4
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 1,524 kB
  • ctags: 695
  • sloc: cpp: 4,484; sh: 4,123; makefile: 224; perl: 184
file content (157 lines) | stat: -rw-r--r-- 3,704 bytes parent folder | download | duplicates (11)
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;
  }
}