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
traverse() const17 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 }
62