lib/mystring/rep.cc
changeset 0 6f7a81934006
equal deleted inserted replaced
-1:000000000000 0:6f7a81934006
       
     1 #include "mystring.h"
       
     2 #include "trace.h"
       
     3 #include <ctype.h>
       
     4 #include <string.h>
       
     5 
       
     6 mystringrep nil = { 0, 1, 1, "" };
       
     7 
       
     8 static const unsigned replength = sizeof(unsigned)*3;
       
     9 
       
    10 static const unsigned sizestep = sizeof(unsigned);
       
    11 static const unsigned slackdiv = 4;
       
    12 static const unsigned slackmax = 16;
       
    13 
       
    14 #ifdef MYSTRINGREP_STATS
       
    15 
       
    16 #include "fdbuf.h"
       
    17 
       
    18 struct _rep_stats
       
    19 {
       
    20   unsigned allocs;
       
    21   unsigned alloc_size;
       
    22   unsigned alloc_len;
       
    23   
       
    24   unsigned appends;
       
    25   unsigned appends_dup;
       
    26 
       
    27   _rep_stats()
       
    28     : allocs(0)
       
    29     {
       
    30     }
       
    31   
       
    32   void stat(const char* name, unsigned value)
       
    33     {
       
    34       ferr << "mystringrep: " << name << ": " << value << '\n';
       
    35     }
       
    36   void pcnt(const char* name, unsigned denom, unsigned divis)
       
    37     {
       
    38       ferr << "mystringrep: " << name << ": "
       
    39 	   << denom << '/' << divis << '=';
       
    40       if(divis) ferr << denom * 100 / divis << '%';
       
    41       else ferr << "N/A";
       
    42       ferr << '\n';
       
    43     }
       
    44   
       
    45   ~_rep_stats()
       
    46     {
       
    47       stat("     size step", sizestep);
       
    48       stat(" slack divisor", slackdiv);
       
    49       stat(" slack maximum", slackmax);
       
    50       stat("        allocs", allocs);
       
    51       stat("  alloc length", alloc_len);
       
    52       stat("    alloc size", alloc_size);
       
    53       pcnt("   alloc slack", alloc_size-alloc_len, alloc_len);
       
    54       stat("alloc overhead", allocs*replength);
       
    55       pcnt("  appends->dup", appends_dup, appends);
       
    56     }
       
    57 };
       
    58 
       
    59 static _rep_stats stats;
       
    60 
       
    61 #define ACCOUNT(NAME,VALUE) stats. NAME += VALUE
       
    62 
       
    63 #else // MYSTRINGREP_STATS
       
    64 
       
    65 #define ACCOUNT(NAME,VALUE)
       
    66 
       
    67 #endif // MYSTRINGREP_STATS
       
    68 
       
    69 ///////////////////////////////////////////////////////////////////////////////
       
    70 // class mystringrep
       
    71 ///////////////////////////////////////////////////////////////////////////////
       
    72 mystringrep* mystringrep::alloc(unsigned length)
       
    73 {
       
    74   ACCOUNT(allocs, 1);
       
    75   trace_static("length=" << length);
       
    76   if(length == 0)
       
    77     return &nil;
       
    78 
       
    79   ACCOUNT(alloc_len, length);
       
    80   unsigned slack = length / slackdiv;
       
    81   if(slack > slackmax)
       
    82     slack = slackmax;
       
    83   unsigned size = length+1 + sizestep-1 + slack;
       
    84   size = size - size % sizestep;
       
    85   ACCOUNT(alloc_size, size);
       
    86 
       
    87   mystringrep* ptr = (mystringrep*)new char[size+replength];
       
    88   ptr->length = length;
       
    89   ptr->references = 0;
       
    90   ptr->size = size;
       
    91   return ptr;
       
    92 }
       
    93 
       
    94 mystringrep* mystringrep::dup(const char* str, unsigned length)
       
    95 {
       
    96   trace_static("str=" << (void*)str << " length=" << length);
       
    97   if(length == 0)
       
    98     return &nil;
       
    99   mystringrep* ptr = alloc(length);
       
   100   memcpy(ptr->buf, str, length);
       
   101   ptr->buf[length] = 0;
       
   102   return ptr;
       
   103 }
       
   104 
       
   105 mystringrep* mystringrep::dup(const char* str1, unsigned length1,
       
   106 			      const char* str2, unsigned length2)
       
   107 {
       
   108   trace_static("");
       
   109   if(length1+length2 == 0)
       
   110     return &nil;
       
   111   mystringrep* ptr = alloc(length1+length2);
       
   112   memcpy(ptr->buf, str1, length1);
       
   113   memcpy(ptr->buf+length1, str2, length2);
       
   114   ptr->buf[length1+length2] = 0;
       
   115   return ptr;
       
   116 }
       
   117 
       
   118 mystringrep* mystringrep::append(const char* str, unsigned len)
       
   119 {
       
   120   ACCOUNT(appends, 1);
       
   121   unsigned newlen = length + len;
       
   122   // If there are more than one references, always make a duplicate
       
   123   // Also, if this does not have enough space to add the new string, dup it
       
   124   if(references > 1 || newlen >= size) {
       
   125     ACCOUNT(appends_dup, 1);
       
   126     mystringrep* tmp = dup(buf, length, str, len);
       
   127     tmp->attach();
       
   128     detach();
       
   129     return tmp;
       
   130   }
       
   131   // Otherwise, just add the new string to the end of this
       
   132   else {
       
   133     memcpy(buf+length, str, len);
       
   134     buf[newlen] = 0;
       
   135     length = newlen;
       
   136     return this;
       
   137   }
       
   138 }
       
   139 
       
   140 #ifdef MYSTRING_TRACE    
       
   141 void mystringrep::attach()
       
   142 {
       
   143   trace("references=" << references);
       
   144   ++references;
       
   145 }
       
   146 #endif
       
   147 
       
   148 void mystringrep::detach()
       
   149 {
       
   150   trace("references=" << references);
       
   151   
       
   152   --references;
       
   153   if(!references) {
       
   154     trace("deleting this");
       
   155     delete this;
       
   156   }
       
   157 }