|
0
|
1 |
#include "mystring.h"
|
|
|
2 |
#include <string.h>
|
|
|
3 |
|
|
|
4 |
// This "join" class relies on one fairly obscure detail in the C++
|
|
|
5 |
// standard: temporaries are destructed only after the entire
|
|
|
6 |
// "full-expression" has completed. That is, if the sequence:
|
|
|
7 |
// f(f(f(x))) creates three temporary objects, the inner objects are
|
|
|
8 |
// destroyed only after the execution has completed. This allows us
|
|
|
9 |
// to build a complete linked-list on the stack. Tricky, but efficient!
|
|
|
10 |
|
|
|
11 |
struct tmpitem
|
|
|
12 |
{
|
|
|
13 |
const char* str;
|
|
|
14 |
unsigned len;
|
|
|
15 |
};
|
|
|
16 |
|
|
|
17 |
mystringrep* mystringjoin::traverse() const
|
|
|
18 |
{
|
|
|
19 |
// At first glance, a recursive implementation would be the most logical
|
|
|
20 |
// way of doing this, but it turned out to be a significant loss. This
|
|
|
21 |
// method traverses the pointer chain to first determine the length, and
|
|
|
22 |
// then to do the actual copying.
|
|
|
23 |
|
|
|
24 |
// Note the use of do/while loops to avoid a test at the head of the loop
|
|
|
25 |
// which will always succeed (there is always at least one node or item).
|
|
|
26 |
unsigned count = 0;
|
|
|
27 |
const mystringjoin* node = this;
|
|
|
28 |
do {
|
|
|
29 |
++count;
|
|
|
30 |
} while((node = node->prev) != 0);
|
|
|
31 |
|
|
|
32 |
// The use of a temporary array avoids re-traversing the pointer
|
|
|
33 |
// chain, which is a slight performance win.
|
|
|
34 |
tmpitem items[count];
|
|
|
35 |
|
|
|
36 |
unsigned length = 0;
|
|
|
37 |
node = this;
|
|
|
38 |
tmpitem* item = items;
|
|
|
39 |
do {
|
|
|
40 |
unsigned l = node->rep ? node->rep->length : strlen(node->str);
|
|
|
41 |
length += l;
|
|
|
42 |
item->str = node->str;
|
|
|
43 |
item->len = l;
|
|
|
44 |
++item;
|
|
|
45 |
} while((node = node->prev) != 0);
|
|
|
46 |
|
|
|
47 |
// Since the chain is constructed such that the last item is the
|
|
|
48 |
// first node, the string gets constructed in reverse order.
|
|
|
49 |
mystringrep* rep = mystringrep::alloc(length);
|
|
|
50 |
char* buf = rep->buf + length;
|
|
|
51 |
item = items;
|
|
|
52 |
do {
|
|
|
53 |
unsigned l = item->len;
|
|
|
54 |
buf -= l;
|
|
|
55 |
memcpy(buf, item->str, l);
|
|
|
56 |
++item;
|
|
|
57 |
} while(--count != 0);
|
|
|
58 |
|
|
|
59 |
rep->buf[length] = 0;
|
|
|
60 |
return rep;
|
|
|
61 |
}
|