Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

/ray/src/lib/tl/tlstring.cc

Go to the documentation of this file.
00001 /*
00002  * lib/tl/tlstring.cc
00003  * 
00004  * Thread-save reference-counting string class. 
00005  * 
00006  * Copyright (c) 2004 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 
00007  * 
00008  * This file may be distributed and/or modified under the terms of the 
00009  * GNU General Public License version 2 as published by the Free Software 
00010  * Foundation. (See COPYING.GPL for details.)
00011  * 
00012  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00013  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00014  * 
00015  */
00016 
00017 #include "tlstring.h"
00018 #include <string.h>
00019 #include <stdio.h>   /* for snprintf() */
00020 
00033 void TLString::SData::_EnsureSize(size_t s)
00034 {
00035     //if(refcnt.val()!=1)
00036     //{  fprintf(stderr,"oops<%d -%s- %u %u %u>\n",
00037     //  refcnt.val(),str,s,asize,len);  }
00038     Assert(refcnt.val()==1);
00039     
00040     // asize<s here. 
00041     // We need to re-allocate the pointer, so allocat a bit too much 
00042     // so that we probably need not realloc the next time. 
00043     // I will allocate 50% more but limited to 256 bytes. 
00044     // (Hint: 512*50% = 256 :)
00045     asize=GrowRoundUp(s);
00046     str=REALLOC(str,asize);
00047 }
00048 
00049 
00050 void TLString::SData::_DoTightenSize()
00051 {
00052     Assert(refcnt.val()==1);
00053     
00054     // asize>len+1 here. 
00055     asize=len+1;
00056     str=REALLOC(str,asize);
00057 }
00058 
00059 
00060 void TLString::SData::DownSizeIfNeeded(size_t s)
00061 {
00062     Assert(refcnt.val()==1);
00063     // If we are 150% above or more than 16k bytes, re-allocate. 
00064     Assert(s<=asize);
00065     if(s<16)  s=10;   // never go below 16 bytes (10+10>>1 = 15 -> round -> 16)
00066     size_t above = asize>s ? asize-s : 0;
00067     if(above>16384 || above>(s+s>>1))
00068     {
00069         size_t old_asize=asize;
00070         asize=GrowRoundUp(s);
00071         Assert(asize<old_asize);  // On failure: tweak threshold above. 
00072         str=REALLOC(str,asize);
00073     }
00074 }
00075 
00076 
00077 TLString::SData::SData(const char *s) : 
00078     refcnt(1)  /* CORRECT. */
00079 {
00080     len=strlen(s);
00081     asize=RoundUp(len+1);
00082     str=ALLOC<char>(asize);
00083     strcpy(str,s);
00084 }
00085 
00086 TLString::SData::SData(const char *s,size_t len) : 
00087     refcnt(1)  /* CORRECT. */
00088 {
00089     asize=RoundUp(len+1);
00090     str=ALLOC<char>(asize);
00091     memcpy(str,s,len);
00092     str[len]='\0';
00093 }
00094 
00095 TLString::SData::SData(const SData &s) : 
00096     refcnt(1)  /* CORRECT. */
00097 {
00098     len=s.len;
00099     asize=RoundUp(len+1);
00100     str=ALLOC<char>(asize);
00101     strcpy(str,s.str);
00102 }
00103 
00104 TLString::SData::SData(size_t ensure_size) : 
00105     refcnt(1)  /* CORRECT. */
00106 {
00107     len=0;
00108     asize=GrowRoundUp(ensure_size);
00109     str=ALLOC<char>(asize);
00110     *str='\0';
00111 }
00112 
00113 //------------------------------------------------------------------------------
00114 
00115 void TLString::append(const char *str)
00116 {
00117     if(!str)  return;
00118     
00119     if(d)
00120     {
00121         _detachN();
00122         size_t len=strlen(str);
00123         d->_EnsureSize(d->len+len+1);
00124         strcpy(d->str+d->len,str);
00125         d->len+=len;
00126     }
00127     else
00128     {  _storeN(str);  }
00129 }
00130 
00131 void TLString::append(const char *str,size_t len)
00132 {
00133     if(!str)  return;
00134     
00135     if(d)
00136     {
00137         _detachN();
00138         d->_EnsureSize(d->len+len+1);
00139         memcpy(d->str+d->len,str,len);
00140         d->len+=len;
00141         d->str[d->len]='\0';
00142     }
00143     else
00144     {  _storeN(str,len);  }
00145 }
00146 
00147 void TLString::append(const TLString &str)
00148 {
00149     if(!str)  return;  // NOTE: This is TLString::operator!(). 
00150     
00151     // NOZE: there is a tricky case one tends to forget: &str==this. 
00152     
00153     // if(d && d->refcnt.val()==1)
00154     // {  optimized version here! }   <-- below str._aqrefN();
00155     
00156     if(d)
00157     {
00158         _detachN();
00159         
00160         // The following is probably not needed and makes problems
00161         // in the case &str==this. 
00162         //str._aqrefN();  // Aquire a refernce so that it will not be modified. 
00163         
00164         SData *s=str.d;
00165         d->_EnsureSize(d->len+s->len+1);
00166         memcpy(d->str+d->len,s->str,s->len);  // <-- not len+1 (aliasing)
00167         d->len+=s->len;
00168         d->str[d->len]='\0';  // <-- Needed in case &str==this. 
00169         
00170         //str._derefN();  // "unlock"
00171     }
00172     else
00173     {
00174         // Simply reference it. 
00175         _referenceN(str);
00176     }
00177 }
00178 
00179 
00180 void TLString::prepend(const char *str)
00181 {
00182     if(!str)  return;
00183     
00184     if(d)
00185     {
00186         _detachN();
00187         size_t len=strlen(str);
00188         d->_EnsureSize(d->len+len+1);
00189         memmove(d->str+len,d->str,d->len+1);
00190         memcpy(d->str,str,len);
00191         d->len+=len;
00192     }
00193     else
00194     {  _storeN(str);  }
00195 }
00196 
00197 void TLString::prepend(const TLString &str)
00198 {
00199     if(!str)  return;  // NOTE: This is TLString::operator!(). 
00200     
00201     if(d)
00202     {
00203         _detachN();
00204         
00205         // The following is probably not needed and makes problems
00206         // in the case &str==this. 
00207         //str._aqrefN();  // Aquire a refernce so that it will not be modified. 
00208         
00209         SData *s=str.d;
00210         d->_EnsureSize(d->len+s->len+1);
00211         memmove(d->str+s->len,d->str,d->len+1);
00212         memcpy(d->str,s->str,s->len);
00213         d->len+=s->len;
00214         
00215         //str._derefN();  // "unlock"
00216     }
00217     else
00218     {
00219         // Simply reference it. 
00220         _referenceN(str);
00221     }
00222 }
00223 
00224 
00225 int TLString::compare(const TLString &strB)
00226 {
00227     // NOTE: All the relational string operators dealing with two TLStrings 
00228     //       could internally use this compare() function. 
00229     
00230     if(!*this || !strB)
00231     {
00232         if(!*this && !strB)  return(0);
00233         return(!*this ? -2 : 2);
00234     }
00235     
00236     int rv;
00237     strB._aqrefN();  // Aquire a refernce so that it will not be modified. 
00238     if(d==strB.d)  rv=0;  // same internal data
00239     else
00240     {
00241         size_t minlen = d->len<strB.d->len ? d->len : strB.d->len;
00242         rv = memcmp(d->str,strB.d->str,minlen);
00243         // The shorter string is smaller. 
00244         if(!rv && d->len!=strB.d->len)
00245         {  rv = d->len<strB.d->len ? -1 : 1;  }
00246     }
00247     strB._derefN();  // "unlock"
00248     
00249     return(rv);
00250 }
00251 
00252 
00253 bool operator==(const TLString &strA,const TLString &strB)
00254 {
00255     if(strA && strB)
00256     {
00257         bool rv;
00258         strA._aqrefN();  // Aquire a refernce so that it will not be modified. 
00259         strB._aqrefN();  // Aquire a refernce so that it will not be modified. 
00260         if(strA.d==strB.d)  rv=1;  // same internal data
00261         else if(strA.d->len!=strB.d->len)  rv=0;   // length mismatch
00262         else  rv=!memcmp(strA.d->str,strB.d->str,strA.d->len);
00263         strB._derefN();  // "unlock"
00264         strA._derefN();  // "unlock"
00265         return(rv);
00266     }
00267     return(!(strA || strB));
00268 }
00269 
00270 bool operator==(const TLString &strA,const char *strB)
00271 {
00272     if(strA && strB)
00273     {
00274         strA._aqrefN();  // Aquire a refernce so that it will not be modified. 
00275         bool equal=1;
00276         for(const char *a=strA.d->str,*aend=a+strA.d->len,*b=strB; ; a++,b++)
00277         {
00278             if(!*b)
00279             {
00280                 if(a!=aend)  equal=0;
00281                 break;
00282             }
00283             if(*a!=*b || a==aend)
00284             {  equal=0;  break;  }
00285         }
00286         strA._derefN();  // "unlock"
00287         return(equal);
00288     }
00289     return(!(strA || strB));
00290 }
00291 
00292 
00293 bool operator<(const TLString &strA,const TLString &strB)
00294 {
00295     if(strA && strB)
00296     {
00297         int rv;
00298         strA._aqrefN();  // Aquire a refernce so that it will not be modified. 
00299         strB._aqrefN();  // Aquire a refernce so that it will not be modified. 
00300         if(strA.d==strB.d)  rv=0;  // same internal data
00301         else
00302         {
00303             size_t minlen=strA.d->len<strB.d->len ? strA.d->len : strB.d->len;
00304             rv = memcmp(strA.d->str,strB.d->str,minlen);
00305             // The shorter string is smaller. 
00306             rv = rv ? (rv<0) : (strA.d->len<strB.d->len);
00307         }
00308         strB._derefN();  // "unlock"
00309         strA._derefN();  // "unlock"
00310         return(rv);
00311     }
00312     return(0);
00313 }
00314 
00315 bool operator<(const TLString &strA,const char *strB)
00316 {
00317     if(strA && strB)
00318     {
00319         strA._aqrefN();  // Aquire a refernce so that it will not be modified. 
00320         bool rv;
00321         for(const char *a=strA.d->str,*aend=a+strA.d->len,*b=strB; ; a++,b++)
00322         {
00323             if(!*b)
00324             {  rv=0;  break;  }
00325             if(a==aend)   // a shorter than b
00326             {  rv=1;  break;  }
00327             if(*a!=*b)
00328             {  rv=*a<*b;  break;  }
00329         }
00330         strA._derefN();  // "unlock"
00331         return(rv);
00332     }
00333     return(0);
00334 }
00335 
00336 bool operator>(const TLString &strA,const char *strB)
00337 {
00338     if(strA && strB)
00339     {
00340         strA._aqrefN();  // Aquire a refernce so that it will not be modified. 
00341         bool rv;
00342         for(const char *a=strA.d->str,*aend=a+strA.d->len,*b=strB; ; a++,b++)
00343         {
00344             if(a==aend)
00345             {  rv=0;  break;  }
00346             if(!*b)   // b shorter than a
00347             {  rv=1;  break;  }
00348             if(*a!=*b)
00349             {  rv=*a>*b;  break;  }
00350         }
00351         strA._derefN();  // "unlock"
00352         return(rv);
00353     }
00354     return(0);
00355 }
00356 
00357 
00358 bool operator<=(const TLString &strA,const TLString &strB)
00359 {
00360     if(strA && strB)
00361     {
00362         int rv;
00363         strA._aqrefN();  // Aquire a refernce so that it will not be modified. 
00364         strB._aqrefN();  // Aquire a refernce so that it will not be modified. 
00365         if(strA.d==strB.d)  rv=1;  // same internal data
00366         else
00367         {
00368             size_t minlen=strA.d->len<strB.d->len ? strA.d->len : strB.d->len;
00369             rv = memcmp(strA.d->str,strB.d->str,minlen);
00370             // The shorter string is smaller. 
00371             rv = rv ? (rv<0) : (strA.d->len<=strB.d->len);
00372         }
00373         strB._derefN();  // "unlock"
00374         strA._derefN();  // "unlock"
00375         return(rv);
00376     }
00377     return(0);
00378 }
00379 
00380 bool operator<=(const TLString &strA,const char *strB)
00381 {
00382     if(strA && strB)
00383     {
00384         strA._aqrefN();  // Aquire a refernce so that it will not be modified. 
00385         bool rv;
00386         for(const char *a=strA.d->str,*aend=a+strA.d->len,*b=strB; ; a++,b++)
00387         {
00388             if(a==aend)
00389             {  rv=1;  break;  }
00390             if(!*b)
00391             {  rv=0;  break;  }
00392             if(*a!=*b)
00393             {  rv=*a<*b;  break;  }
00394         }
00395         strA._derefN();  // "unlock"
00396         return(rv);
00397     }
00398     return(0);
00399 }
00400 
00401 bool operator>=(const TLString &strA,const char *strB)
00402 {
00403     if(strA && strB)
00404     {
00405         strA._aqrefN();  // Aquire a refernce so that it will not be modified. 
00406         bool rv;
00407         for(const char *a=strA.d->str,*aend=a+strA.d->len,*b=strB; ; a++,b++)
00408         {
00409             if(!*b)
00410             {  rv=1;  break;  }
00411             if(a==aend)
00412             {  rv=0;  break;  }
00413             if(*a!=*b)
00414             {  rv=*a>*b;  break;  }
00415         }
00416         strA._derefN();  // "unlock"
00417         return(rv);
00418     }
00419     return(0);
00420 }
00421 
00422 
00423 int TLString::zero()
00424 {
00425     if(!d)  return(0);
00426     if(d->refcnt.val()>1)  return(1);
00427     // We are the only user. 
00428     memset(d->str,'\0',d->len);
00429     _derefN();
00430     return(0);
00431 }
00432 
00433 
00434 void TLString::trunc(size_t len,bool do_not_shrink)
00435 {
00436     if(!d)  return;
00437     if(d->len<=len)  return;
00438     
00439     if(d->refcnt.val()==1)
00440     {
00441         // We are the only user. 
00442         d->len=len;
00443         d->str[len]='\0';
00444         if(!do_not_shrink)
00445         {  d->DownSizeIfNeeded(len+1); }
00446     }
00447     else
00448     {
00449         // There are more users. 
00450         SData *nd=new SData(len+1);
00451         memcpy(nd->str,d->str,len);
00452         nd->str[len]='\0';
00453         _derefN();
00454         d=nd;
00455     }
00456 }
00457 
00458 
00459 void TLString::skip(size_t n)
00460 {
00461     if(!d || !n)  return;
00462     
00463     if(d->refcnt.val()==1)
00464     {
00465         // We are the only user. 
00466         if(d->len<=n)
00467         {
00468             d->len=0;
00469             d->str[0]='\0';
00470             d->DownSizeIfNeeded(1);
00471         }
00472         else
00473         {
00474             d->len-=n;
00475             memmove(d->str,d->str+n,d->len+1);
00476             d->DownSizeIfNeeded(d->len+1);
00477         }
00478     }
00479     else
00480     {
00481         // There are more users. 
00482         if(d->len<=n)
00483         {
00484             _derefN();
00485             _storeN("");
00486         }
00487         else
00488         {
00489             size_t len=d->len-n;
00490             SData *nd=new SData(len+1);
00491             memcpy(nd->str,d->str+n,len);
00492             nd->str[len]='\0';
00493             _derefN();
00494             d=nd;
00495         }
00496     }
00497 }
00498 
00499 
00500 size_t TLString::TightenSize()
00501 {
00502     if(!d)  return(0);
00503     if(d->refcnt.val()==1)
00504     {  d->TightenSize();  }
00505     return(d->asize+sizeof(SData));
00506 }
00507 
00508 
00509 void TLString::vsprintf(const char *fmt,va_list ap)
00510 {
00511     if(d && d->refcnt.val()==1 && d->asize>=32)
00512     {
00513         // Optimized version. We are the only user. 
00514         
00515         // First, we must get the length of the string in fmt,...
00516         ssize_t rv=vsnprintf(d->str,d->asize,fmt,ap);
00517 #if 0
00518         if(rv<0)
00519         {  fprintf(stderr,"tlstring.cc:%d: vsnprintf() not C99 conform."
00520             " Please upgrade your libc.\n",__LINE__);  abort();  }
00521 #endif
00522         CritAssert(rv>=0);   // critical: libc
00523         
00524         size_t dlen=rv;  // (without trailing '\0')
00525         // The length of the string in fmt,... is dlen. 
00526         if(dlen+1<=d->asize)
00527         {
00528             // Wow, the whole string is already there. 
00529             d->len=dlen;
00530             return;
00531         }
00532         
00533         d->EnsureSize(dlen+1);
00534         // Must re-format the string. 
00535         ssize_t rv2=vsnprintf(d->str,dlen+1,fmt,ap);
00536         CritAssert(rv==rv2);   // critical: libc
00537         d->len=dlen;
00538         
00539         return;
00540     }
00541     
00542     // Get rid of old stuff: 
00543     _deref();
00544     
00545     // First, we must get the length of the string in fmt,...
00546     static const ssize_t prealloc=64;
00547     char buf[prealloc];
00548     ssize_t rv=vsnprintf(buf,prealloc,fmt,ap);
00549 #if 0
00550     if(rv<0)
00551     {  fprintf(stderr,"tlstring.cc:%d: vsnprintf() not C99 conform."
00552         " Please upgrade your libc.\n",__LINE__);  abort();  }
00553 #endif
00554     CritAssert(rv>=0);   // critical: libc
00555     
00556     size_t dlen=rv;  // (without trailing '\0')
00557     // The length of the string in fmt,... is dlen. 
00558     // First, allocate the needed bytes: 
00559     d=new SData(dlen+1);   // +1 for terminating '\0'
00560     if(rv<prealloc)  // okay.
00561     {
00562         // Whole string fits into prealloc buf. Simply copy. 
00563         memcpy(d->str,buf,dlen);  // okay. 
00564     }
00565     else
00566     {
00567         // Must re-format the string. 
00568         ssize_t rv2=vsnprintf(d->str,dlen+1,fmt,ap);
00569         CritAssert(rv==rv2);   // critical: libc
00570     }
00571     d->len=dlen;
00572     d->str[dlen]='\0';  // to be sure...
00573 }
00574 
00575 
00576 void TLString::sprintf(const char *fmt,...)
00577 {
00578     va_list ap;
00579     va_start(ap,fmt);
00580     vsprintf(fmt,ap);
00581     va_end(ap);
00582 }
00583 
00584 
00585 ssize_t TLString::index(char c) const
00586 {
00587     if(!d)  return(-1);
00588     for(const char *i=d->str,*iend=i+d->len; i<iend; i++)
00589         if(*i==c)  return(i-d->str);
00590     return(-1);
00591 }
00592 
00593 ssize_t TLString::rindex(char c) const
00594 {
00595     if(!d)  return(-1);
00596     for(ssize_t idx=d->len-1; idx>=0; idx--)
00597         if(d->str[idx]==c)  return(idx);
00598     return(-1);
00599 }
00600 
00601 
00602 static char *memfind(const char *buf,const char *tofind,size_t len)
00603 {
00604     size_t findlen=strlen(tofind);
00605     if(findlen>len)
00606     {  return((char*)NULL);  }
00607     if(len<1)
00608     {  return((char*)buf);  }
00609     
00610     const char *bufend=&buf[len-findlen+1];
00611     for(const char *c=buf; c<bufend; c++)
00612     {
00613         if(*c==*tofind)  // first letter matches
00614         {
00615             if(!memcmp(c+1,tofind+1,findlen-1))  // found
00616             {  return((char*)c);  }
00617         }
00618     }
00619     
00620     return((char*)NULL);
00621 }
00622 
00623 ssize_t TLString::find(const char *str) const
00624 {
00625     if(!d)  return(-1);
00626     if(!str)  return(0);
00627     char *ptr=memfind(d->str,str,d->len);
00628     if(!ptr)  return(-1);
00629     return(ptr-d->str);
00630 }
00631 
00632 ssize_t TLString::find(const TLString &str) const
00633 {
00634     if(!d)  return(-1);
00635     if(!str)  return(0);
00636     
00637     ssize_t rv=-1;
00638     str._aqrefN();  // Aquire a refernce so that it will not be modified. 
00639     
00640     do {
00641         if(str.d->len>d->len)  break;
00642         if(str.d->len<1)
00643         {  rv=0;  break;  }
00644         
00645         const char *bufend=&d->str[d->len-str.d->len];
00646         for(const char *c=d->str; c<=bufend; c++)  // <= is OK
00647         {
00648             if(*c!=*str.d->str) continue;  // first letter mismatch
00649             if(!memcmp(c+1,str.d->str+1,str.d->len-1))  // found
00650             {  rv=c-d->str;  break;  }
00651         }
00652     } while(0);
00653     
00654     str._derefN();  // "unlock"
00655     return(rv);
00656 }
00657 
00658 
00659 ssize_t TLString::rfind(const char *str) const
00660 {
00661     if(!d)  return(-1);
00662     if(!str || !*str)  return(d->len);
00663     size_t len=strlen(str);
00664     if(len>d->len)  return(-1);
00665     if(!len)  return(d->len);
00666     const char *end=d->str+d->len-len;
00667     for(const char *start=end; start>=d->str;  start--)
00668     {
00669         if(*start!=*str)  continue;
00670         if(!memcmp(start+1,str+1,len-1))  return(start-d->str);
00671     }
00672     return(-1);
00673 }
00674 
00675 ssize_t TLString::rfind(const TLString &str) const
00676 {
00677     if(!d)  return(-1);
00678     if(!str)  return(d->len);
00679     
00680     ssize_t rv=-1;
00681     str._aqrefN();  // Aquire a refernce so that it will not be modified. 
00682     
00683     do {
00684         if(str.d->len>d->len)  break;
00685         if(str.d->len<1)
00686         {  rv=d->len;  break;  }
00687         
00688         const char *end=d->str+d->len-str.d->len;
00689         for(const char *start=end; start>=d->str;  start--)
00690         {
00691             if(*start!=*str.d->str)  continue;
00692             if(!memcmp(start+1,str.d->str+1,str.d->len-1))
00693             {  rv=start-d->str;  break;  }
00694         }
00695     } while(0);
00696     
00697     str._derefN();  // "unlock"
00698     return(rv);
00699 }
00700 
00701 
00702 TLString::TLString(const char *strA,const char *strB)
00703 {
00704     if(strA && strB)
00705     {
00706         size_t lenA=strlen(strA);
00707         size_t lenAB=lenA+strlen(strB);
00708         d=new SData(lenAB+1);
00709         strcpy(d->str,strA);
00710         strcpy(d->str+lenA,strB);
00711         d->len=lenAB;
00712     }
00713     else if(strA)  _storeN(strA);
00714     else if(strB)  _storeN(strB);
00715     else  d=NULL;
00716 }
00717 
00718 TLString::TLString(const char *strA,const TLString &strB)
00719 {
00720     if(strA && strB)
00721     {
00722         size_t lenA=strlen(strA);
00723         strB._aqrefN();  // Aquire a refernce so that it will not be modified. 
00724         size_t lenAB=lenA+strB.d->len;
00725         d=new SData(lenAB+1);
00726         strcpy(d->str,strA);
00727         memcpy(d->str+lenA,strB.d->str,strB.d->len+1);
00728         strB._derefN();  // "unlock"
00729         d->len=lenAB;
00730     }
00731     else if(strA)  _storeN(strA);
00732     else if(strB)  _referenceN(strB);
00733     else  d=NULL;
00734 }
00735 
00736 TLString::TLString(const TLString &strA,const char *strB)
00737 {
00738     if(strA && strB)
00739     {
00740         strA._aqrefN();  // Aquire a refernce so that it will not be modified. 
00741         size_t lenAB=strA.d->len+strlen(strB);
00742         d=new SData(lenAB+1);
00743         memcpy(d->str,strA.d->str,strA.d->len);
00744         strcpy(d->str+strA.d->len,strB);
00745         strA._derefN();  // "unlock"
00746         d->len=lenAB;
00747     }
00748     else if(strA)  _referenceN(strA);
00749     else if(strB)  _storeN(strB);
00750     else  d=NULL;
00751 }
00752 
00753 TLString::TLString(const TLString &strA,const TLString &strB)
00754 {
00755     if(strA && strB)
00756     {
00757         strA._aqrefN();  // Aquire a refernce so that it will not be modified. 
00758         strB._aqrefN();  // Aquire a refernce so that it will not be modified. 
00759         size_t lenAB=strA.d->len+strB.d->len;
00760         d=new SData(lenAB+1);
00761         memcpy(d->str,strA.d->str,strA.d->len);
00762         memcpy(d->str+strA.d->len,strB.d->str,strB.d->len+1);
00763         strB._derefN();  // "unlock"
00764         strA._derefN();  // "unlock"
00765         d->len=lenAB;
00766     }
00767     else if(strA)  _referenceN(strA);
00768     else if(strB)  _referenceN(strB);
00769     else  d=NULL;
00770 }

Generated on Sat Feb 19 22:33:46 2005 for Ray by doxygen 1.3.5