00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "tlstring.h"
00018 #include <string.h>
00019 #include <stdio.h>
00020
00033 void TLString::SData::_EnsureSize(size_t s)
00034 {
00035
00036
00037
00038 Assert(refcnt.val()==1);
00039
00040
00041
00042
00043
00044
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
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
00064 Assert(s<=asize);
00065 if(s<16) s=10;
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);
00072 str=REALLOC(str,asize);
00073 }
00074 }
00075
00076
00077 TLString::SData::SData(const char *s) :
00078 refcnt(1)
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)
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)
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)
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;
00150
00151
00152
00153
00154
00155
00156 if(d)
00157 {
00158 _detachN();
00159
00160
00161
00162
00163
00164 SData *s=str.d;
00165 d->_EnsureSize(d->len+s->len+1);
00166 memcpy(d->str+d->len,s->str,s->len);
00167 d->len+=s->len;
00168 d->str[d->len]='\0';
00169
00170
00171 }
00172 else
00173 {
00174
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;
00200
00201 if(d)
00202 {
00203 _detachN();
00204
00205
00206
00207
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
00216 }
00217 else
00218 {
00219
00220 _referenceN(str);
00221 }
00222 }
00223
00224
00225 int TLString::compare(const TLString &strB)
00226 {
00227
00228
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();
00238 if(d==strB.d) rv=0;
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
00244 if(!rv && d->len!=strB.d->len)
00245 { rv = d->len<strB.d->len ? -1 : 1; }
00246 }
00247 strB._derefN();
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();
00259 strB._aqrefN();
00260 if(strA.d==strB.d) rv=1;
00261 else if(strA.d->len!=strB.d->len) rv=0;
00262 else rv=!memcmp(strA.d->str,strB.d->str,strA.d->len);
00263 strB._derefN();
00264 strA._derefN();
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();
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();
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();
00299 strB._aqrefN();
00300 if(strA.d==strB.d) rv=0;
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
00306 rv = rv ? (rv<0) : (strA.d->len<strB.d->len);
00307 }
00308 strB._derefN();
00309 strA._derefN();
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();
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)
00326 { rv=1; break; }
00327 if(*a!=*b)
00328 { rv=*a<*b; break; }
00329 }
00330 strA._derefN();
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();
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)
00347 { rv=1; break; }
00348 if(*a!=*b)
00349 { rv=*a>*b; break; }
00350 }
00351 strA._derefN();
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();
00364 strB._aqrefN();
00365 if(strA.d==strB.d) rv=1;
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
00371 rv = rv ? (rv<0) : (strA.d->len<=strB.d->len);
00372 }
00373 strB._derefN();
00374 strA._derefN();
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();
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();
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();
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();
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
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
00442 d->len=len;
00443 d->str[len]='\0';
00444 if(!do_not_shrink)
00445 { d->DownSizeIfNeeded(len+1); }
00446 }
00447 else
00448 {
00449
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
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
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
00514
00515
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);
00523
00524 size_t dlen=rv;
00525
00526 if(dlen+1<=d->asize)
00527 {
00528
00529 d->len=dlen;
00530 return;
00531 }
00532
00533 d->EnsureSize(dlen+1);
00534
00535 ssize_t rv2=vsnprintf(d->str,dlen+1,fmt,ap);
00536 CritAssert(rv==rv2);
00537 d->len=dlen;
00538
00539 return;
00540 }
00541
00542
00543 _deref();
00544
00545
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);
00555
00556 size_t dlen=rv;
00557
00558
00559 d=new SData(dlen+1);
00560 if(rv<prealloc)
00561 {
00562
00563 memcpy(d->str,buf,dlen);
00564 }
00565 else
00566 {
00567
00568 ssize_t rv2=vsnprintf(d->str,dlen+1,fmt,ap);
00569 CritAssert(rv==rv2);
00570 }
00571 d->len=dlen;
00572 d->str[dlen]='\0';
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)
00614 {
00615 if(!memcmp(c+1,tofind+1,findlen-1))
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();
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++)
00647 {
00648 if(*c!=*str.d->str) continue;
00649 if(!memcmp(c+1,str.d->str+1,str.d->len-1))
00650 { rv=c-d->str; break; }
00651 }
00652 } while(0);
00653
00654 str._derefN();
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();
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();
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();
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();
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();
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();
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();
00758 strB._aqrefN();
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();
00764 strA._derefN();
00765 d->len=lenAB;
00766 }
00767 else if(strA) _referenceN(strA);
00768 else if(strB) _referenceN(strB);
00769 else d=NULL;
00770 }