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