filters

ustring.cpp

00001 /*
00002  *  This file is part of the KDE libraries
00003  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
00004  *  Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Library General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Library General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU Library General Public License
00017  *  along with this library; see the file COPYING.LIB.  If not, write to
00018  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  *  Boston, MA 02110-1301, USA.
00020  */
00021 
00022 #include "ustring.h"
00023 
00024 #include <string.h>
00025 #include <ctype.h>
00026 #include <stdlib.h>
00027 #include <stdio.h>
00028 #include <math.h>
00029 
00030 #ifdef _MSC_VER
00031 #define snprintf _snprintf
00032 #endif
00033 
00034 using namespace Swinder;
00035 
00036 UChar UChar::null;
00037 UString::Rep UString::Rep::null = { 0, 0, 1, 0 };
00038 UString UString::null;
00039 static char *statBuffer = 0L;
00040 
00041 UChar::UChar(const UCharReference &c)
00042     : uc( c.unicode() )
00043 {
00044 }
00045 
00046 UCharReference& UCharReference::operator=(UChar c)
00047 {
00048   str->detach();
00049   if (offset < str->rep->len)
00050     *(str->rep->dat + offset) = c;
00051   /* TODO: lengthen string ? */
00052   return *this;
00053 }
00054 
00055 UChar& UCharReference::ref() const
00056 {
00057   if (offset < str->rep->len)
00058     return *(str->rep->dat + offset);
00059   else
00060   {
00061     static UChar nullRef('\0');
00062     return nullRef;
00063   }
00064 }
00065 
00066 namespace {
00067   // return an uninitialized UChar array of size s
00068   static inline UChar* allocateChars(int s)
00069   {
00070     // work around default UChar constructor code
00071     return reinterpret_cast<UChar*>(new short[s]);
00072   }
00073 }
00074 
00075 
00076 UString::Rep *UString::Rep::create(UChar *d, int l)
00077 {
00078   Rep *r = new Rep;
00079   r->dat = d;
00080   r->len = l;
00081   r->cap = l;
00082   r->rc = 1;
00083 
00084   return r;
00085 }
00086 
00087 UString::Rep *UString::Rep::create(UChar *d, int l, int c)
00088 {
00089   Rep *r = new Rep;
00090   r->dat = d;
00091   r->len = l;
00092   r->cap = c;
00093   r->rc = 1;
00094 
00095   return r;
00096 }
00097 
00098 UString::UString()
00099 {
00100   null.rep = &Rep::null;
00101   attach(&Rep::null);
00102 }
00103 
00104 UString::UString(char c)
00105 {
00106   UChar *d = allocateChars( 1 );
00107   d[0] = UChar(0, c);
00108   rep = Rep::create(d, 1);
00109 }
00110 
00111 UString::UString(UChar c)
00112 {
00113   UChar *d = allocateChars( 1 );
00114   d[0] = c;
00115   rep = Rep::create(d, 1);
00116 }
00117 
00118 UString::UString(const char *c)
00119 {
00120   attach(&Rep::null);
00121   operator=(c);
00122 }
00123 
00124 UString::UString(const UChar *c, int length)
00125 {
00126   UChar *d = allocateChars( length );
00127   memcpy(d, c, length * sizeof(UChar));
00128   rep = Rep::create(d, length);
00129 }
00130 
00131 UString::UString(UChar *c, int length, bool copy)
00132 {
00133   UChar *d;
00134   if (copy) {
00135     d = allocateChars( length );
00136     memcpy(d, c, length * sizeof(UChar));
00137   } else
00138     d = c;
00139   rep = Rep::create(d, length);
00140 }
00141 
00142 UString::UString(const UString &b)
00143 {
00144   attach(b.rep);
00145 }
00146 
00147 // NOTE: this is private, be careful when using it !
00148 UString::UString(Rep *r): rep(r)
00149 {
00150 }
00151 
00152 
00153 UString::~UString()
00154 {
00155   release();
00156 }
00157 
00158 UString UString::number(int i)
00159 {
00160 #if 0
00161   // standard and safe way
00162   char buf[1+sizeof(int)*3];
00163   snprintf(buf, sizeof(int)*3, "%d", i);
00164   buf[sizeof(int)*3] = '\0';
00165   return UString(buf);
00166 #else
00167   // micro-optimized version
00168   static unsigned short digits[] = 
00169     { '9', '8', '7', '6', '5', '4', '3', '2', '1', 
00170       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
00171       
00172   UString::Rep* rep = 0;
00173       
00174   if(i == 0)
00175   {
00176     UChar* buf = allocateChars(1);
00177     buf[0] = '0';
00178     rep = Rep::create(buf, 1);
00179   }
00180   else
00181   {
00182     bool neg = (i < 0);
00183     int ndig = 1 + sizeof(int)*3;
00184 
00185     UChar* buf = allocateChars(ndig);
00186     UChar* ptr = buf + ndig - 1;
00187     int len = (neg) ? 1 : 0;
00188 
00189     // construct all the digits
00190     for(; i != 0; i/=10, len++) 
00191       *ptr-- = digits[9+i%10];
00192 
00193     if(neg) 
00194       *ptr-- = '-';  
00195   
00196     // shift, don't use memcpy because overlapping area
00197     memmove(buf, ptr+1, len*sizeof(unsigned short));
00198     
00199     rep = Rep::create(buf, len, ndig);
00200   }
00201   
00202   return UString(rep);
00203 #endif
00204 }
00205 
00206 UString UString::number(unsigned int u)
00207 {
00208 #if 0
00209   // standard and safe way
00210   char buf[1+sizeof(unsigned int)*3];
00211   snprintf(buf, sizeof(unsigned int)*3, "%d", u);
00212   buf[sizeof(int)*3] = '\0';
00213   return UString(buf);
00214 #else
00215   // micro-optimized version
00216   static unsigned short digits[] = 
00217     { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
00218 
00219   UString::Rep* rep = 0;
00220       
00221   if(u < 10)
00222   {
00223     UChar* buf = allocateChars(1);
00224     buf[0] = digits[u];
00225     rep = Rep::create(buf, 1);
00226   }
00227   else
00228   {
00229     int ndig = 1 + sizeof(int)*3;
00230     UChar* buf = allocateChars(ndig);
00231     UChar* ptr = buf + ndig - 1;
00232     int len = 0;
00233 
00234     // construct all the digits
00235     for(; u != 0; u/=10, len++) 
00236       *ptr-- = digits[u%10];
00237   
00238     // shift, don't use memcpy because overlapping area
00239     memmove(buf, ptr+1, len*sizeof(unsigned short));
00240     
00241     rep = Rep::create(buf, len, ndig);
00242   }
00243   
00244   return UString(rep);
00245 #endif
00246 }
00247 
00248 UString UString::number(double d)
00249 {
00250   char buf[40];
00251   snprintf(buf, 39, "%.16g", d);
00252   buf[sizeof(int)*3] = '\0';
00253   return UString(buf);
00254 }
00255 
00256 void UString::truncate(int n)
00257 {
00258   if((n >= 0) && (n < length()))
00259   {
00260     detach();
00261     rep->len = n;
00262   }
00263 }
00264 
00265 void UString::reserve(int r)
00266 {
00267   if(r > length())
00268   {
00269     int l = length();
00270     UChar* n = allocateChars( r );
00271     memcpy(n, data(), l * sizeof(UChar));
00272     release();
00273     rep = Rep::create(n, l, r); 
00274   }
00275 }
00276 
00277 UString &UString::append(const UString &t)
00278 {
00279   int tl = t.length();
00280   if(tl > 0)
00281   {
00282     detach();
00283     int l = length();
00284     
00285     // no space, we have to reallocate first
00286     if(capacity() < tl + l)
00287       reserve(tl +l);
00288       
00289     UChar *dd = rep->data();
00290     memcpy(dd+l, t.data(), tl * sizeof(UChar));
00291     rep->len += tl;
00292   }
00293 
00294   return *this;
00295 }
00296 
00297 UString &UString::append(const char* s)
00298 {
00299   int tl = strlen(s);
00300   if(tl > 0)
00301   {
00302     detach();
00303     int l = length();
00304     
00305     // no space, we have to reallocate first
00306     if(capacity() < tl + l)
00307       reserve(tl +l);
00308 
00309     // copy each character        
00310     UChar *dd = rep->data();
00311     for (int i = 0; i < tl; i++)
00312       dd[l+i].uc = static_cast<unsigned char>( s[i] );
00313     rep->len += tl;
00314   }
00315 
00316   return *this;
00317 }
00318 
00319 UString &UString::append(UChar c)
00320 {
00321   detach();
00322   int l = length();
00323   
00324   // we need to reallocate
00325   // in case another append follows, so let's reserve()
00326   // this avoids subsequent expensive reallocation
00327   if(capacity() < l + 1)
00328     reserve(l + 8);
00329   
00330   UChar *dd = rep->data();
00331   dd[l] = c;
00332   rep->len++;
00333 
00334   return *this;
00335 }
00336 
00337 UString &UString::append(char c)
00338 {
00339   return append( UChar((unsigned short)c) );
00340 }
00341 
00342 
00343 UString &UString::prepend(const UString &t)
00344 {
00345   int tl = t.length();
00346   if(tl > 0)
00347   {
00348     int l = length();
00349     
00350     // no space, we have to reallocate first
00351     if(capacity() < tl + l)
00352       reserve(tl +l);
00353 
00354     // shift the string, then place the new string      
00355     UChar *dd = rep->data();
00356     for(int i = l-1; i >= 0; i--)
00357       dd[i+tl] = dd[i];
00358     memcpy(dd, t.data(), tl * sizeof(UChar));
00359     rep->len += tl;
00360   }
00361 
00362   return *this;
00363 }
00364 
00365 UString &UString::prepend(const char* s)
00366 {
00367   int tl = strlen(s);
00368   if(tl > 0)
00369   {
00370     int l = length();
00371     
00372     // no space, we have to reallocate first
00373     if(capacity() < tl + l)
00374       reserve(tl +l);
00375 
00376     // shift the string, then copy each new character        
00377     UChar *dd = rep->data();
00378     for(int i = l-1; i >= 0; i--)
00379       dd[i+tl] = dd[i];
00380     for(int j = 0; j < tl; j++)
00381       dd[j].uc = static_cast<unsigned char>( s[j] );
00382     rep->len += tl;
00383   }
00384 
00385   return *this;
00386 }
00387 
00388 UString &UString::prepend(UChar c)
00389 {
00390   int l = length();
00391   
00392   // we need to reallocate and reserve
00393   // see also append(UChar c) function
00394   if(capacity() < l + 1)
00395     reserve(l + 8);
00396   
00397   UChar *dd = rep->data();
00398   for(int i = l-1; i >= 0; i--)
00399     dd[i+1] = dd[i];
00400   dd[0] = c;
00401   rep->len++;
00402 
00403   return *this;
00404 }
00405 
00406 UString &UString::prepend(char c)
00407 {
00408   return prepend( UChar((unsigned short)c) );
00409 }
00410 
00411 char *UString::ascii() const
00412 {
00413   if (statBuffer)
00414     delete [] statBuffer;
00415 
00416   statBuffer = new char[length()+1];
00417   for(int i = 0; i < length(); i++)
00418     statBuffer[i] = data()[i].low();
00419   statBuffer[length()] = '\0';
00420 
00421   return statBuffer;
00422 }
00423 
00424 UString &UString::operator=(const char *c)
00425 {
00426   release();
00427   int l = c ? strlen(c) : 0;
00428   UChar *d = allocateChars( l );
00429   for (int i = 0; i < l; i++)
00430     d[i].uc = static_cast<unsigned char>( c[i] );
00431   rep = Rep::create(d, l);
00432 
00433   return *this;
00434 }
00435 
00436 UString &UString::operator=(const UString &str)
00437 {
00438   str.rep->ref();
00439   release();
00440   rep=str.rep;
00441 
00442   return *this;
00443 }
00444 
00445 UString &UString::operator+=(const UString &s)
00446 {
00447   return append(s);
00448 }
00449 
00450 bool UString::is8Bit() const
00451 {
00452   const UChar *u = data();
00453   for(int i = 0; i < length(); i++, u++)
00454     if (u->uc > 0xFF)
00455       return false;
00456 
00457   return true;
00458 }
00459 
00460 UChar UString::operator[](int pos) const
00461 {
00462   if (pos >= length())
00463     return UChar::null;
00464 
00465   return static_cast<const UChar *>( data() )[pos];
00466 }
00467 
00468 UCharReference UString::operator[](int pos)
00469 {
00470   /* TODO: boundary check */
00471   return UCharReference(this, pos);
00472 }
00473 
00474 UString UString::substr(int pos, int len) const
00475 {
00476   if (isNull())
00477     return UString();
00478   if (pos < 0)
00479     pos = 0;
00480   else if (pos >= static_cast<int>( length() ))
00481     pos = length();
00482   if (len < 0)
00483     len = length();
00484   if (pos + len >= static_cast<int>( length() ))
00485     len = length() - pos;
00486 
00487   UChar *tmp = allocateChars( len );
00488   memcpy(tmp, data()+pos, len * sizeof(UChar));
00489   UString result(tmp, len);
00490   delete [] tmp;
00491 
00492   return result;
00493 }
00494 
00495 int UString::find(const UString &f, int pos) const
00496 {
00497   if (isNull())
00498     return -1;
00499   long fsize = f.length() * sizeof(UChar);
00500   if (pos < 0)
00501     pos = 0;
00502   const UChar *end = data() + length() - f.length();
00503   for (const UChar *c = data() + pos; c <= end; c++)
00504     if (!memcmp(c, f.data(), fsize))
00505       return (c-data());
00506 
00507   return -1;
00508 }
00509 
00510 void UString::attach(Rep *r)
00511 {
00512   rep = r;
00513   rep->ref();
00514 }
00515 
00516 void UString::detach()
00517 {
00518   if (rep->rc > 1) 
00519   {
00520     int c = capacity();
00521     int l = length();
00522     UChar *n = allocateChars( c );
00523     memcpy(n, data(), l * sizeof(UChar));
00524     release();
00525     rep = Rep::create(n, l, c);
00526   }
00527 }
00528 
00529 void UString::release()
00530 {
00531   if (!rep->deref()) 
00532   {
00533     delete [] rep->dat;
00534     delete rep;
00535   }
00536 }
00537 
00538 bool Swinder::operator==(const UString& s1, const UString& s2)
00539 {
00540   if (s1.rep->len != s2.rep->len)
00541     return false;
00542 
00543   return (memcmp(s1.rep->dat, s2.rep->dat,
00544          s1.rep->len * sizeof(UChar)) == 0);
00545 }
00546 
00547 bool Swinder::operator==(const UString& s1, const char *s2)
00548 {
00549   if (s2 == 0L)
00550     return s1.isEmpty();
00551 
00552   if (s1.length() != static_cast<int>( strlen(s2) ))
00553     return false;
00554 
00555   const UChar *u = s1.data();
00556   while (*s2) 
00557   {
00558     if (u->uc != *s2 )
00559       return false;
00560     s2++;
00561     u++;
00562   }
00563 
00564   return true;
00565 }
00566 
00567 bool Swinder::operator<(const UString& s1, const UString& s2)
00568 {
00569   const int l1 = s1.length();
00570   const int l2 = s2.length();
00571   const int lmin = l1 < l2 ? l1 : l2;
00572   const UChar *c1 = s1.data();
00573   const UChar *c2 = s2.data();
00574   int l = 0;
00575   while (l < lmin && *c1 == *c2) 
00576   {
00577     c1++;
00578     c2++;
00579     l++;
00580   }
00581   if (l < lmin)
00582     return (c1->unicode() < c2->unicode());
00583 
00584   return (l1 < l2);
00585 }
00586 
00587 UString Swinder::operator+(const UString& s1, const UString& s2)
00588 {
00589   UString tmp(s1);
00590   tmp.append(s2);
00591 
00592   return tmp;
00593 }
00594 
00595 
00596 UConstString::UConstString( UChar* data, unsigned int length ) : 
00597 UString( data, length, false )
00598 {
00599 }
00600 
00601 UConstString::~UConstString()
00602 {
00603   if ( rep->rc > 1 ) {
00604     int l = length();
00605     UChar* n = allocateChars( l );
00606     memcpy( n, data(), l * sizeof( UChar ) );
00607     rep->dat = n;
00608   }
00609   else
00610     rep->dat = 0;
00611 }
KDE Home | KDE Accessibility Home | Description of Access Keys