lib/mystring/join.cc
changeset 0 6f7a81934006
equal deleted inserted replaced
-1:000000000000 0:6f7a81934006
       
     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 }