(file) Return to String.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

Diff for /pegasus/src/Pegasus/Common/String.cpp between version 1.7 and 1.111.2.4

version 1.7, 2001/04/10 22:42:55 version 1.111.2.4, 2005/09/29 02:22:39
Line 1 
Line 1 
 //BEGIN_LICENSE  //%2005////////////////////////////////////////////////////////////////////////
 // //
 // Copyright (c) 2000 The Open Group, BMC Software, Tivoli Systems, IBM  // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
   // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
   // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
   // IBM Corp.; EMC Corporation, The Open Group.
   // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
   // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
   // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
   // EMC Corporation; VERITAS Software Corporation; The Open Group.
 // //
 // Permission is hereby granted, free of charge, to any person obtaining a  // Permission is hereby granted, free of charge, to any person obtaining a copy
 // copy of this software and associated documentation files (the "Software"),  // of this software and associated documentation files (the "Software"), to
 // to deal in the Software without restriction, including without limitation  // deal in the Software without restriction, including without limitation the
 // the rights to use, copy, modify, merge, publish, distribute, sublicense,  // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 // and/or sell copies of the Software, and to permit persons to whom the  // sell copies of the Software, and to permit persons to whom the Software is
 // Software is furnished to do so, subject to the following conditions:  // furnished to do so, subject to the following conditions:
 // //
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL  // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER  // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 // DEALINGS IN THE SOFTWARE.  // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 // //
 //END_LICENSE  //==============================================================================
 //BEGIN_HISTORY  
 // //
 // Author:  // Author: Mike Brasher (mbrasher@bmc.com)
 // //
 // $Log$  //%/////////////////////////////////////////////////////////////////////////////
 // Revision 1.7  2001/04/10 22:42:55  karl  
 // Correct error in String find  #include <cassert>
 //  #include "String.h"
 // Revision 1.6  2001/04/09 20:18:47  karl  #include "InternalException.h"
 // add find substring function  #include "CommonUTF.h"
 //  #include "CharSet.h"
 // Revision 1.5  2001/03/09 19:49:32  karl  
 // long lines  #ifdef PEGASUS_STRING_ENABLE_ICU
 //  #include <unicode/ustring.h>
 // Revision 1.4  2001/02/26 04:33:28  mike  #include <unicode/uchar.h>
 // Fixed many places where cim names compared with operator==(String,String).  #endif
 // Changed all of these to use CIMName::equal()  
 //  PEGASUS_NAMESPACE_BEGIN
 // Revision 1.3  2001/02/11 17:19:30  mike  
 // added reverseFind() method  //==============================================================================
 //  
 // Revision 1.2  2001/02/11 05:42:33  mike  
 // new  
 //  
 // Revision 1.1.1.1  2001/01/14 19:53:14  mike  
 // Pegasus import  
 // //
   // File-scope definitions:
 // //
 //END_HISTORY  //==============================================================================
  
   // Converts 16-bit characters to upper case.
   inline Uint16 _to_upper(Uint16 x)
   {
       return (x & 0xFF00) ? x : CharSet::to_upper(x);
   }
  
 #include <cctype>  // Converts 16-bit characters to lower case.
 #include "String.h"  inline Uint16 _to_lower(Uint16 x)
 #include "Exception.h"  {
 #include "String.h"      return (x & 0xFF00) ? x : CharSet::to_lower(x);
   }
  
 // For debugging  // Rounds x to the next power of two (or just returns 8 if x < 8).
 #include <iostream>  static Uint32 _next_pow_2(Uint32 x)
 using namespace std;  {
       if (x < 8)
           return 8;
  
       x--;
       x |= (x >> 1);
       x |= (x >> 2);
       x |= (x >> 4);
       x |= (x >> 8);
       x |= (x >> 16);
       x++;
  
 PEGASUS_NAMESPACE_BEGIN      return x;
   }
  
 const String String::EMPTY;  template<class P, class Q>
   static void _copy(P* p, const Q* q, size_t n)
   {
       // Use loop unrolling.
  
 inline Uint32 StrLen(const char* str)      while (n >= 8)
 { {
     if (!str)          p[0] = q[0];
         throw NullPointer();          p[1] = q[1];
           p[2] = q[2];
           p[3] = q[3];
           p[4] = q[4];
           p[5] = q[5];
           p[6] = q[6];
           p[7] = q[7];
           p += 8;
           q += 8;
           n -= 8;
       }
   
       while (n >= 4)
       {
           p[0] = q[0];
           p[1] = q[1];
           p[2] = q[2];
           p[3] = q[3];
           p += 4;
           q += 4;
           n -= 4;
       }
  
     return strlen(str);      while (n--)
           *p++ = *q++;
 } }
  
 inline Uint32 StrLen(const Char16* str)  static Uint16* _find(const Uint16* s, size_t n, Uint16 c)
 { {
     if (!str)      while (n >= 4)
         throw NullPointer();      {
           if (s[0] == c)
               return (Uint16*)s;
           if (s[1] == c)
               return (Uint16*)&s[1];
           if (s[2] == c)
               return (Uint16*)&s[2];
           if (s[3] == c)
               return (Uint16*)&s[3];
  
     Uint32 n = 0;          n -= 4;
           s += 4;
       }
  
     while (*str++)      if (n)
         n++;      {
           if (*s == c)
               return (Uint16*)s;
           s++;
           n--;
       }
  
     return n;      if (n)
       {
           if (*s == c)
               return (Uint16*)s;
           s++;
           n--;
 } }
  
 String::String()      if (n && *s == c)
           return (Uint16*)s;
   
       // Not found!
       return 0;
   }
   
   static int _compare(const Uint16* s1, const Uint16* s2)
   {
       while (*s1 && *s2)
 { {
     _rep.append('\0');          int r = *s1++ - *s2++;
   
           if (r)
               return r;
       }
   
       if (*s2)
           return -1;
       else if (*s1)
           return 1;
   
       return 0;
 } }
  
 String::String(const String& x) : _rep(x._rep)  static int _compare_no_utf8(const Uint16* s1, const char* s2)
 { {
       Uint16 c1;
       Uint16 c2;
   
       do
       {
           c1 = *s1++;
           c2 = *s2++;
   
           if (c1 == 0)
               return c1 - c2;
       }
       while (c1 == c2);
  
       return c1 - c2;
 } }
  
 String::String(const String& x, Uint32 n)  static int _compare(const Uint16* s1, const Uint16* s2, size_t n)
 { {
     _rep.append('\0');      // This should only be called when s1 and s2 have the same length.
     append(x.getData(), n);  
       while (n-- && (*s1++ - *s2++) == 0)
           ;
   
       return s1[-1] - s2[-1];
 } }
  
 String::String(const Char16* x) : _rep(x, StrLen(x) + 1)  static inline void _copy(Uint16* s1, const Uint16* s2, size_t n)
 { {
       memcpy(s1, s2, n * sizeof(Uint16));
   }
  
   void String_throw_out_of_bounds()
   {
       throw IndexOutOfBoundsException();
 } }
  
 String::String(const Char16* x, Uint32 n)  #ifdef PEGASUS_STRING_NO_THROW
   # define _check_null_pointer(ARG) /* empty */
   #else
   template<class T>
   inline void _check_null_pointer(const T* ptr)
 { {
     assign(x, n);      if (!ptr)
           throw NullPointer();
 } }
   #endif
  
 String::String(const char* str)  static size_t _copy_from_utf8(Uint16* dest, const char* src, size_t n)
 { {
     Uint32 n = ::strlen(str) + 1;      Uint16* p = dest;
     reserve(n);      const Uint8* q = (const Uint8*)src;
  
     while (n--)      // Process leading 7-bit ASCII characters (to avoid UTF8 overhead below
         _rep.append(*str++);      // this loop). Use factor-four loop-unrolling.
   
       while (n >= 4 && q[0] < 128 && q[1] < 128 && q[2] < 128 && q[3] < 128)
       {
           p[0] = q[0];
           p[1] = q[1];
           p[2] = q[2];
           p[3] = q[3];
           p += 4;
           q += 4;
           n -= 4;
 } }
  
 String::String(const char* str, Uint32 n_)      switch (n)
       {
           case 0:
               return p - dest;
           case 1:
               if (q[0] < 128)
               {
                   p[0] = q[0];
                   return p + 1 - dest;
               }
               break;
           case 2:
               if (q[0] < 128 && q[1] < 128)
 { {
     Uint32 n = _min(strlen(str), n_);                  p[0] = q[0];
     reserve(n + 1);                  p[1] = q[1];
                   return p + 2 - dest;
               }
               break;
           case 3:
               if (q[0] < 128 && q[1] < 128 && q[2] < 128)
               {
                   p[0] = q[0];
                   p[1] = q[1];
                   p[2] = q[2];
                   return p + 3 - dest;
               }
               break;
       }
  
     while (n--)      // Process remaining characters.
         _rep.append(*str++);  
       while (n)
       {
           // Optimize for 7-bit ASCII case.
  
     _rep.append('\0');          if (*q < 128)
           {
               *p++ = *q++;
               n--;
 } }
           else
           {
               Uint8 c = UTF_8_COUNT_TRAIL_BYTES(*q) + 1;
  
 String& String::assign(const Char16* x)              if (c > n || !isValid_U8(q, c) ||
                   UTF8toUTF16(&q, q + c, &p, p + n) != 0)
 { {
     _rep.clear();                  throw Exception("Bad UTF8 encoding");
     _rep.append(x, StrLen(x) + 1);  
     return *this;  
 } }
  
 String& String::assign(const Char16* str, Uint32 n)              n -= c;
           }
       }
   
       return p - dest;
   }
   
   // Note: dest must be at least three times src (plus an extra byte for
   // terminator).
   static inline size_t _copy_to_utf8(char* dest, const Uint16* src, size_t n)
 { {
     _rep.clear();      const Uint16* q = src;
     Uint32 m = _min(StrLen(str), n);      Uint8* p = (Uint8*)dest;
     _rep.append(str, m);  
     _rep.append('\0');      while (n >= 4 && q[0] < 128 && q[1] < 128 && q[2] < 128 && q[3] < 128)
     return *this;      {
           p[0] = q[0];
           p[1] = q[1];
           p[2] = q[2];
           p[3] = q[3];
           p += 4;
           q += 4;
           n -= 4;
 } }
  
 String& String::assign(const char* x)      switch (n)
       {
           case 0:
               return p - (Uint8*)dest;
           case 1:
               if (q[0] < 128)
               {
                   p[0] = q[0];
                   return p + 1 - (Uint8*)dest;
               }
               break;
           case 2:
               if (q[0] < 128 && q[1] < 128)
               {
                   p[0] = q[0];
                   p[1] = q[1];
                   return p + 2 - (Uint8*)dest;
               }
               break;
           case 3:
               if (q[0] < 128 && q[1] < 128 && q[2] < 128)
 { {
     _rep.clear();                  p[0] = q[0];
     Uint32 n = strlen(x);                  p[1] = q[1];
     _rep.reserve(n + 1);                  p[2] = q[2];
                   return p + 3 - (Uint8*)dest;
               }
               break;
       }
  
     while (n--)      // If this line was reached, there must be characters greater than 128.
         _rep.append(*x++);  
  
     _rep.append('\0');      UTF16toUTF8(&q, q + n, &p, p + 3 * n);
  
     return *this;      return p - (Uint8*)dest;
 } }
  
 String& String::assign(const char* x, Uint32 n_)  static inline size_t _convert(Uint16* p, const char* q, size_t n)
 { {
     _rep.clear();  #ifdef PEGASUS_STRING_NO_UTF8
       _copy(p, q, n);
       return n;
   #else
       return _copy_from_utf8(p, q, n);
   #endif
   }
  
     Uint32 n = _min(strlen(x), n_);  //==============================================================================
     _rep.reserve(n + 1);  //
   // class CString
   //
   //==============================================================================
  
     while (n--)  CString::CString(const CString& cstr) : _rep(0)
         _rep.append(*x++);  {
       if (cstr._rep)
       {
           size_t n = strlen(cstr._rep) + 1;
           _rep = (char*)operator new(n);
           memcpy(_rep, cstr._rep, n);
       }
   }
  
     _rep.append('\0');  CString& CString::operator=(const CString& cstr)
   {
       if (&cstr != this)
       {
           if (_rep)
           {
               operator delete(_rep);
               _rep = 0;
           }
   
           if (cstr._rep)
           {
               size_t n = strlen(cstr._rep) + 1;
               _rep = (char*)operator new(n);
               memcpy(_rep, cstr._rep, n);
           }
       }
  
     return *this;     return *this;
 } }
  
 char* String::allocateCString(Uint32 extraBytes, Boolean noThrow) const  //==============================================================================
   //
   // class StringRep
   //
   //==============================================================================
   
   StringRep StringRep::_empty_rep;
   
   inline StringRep* StringRep::alloc(size_t cap)
 { {
     Uint32 n = getLength() + 1;      StringRep* rep = (StringRep*)::operator new(
     char* str = new char[n + extraBytes];          sizeof(StringRep) + cap * sizeof(Uint16));
     char* p = str;      rep->cap = cap;
     const Char16* q = getData();      Atomic_create(&rep->refs, 1);
  
     for (Uint32 i = 0; i < n; i++)      return rep;
   }
   
   static inline void _reserve(StringRep*& rep, Uint32 cap)
   {
       if (cap > rep->cap || Atomic_get(&rep->refs) != 1)
     {     {
         Uint16 c = *q++;          size_t n = _next_pow_2(cap);
         *p++ = char(c);          StringRep* new_rep = StringRep::alloc(n);
           new_rep->size = rep->size;
           _copy(new_rep->data, rep->data, rep->size + 1);
           StringRep::unref(rep);
           rep = new_rep;
       }
   }
  
         if ((c & 0xff00) && !noThrow)  StringRep* StringRep::create(const Uint16* data, size_t size)
             throw TruncatedCharacter();  {
       StringRep* rep = StringRep::alloc(size);
       rep->size = size;
       _copy(rep->data, data, size);
       rep->data[size] = '\0';
       return rep;
     }     }
  
     return str;  StringRep* StringRep::copy_on_write(StringRep* rep)
   {
       // Return a new copy of rep. Release rep.
   
       StringRep* new_rep = StringRep::alloc(rep->size);
       new_rep->size = rep->size;
       _copy(new_rep->data, rep->data, rep->size);
       new_rep->data[new_rep->size] = '\0';
       StringRep::unref(rep);
       return new_rep;
 } }
  
 void String::appendToCString(  StringRep* StringRep::create(const char* data, size_t size)
     char* str,  
     Uint32 length,  
     Boolean noThrow) const  
 { {
     if (!str)      StringRep* rep = StringRep::alloc(size);
         throw NullPointer();      rep->size = _convert((Uint16*)rep->data, data, size);
       rep->data[rep->size] = '\0';
  
     Uint32 n = _min(getLength(), length);      return rep;
   }
  
     char* p = str + strlen(str);  StringRep* StringRep::createASCII7(const char* data, size_t size)
     const Char16* q = getData();  {
       StringRep* rep = StringRep::alloc(size);
       _copy((Uint16*)rep->data, data, size);
       rep->data[rep->size = size] = '\0';
       return rep;
   }
  
     for (Uint32 i = 0; i < n; i++)  Uint32 StringRep::length(const Uint16* str)
     {     {
         Uint16 c = *q++;      // ATTN: We could unroll this but it is infrequently called.
         *p++ = char(c);  
       const Uint16* end = (Uint16*)str;
  
         if ((c & 0xff00) && !noThrow)      while (*end++)
             throw TruncatedCharacter();          ;
   
       return end - str - 1;
     }     }
  
     *p = '\0';  //==============================================================================
   //
   // class String
   //
   //==============================================================================
   
   const String String::EMPTY;
   
   String::String(const String& str, Uint32 n)
   {
       _check_bounds(n, str._rep->size);
       _rep = StringRep::create(str._rep->data, n);
 } }
  
 Char16& String::operator[](Uint32 i)  String::String(const Char16* str)
 { {
     if (i > getLength())      _check_null_pointer(str);
         ThrowOutOfBounds();      _rep = StringRep::create((Uint16*)str, StringRep::length((Uint16*)str));
   }
  
     return _rep[i];  String::String(const Char16* str, Uint32 n)
   {
       _check_null_pointer(str);
       _rep = StringRep::create((Uint16*)str, n);
 } }
  
 const Char16 String::operator[](Uint32 i) const  String::String(const char* str)
 { {
     if (i > getLength())      _check_null_pointer(str);
         ThrowOutOfBounds();      _rep = StringRep::create(str, strlen(str));
   }
  
     return _rep[i];  String::String(const char* str, String::ASCII7Tag tag)
   {
       _check_null_pointer(str);
       _rep = StringRep::createASCII7(str, strlen(str));
 } }
  
 String& String::append(const Char16* str, Uint32 n)  String::String(const char* str, Uint32 n)
 { {
     Uint32 m = _min(StrLen(str), n);      _check_null_pointer(str);
     _rep.reserve(_rep.getSize() + m);      _rep = StringRep::create(str, n);
     _rep.remove(_rep.getSize() - 1);  
     _rep.append(str, m);  
     _rep.append('\0');  
     return *this;  
 } }
  
 void String::remove(Uint32 pos, Uint32 size)  String::String(const char* str, size_t n, String::ASCII7Tag tag)
 { {
     if (size == Uint32(-1))      _check_null_pointer(str);
         size = getLength() - pos;      _rep = StringRep::createASCII7(str, n);
   }
  
     if (pos + size > getLength())  String::String(const String& s1, const String& s2)
         ThrowOutOfBounds();  {
       size_t n1 = s1._rep->size;
       size_t n2 = s2._rep->size;
       size_t n = n1 + n2;
       _rep = StringRep::alloc(n);
       _copy(_rep->data, s1._rep->data, n1);
       _copy(_rep->data + n1, s2._rep->data, n2);
       _rep->size = n;
       _rep->data[n] = '\0';
   }
  
     if (size)  String::String(const String& s1, const char* s2)
         _rep.remove(pos, size);  {
       _check_null_pointer(s2);
       size_t n1 = s1._rep->size;
       size_t n2 = strlen(s2);
       _rep = StringRep::alloc(n1 + n2);
       _copy(_rep->data, s1._rep->data, n1);
       _rep->size = n1 + _convert((Uint16*)_rep->data + n1, s2, n2);
       _rep->data[_rep->size] = '\0';
 } }
  
 int String::compare(const Char16* s1, const Char16* s2, Uint32 n)  String::String(const char* s1, const String& s2)
 { {
     while (n--)      _check_null_pointer(s1);
       size_t n1 = strlen(s1);
       size_t n2 = s2._rep->size;
       _rep = StringRep::alloc(n1 + n2);
       _rep->size = n2 + _convert((Uint16*)_rep->data, s1, n1);
       _copy(_rep->data + n1, s2._rep->data, n2);
       _rep->data[_rep->size] = '\0';
   }
   
   String& String::assign(const String& str)
     {     {
         int r = *s1++ - *s2++;      if (_rep != str._rep)
       {
           StringRep::unref(_rep);
           StringRep::ref(_rep = str._rep);
       }
  
         if (r)      return *this;
             return r;  
     }     }
  
     return 0;  String& String::assign(const Char16* str, Uint32 n)
   {
       _check_null_pointer(str);
   
       if (n > _rep->cap || Atomic_get(&_rep->refs) != 1)
       {
           StringRep::unref(_rep);
           _rep = StringRep::alloc(n);
       }
   
       _rep->size = n;
       _copy(_rep->data, (Uint16*)str, n);
       _rep->data[n] = '\0';
   
       return *this;
 } }
  
 Boolean String::equal(const String& x, const String& y)  String& String::assign(const char* str, Uint32 n)
 { {
     if (x.getLength() != y.getLength())      _check_null_pointer(str);
         return false;  
  
     return String::compare(x.getData(), y.getData(), x.getLength()) == 0;      if (n > _rep->cap || Atomic_get(&_rep->refs) != 1)
       {
           StringRep::unref(_rep);
           _rep = StringRep::alloc(n);
       }
   
       _rep->size = _convert(_rep->data, str, n);
       _rep->data[_rep->size] = 0;
   
       return *this;
 } }
  
 Boolean String::equal(const String& x, const Char16* y)  String& String::assignASCII7(const char* str, Uint32 n)
 { {
     if (x.getLength() != StrLen(y))      _check_null_pointer(str);
         return false;  
  
     return String::compare(x.getData(), y, x.getLength()) == 0;      if (n > _rep->cap || Atomic_get(&_rep->refs) != 1)
       {
           StringRep::unref(_rep);
           _rep = StringRep::alloc(n);
       }
   
       _copy(_rep->data, str, n);
       _rep->data[_rep->size = n] = 0;
   
       return *this;
 } }
  
 Boolean String::equal(const Char16* x, const String& y)  void String::clear()
   {
       if (_rep->size)
 { {
     return equal(y, x);          if (Atomic_get(&_rep->refs) == 1)
               _rep->size = 0;
           else
           {
               StringRep::unref(_rep);
               _rep = &StringRep::_empty_rep;
           }
       }
 } }
  
 Boolean String::equal(const String& x, const char* y)  void String::reserveCapacity(Uint32 cap)
 { {
     return equal(x, String(y));      _reserve(_rep, cap);
 } }
  
 Boolean String::equal(const char* x, const String& y)  CString String::getCString() const
 { {
     return equal(String(x), y);  #ifdef PEGASUS_STRING_NO_UTF8
       char* str = (char*)operator new(_rep->size + 1);
       _copy(str, _rep->data, _rep->size);
       str[_rep->size] = '\0';
       return CString(str);
   #else
       Uint32 n = 3 * _rep->size;
       char* str = (char*)operator new(n + 1);
       size_t size = _copy_to_utf8(str, _rep->data, _rep->size);
       str[size] = '\0';
       return CString(str);
   #endif
 } }
  
   String& String::append(const Char16* str, Uint32 n)
   {
       _check_null_pointer(str);
   
       size_t old_size = _rep->size;
       size_t new_size = old_size + n;
       _reserve(_rep, new_size);
       _copy(_rep->data + old_size, (Uint16*)str, n);
       _rep->size = new_size;
       _rep->data[new_size] = '\0';
   
       return *this;
   }
  
 String String::subString(Uint32 pos, Uint32 length) const  String& String::append(const String& str)
 { {
     if (pos < getLength())      return append((Char16*)str._rep->data, str._rep->size);
   }
   
   String& String::append(const char* str, Uint32 size)
     {     {
         if (length == Uint32(-1))      _check_null_pointer(str);
             length = getLength() - pos;  
  
         return String(getData() + pos, length);      size_t old_size = _rep->size;
       size_t cap = old_size + size;
   
       _reserve(_rep, cap);
       _rep->size += _convert((Uint16*)_rep->data + old_size, str, size);
       _rep->data[_rep->size] = '\0';
   
       return *this;
     }     }
     else  
         return String();  void String::remove(Uint32 index, Uint32 n)
   {
       if (n == PEG_NOT_FOUND)
           n = _rep->size - index;
   
       _check_bounds(index + n, _rep->size);
   
       if (Atomic_get(&_rep->refs) != 1)
           _rep = StringRep::copy_on_write(_rep);
   
       assert(index + n <= _rep->size);
   
       size_t rem = _rep->size - (index + n);
       Uint16* data = _rep->data;
   
       if (rem)
           memmove(data + index, data + index + n, rem * sizeof(Uint16));
   
       _rep->size -= n;
       data[_rep->size] = '\0';
 } }
  
 Uint32 String::find(Char16 c) const  String String::subString(Uint32 index, Uint32 n) const
 { {
     const Char16* first = getData();      // ATTN: this implementation is very permissive but used for
       // backwards compatibility.
  
     for (const Char16* p = first; *p; p++)      if (index < _rep->size)
     {     {
         if (*p == c)          if (n == PEG_NOT_FOUND || n > _rep->size - index)
             return  p - first;              n = _rep->size - index;
   
           return String((Char16*)_rep->data + index, n);
     }     }
  
     return Uint32(-1);      return String();
 } }
  
 Uint32 String::find(const String& s) const  Uint32 String::find(Char16 c) const
 { {
     const Char16* pSubStr = s.getData();      Uint16* p = (Uint16*)_find(_rep->data, _rep->size, c);
     const Char16* pStr = getData();  
     Uint32 subStrLen = s.getLength();  
     Uint32 strLen = getLength();  
  
     // loop to find first char match      if (p)
     Uint32 loc = 0;          return p - _rep->data;
     for( ; loc <= (strLen-subStrLen); loc++)  
     {      return PEG_NOT_FOUND;
         if (*pStr++ == *pSubStr)  // match first char  }
   
   Uint32 String::find(Uint32 index, Char16 c) const
         {         {
             // point to substr 2nd char      _check_bounds(index, _rep->size);
             const Char16* p = pSubStr + 1;  
       if (index >= _rep->size)
           return PEG_NOT_FOUND;
  
             // Test remaining chars for equal      Uint16* p = (Uint16*)_find(_rep->data + index, _rep->size - index, c);
             Uint32 i = 1;  
             for (; i < subStrLen; i++)      if (p)
                 if (*pStr++ != *p++ )          return p - _rep->data;
                     {pStr--; break;} // break from loop  
             if (i == subStrLen)      return PEG_NOT_FOUND;
                 return loc;  
         }         }
   
   Uint32 String::_find_aux(const Char16* s, Uint32 n) const
   {
       _check_null_pointer(s);
   
       const Uint16* data = _rep->data;
       size_t rem = _rep->size;
   
       while (n <= rem)
       {
           Uint16* p = (Uint16*)_find(data, rem, s[0]);
   
           if (!p)
               break;
   
           if (memcmp(p, s, n * sizeof(Uint16)) == 0)
               return p - _rep->data;
   
           p++;
           rem -= p - data;
           data = p;
     }     }
     return -1;  
       return PEG_NOT_FOUND;
 } }
 // ATTN:KS 5 apr 2000 Need to add the Char16* version.  
 Uint32 String::find(const char* s) const Uint32 String::find(const char* s) const
 { {
       _check_null_pointer(s);
   
       // ATTN: implement faster version of this that doesn't create a string
       // object.
     return find(String(s));     return find(String(s));
 } }
  
 Uint32 String::reverseFind(Char16 c) const Uint32 String::reverseFind(Char16 c) const
 { {
     const Char16* first = getData();      Uint16 x = c;
     const Char16* last = getData() + getLength();      Uint16* p = _rep->data;
       Uint16* q = _rep->data + _rep->size;
  
     while (last != first)      while (q != p)
     {     {
         if (*--last == c)          if (*--q == x)
             return last - first;              return q - p;
     }     }
  
     return Uint32(-1);      return PEG_NOT_FOUND;
 } }
  
 int String::compare(const Char16* s1, const Char16* s2)  void String::toLower()
   {
   #ifdef PEGASUS_STRING_ENABLE_ICU
   
       if (InitializeICU::initICUSuccessful())
 { {
           //// First calculate size of resulting string. u_strToLower() returns
           //// only the size when zero is passed as the destination size argument.
   
           UErrorCode err = U_ZERO_ERROR;
   
           int32_t new_size = u_strToLower(
               NULL, 0, (UChar*)_rep->data, _rep->size, NULL, &err);
   
           //// Reserve enough space for the result.
   
           if ((Uint32)new_size > _rep->cap)
               _reserve(_rep, new_size);
   
           //// Perform the conversion (overlapping buffers are allowed).
   
           u_strToLower((UChar*)_rep->data, new_size,
               (UChar*)_rep->data, _rep->size, NULL, &err);
   
           _rep->size = new_size;
       }
   
   #endif /* PEGASUS_STRING_ENABLE_ICU */
   
       if (Atomic_get(&_rep->refs) != 1)
           _rep = StringRep::copy_on_write(_rep);
   
       Uint16* p = _rep->data;
       size_t n = _rep->size;
   
       for (; n--; p++)
       {
           if (!(*p & 0xFF00))
               *p = _to_lower(*p);
       }
   }
   
   void String::toUpper()
   {
   #ifdef PEGASUS_STRING_ENABLE_ICU
   
       if (InitializeICU::initICUSuccessful())
       {
           //// First calculate size of resulting string. u_strToUpper() returns
           //// only the size when zero is passed as the destination size argument.
   
           UErrorCode err = U_ZERO_ERROR;
   
           int32_t new_size = u_strToUpper(
               NULL, 0, (UChar*)_rep->data, _rep->size, NULL, &err);
   
           //// Reserve enough space for the result.
   
           if ((Uint32)new_size > _rep->cap)
               _reserve(_rep, new_size);
   
           //// Perform the conversion (overlapping buffers are allowed).
   
           u_strToUpper((UChar*)_rep->data, new_size,
               (UChar*)_rep->data, _rep->size, NULL, &err);
   
           _rep->size = new_size;
       }
   
   #endif /* PEGASUS_STRING_ENABLE_ICU */
   
       if (Atomic_get(&_rep->refs) != 1)
           _rep = StringRep::copy_on_write(_rep);
   
       Uint16* p = _rep->data;
       size_t n = _rep->size;
   
       for (; n--; p++)
           *p = _to_upper(*p);
   }
   
   int String::compare(const String& s1, const String& s2, Uint32 n)
   {
       assert(n <= s1._rep->size);
       assert(n <= s2._rep->size);
   
       // Ignoring error in which n is greater than s1.size() or s2.size()
       return _compare(s1._rep->data, s2._rep->data, n);
   }
   
   int String::compare(const String& s1, const String& s2)
   {
       return _compare(s1._rep->data, s2._rep->data);
   }
   
   int String::compare(const String& s1, const char* s2)
   {
       _check_null_pointer(s2);
   
   #ifdef PEGASUS_STRING_NO_UTF8
       return _compare_no_utf8(s1._rep->data, s2);
   #else
       // ATTN: optimize this!
       return String::compare(s1, String(s2));
   #endif
   }
   
   int String::compareNoCase(const String& str1, const String& str2)
   {
   #ifdef PEGASUS_STRING_ENABLE_ICU
   
       if (InitializeICU::initICUSuccessful())
       {
           return  u_strcasecmp(
               str1._rep->data, str2._rep->data, U_FOLD_CASE_DEFAULT);
       }
   
   #endif /* PEGASUS_STRING_ENABLE_ICU */
   
       const Uint16* s1 = str1._rep->data;
       const Uint16* s2 = str2._rep->data;
   
     while (*s1 && *s2)     while (*s1 && *s2)
     {     {
         int r = *s1++ - *s2++;          int r = _to_lower(*s1++) - _to_lower(*s2++);
  
         if (r)         if (r)
             return r;             return r;
Line 393 
Line 943 
     return 0;     return 0;
 } }
  
 std::ostream& operator<<(std::ostream& os, const String& x)  Boolean String::equalNoCase_aux(const String& s1, const String& s2)
 { {
     for (Uint32 i = 0, n = x.getLength(); i < n; i++)  #ifdef PEGASUS_STRING_ENABLE_ICU
         os << x[i];  
  
     return os;      return String::compareNoCase(s1, s2) == 0;
   
   #else /* PEGASUS_STRING_ENABLE_ICU */
   
       Uint16* p = (Uint16*)s1._rep->data;
       Uint16* q = (Uint16*)s2._rep->data;
       Uint32 n = s2._rep->size;
   
       while (n >= 8)
       {
           if (((p[0] - q[0]) && (_to_upper(p[0]) - _to_upper(q[0]))) ||
               ((p[1] - q[1]) && (_to_upper(p[1]) - _to_upper(q[1]))) ||
               ((p[2] - q[2]) && (_to_upper(p[2]) - _to_upper(q[2]))) ||
               ((p[3] - q[3]) && (_to_upper(p[3]) - _to_upper(q[3]))) ||
               ((p[4] - q[4]) && (_to_upper(p[4]) - _to_upper(q[4]))) ||
               ((p[5] - q[5]) && (_to_upper(p[5]) - _to_upper(q[5]))) ||
               ((p[6] - q[6]) && (_to_upper(p[6]) - _to_upper(q[6]))) ||
               ((p[7] - q[7]) && (_to_upper(p[7]) - _to_upper(q[7]))))
           {
               return false;
           }
   
           n -= 8;
           p += 8;
           q += 8;
       }
   
       while (n >= 4)
       {
           if (((p[0] - q[0]) && (_to_upper(p[0]) - _to_upper(q[0]))) ||
               ((p[1] - q[1]) && (_to_upper(p[1]) - _to_upper(q[1]))) ||
               ((p[2] - q[2]) && (_to_upper(p[2]) - _to_upper(q[2]))) ||
               ((p[3] - q[3]) && (_to_upper(p[3]) - _to_upper(q[3]))))
           {
               return false;
           }
   
           n -= 4;
           p += 4;
           q += 4;
       }
   
       while (n--)
       {
           if (((p[0] - q[0]) && (_to_upper(p[0]) - _to_upper(q[0]))))
               return false;
   
           p++;
           q++;
       }
   
       return true;
   
   #endif /* PEGASUS_STRING_ENABLE_ICU */
   }
   
   Boolean String::equalNoCase(const String& s1, const char* s2)
   {
       _check_null_pointer(s2);
   
   #if defined(PEGASUS_STRING_ENABLE_ICU)
   
       return String::equalNoCase(s1, String(s2));
   
   #elif defined(PEGASUS_STRING_NO_UTF8)
   
       const Uint16* p1 = (Uint16*)s1._rep->data;
       const char* p2 = s2;
       size_t n = s1._rep->size;
   
       while (n--)
       {
           if (!*p2)
               return false;
   
           if (_to_upper(*p1++) != CharSet::to_upper(int(*p2++)))
               return false;
       }
   
       return true;
   
   #else /* PEGASUS_STRING_ENABLE_ICU */
   
       // ATTN: optimize this!
       return String::equalNoCase(s1, String(s2));
   
   #endif /* PEGASUS_STRING_ENABLE_ICU */
 } }
  
 void String::toLower(char* str)  Boolean String::equal(const String& s1, const String& s2)
 { {
     while (*str)      return s1._rep->size == s2._rep->size && memcmp(s1._rep->data,
         tolower(*str++);          s2._rep->data, s1._rep->size * sizeof(Uint16)) == 0;
 } }
  
 String ToLower(const String& str)  Boolean String::equal(const String& s1, const char* s2)
 { {
     String tmp(str);  #ifdef PEGASUS_STRING_NO_UTF8
   
       _check_null_pointer(s2);
  
     for (Uint32 i = 0, n = tmp.getLength(); i < n; i++)      const Uint16* p = (Uint16*)s1._rep->data;
       const char* q = s2;
   
       while (*p && *q)
     {     {
         Char16 c = tmp[i];          if (*p++ != Uint16(*q++))
               return false;
       }
  
         if (c <= 127)      return !(*p || *q);
             tmp[i] = tolower(c);  
   #else /* PEGASUS_STRING_NO_UTF8 */
   
       // ATTN: optimize this!
       return String::equal(s1, String(s2));
   
   #endif /* PEGASUS_STRING_NO_UTF8 */
     }     }
  
     return tmp;  PEGASUS_STD(ostream)& operator<<(PEGASUS_STD(ostream)& os, const String& str)
   {
   #if defined(PEGASUS_OS_OS400)
   
       CString cstr = str.getCString();
       const char* utf8str = cstr;
       os << utf8str;
   
   #elif defined(PEGASUS_STRING_ENABLE_ICU)
   
       if (InitializeICU::initICUSuccessful())
       {
           char *buf = NULL;
           const int size = str.size() * 6;
           UnicodeString UniStr(
               (const UChar *)str.getChar16Data(), (int32_t)str.size());
           Uint32 bufsize = UniStr.extract(0,size,buf);
           buf = new char[bufsize+1];
           UniStr.extract(0,bufsize,buf);
           os << buf;
           os.flush();
           delete [] buf;
       }
   
   #endif /* PEGASUS_OS_OS400 */
   
       for (Uint32 i = 0, n = str.size(); i < n; i++)
       {
           Uint16 code = str[i];
   
           if (code > 0 && !(code & 0xFF00))
               os << char(code);
           else
           {
               // Print in hex format:
               char buffer[8];
               sprintf(buffer, "\\x%04X", code);
               os << buffer;
           }
       }
   
       return os;
   }
   
   void String::_append_char_aux()
   {
       StringRep* tmp;
   
       if (_rep->cap)
       {
           tmp = StringRep::alloc(2 * _rep->cap);
           tmp->size = _rep->size;
           _copy(tmp->data, _rep->data, _rep->size);
       }
       else
       {
           tmp = StringRep::alloc(8);
           tmp->size = 0;
       }
   
       StringRep::unref(_rep);
       _rep = tmp;
 } }
  
 PEGASUS_NAMESPACE_END PEGASUS_NAMESPACE_END
   
   /*
   ================================================================================
   
   String optimizations:
   
       1.  Added mechanism allowing certain functions to be inlined only when
           used by internal Pegasus modules. External modules (i.e., providers)
           link to a non-inline version, which allows for binary compatibility.
   
       2.  Implemented copy-on-write with atomic increment/decrement. This
           yieled a 10% improvement for the 'gc' benchmark and a 11% improvment
           for the 'ni1000' benchmark.
   
       3.  Employed loop unrolling in several places. For example, see:
   
               static Uint16* _find(const Uint16* s, size_t n, Uint16 c);
   
       4.  Used the "empty-rep" optimization (described in whitepaper from the
           GCC Developers Summit). This reduced default construction to a simple
           pointer assignment.
   
               inline String::String() : _rep(&_empty_rep) { }
   
       5.  Implemented Uint16 versions of toupper() and tolower() using tables.
           For example:
   
               static const char _upper[] =
               {
                   0,1,2,...255
               };
   
               inline Uint16 _to_upper(Uint16 x)
               {
                   return (x & 0xFF00) ? x : _upper[x];
               }
   
           This outperforms the system implementation by avoiding an anding
           operation.
   
       6.  Implemented char* version of the following member functions to
           eliminate unecessary creation of anonymous string objects
           (temporaries).
   
               String(const String& s1, const char* s2);
               String(const char* s1, const String& s2);
               String& String::operator=(const char* str);
               Uint32 String::find(const char* s) const;
               bool String::equal(const String& s1, const char* s2);
               static int String::compare(const String& s1, const char* s2);
               String& String::append(const char* str);
               String& String::append(const char* str, Uint32 size);
               static bool String::equalNoCase(const String& s1, const char* s2);
               String& operator=(const char* str)
               String& String::assign(const char* str)
               String& String::append(const char* str)
               Boolean operator==(const String& s1, const char* s2)
               Boolean operator==(const char* s1, const String& s2)
               Boolean operator!=(const String& s1, const char* s2)
               Boolean operator!=(const char* s1, const String& s2)
               Boolean operator<(const String& s1, const char* s2)
               Boolean operator<(const char* s1, const String& s2)
               Boolean operator>(const String& s1, const char* s2)
               Boolean operator>(const char* s1, const String& s2)
               Boolean operator<=(const String& s1, const char* s2)
               Boolean operator<=(const char* s1, const String& s2)
               Boolean operator>=(const String& s1, const char* s2)
               Boolean operator>=(const char* s1, const String& s2)
               String operator+(const String& s1, const char* s2)
               String operator+(const char* s1, const String& s2)
   
       7.  Optimized _next_pow_2(), used in rounding the capacity to the next
           power of two (algorithm from the book "Hacker's Delight").
   
               static Uint32 _next_pow_2(Uint32 x)
               {
                   if (x < 8)
                       return 8;
   
                   x--;
                   x |= (x >> 1);
                   x |= (x >> 2);
                   x |= (x >> 4);
                   x |= (x >> 8);
                   x |= (x >> 16);
                   x++;
   
                   return x;
               }
   
       8.  Implemented "concatenating constructors" to eliminate temporaries
           created by operator+(). This scheme employs the "return-value
           optimization" described by Stan Lippman.
   
               inline String operator+(const String& s1, const String& s2)
               {
                   return String(s1, s2, 0);
               }
   
       9.  Experimented to find the optimial initial size for a short string.
           Eight seems to offer the best tradoff between space and time.
   
       10. Inlined all members of the Char16 class.
   
       11. Used Uint16 internally in the String class. This showed no improvememnt
           since Char16 was already fully inlined and was essentially reduced to
           Uint16 in any case.
   
       12. Implemented conditional logic (#if) allowing error checking logic to
           be excluded to better performance. Examples include bounds checking
           and null-pointer checking.
   
       13. Used memcpy() and memcmp() where possible. These are implemented using
           the rep family of intructions under Intel and are much faster.
   
       14. Used loop unrolling, jump-tables, and short-circuiting to reduce UTF8
           copy routine overhead.
   
       15. Added ASCII7 form of the constructor and assign().
   
               String s("hello world", String::ASCII7);
   
               s.assignASCII7("hello world");
   
           This avoids checking for UTF8 when it is not needed.
   
   ================================================================================
   */


Legend:
Removed from v.1.7  
changed lines
  Added in v.1.111.2.4

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2