(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.23 and 1.111.6.2

version 1.23, 2001/06/16 17:30:38 version 1.111.6.2, 2005/10/08 01:59:52
Line 1 
Line 1 
 //%/////////////////////////////////////////////////////////////////////////////  //%2005////////////////////////////////////////////////////////////////////////
 // //
 // Copyright (c) 2000, 2001 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 copy // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to // of this software and associated documentation files (the "Software"), to
Line 23 
Line 30 
 // Author: Mike Brasher (mbrasher@bmc.com) // Author: Mike Brasher (mbrasher@bmc.com)
 // //
 // Modified By: // Modified By:
   //     Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
   //     Josephine Eskaline Joyce, IBM (jojustin@in.ibm.com) for Bug#3297
   //     David Dillard, VERITAS Software Corp. (david.dillard@veritas.com)
   //     Mike Brasher (mike-brasher@austin.rr.com)
 // //
 //%///////////////////////////////////////////////////////////////////////////// //%/////////////////////////////////////////////////////////////////////////////
  
   #include <cassert>
 #include <cctype>  #include "InternalException.h"
 #include "String.h"  #include "CommonUTF.h"
 #include "Exception.h"  #include "MessageLoader.h"
 #include "String.h"  #include "StringRep.h"
 #include <iostream>  
   #ifdef PEGASUS_HAS_ICU
   #include <unicode/ustring.h>
   #include <unicode/uchar.h>
   #endif
  
 PEGASUS_NAMESPACE_BEGIN PEGASUS_NAMESPACE_BEGIN
  
 #define PEGASUS_ARRAY_T String  //==============================================================================
 #include <Pegasus/Common/ArrayImpl.h>  //
 #undef PEGASUS_ARRAY_T  // Compile-time macros (undefined by default).
   //
   //     PEGASUS_STRING_NO_THROW -- suppresses throwing of exceptions
   //
   //     PEGASUS_STRING_NO_UTF8 -- don't generate slower UTF8 code.
   //
   //     PEGASUS_USE_INTERNAL_INLINES -- enables internal inlining feature.
   //
   //==============================================================================
  
 const String String::EMPTY;  //==============================================================================
   //
   // File-scope definitions:
   //
   //==============================================================================
  
 static inline void _SkipWhitespace(const Char16*& p)  const Uint8 _to_upper_tbl[256] =
 { {
     while (*p && isspace(*p))      0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
         p++;      0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
       0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
       0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
       0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
       0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
       0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
       0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
       0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
       0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
       0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
       0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
       0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
       0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
       0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
       0x58,0x59,0x5A,0x7B,0x7C,0x7D,0x7E,0x7F,
       0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
       0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
       0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
       0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
       0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
       0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
       0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
       0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
       0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
       0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
       0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
       0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
       0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
       0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
       0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
       0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
   };
   
   const Uint8 _to_lower_tbl[256] =
   {
       0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
       0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
       0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
       0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
       0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
       0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
       0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
       0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
       0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
       0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
       0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
       0x78,0x79,0x7A,0x5B,0x5C,0x5D,0x5E,0x5F,
       0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
       0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
       0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
       0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
       0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
       0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
       0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
       0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
       0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
       0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
       0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
       0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
       0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
       0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
       0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
       0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
       0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
       0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
       0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
       0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
   };
   
   // Converts 16-bit characters to upper case.
   inline Uint16 _to_upper(Uint16 x)
   {
       return (x & 0xFF00) ? x : _to_upper_tbl[x];
   }
   
   // Converts 16-bit characters to lower case.
   inline Uint16 _to_lower(Uint16 x)
   {
       return (x & 0xFF00) ? x : _to_lower_tbl[x];
   }
   
   // Rounds x to the next power of two (or just returns 8 if x < 8).
   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;
   }
   
   template<class P, class Q>
   static void _copy(P* p, const Q* q, size_t n)
   {
       // Use loop unrolling.
   
       while (n >= 8)
       {
           p[0] = q[0];
           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;
 } }
  
 inline Uint32 StrLen(const char* str)      while (n--)
           *p++ = *q++;
   }
   
   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];
  
     return strlen(str);          n -= 4;
           s += 4;
 } }
  
 inline Uint32 StrLen(const Char16* str)      if (n)
 { {
     if (!str)          if (*s == c)
         throw NullPointer();              return (Uint16*)s;
           s++;
           n--;
       }
  
     Uint32 n = 0;      if (n)
       {
           if (*s == c)
               return (Uint16*)s;
           s++;
           n--;
       }
  
     while (*str++)      if (n && *s == c)
         n++;          return (Uint16*)s;
  
     return n;      // Not found!
       return 0;
 } }
  
 String::String()  static int _compare(const Uint16* s1, const Uint16* s2)
 { {
     _rep.append('\0');      while (*s1 && *s2)
       {
           int r = *s1++ - *s2++;
   
           if (r)
               return r;
 } }
  
 String::String(const String& x) : _rep(x._rep)      if (*s2)
           return -1;
       else if (*s1)
           return 1;
   
       return 0;
   }
   
   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);
  
 String::String(const String& x, Uint32 n)      return c1 - c2;
   }
   
   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 later).
         _rep.append(*str++);      // Use loop-unrolling.
   
       while (n >=8 && ((q[0]|q[1]|q[2]|q[3]|q[4]|q[5]|q[6]|q[7]) & 0x80) == 0)
       {
           p[0] = q[0];
           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;
 } }
  
 String::String(const char* str, Uint32 n_)      while (n >=4 && ((q[0]|q[1]|q[2]|q[3]) & 0x80) == 0)
 { {
     Uint32 n = _min(strlen(str), n_);          p[0] = q[0];
     reserve(n + 1);          p[1] = q[1];
           p[2] = q[2];
           p[3] = q[3];
           p += 4;
           q += 4;
           n -= 4;
       }
  
     while (n--)      switch (n)
         _rep.append(*str++);      {
           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]|q[1]) & 0x80) == 0)
               {
                   p[0] = q[0];
                   p[1] = q[1];
                   return p + 2 - dest;
               }
               break;
           case 3:
               if (((q[0]|q[1]|q[2]) & 0x80) == 0)
               {
                   p[0] = q[0];
                   p[1] = q[1];
                   p[2] = q[2];
                   return p + 3 - dest;
               }
               break;
       }
   
       // Process remaining characters.
   
       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();                  MessageLoaderParms parms("Common.String.BAD_UTF8",
     _rep.append(x, StrLen(x) + 1);                      "The byte sequence starting at index $0 "
     return *this;                      "is not valid UTF-8 encoding.",
                        q - (const Uint8*)src);
                   throw Exception(parms);
 } }
  
 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)
 { {
     _rep.clear();                  p[0] = q[0];
     Uint32 n = strlen(x);                  p[1] = q[1];
     _rep.reserve(n + 1);                  return p + 2 - (Uint8*)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 - (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  //==============================================================================
 {  //
     Uint32 n = size() + 1;  // class StringRep
     char* str = new char[n + extraBytes];  //
     char* p = str;  //==============================================================================
     const Char16* q = getData();  
  
     for (Uint32 i = 0; i < n; i++)  StringRep StringRep::_empty_rep;
   
   inline StringRep* StringRep::alloc(size_t cap)
     {     {
         Uint16 c = *q++;      StringRep* rep = (StringRep*)::operator new(
         *p++ = char(c);          sizeof(StringRep) + cap * sizeof(Uint16));
       rep->cap = cap;
       Atomic_create(&rep->refs, 1);
  
         if ((c & 0xff00) && !noThrow)      return rep;
             throw TruncatedCharacter();  
     }     }
  
     return str;  static inline void _reserve(StringRep*& rep, Uint32 cap)
   {
       if (cap > rep->cap || Atomic_get(&rep->refs) != 1)
       {
           size_t n = _next_pow_2(cap);
           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;
       }
 } }
  
 void String::appendToCString(  StringRep* StringRep::create(const Uint16* data, size_t size)
     char* str,  
     Uint32 length,  
     Boolean noThrow) const  
 { {
     if (!str)      StringRep* rep = StringRep::alloc(size);
         throw NullPointer();      rep->size = size;
       _copy(rep->data, data, size);
       rep->data[size] = '\0';
       return rep;
   }
  
     Uint32 n = _min(size(), length);  StringRep* StringRep::copy_on_write(StringRep* rep)
   {
       // Return a new copy of rep. Release rep.
  
     char* p = str + strlen(str);      StringRep* new_rep = StringRep::alloc(rep->size);
     const Char16* q = getData();      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;
   }
  
     for (Uint32 i = 0; i < n; i++)  StringRep* StringRep::create(const char* data, size_t size)
     {     {
         Uint16 c = *q++;      StringRep* rep = StringRep::alloc(size);
         *p++ = char(c);      rep->size = _convert((Uint16*)rep->data, data, size);
       rep->data[rep->size] = '\0';
  
         if ((c & 0xff00) && !noThrow)      return rep;
             throw TruncatedCharacter();  
     }     }
  
     *p = '\0';  StringRep* StringRep::createASCII7(const char* data, size_t size)
   {
       StringRep* rep = StringRep::alloc(size);
       _copy((Uint16*)rep->data, data, size);
       rep->data[rep->size = size] = '\0';
       return rep;
 } }
  
 Char16& String::operator[](Uint32 i)  Uint32 StringRep::length(const Uint16* str)
 { {
     if (i > size())      // Note: We could unroll this but it is rarely called.
         ThrowOutOfBounds();  
       const Uint16* end = (Uint16*)str;
  
     return _rep[i];      while (*end++)
           ;
   
       return end - str - 1;
 } }
  
 const Char16 String::operator[](Uint32 i) const  //==============================================================================
   //
   // class String
   //
   //==============================================================================
   
   const String String::EMPTY;
   
   String::String(const String& str, Uint32 n)
 { {
     if (i > size())      _check_bounds(n, str._rep->size);
         ThrowOutOfBounds();      _rep = StringRep::create(str._rep->data, n);
   }
  
     return _rep[i];  String::String(const Char16* str)
   {
       _check_null_pointer(str);
       _rep = StringRep::create((Uint16*)str, StringRep::length((Uint16*)str));
 } }
  
 String& String::append(const Char16* str, Uint32 n)  String::String(const Char16* str, Uint32 n)
 { {
     Uint32 m = _min(StrLen(str), n);      _check_null_pointer(str);
     _rep.reserve(_rep.size() + m);      _rep = StringRep::create((Uint16*)str, n);
     _rep.remove(_rep.size() - 1);  
     _rep.append(str, m);  
     _rep.append('\0');  
     return *this;  
 } }
  
 void String::remove(Uint32 pos, Uint32 size)  String::String(const char* str)
 { {
     if (size == PEG_NOT_FOUND)      _check_null_pointer(str);
         size = this->size() - pos;      _rep = StringRep::create(str, strlen(str));
   }
  
     if (pos + size > this->size())  String::String(const char* str, String::ASCII7Tag tag)
         ThrowOutOfBounds();  {
       _check_null_pointer(str);
       _rep = StringRep::createASCII7(str, strlen(str));
   }
  
     if (size)  String::String(const char* str, Uint32 n)
         _rep.remove(pos, size);  {
       _check_null_pointer(str);
       _rep = StringRep::create(str, n);
 } }
  
 int String::compare(const Char16* s1, const Char16* s2, Uint32 n)  String::String(const char* str, size_t n, String::ASCII7Tag tag)
 { {
     while (n--)      _check_null_pointer(str);
       _rep = StringRep::createASCII7(str, n);
   }
   
   String::String(const String& s1, const String& s2)
     {     {
         int r = *s1++ - *s2++;      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 (r)  String::String(const String& s1, const char* s2)
             return r;  {
       _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';
     }     }
  
     return 0;  String::String(const char* s1, const String& s2)
   {
       _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';
 } }
  
 int String::compareNoCase(const char* s1, const char* s2, Uint32 n)  String& String::assign(const String& str)
 { {
     while (n--)      if (_rep != str._rep)
     {     {
         int r = tolower(*s1++) - tolower(*s2++);          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.size() != y.size())      _check_null_pointer(str);
         return false;  
       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 String::compare(x.getData(), y.getData(), x.size()) == 0;      return *this;
 } }
  
 Boolean String::equal(const String& x, const Char16* y)  String& String::assignASCII7(const char* str, Uint32 n)
 { {
     if (x.size() != StrLen(y))      _check_null_pointer(str);
         return false;  
  
     return String::compare(x.getData(), y, x.size()) == 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)
       {
           if (Atomic_get(&_rep->refs) == 1)
               _rep->size = 0;
           else
 { {
     return equal(y, x);              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
 } }
  
 Boolean String::equalNoCase(const String& x, const String& y)  String& String::append(const Char16* str, Uint32 n)
 { {
     if (x.size() != y.size())      _check_null_pointer(str);
         return false;  
  
     const Char16* p = x.getData();      size_t old_size = _rep->size;
     const Char16* q = y.getData();      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';
  
     Uint32 n = x.size();      return *this;
   }
  
     while (n--)  String& String::append(const String& str)
     {  
         if (*p <= 127 && *q <= 127)  
         {         {
             if (tolower(*p++) != tolower(*q++))      return append((Char16*)str._rep->data, str._rep->size);
                 return false;  
         }         }
         else if (*p++ != *q++)  
             return false;  String& String::append(const char* str, Uint32 size)
   {
       _check_null_pointer(str);
   
       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;
     }     }
  
     return true;  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';
 } }
  
 String String::subString(Uint32 pos, Uint32 length) const  String String::subString(Uint32 index, Uint32 n) const
 { {
     if (pos < size())      // Note: this implementation is very permissive but used for
       // backwards compatibility.
   
       if (index < _rep->size)
     {     {
         if (length == PEG_NOT_FOUND)          if (n == PEG_NOT_FOUND || n > _rep->size - index)
             length = size() - pos;              n = _rep->size - index;
  
         return String(getData() + pos, length);          return String((Char16*)_rep->data + index, n);
     }     }
     else  
         return String();         return String();
 } }
  
 Uint32 String::find(Char16 c) const Uint32 String::find(Char16 c) const
 { {
     const Char16* first = getData();      Uint16* p = (Uint16*)_find(_rep->data, _rep->size, c);
  
     for (const Char16* p = first; *p; p++)      if (p)
     {          return p - _rep->data;
         if (*p == c)  
             return  p - first;  
     }  
  
     return PEG_NOT_FOUND;     return PEG_NOT_FOUND;
 } }
  
 Uint32 String::find(const String& s) const  Uint32 String::find(Uint32 index, Char16 c) const
 { {
     const Char16* pSubStr = s.getData();      _check_bounds(index, _rep->size);
     const Char16* pStr = getData();  
     Uint32 subStrLen = s.size();      if (index >= _rep->size)
     Uint32 strLen = size();          return PEG_NOT_FOUND;
   
     // loop to find first char match      Uint16* p = (Uint16*)_find(_rep->data + index, _rep->size - index, c);
     Uint32 loc = 0;  
     for( ; loc <= (strLen-subStrLen); loc++)      if (p)
     {          return p - _rep->data;
         if (*pStr++ == *pSubStr)  // match first char  
         {      return PEG_NOT_FOUND;
             // point to substr 2nd char  
             const Char16* p = pSubStr + 1;  
   
             // Test remaining chars for equal  
             Uint32 i = 1;  
             for (; i < subStrLen; i++)  
                 if (*pStr++ != *p++ )  
                     {pStr--; break;} // break from loop  
             if (i == subStrLen)  
                 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 PEG_NOT_FOUND;     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);
   
       // Note: could optimize away creation of temporary, but this is rarely
       // called.
     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() + size();      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 PEG_NOT_FOUND;     return PEG_NOT_FOUND;
Line 398 
Line 918 
  
 void String::toLower() void String::toLower()
 { {
     for (Char16* p = &_rep[0]; *p; p++)  #ifdef PEGASUS_HAS_ICU
   
       if (InitializeICU::initICUSuccessful())
     {     {
         if (*p <= 127)          if (Atomic_get(&_rep->refs) != 1)
             *p = tolower(*p);                  _rep = StringRep::copy_on_write(_rep);
     }  
           // This will do a locale-insensitive, but context-sensitive convert.
           // Since context-sensitive casing looks at adjacent chars, this
           // prevents optimizations where the us-ascii is converted before
           // calling ICU.
           // The string may shrink or expand after the convert.
   
           //// 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);
   
           err = U_ZERO_ERROR;
   
           //// 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;
           return;
 } }
  
 void String::translate(Char16 fromChar, Char16 toChar)  #endif /* PEGASUS_HAS_ICU */
 {  
     for (Char16* p = &_rep[0]; *p; p++)      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 == fromChar)          if (!(*p & 0xFF00))
             *p = toChar;              *p = _to_lower(*p);
     }     }
 } }
  
 int String::compare(const Char16* s1, const Char16* s2)  void String::toUpper()
 { {
     while (*s1 && *s2)  #ifdef PEGASUS_HAS_ICU
   
       if (InitializeICU::initICUSuccessful())
     {     {
         int r = *s1++ - *s2++;          if (Atomic_get(&_rep->refs) != 1)
               _rep = StringRep::copy_on_write(_rep);
  
         if (r)          // This will do a locale-insensitive, but context-sensitive convert.
             return r;          // Since context-sensitive casing looks at adjacent chars, this
           // prevents optimizations where the us-ascii is converted before
           // calling ICU.
           // The string may shrink or expand after the convert.
   
           //// 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);
   
           err = U_ZERO_ERROR;
   
           //// 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;
   
           return;
     }     }
  
     if (*s2)  #endif /* PEGASUS_HAS_ICU */
         return -1;  
     else if (*s1)  
         return 1;  
  
     return 0;      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);
 } }
  
 PEGASUS_STD(ostream)& operator<<(PEGASUS_STD(ostream)& os, const String& x)  int String::compare(const String& s1, const String& s2, Uint32 n)
 { {
     for (Uint32 i = 0, n = x.size(); i < n; i++)      assert(n <= s1._rep->size);
         os << x[i];      assert(n <= s2._rep->size);
  
     return os;      // Ignoring error in which n is greater than s1.size() or s2.size()
       return _compare(s1._rep->data, s2._rep->data, n);
 } }
  
 void String::toLower(char* str)  int String::compare(const String& s1, const String& s2)
 { {
     while (*str)      return _compare(s1._rep->data, s2._rep->data);
         tolower(*str++);  
 } }
  
 String ToLower(const String& str)  int String::compare(const String& s1, const char* s2)
 { {
     String tmp(str);      _check_null_pointer(s2);
  
     for (Uint32 i = 0, n = tmp.size(); i < n; i++)  #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)
     {     {
         Char16 c = tmp[i];  #ifdef PEGASUS_HAS_ICU
  
         if (c <= 127)      if (InitializeICU::initICUSuccessful())
             tmp[i] = tolower(c);      {
           return  u_strcasecmp(
               str1._rep->data, str2._rep->data, U_FOLD_CASE_DEFAULT);
     }     }
  
     return tmp;  #endif /* PEGASUS_HAS_ICU */
 }  
       const Uint16* s1 = str1._rep->data;
       const Uint16* s2 = str2._rep->data;
  
 int CompareNoCase(const char* s1, const char* s2)  
 {  
     while (*s1 && *s2)     while (*s1 && *s2)
     {     {
         int r = tolower(*s1++) - tolower(*s2++);          int r = _to_lower(*s1++) - _to_lower(*s2++);
  
         if (r)         if (r)
             return r;             return r;
Line 479 
Line 1079 
     return 0;     return 0;
 } }
  
 Boolean GetLine(PEGASUS_STD(istream)& is, String& line)  Boolean String::equalNoCase_aux(const String& s1, const String& s2)
 { {
     line.clear();  #ifdef PEGASUS_HAS_ICU
  
     Boolean gotChar = false;      return String::compareNoCase(s1, s2) == 0;
     char c;  
  
     while (is.get(c))  #else /* PEGASUS_HAS_ICU */
     {  
         gotChar = true;  
  
         if (c == '\n')      Uint16* p = (Uint16*)s1._rep->data;
             break;      Uint16* q = (Uint16*)s2._rep->data;
       Uint32 n = s2._rep->size;
  
         line.append(c);      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;
     }     }
  
     return gotChar;          n -= 8;
           p += 8;
           q += 8;
 } }
  
 String::~String()      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;
 } }
  
 String& String::assign(const String& x)          n -= 4;
 {          p += 4;
     _rep = x._rep;          q += 4;
     return *this;  
 } }
  
 String& String::append(const Char16& c)      while (n--)
 { {
     _rep.insert(_rep.size() - 1, c);          if (((p[0] - q[0]) && (_to_upper(p[0]) - _to_upper(q[0]))))
     return *this;              return false;
   
           p++;
           q++;
 } }
  
 void String::clear()      return true;
 {  
     _rep.clear();  #endif /* PEGASUS_HAS_ICU */
     _rep.append('\0');  
 } }
  
 void String::reserve(Uint32 capacity)  Boolean String::equalNoCase(const String& s1, const char* s2)
 { {
     _rep.reserve(capacity + 1);      _check_null_pointer(s2);
 }  
   #if defined(PEGASUS_HAS_ICU)
   
       return String::equalNoCase(s1, String(s2));
   
   #elif defined(PEGASUS_STRING_NO_UTF8)
  
 const Array<String>& EmptyStringArray()      const Uint16* p1 = (Uint16*)s1._rep->data;
       const char* p2 = s2;
       size_t n = s1._rep->size;
   
       while (n--)
 { {
     static Array<String> tmp;          if (!*p2)
     return tmp;              return false;
   
           if (_to_upper(*p1++) != _to_upper_tbl[int(*p2++)])
               return false;
 } }
  
 void String::split(const String& line, Array<String>& fields)      if (*p2)
 {          return false;
     fields.clear();  
  
     for (const Char16* p = line.getData(); *p; p++)      return true;
     {  
         _SkipWhitespace(p);  
  
         if (!*p)  #else /* PEGASUS_HAS_ICU */
             break;  
  
         String field;      // ATTN: optimize this!
       return String::equalNoCase(s1, String(s2));
  
         if (*p == '"')  #endif /* PEGASUS_HAS_ICU */
         {  }
             p++;  
  
             for (; *p && *p != '"'; p++)  Boolean String::equal(const String& s1, const String& s2)
             {             {
                 if (*p == '\\')      return s1._rep->size == s2._rep->size && memcmp(s1._rep->data,
                 {          s2._rep->data, s1._rep->size * sizeof(Uint16)) == 0;
                     p++;  }
  
                     switch (*p)  Boolean String::equal(const String& s1, const char* s2)
                     {                     {
                         case '\0':  #ifdef PEGASUS_STRING_NO_UTF8
                             break;  
  
                         case 'n':      _check_null_pointer(s2);
                             field.append('\n');  
                             break;  
  
                         case 't':      const Uint16* p = (Uint16*)s1._rep->data;
                             field.append('\t');      const char* q = s2;
                             break;  
  
                         case 'r':      while (*p && *q)
                             field.append('\r');      {
                             break;          if (*p++ != Uint16(*q++))
               return false;
       }
  
                         case 'f':      return !(*p || *q);
                             field.append('\f');  
                             break;  #else /* PEGASUS_STRING_NO_UTF8 */
  
                         default:      return String::equal(s1, String(s2));
                             field.append(*p);  
   #endif /* PEGASUS_STRING_NO_UTF8 */
                     }                     }
   
   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;
       return os;
   #else
   
   #if defined(PEGASUS_HAS_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;
           return os;
                 }                 }
   
   #endif  // PEGASUS_HAS_ICU
   
       for (Uint32 i = 0, n = str.size(); i < n; i++)
       {
           Uint16 code = str[i];
   
           if (code > 0 && !(code & 0xFF00))
                   os << char(code);
                 else                 else
                     field.append(*p);              {
               // Print in hex format:
               char buffer[8];
               sprintf(buffer, "\\x%04X", code);
               os << buffer;
           }
             }             }
  
             fields.append(field);      return os;
   #endif // PEGASUS_OS_OS400
         }         }
         else  
   void String::_append_char_aux()
         {         {
             for (; *p && !isspace(*p); p++)      StringRep* tmp;
   
       if (_rep->cap)
             {             {
                 if (*p == '\\')          tmp = StringRep::alloc(2 * _rep->cap);
           tmp->size = _rep->size;
           _copy(tmp->data, _rep->data, _rep->size);
       }
       else
                 {                 {
                     p++;          tmp = StringRep::alloc(8);
           tmp->size = 0;
       }
  
                     switch (*p)      StringRep::unref(_rep);
                     {      _rep = tmp;
                         case '\0':  }
                             break;  
  
                         case 'n':  PEGASUS_NAMESPACE_END
                             field.append('\n');  
                             break;  
  
                         case 't':  /*
                             field.append('\t');  ================================================================================
                             break;  
  
                         case 'r':  String optimizations:
                             field.append('\r');  
                             break;  
  
                         case 'f':      1.  Added mechanism allowing certain functions to be inlined only when
                             field.append('\f');          used by internal Pegasus modules. External modules (i.e., providers)
                             break;          link to a non-inline version, which allows for binary compatibility.
  
                         default:      2.  Implemented copy-on-write with atomic increment/decrement. This
                             field.append(*p);          yieled a 10% improvement for the 'gc' benchmark and a 11% improvment
                     }          for the 'ni1000' benchmark.
                 }  
                 else  
                     field.append(*p);  
             }  
  
             fields.append(field);      3.  Employed loop unrolling in several places. For example, see:
         }  
  
         if (!*p)              static Uint16* _find(const Uint16* s, size_t n, Uint16 c);
             break;  
     }      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) { }
  
 void String::join(Array<String>& fields, String& line)      5.  Implemented Uint16 versions of toupper() and tolower() using tables.
           For example:
   
               static const char _upper[] =
 { {
     for (Uint32 i = 0, n = fields.size(); i < n; i++)                  0,1,2,...255
               };
   
               inline Uint16 _to_upper(Uint16 x)
     {     {
         String tmp;                  return (x & 0xFF00) ? x : _upper[x];
         Boolean hasSpaces = escape(fields[i], tmp);              }
  
         if (hasSpaces || tmp.size() == 0)          This outperforms the system implementation by avoiding an anding
             line += '"';          operation.
  
         line += tmp;      6.  Implemented char* version of the following member functions to
           eliminate unecessary creation of anonymous string objects
           (temporaries).
  
         if (hasSpaces || tmp.size() == 0)              String(const String& s1, const char* s2);
             line += '"';              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)
  
         if (i + 1 != n)      7.  Optimized _next_pow_2(), used in rounding the capacity to the next
             line += ' ';          power of two (algorithm from the book "Hacker's Delight").
     }  
 }  
  
 Boolean String::escape(const String& in, String& out)              static Uint32 _next_pow_2(Uint32 x)
 { {
     Boolean hasSpaces = false;                  if (x < 8)
                       return 8;
  
     out.reserve(out.size() + (2 * in.size()));                  x--;
                   x |= (x >> 1);
                   x |= (x >> 2);
                   x |= (x >> 4);
                   x |= (x >> 8);
                   x |= (x >> 16);
                   x++;
  
     for (Uint32 i = 0, n = in.size(); i < n; i++)                  return x;
     {              }
         Char16 c = in[i];  
       8.  Implemented "concatenating constructors" to eliminate temporaries
           created by operator+(). This scheme employs the "return-value
           optimization" described by Stan Lippman.
  
         switch (c)              inline String operator+(const String& s1, const String& s2)
         {         {
             case '\n':                  return String(s1, s2, 0);
                 out += "\\n";              }
                 break;  
  
             case '\t':      9.  Experimented to find the optimial initial size for a short string.
                 out += "\\t";          Eight seems to offer the best tradeoff between space and time.
                 break;  
  
             case '\r':      10. Inlined all members of the Char16 class.
                 out += "\\r";  
                 break;  
  
             case '\f':      11. Used Uint16 internally in the String class. This showed no improvememnt
                 out += "\\f";          since Char16 was already fully inlined and was essentially reduced to
                 break;          Uint16 in any case.
  
             case '\"':      12. Implemented conditional logic (#if) allowing error checking logic to
                 out += "\\\"";          be excluded to better performance. Examples include bounds checking
                 break;          and null-pointer checking.
  
             default:      13. Used memcpy() and memcmp() where possible. These are implemented using
                 out += c;          the rep family of intructions under Intel and are much faster.
                 if (!hasSpaces)  
                     hasSpaces = c == ' ';  
                 break;  
         }  
     }  
  
     return hasSpaces;      14. Used loop unrolling, jump-tables, and short-circuiting to reduce UTF8
 }          copy routine overhead.
  
 PEGASUS_NAMESPACE_END      15. Added ASCII7 form of the constructor and assign().
   
               String s("hello world", String::ASCII7);
   
               s.assignASCII7("hello world");
   
           This avoids slower UTF8 processing when not needed.
   
   BUG-4200 Review actions:
   
       1.  Use PEGASUS_USE_EXPERIMENTAL_INTERFACES instead of
           PEGASUS_STRING_EXTENSIONS.
   
           Status: done
   
       2.  Doc++ String.h
   
           Status: pending
   
       3.  Look at PEP223 for security coding guidelines for strings.
   
           Status: pending
   
       4.  Increasing the number of objects may break Windows 2000 build
           (limit of 2048 bytes for command line). See BUG-2754
   
           Status: looking into the use auto-generated linker files.
   
       5.  Concerns about whether generating inlines and non-inline versions
           of functions will work with all compilers.
   
           Status: confident it will work on platforms except maybe Windows.
   
   ================================================================================
   */


Legend:
Removed from v.1.23  
changed lines
  Added in v.1.111.6.2

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2