oculus1

diff libovr/Src/Kernel/OVR_String.h @ 3:b069a5c27388

added a couple more stuff, fixed all the LibOVR line endings
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 15 Sep 2013 04:10:05 +0300
parents e2f9e4603129
children
line diff
     1.1 --- a/libovr/Src/Kernel/OVR_String.h	Sat Sep 14 17:51:03 2013 +0300
     1.2 +++ b/libovr/Src/Kernel/OVR_String.h	Sun Sep 15 04:10:05 2013 +0300
     1.3 @@ -1,1 +1,645 @@
     1.4 -/************************************************************************************
     1.5 
     1.6 PublicHeader:   OVR.h
     1.7 Filename    :   OVR_String.h
     1.8 Content     :   String UTF8 string implementation with copy-on-write semantics
     1.9                 (thread-safe for assignment but not modification).
    1.10 Created     :   September 19, 2012
    1.11 Notes       : 
    1.12 
    1.13 Copyright   :   Copyright 2012 Oculus VR, Inc. All Rights reserved.
    1.14 
    1.15 Use of this software is subject to the terms of the Oculus license
    1.16 agreement provided at the time of installation or download, or which
    1.17 otherwise accompanies this software in either electronic or hard copy form.
    1.18 
    1.19 ************************************************************************************/
    1.20 
    1.21 #ifndef OVR_String_h
    1.22 #define OVR_String_h
    1.23 
    1.24 #include "OVR_Types.h"
    1.25 #include "OVR_Allocator.h"
    1.26 #include "OVR_UTF8Util.h"
    1.27 #include "OVR_Atomic.h"
    1.28 #include "OVR_Std.h"
    1.29 #include "OVR_Alg.h"
    1.30 
    1.31 namespace OVR {
    1.32 
    1.33 // ***** Classes
    1.34 
    1.35 class String;
    1.36 class StringBuffer;
    1.37 
    1.38 
    1.39 //-----------------------------------------------------------------------------------
    1.40 // ***** String Class 
    1.41 
    1.42 // String is UTF8 based string class with copy-on-write implementation
    1.43 // for assignment.
    1.44 
    1.45 class String
    1.46 {
    1.47 protected:
    1.48 
    1.49     enum FlagConstants
    1.50     {
    1.51         //Flag_GetLength      = 0x7FFFFFFF,
    1.52         // This flag is set if GetLength() == GetSize() for a string.
    1.53         // Avoid extra scanning is Substring and indexing logic.
    1.54         Flag_LengthIsSizeShift   = (sizeof(UPInt)*8 - 1)
    1.55     };
    1.56 
    1.57 
    1.58     // Internal structure to hold string data
    1.59     struct DataDesc
    1.60     {
    1.61         // Number of bytes. Will be the same as the number of chars if the characters
    1.62         // are ascii, may not be equal to number of chars in case string data is UTF8.
    1.63         UPInt   Size;       
    1.64         volatile SInt32 RefCount;
    1.65         char    Data[1];
    1.66 
    1.67         void    AddRef()
    1.68         {
    1.69             AtomicOps<SInt32>::ExchangeAdd_NoSync(&RefCount, 1);
    1.70         }
    1.71         // Decrement ref count. This needs to be thread-safe, since
    1.72         // a different thread could have also decremented the ref count.
    1.73         // For example, if u start off with a ref count = 2. Now if u
    1.74         // decrement the ref count and check against 0 in different
    1.75         // statements, a different thread can also decrement the ref count
    1.76         // in between our decrement and checking against 0 and will find
    1.77         // the ref count = 0 and delete the object. This will lead to a crash
    1.78         // when context switches to our thread and we'll be trying to delete
    1.79         // an already deleted object. Hence decrementing the ref count and
    1.80         // checking against 0 needs to made an atomic operation.
    1.81         void    Release()
    1.82         {
    1.83             if ((AtomicOps<SInt32>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
    1.84                 OVR_FREE(this);
    1.85         }
    1.86 
    1.87         static UPInt GetLengthFlagBit()     { return UPInt(1) << Flag_LengthIsSizeShift; }
    1.88         UPInt       GetSize() const         { return Size & ~GetLengthFlagBit() ; }
    1.89         UPInt       GetLengthFlag()  const  { return Size & GetLengthFlagBit(); }
    1.90         bool        LengthIsSize() const    { return GetLengthFlag() != 0; }
    1.91     };
    1.92 
    1.93     // Heap type of the string is encoded in the lower bits.
    1.94     enum HeapType
    1.95     {
    1.96         HT_Global   = 0,    // Heap is global.
    1.97         HT_Local    = 1,    // SF::String_loc: Heap is determined based on string's address.
    1.98         HT_Dynamic  = 2,    // SF::String_temp: Heap is stored as a part of the class.
    1.99         HT_Mask     = 3
   1.100     };
   1.101 
   1.102     union {
   1.103         DataDesc* pData;
   1.104         UPInt     HeapTypeBits;
   1.105     };
   1.106     typedef union {
   1.107         DataDesc* pData;
   1.108         UPInt     HeapTypeBits;
   1.109     } DataDescUnion;
   1.110 
   1.111     inline HeapType    GetHeapType() const { return (HeapType) (HeapTypeBits & HT_Mask); }
   1.112 
   1.113     inline DataDesc*   GetData() const
   1.114     {
   1.115         DataDescUnion u;
   1.116         u.pData    = pData;
   1.117         u.HeapTypeBits = (u.HeapTypeBits & ~(UPInt)HT_Mask);
   1.118         return u.pData;
   1.119     }
   1.120     
   1.121     inline void        SetData(DataDesc* pdesc)
   1.122     {
   1.123         HeapType ht = GetHeapType();
   1.124         pData = pdesc;
   1.125         OVR_ASSERT((HeapTypeBits & HT_Mask) == 0);
   1.126         HeapTypeBits |= ht;        
   1.127     }
   1.128 
   1.129     
   1.130     DataDesc*   AllocData(UPInt size, UPInt lengthIsSize);
   1.131     DataDesc*   AllocDataCopy1(UPInt size, UPInt lengthIsSize,
   1.132                                const char* pdata, UPInt copySize);
   1.133     DataDesc*   AllocDataCopy2(UPInt size, UPInt lengthIsSize,
   1.134                                const char* pdata1, UPInt copySize1,
   1.135                                const char* pdata2, UPInt copySize2);
   1.136 
   1.137     // Special constructor to avoid data initalization when used in derived class.
   1.138     struct NoConstructor { };
   1.139     String(const NoConstructor&) { }
   1.140 
   1.141 public:
   1.142 
   1.143     // For initializing string with dynamic buffer
   1.144     struct InitStruct
   1.145     {
   1.146         virtual ~InitStruct() { }
   1.147         virtual void InitString(char* pbuffer, UPInt size) const = 0;
   1.148     };
   1.149 
   1.150 
   1.151     // Constructors / Destructors.
   1.152     String();
   1.153     String(const char* data);
   1.154     String(const char* data1, const char* pdata2, const char* pdata3 = 0);
   1.155     String(const char* data, UPInt buflen);
   1.156     String(const String& src);
   1.157     String(const StringBuffer& src);
   1.158     String(const InitStruct& src, UPInt size);
   1.159     explicit String(const wchar_t* data);      
   1.160 
   1.161     // Destructor (Captain Obvious guarantees!)
   1.162     ~String()
   1.163     {
   1.164         GetData()->Release();
   1.165     }
   1.166 
   1.167     // Declaration of NullString
   1.168     static DataDesc NullData;
   1.169 
   1.170 
   1.171     // *** General Functions
   1.172 
   1.173     void        Clear();
   1.174 
   1.175     // For casting to a pointer to char.
   1.176     operator const char*() const        { return GetData()->Data; }
   1.177     // Pointer to raw buffer.
   1.178     const char* ToCStr() const          { return GetData()->Data; }
   1.179 
   1.180     // Returns number of bytes
   1.181     UPInt       GetSize() const         { return GetData()->GetSize() ; }
   1.182     // Tells whether or not the string is empty
   1.183     bool        IsEmpty() const         { return GetSize() == 0; }
   1.184 
   1.185     // Returns  number of characters
   1.186     UPInt       GetLength() const;
   1.187 
   1.188     // Returns  character at the specified index
   1.189     UInt32      GetCharAt(UPInt index) const;
   1.190     UInt32      GetFirstCharAt(UPInt index, const char** offset) const;
   1.191     UInt32      GetNextChar(const char** offset) const;
   1.192 
   1.193     // Appends a character
   1.194     void        AppendChar(UInt32 ch);
   1.195 
   1.196     // Append a string
   1.197     void        AppendString(const wchar_t* pstr, SPInt len = -1);
   1.198     void        AppendString(const char* putf8str, SPInt utf8StrSz = -1);
   1.199 
   1.200     // Assigned a string with dynamic data (copied through initializer).
   1.201     void        AssignString(const InitStruct& src, UPInt size);
   1.202     // Assigns string with known size.
   1.203     void        AssignString(const char* putf8str, UPInt size);
   1.204 
   1.205     //  Resize the string to the new size
   1.206 //  void        Resize(UPInt _size);
   1.207 
   1.208     // Removes the character at posAt
   1.209     void        Remove(UPInt posAt, SPInt len = 1);
   1.210 
   1.211     // Returns a String that's a substring of this.
   1.212     //  -start is the index of the first UTF8 character you want to include.
   1.213     //  -end is the index one past the last UTF8 character you want to include.
   1.214     String   Substring(UPInt start, UPInt end) const;
   1.215 
   1.216     // Case-conversion
   1.217     String   ToUpper() const;
   1.218     String   ToLower() const;
   1.219 
   1.220     // Inserts substr at posAt
   1.221     String&    Insert (const char* substr, UPInt posAt, SPInt len = -1);
   1.222 
   1.223     // Inserts character at posAt
   1.224     UPInt       InsertCharAt(UInt32 c, UPInt posAt);
   1.225 
   1.226     // Inserts substr at posAt, which is an index of a character (not byte).
   1.227     // Of size is specified, it is in bytes.
   1.228 //  String&    Insert(const UInt32* substr, UPInt posAt, SPInt size = -1);
   1.229 
   1.230     // Get Byte index of the character at position = index
   1.231     UPInt       GetByteIndex(UPInt index) const { return (UPInt)UTF8Util::GetByteIndex(index, GetData()->Data); }
   1.232 
   1.233     // Utility: case-insensitive string compare.  stricmp() & strnicmp() are not
   1.234     // ANSI or POSIX, do not seem to appear in Linux.
   1.235     static int OVR_STDCALL   CompareNoCase(const char* a, const char* b);
   1.236     static int OVR_STDCALL   CompareNoCase(const char* a, const char* b, SPInt len);
   1.237 
   1.238     // Hash function, case-insensitive
   1.239     static UPInt OVR_STDCALL BernsteinHashFunctionCIS(const void* pdataIn, UPInt size, UPInt seed = 5381);
   1.240 
   1.241     // Hash function, case-sensitive
   1.242     static UPInt OVR_STDCALL BernsteinHashFunction(const void* pdataIn, UPInt size, UPInt seed = 5381);
   1.243 
   1.244 
   1.245     // ***** File path parsing helper functions.
   1.246     // Implemented in OVR_String_FilePath.cpp.
   1.247 
   1.248     // Absolute paths can star with:
   1.249     //  - protocols:        'file://', 'http://'
   1.250     //  - windows drive:    'c:\'
   1.251     //  - UNC share name:   '\\share'
   1.252     //  - unix root         '/'
   1.253     static bool HasAbsolutePath(const char* path);
   1.254     static bool HasExtension(const char* path);
   1.255     static bool HasProtocol(const char* path);
   1.256 
   1.257     bool    HasAbsolutePath() const { return HasAbsolutePath(ToCStr()); }
   1.258     bool    HasExtension() const    { return HasExtension(ToCStr()); }
   1.259     bool    HasProtocol() const     { return HasProtocol(ToCStr()); }
   1.260 
   1.261     String  GetProtocol() const;    // Returns protocol, if any, with trailing '://'.
   1.262     String  GetPath() const;        // Returns path with trailing '/'.
   1.263     String  GetFilename() const;    // Returns filename, including extension.
   1.264     String  GetExtension() const;   // Returns extension with a dot.
   1.265 
   1.266     void    StripProtocol();        // Strips front protocol, if any, from the string.
   1.267     void    StripExtension();       // Strips off trailing extension.
   1.268     
   1.269 
   1.270     // Operators
   1.271     // Assignment
   1.272     void        operator =  (const char* str);
   1.273     void        operator =  (const wchar_t* str);
   1.274     void        operator =  (const String& src);
   1.275     void        operator =  (const StringBuffer& src);
   1.276 
   1.277     // Addition
   1.278     void        operator += (const String& src);
   1.279     void        operator += (const char* psrc)       { AppendString(psrc); }
   1.280     void        operator += (const wchar_t* psrc)    { AppendString(psrc); }
   1.281     void        operator += (char  ch)               { AppendChar(ch); }
   1.282     String      operator +  (const char* str) const;
   1.283     String      operator +  (const String& src)  const;
   1.284 
   1.285     // Comparison
   1.286     bool        operator == (const String& str) const
   1.287     {
   1.288         return (OVR_strcmp(GetData()->Data, str.GetData()->Data)== 0);
   1.289     }
   1.290 
   1.291     bool        operator != (const String& str) const
   1.292     {
   1.293         return !operator == (str);
   1.294     }
   1.295 
   1.296     bool        operator == (const char* str) const
   1.297     {
   1.298         return OVR_strcmp(GetData()->Data, str) == 0;
   1.299     }
   1.300 
   1.301     bool        operator != (const char* str) const
   1.302     {
   1.303         return !operator == (str);
   1.304     }
   1.305 
   1.306     bool        operator <  (const char* pstr) const
   1.307     {
   1.308         return OVR_strcmp(GetData()->Data, pstr) < 0;
   1.309     }
   1.310 
   1.311     bool        operator <  (const String& str) const
   1.312     {
   1.313         return *this < str.GetData()->Data;
   1.314     }
   1.315 
   1.316     bool        operator >  (const char* pstr) const
   1.317     {
   1.318         return OVR_strcmp(GetData()->Data, pstr) > 0;
   1.319     }
   1.320 
   1.321     bool        operator >  (const String& str) const
   1.322     {
   1.323         return *this > str.GetData()->Data;
   1.324     }
   1.325 
   1.326     int CompareNoCase(const char* pstr) const
   1.327     {
   1.328         return CompareNoCase(GetData()->Data, pstr);
   1.329     }
   1.330     int CompareNoCase(const String& str) const
   1.331     {
   1.332         return CompareNoCase(GetData()->Data, str.ToCStr());
   1.333     }
   1.334 
   1.335     // Accesses raw bytes
   1.336     const char&     operator [] (int index) const
   1.337     {
   1.338         OVR_ASSERT(index >= 0 && (UPInt)index < GetSize());
   1.339         return GetData()->Data[index];
   1.340     }
   1.341     const char&     operator [] (UPInt index) const
   1.342     {
   1.343         OVR_ASSERT(index < GetSize());
   1.344         return GetData()->Data[index];
   1.345     }
   1.346 
   1.347 
   1.348     // Case insensitive keys are used to look up insensitive string in hash tables
   1.349     // for SWF files with version before SWF 7.
   1.350     struct NoCaseKey
   1.351     {   
   1.352         const String* pStr;
   1.353         NoCaseKey(const String &str) : pStr(&str){};
   1.354     };
   1.355 
   1.356     bool    operator == (const NoCaseKey& strKey) const
   1.357     {
   1.358         return (CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
   1.359     }
   1.360     bool    operator != (const NoCaseKey& strKey) const
   1.361     {
   1.362         return !(CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
   1.363     }
   1.364 
   1.365     // Hash functor used for strings.
   1.366     struct HashFunctor
   1.367     {    
   1.368         UPInt  operator()(const String& data) const
   1.369         {
   1.370             UPInt  size = data.GetSize();
   1.371             return String::BernsteinHashFunction((const char*)data, size);
   1.372         }        
   1.373     };
   1.374     // Case-insensitive hash functor used for strings. Supports additional
   1.375     // lookup based on NoCaseKey.
   1.376     struct NoCaseHashFunctor
   1.377     {    
   1.378         UPInt  operator()(const String& data) const
   1.379         {
   1.380             UPInt  size = data.GetSize();
   1.381             return String::BernsteinHashFunctionCIS((const char*)data, size);
   1.382         }
   1.383         UPInt  operator()(const NoCaseKey& data) const
   1.384         {       
   1.385             UPInt  size = data.pStr->GetSize();
   1.386             return String::BernsteinHashFunctionCIS((const char*)data.pStr->ToCStr(), size);
   1.387         }
   1.388     };
   1.389 
   1.390 };
   1.391 
   1.392 
   1.393 //-----------------------------------------------------------------------------------
   1.394 // ***** String Buffer used for Building Strings
   1.395 
   1.396 class StringBuffer
   1.397 {
   1.398     char*           pData;
   1.399     UPInt           Size;
   1.400     UPInt           BufferSize;
   1.401     UPInt           GrowSize;    
   1.402     mutable bool    LengthIsSize;    
   1.403 
   1.404 public:
   1.405 
   1.406     // Constructors / Destructor.    
   1.407     StringBuffer();
   1.408     explicit StringBuffer(UPInt growSize);
   1.409     StringBuffer(const char* data);
   1.410     StringBuffer(const char* data, UPInt buflen);
   1.411     StringBuffer(const String& src);
   1.412     StringBuffer(const StringBuffer& src);
   1.413     explicit StringBuffer(const wchar_t* data);
   1.414     ~StringBuffer();
   1.415     
   1.416 
   1.417     // Modify grow size used for growing/shrinking the buffer.
   1.418     UPInt       GetGrowSize() const         { return GrowSize; }
   1.419     void        SetGrowSize(UPInt growSize);
   1.420     
   1.421 
   1.422     // *** General Functions
   1.423     // Does not release memory, just sets Size to 0
   1.424     void        Clear();
   1.425 
   1.426     // For casting to a pointer to char.
   1.427     operator const char*() const        { return (pData) ? pData : ""; }
   1.428     // Pointer to raw buffer.
   1.429     const char* ToCStr() const          { return (pData) ? pData : ""; }
   1.430 
   1.431     // Returns number of bytes.
   1.432     UPInt       GetSize() const         { return Size ; }
   1.433     // Tells whether or not the string is empty.
   1.434     bool        IsEmpty() const         { return GetSize() == 0; }
   1.435 
   1.436     // Returns  number of characters
   1.437     UPInt       GetLength() const;
   1.438 
   1.439     // Returns  character at the specified index
   1.440     UInt32      GetCharAt(UPInt index) const;
   1.441     UInt32      GetFirstCharAt(UPInt index, const char** offset) const;
   1.442     UInt32      GetNextChar(const char** offset) const;
   1.443 
   1.444 
   1.445     //  Resize the string to the new size
   1.446     void        Resize(UPInt _size);
   1.447     void        Reserve(UPInt _size);
   1.448 
   1.449     // Appends a character
   1.450     void        AppendChar(UInt32 ch);
   1.451 
   1.452     // Append a string
   1.453     void        AppendString(const wchar_t* pstr, SPInt len = -1);
   1.454     void        AppendString(const char* putf8str, SPInt utf8StrSz = -1);
   1.455     void        AppendFormat(const char* format, ...);
   1.456 
   1.457     // Assigned a string with dynamic data (copied through initializer).
   1.458     //void        AssignString(const InitStruct& src, UPInt size);
   1.459 
   1.460     // Inserts substr at posAt
   1.461     void        Insert (const char* substr, UPInt posAt, SPInt len = -1);
   1.462     // Inserts character at posAt
   1.463     UPInt       InsertCharAt(UInt32 c, UPInt posAt);
   1.464 
   1.465     // Assignment
   1.466     void        operator =  (const char* str);
   1.467     void        operator =  (const wchar_t* str);
   1.468     void        operator =  (const String& src);
   1.469 
   1.470     // Addition
   1.471     void        operator += (const String& src)      { AppendString(src.ToCStr(),src.GetSize()); }
   1.472     void        operator += (const char* psrc)       { AppendString(psrc); }
   1.473     void        operator += (const wchar_t* psrc)    { AppendString(psrc); }
   1.474     void        operator += (char  ch)               { AppendChar(ch); }
   1.475     //String   operator +  (const char* str) const ;
   1.476     //String   operator +  (const String& src)  const ;
   1.477 
   1.478     // Accesses raw bytes
   1.479     char&       operator [] (int index)
   1.480     {
   1.481         OVR_ASSERT(((UPInt)index) < GetSize());
   1.482         return pData[index];
   1.483     }
   1.484     char&       operator [] (UPInt index)
   1.485     {
   1.486         OVR_ASSERT(index < GetSize());
   1.487         return pData[index];
   1.488     }
   1.489 
   1.490     const char&     operator [] (int index) const 
   1.491     {
   1.492         OVR_ASSERT(((UPInt)index) < GetSize());
   1.493         return pData[index];
   1.494     }
   1.495     const char&     operator [] (UPInt index) const
   1.496     {
   1.497         OVR_ASSERT(index < GetSize());
   1.498         return pData[index];
   1.499     }
   1.500 };
   1.501 
   1.502 
   1.503 //
   1.504 // Wrapper for string data. The data must have a guaranteed 
   1.505 // lifespan throughout the usage of the wrapper. Not intended for 
   1.506 // cached usage. Not thread safe.
   1.507 //
   1.508 class StringDataPtr
   1.509 {
   1.510 public:
   1.511     StringDataPtr() : pStr(NULL), Size(0) {}
   1.512     StringDataPtr(const StringDataPtr& p)
   1.513         : pStr(p.pStr), Size(p.Size) {}
   1.514     StringDataPtr(const char* pstr, UPInt sz)
   1.515         : pStr(pstr), Size(sz) {}
   1.516     StringDataPtr(const char* pstr)
   1.517         : pStr(pstr), Size((pstr != NULL) ? OVR_strlen(pstr) : 0) {}
   1.518     explicit StringDataPtr(const String& str)
   1.519         : pStr(str.ToCStr()), Size(str.GetSize()) {}
   1.520     template <typename T, int N> 
   1.521     StringDataPtr(const T (&v)[N])
   1.522         : pStr(v), Size(N) {}
   1.523 
   1.524 public:
   1.525     const char* ToCStr() const { return pStr; }
   1.526     UPInt       GetSize() const { return Size; }
   1.527     bool        IsEmpty() const { return GetSize() == 0; }
   1.528 
   1.529     // value is a prefix of this string
   1.530     // Character's values are not compared.
   1.531     bool        IsPrefix(const StringDataPtr& value) const
   1.532     {
   1.533         return ToCStr() == value.ToCStr() && GetSize() >= value.GetSize();
   1.534     }
   1.535     // value is a suffix of this string
   1.536     // Character's values are not compared.
   1.537     bool        IsSuffix(const StringDataPtr& value) const
   1.538     {
   1.539         return ToCStr() <= value.ToCStr() && (End()) == (value.End());
   1.540     }
   1.541 
   1.542     // Find first character.
   1.543     // init_ind - initial index.
   1.544     SPInt       FindChar(char c, UPInt init_ind = 0) const 
   1.545     {
   1.546         for (UPInt i = init_ind; i < GetSize(); ++i)
   1.547             if (pStr[i] == c)
   1.548                 return static_cast<SPInt>(i);
   1.549 
   1.550         return -1; 
   1.551     }
   1.552 
   1.553     // Find last character.
   1.554     // init_ind - initial index.
   1.555     SPInt       FindLastChar(char c, UPInt init_ind = ~0) const 
   1.556     {
   1.557         if (init_ind == (UPInt)~0 || init_ind > GetSize())
   1.558             init_ind = GetSize();
   1.559         else
   1.560             ++init_ind;
   1.561 
   1.562         for (UPInt i = init_ind; i > 0; --i)
   1.563             if (pStr[i - 1] == c)
   1.564                 return static_cast<SPInt>(i - 1);
   1.565 
   1.566         return -1; 
   1.567     }
   1.568 
   1.569     // Create new object and trim size bytes from the left.
   1.570     StringDataPtr  GetTrimLeft(UPInt size) const
   1.571     {
   1.572         // Limit trim size to the size of the string.
   1.573         size = Alg::PMin(GetSize(), size);
   1.574 
   1.575         return StringDataPtr(ToCStr() + size, GetSize() - size);
   1.576     }
   1.577     // Create new object and trim size bytes from the right.
   1.578     StringDataPtr  GetTrimRight(UPInt size) const
   1.579     {
   1.580         // Limit trim to the size of the string.
   1.581         size = Alg::PMin(GetSize(), size);
   1.582 
   1.583         return StringDataPtr(ToCStr(), GetSize() - size);
   1.584     }
   1.585 
   1.586     // Create new object, which contains next token.
   1.587     // Useful for parsing.
   1.588     StringDataPtr GetNextToken(char separator = ':') const
   1.589     {
   1.590         UPInt cur_pos = 0;
   1.591         const char* cur_str = ToCStr();
   1.592 
   1.593         for (; cur_pos < GetSize() && cur_str[cur_pos]; ++cur_pos)
   1.594         {
   1.595             if (cur_str[cur_pos] == separator)
   1.596             {
   1.597                 break;
   1.598             }
   1.599         }
   1.600 
   1.601         return StringDataPtr(ToCStr(), cur_pos);
   1.602     }
   1.603 
   1.604     // Trim size bytes from the left.
   1.605     StringDataPtr& TrimLeft(UPInt size)
   1.606     {
   1.607         // Limit trim size to the size of the string.
   1.608         size = Alg::PMin(GetSize(), size);
   1.609         pStr += size;
   1.610         Size -= size;
   1.611 
   1.612         return *this;
   1.613     }
   1.614     // Trim size bytes from the right.
   1.615     StringDataPtr& TrimRight(UPInt size)
   1.616     {
   1.617         // Limit trim to the size of the string.
   1.618         size = Alg::PMin(GetSize(), size);
   1.619         Size -= size;
   1.620 
   1.621         return *this;
   1.622     }
   1.623 
   1.624     const char* Begin() const { return ToCStr(); }
   1.625     const char* End() const { return ToCStr() + GetSize(); }
   1.626 
   1.627     // Hash functor used string data pointers
   1.628     struct HashFunctor
   1.629     {    
   1.630         UPInt operator()(const StringDataPtr& data) const
   1.631         {
   1.632             return String::BernsteinHashFunction(data.ToCStr(), data.GetSize());
   1.633         }        
   1.634     };
   1.635 
   1.636     bool operator== (const StringDataPtr& data) const 
   1.637     {
   1.638         return (OVR_strncmp(pStr, data.pStr, data.Size) == 0);
   1.639     }
   1.640 
   1.641 protected:
   1.642     const char* pStr;
   1.643     UPInt       Size;
   1.644 };
   1.645 
   1.646 } // OVR
   1.647 
   1.648 #endif
   1.649 \ No newline at end of file
   1.650 +/************************************************************************************
   1.651 +
   1.652 +PublicHeader:   OVR.h
   1.653 +Filename    :   OVR_String.h
   1.654 +Content     :   String UTF8 string implementation with copy-on-write semantics
   1.655 +                (thread-safe for assignment but not modification).
   1.656 +Created     :   September 19, 2012
   1.657 +Notes       : 
   1.658 +
   1.659 +Copyright   :   Copyright 2012 Oculus VR, Inc. All Rights reserved.
   1.660 +
   1.661 +Use of this software is subject to the terms of the Oculus license
   1.662 +agreement provided at the time of installation or download, or which
   1.663 +otherwise accompanies this software in either electronic or hard copy form.
   1.664 +
   1.665 +************************************************************************************/
   1.666 +
   1.667 +#ifndef OVR_String_h
   1.668 +#define OVR_String_h
   1.669 +
   1.670 +#include "OVR_Types.h"
   1.671 +#include "OVR_Allocator.h"
   1.672 +#include "OVR_UTF8Util.h"
   1.673 +#include "OVR_Atomic.h"
   1.674 +#include "OVR_Std.h"
   1.675 +#include "OVR_Alg.h"
   1.676 +
   1.677 +namespace OVR {
   1.678 +
   1.679 +// ***** Classes
   1.680 +
   1.681 +class String;
   1.682 +class StringBuffer;
   1.683 +
   1.684 +
   1.685 +//-----------------------------------------------------------------------------------
   1.686 +// ***** String Class 
   1.687 +
   1.688 +// String is UTF8 based string class with copy-on-write implementation
   1.689 +// for assignment.
   1.690 +
   1.691 +class String
   1.692 +{
   1.693 +protected:
   1.694 +
   1.695 +    enum FlagConstants
   1.696 +    {
   1.697 +        //Flag_GetLength      = 0x7FFFFFFF,
   1.698 +        // This flag is set if GetLength() == GetSize() for a string.
   1.699 +        // Avoid extra scanning is Substring and indexing logic.
   1.700 +        Flag_LengthIsSizeShift   = (sizeof(UPInt)*8 - 1)
   1.701 +    };
   1.702 +
   1.703 +
   1.704 +    // Internal structure to hold string data
   1.705 +    struct DataDesc
   1.706 +    {
   1.707 +        // Number of bytes. Will be the same as the number of chars if the characters
   1.708 +        // are ascii, may not be equal to number of chars in case string data is UTF8.
   1.709 +        UPInt   Size;       
   1.710 +        volatile SInt32 RefCount;
   1.711 +        char    Data[1];
   1.712 +
   1.713 +        void    AddRef()
   1.714 +        {
   1.715 +            AtomicOps<SInt32>::ExchangeAdd_NoSync(&RefCount, 1);
   1.716 +        }
   1.717 +        // Decrement ref count. This needs to be thread-safe, since
   1.718 +        // a different thread could have also decremented the ref count.
   1.719 +        // For example, if u start off with a ref count = 2. Now if u
   1.720 +        // decrement the ref count and check against 0 in different
   1.721 +        // statements, a different thread can also decrement the ref count
   1.722 +        // in between our decrement and checking against 0 and will find
   1.723 +        // the ref count = 0 and delete the object. This will lead to a crash
   1.724 +        // when context switches to our thread and we'll be trying to delete
   1.725 +        // an already deleted object. Hence decrementing the ref count and
   1.726 +        // checking against 0 needs to made an atomic operation.
   1.727 +        void    Release()
   1.728 +        {
   1.729 +            if ((AtomicOps<SInt32>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
   1.730 +                OVR_FREE(this);
   1.731 +        }
   1.732 +
   1.733 +        static UPInt GetLengthFlagBit()     { return UPInt(1) << Flag_LengthIsSizeShift; }
   1.734 +        UPInt       GetSize() const         { return Size & ~GetLengthFlagBit() ; }
   1.735 +        UPInt       GetLengthFlag()  const  { return Size & GetLengthFlagBit(); }
   1.736 +        bool        LengthIsSize() const    { return GetLengthFlag() != 0; }
   1.737 +    };
   1.738 +
   1.739 +    // Heap type of the string is encoded in the lower bits.
   1.740 +    enum HeapType
   1.741 +    {
   1.742 +        HT_Global   = 0,    // Heap is global.
   1.743 +        HT_Local    = 1,    // SF::String_loc: Heap is determined based on string's address.
   1.744 +        HT_Dynamic  = 2,    // SF::String_temp: Heap is stored as a part of the class.
   1.745 +        HT_Mask     = 3
   1.746 +    };
   1.747 +
   1.748 +    union {
   1.749 +        DataDesc* pData;
   1.750 +        UPInt     HeapTypeBits;
   1.751 +    };
   1.752 +    typedef union {
   1.753 +        DataDesc* pData;
   1.754 +        UPInt     HeapTypeBits;
   1.755 +    } DataDescUnion;
   1.756 +
   1.757 +    inline HeapType    GetHeapType() const { return (HeapType) (HeapTypeBits & HT_Mask); }
   1.758 +
   1.759 +    inline DataDesc*   GetData() const
   1.760 +    {
   1.761 +        DataDescUnion u;
   1.762 +        u.pData    = pData;
   1.763 +        u.HeapTypeBits = (u.HeapTypeBits & ~(UPInt)HT_Mask);
   1.764 +        return u.pData;
   1.765 +    }
   1.766 +    
   1.767 +    inline void        SetData(DataDesc* pdesc)
   1.768 +    {
   1.769 +        HeapType ht = GetHeapType();
   1.770 +        pData = pdesc;
   1.771 +        OVR_ASSERT((HeapTypeBits & HT_Mask) == 0);
   1.772 +        HeapTypeBits |= ht;        
   1.773 +    }
   1.774 +
   1.775 +    
   1.776 +    DataDesc*   AllocData(UPInt size, UPInt lengthIsSize);
   1.777 +    DataDesc*   AllocDataCopy1(UPInt size, UPInt lengthIsSize,
   1.778 +                               const char* pdata, UPInt copySize);
   1.779 +    DataDesc*   AllocDataCopy2(UPInt size, UPInt lengthIsSize,
   1.780 +                               const char* pdata1, UPInt copySize1,
   1.781 +                               const char* pdata2, UPInt copySize2);
   1.782 +
   1.783 +    // Special constructor to avoid data initalization when used in derived class.
   1.784 +    struct NoConstructor { };
   1.785 +    String(const NoConstructor&) { }
   1.786 +
   1.787 +public:
   1.788 +
   1.789 +    // For initializing string with dynamic buffer
   1.790 +    struct InitStruct
   1.791 +    {
   1.792 +        virtual ~InitStruct() { }
   1.793 +        virtual void InitString(char* pbuffer, UPInt size) const = 0;
   1.794 +    };
   1.795 +
   1.796 +
   1.797 +    // Constructors / Destructors.
   1.798 +    String();
   1.799 +    String(const char* data);
   1.800 +    String(const char* data1, const char* pdata2, const char* pdata3 = 0);
   1.801 +    String(const char* data, UPInt buflen);
   1.802 +    String(const String& src);
   1.803 +    String(const StringBuffer& src);
   1.804 +    String(const InitStruct& src, UPInt size);
   1.805 +    explicit String(const wchar_t* data);      
   1.806 +
   1.807 +    // Destructor (Captain Obvious guarantees!)
   1.808 +    ~String()
   1.809 +    {
   1.810 +        GetData()->Release();
   1.811 +    }
   1.812 +
   1.813 +    // Declaration of NullString
   1.814 +    static DataDesc NullData;
   1.815 +
   1.816 +
   1.817 +    // *** General Functions
   1.818 +
   1.819 +    void        Clear();
   1.820 +
   1.821 +    // For casting to a pointer to char.
   1.822 +    operator const char*() const        { return GetData()->Data; }
   1.823 +    // Pointer to raw buffer.
   1.824 +    const char* ToCStr() const          { return GetData()->Data; }
   1.825 +
   1.826 +    // Returns number of bytes
   1.827 +    UPInt       GetSize() const         { return GetData()->GetSize() ; }
   1.828 +    // Tells whether or not the string is empty
   1.829 +    bool        IsEmpty() const         { return GetSize() == 0; }
   1.830 +
   1.831 +    // Returns  number of characters
   1.832 +    UPInt       GetLength() const;
   1.833 +
   1.834 +    // Returns  character at the specified index
   1.835 +    UInt32      GetCharAt(UPInt index) const;
   1.836 +    UInt32      GetFirstCharAt(UPInt index, const char** offset) const;
   1.837 +    UInt32      GetNextChar(const char** offset) const;
   1.838 +
   1.839 +    // Appends a character
   1.840 +    void        AppendChar(UInt32 ch);
   1.841 +
   1.842 +    // Append a string
   1.843 +    void        AppendString(const wchar_t* pstr, SPInt len = -1);
   1.844 +    void        AppendString(const char* putf8str, SPInt utf8StrSz = -1);
   1.845 +
   1.846 +    // Assigned a string with dynamic data (copied through initializer).
   1.847 +    void        AssignString(const InitStruct& src, UPInt size);
   1.848 +    // Assigns string with known size.
   1.849 +    void        AssignString(const char* putf8str, UPInt size);
   1.850 +
   1.851 +    //  Resize the string to the new size
   1.852 +//  void        Resize(UPInt _size);
   1.853 +
   1.854 +    // Removes the character at posAt
   1.855 +    void        Remove(UPInt posAt, SPInt len = 1);
   1.856 +
   1.857 +    // Returns a String that's a substring of this.
   1.858 +    //  -start is the index of the first UTF8 character you want to include.
   1.859 +    //  -end is the index one past the last UTF8 character you want to include.
   1.860 +    String   Substring(UPInt start, UPInt end) const;
   1.861 +
   1.862 +    // Case-conversion
   1.863 +    String   ToUpper() const;
   1.864 +    String   ToLower() const;
   1.865 +
   1.866 +    // Inserts substr at posAt
   1.867 +    String&    Insert (const char* substr, UPInt posAt, SPInt len = -1);
   1.868 +
   1.869 +    // Inserts character at posAt
   1.870 +    UPInt       InsertCharAt(UInt32 c, UPInt posAt);
   1.871 +
   1.872 +    // Inserts substr at posAt, which is an index of a character (not byte).
   1.873 +    // Of size is specified, it is in bytes.
   1.874 +//  String&    Insert(const UInt32* substr, UPInt posAt, SPInt size = -1);
   1.875 +
   1.876 +    // Get Byte index of the character at position = index
   1.877 +    UPInt       GetByteIndex(UPInt index) const { return (UPInt)UTF8Util::GetByteIndex(index, GetData()->Data); }
   1.878 +
   1.879 +    // Utility: case-insensitive string compare.  stricmp() & strnicmp() are not
   1.880 +    // ANSI or POSIX, do not seem to appear in Linux.
   1.881 +    static int OVR_STDCALL   CompareNoCase(const char* a, const char* b);
   1.882 +    static int OVR_STDCALL   CompareNoCase(const char* a, const char* b, SPInt len);
   1.883 +
   1.884 +    // Hash function, case-insensitive
   1.885 +    static UPInt OVR_STDCALL BernsteinHashFunctionCIS(const void* pdataIn, UPInt size, UPInt seed = 5381);
   1.886 +
   1.887 +    // Hash function, case-sensitive
   1.888 +    static UPInt OVR_STDCALL BernsteinHashFunction(const void* pdataIn, UPInt size, UPInt seed = 5381);
   1.889 +
   1.890 +
   1.891 +    // ***** File path parsing helper functions.
   1.892 +    // Implemented in OVR_String_FilePath.cpp.
   1.893 +
   1.894 +    // Absolute paths can star with:
   1.895 +    //  - protocols:        'file://', 'http://'
   1.896 +    //  - windows drive:    'c:\'
   1.897 +    //  - UNC share name:   '\\share'
   1.898 +    //  - unix root         '/'
   1.899 +    static bool HasAbsolutePath(const char* path);
   1.900 +    static bool HasExtension(const char* path);
   1.901 +    static bool HasProtocol(const char* path);
   1.902 +
   1.903 +    bool    HasAbsolutePath() const { return HasAbsolutePath(ToCStr()); }
   1.904 +    bool    HasExtension() const    { return HasExtension(ToCStr()); }
   1.905 +    bool    HasProtocol() const     { return HasProtocol(ToCStr()); }
   1.906 +
   1.907 +    String  GetProtocol() const;    // Returns protocol, if any, with trailing '://'.
   1.908 +    String  GetPath() const;        // Returns path with trailing '/'.
   1.909 +    String  GetFilename() const;    // Returns filename, including extension.
   1.910 +    String  GetExtension() const;   // Returns extension with a dot.
   1.911 +
   1.912 +    void    StripProtocol();        // Strips front protocol, if any, from the string.
   1.913 +    void    StripExtension();       // Strips off trailing extension.
   1.914 +    
   1.915 +
   1.916 +    // Operators
   1.917 +    // Assignment
   1.918 +    void        operator =  (const char* str);
   1.919 +    void        operator =  (const wchar_t* str);
   1.920 +    void        operator =  (const String& src);
   1.921 +    void        operator =  (const StringBuffer& src);
   1.922 +
   1.923 +    // Addition
   1.924 +    void        operator += (const String& src);
   1.925 +    void        operator += (const char* psrc)       { AppendString(psrc); }
   1.926 +    void        operator += (const wchar_t* psrc)    { AppendString(psrc); }
   1.927 +    void        operator += (char  ch)               { AppendChar(ch); }
   1.928 +    String      operator +  (const char* str) const;
   1.929 +    String      operator +  (const String& src)  const;
   1.930 +
   1.931 +    // Comparison
   1.932 +    bool        operator == (const String& str) const
   1.933 +    {
   1.934 +        return (OVR_strcmp(GetData()->Data, str.GetData()->Data)== 0);
   1.935 +    }
   1.936 +
   1.937 +    bool        operator != (const String& str) const
   1.938 +    {
   1.939 +        return !operator == (str);
   1.940 +    }
   1.941 +
   1.942 +    bool        operator == (const char* str) const
   1.943 +    {
   1.944 +        return OVR_strcmp(GetData()->Data, str) == 0;
   1.945 +    }
   1.946 +
   1.947 +    bool        operator != (const char* str) const
   1.948 +    {
   1.949 +        return !operator == (str);
   1.950 +    }
   1.951 +
   1.952 +    bool        operator <  (const char* pstr) const
   1.953 +    {
   1.954 +        return OVR_strcmp(GetData()->Data, pstr) < 0;
   1.955 +    }
   1.956 +
   1.957 +    bool        operator <  (const String& str) const
   1.958 +    {
   1.959 +        return *this < str.GetData()->Data;
   1.960 +    }
   1.961 +
   1.962 +    bool        operator >  (const char* pstr) const
   1.963 +    {
   1.964 +        return OVR_strcmp(GetData()->Data, pstr) > 0;
   1.965 +    }
   1.966 +
   1.967 +    bool        operator >  (const String& str) const
   1.968 +    {
   1.969 +        return *this > str.GetData()->Data;
   1.970 +    }
   1.971 +
   1.972 +    int CompareNoCase(const char* pstr) const
   1.973 +    {
   1.974 +        return CompareNoCase(GetData()->Data, pstr);
   1.975 +    }
   1.976 +    int CompareNoCase(const String& str) const
   1.977 +    {
   1.978 +        return CompareNoCase(GetData()->Data, str.ToCStr());
   1.979 +    }
   1.980 +
   1.981 +    // Accesses raw bytes
   1.982 +    const char&     operator [] (int index) const
   1.983 +    {
   1.984 +        OVR_ASSERT(index >= 0 && (UPInt)index < GetSize());
   1.985 +        return GetData()->Data[index];
   1.986 +    }
   1.987 +    const char&     operator [] (UPInt index) const
   1.988 +    {
   1.989 +        OVR_ASSERT(index < GetSize());
   1.990 +        return GetData()->Data[index];
   1.991 +    }
   1.992 +
   1.993 +
   1.994 +    // Case insensitive keys are used to look up insensitive string in hash tables
   1.995 +    // for SWF files with version before SWF 7.
   1.996 +    struct NoCaseKey
   1.997 +    {   
   1.998 +        const String* pStr;
   1.999 +        NoCaseKey(const String &str) : pStr(&str){};
  1.1000 +    };
  1.1001 +
  1.1002 +    bool    operator == (const NoCaseKey& strKey) const
  1.1003 +    {
  1.1004 +        return (CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
  1.1005 +    }
  1.1006 +    bool    operator != (const NoCaseKey& strKey) const
  1.1007 +    {
  1.1008 +        return !(CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
  1.1009 +    }
  1.1010 +
  1.1011 +    // Hash functor used for strings.
  1.1012 +    struct HashFunctor
  1.1013 +    {    
  1.1014 +        UPInt  operator()(const String& data) const
  1.1015 +        {
  1.1016 +            UPInt  size = data.GetSize();
  1.1017 +            return String::BernsteinHashFunction((const char*)data, size);
  1.1018 +        }        
  1.1019 +    };
  1.1020 +    // Case-insensitive hash functor used for strings. Supports additional
  1.1021 +    // lookup based on NoCaseKey.
  1.1022 +    struct NoCaseHashFunctor
  1.1023 +    {    
  1.1024 +        UPInt  operator()(const String& data) const
  1.1025 +        {
  1.1026 +            UPInt  size = data.GetSize();
  1.1027 +            return String::BernsteinHashFunctionCIS((const char*)data, size);
  1.1028 +        }
  1.1029 +        UPInt  operator()(const NoCaseKey& data) const
  1.1030 +        {       
  1.1031 +            UPInt  size = data.pStr->GetSize();
  1.1032 +            return String::BernsteinHashFunctionCIS((const char*)data.pStr->ToCStr(), size);
  1.1033 +        }
  1.1034 +    };
  1.1035 +
  1.1036 +};
  1.1037 +
  1.1038 +
  1.1039 +//-----------------------------------------------------------------------------------
  1.1040 +// ***** String Buffer used for Building Strings
  1.1041 +
  1.1042 +class StringBuffer
  1.1043 +{
  1.1044 +    char*           pData;
  1.1045 +    UPInt           Size;
  1.1046 +    UPInt           BufferSize;
  1.1047 +    UPInt           GrowSize;    
  1.1048 +    mutable bool    LengthIsSize;    
  1.1049 +
  1.1050 +public:
  1.1051 +
  1.1052 +    // Constructors / Destructor.    
  1.1053 +    StringBuffer();
  1.1054 +    explicit StringBuffer(UPInt growSize);
  1.1055 +    StringBuffer(const char* data);
  1.1056 +    StringBuffer(const char* data, UPInt buflen);
  1.1057 +    StringBuffer(const String& src);
  1.1058 +    StringBuffer(const StringBuffer& src);
  1.1059 +    explicit StringBuffer(const wchar_t* data);
  1.1060 +    ~StringBuffer();
  1.1061 +    
  1.1062 +
  1.1063 +    // Modify grow size used for growing/shrinking the buffer.
  1.1064 +    UPInt       GetGrowSize() const         { return GrowSize; }
  1.1065 +    void        SetGrowSize(UPInt growSize);
  1.1066 +    
  1.1067 +
  1.1068 +    // *** General Functions
  1.1069 +    // Does not release memory, just sets Size to 0
  1.1070 +    void        Clear();
  1.1071 +
  1.1072 +    // For casting to a pointer to char.
  1.1073 +    operator const char*() const        { return (pData) ? pData : ""; }
  1.1074 +    // Pointer to raw buffer.
  1.1075 +    const char* ToCStr() const          { return (pData) ? pData : ""; }
  1.1076 +
  1.1077 +    // Returns number of bytes.
  1.1078 +    UPInt       GetSize() const         { return Size ; }
  1.1079 +    // Tells whether or not the string is empty.
  1.1080 +    bool        IsEmpty() const         { return GetSize() == 0; }
  1.1081 +
  1.1082 +    // Returns  number of characters
  1.1083 +    UPInt       GetLength() const;
  1.1084 +
  1.1085 +    // Returns  character at the specified index
  1.1086 +    UInt32      GetCharAt(UPInt index) const;
  1.1087 +    UInt32      GetFirstCharAt(UPInt index, const char** offset) const;
  1.1088 +    UInt32      GetNextChar(const char** offset) const;
  1.1089 +
  1.1090 +
  1.1091 +    //  Resize the string to the new size
  1.1092 +    void        Resize(UPInt _size);
  1.1093 +    void        Reserve(UPInt _size);
  1.1094 +
  1.1095 +    // Appends a character
  1.1096 +    void        AppendChar(UInt32 ch);
  1.1097 +
  1.1098 +    // Append a string
  1.1099 +    void        AppendString(const wchar_t* pstr, SPInt len = -1);
  1.1100 +    void        AppendString(const char* putf8str, SPInt utf8StrSz = -1);
  1.1101 +    void        AppendFormat(const char* format, ...);
  1.1102 +
  1.1103 +    // Assigned a string with dynamic data (copied through initializer).
  1.1104 +    //void        AssignString(const InitStruct& src, UPInt size);
  1.1105 +
  1.1106 +    // Inserts substr at posAt
  1.1107 +    void        Insert (const char* substr, UPInt posAt, SPInt len = -1);
  1.1108 +    // Inserts character at posAt
  1.1109 +    UPInt       InsertCharAt(UInt32 c, UPInt posAt);
  1.1110 +
  1.1111 +    // Assignment
  1.1112 +    void        operator =  (const char* str);
  1.1113 +    void        operator =  (const wchar_t* str);
  1.1114 +    void        operator =  (const String& src);
  1.1115 +
  1.1116 +    // Addition
  1.1117 +    void        operator += (const String& src)      { AppendString(src.ToCStr(),src.GetSize()); }
  1.1118 +    void        operator += (const char* psrc)       { AppendString(psrc); }
  1.1119 +    void        operator += (const wchar_t* psrc)    { AppendString(psrc); }
  1.1120 +    void        operator += (char  ch)               { AppendChar(ch); }
  1.1121 +    //String   operator +  (const char* str) const ;
  1.1122 +    //String   operator +  (const String& src)  const ;
  1.1123 +
  1.1124 +    // Accesses raw bytes
  1.1125 +    char&       operator [] (int index)
  1.1126 +    {
  1.1127 +        OVR_ASSERT(((UPInt)index) < GetSize());
  1.1128 +        return pData[index];
  1.1129 +    }
  1.1130 +    char&       operator [] (UPInt index)
  1.1131 +    {
  1.1132 +        OVR_ASSERT(index < GetSize());
  1.1133 +        return pData[index];
  1.1134 +    }
  1.1135 +
  1.1136 +    const char&     operator [] (int index) const 
  1.1137 +    {
  1.1138 +        OVR_ASSERT(((UPInt)index) < GetSize());
  1.1139 +        return pData[index];
  1.1140 +    }
  1.1141 +    const char&     operator [] (UPInt index) const
  1.1142 +    {
  1.1143 +        OVR_ASSERT(index < GetSize());
  1.1144 +        return pData[index];
  1.1145 +    }
  1.1146 +};
  1.1147 +
  1.1148 +
  1.1149 +//
  1.1150 +// Wrapper for string data. The data must have a guaranteed 
  1.1151 +// lifespan throughout the usage of the wrapper. Not intended for 
  1.1152 +// cached usage. Not thread safe.
  1.1153 +//
  1.1154 +class StringDataPtr
  1.1155 +{
  1.1156 +public:
  1.1157 +    StringDataPtr() : pStr(NULL), Size(0) {}
  1.1158 +    StringDataPtr(const StringDataPtr& p)
  1.1159 +        : pStr(p.pStr), Size(p.Size) {}
  1.1160 +    StringDataPtr(const char* pstr, UPInt sz)
  1.1161 +        : pStr(pstr), Size(sz) {}
  1.1162 +    StringDataPtr(const char* pstr)
  1.1163 +        : pStr(pstr), Size((pstr != NULL) ? OVR_strlen(pstr) : 0) {}
  1.1164 +    explicit StringDataPtr(const String& str)
  1.1165 +        : pStr(str.ToCStr()), Size(str.GetSize()) {}
  1.1166 +    template <typename T, int N> 
  1.1167 +    StringDataPtr(const T (&v)[N])
  1.1168 +        : pStr(v), Size(N) {}
  1.1169 +
  1.1170 +public:
  1.1171 +    const char* ToCStr() const { return pStr; }
  1.1172 +    UPInt       GetSize() const { return Size; }
  1.1173 +    bool        IsEmpty() const { return GetSize() == 0; }
  1.1174 +
  1.1175 +    // value is a prefix of this string
  1.1176 +    // Character's values are not compared.
  1.1177 +    bool        IsPrefix(const StringDataPtr& value) const
  1.1178 +    {
  1.1179 +        return ToCStr() == value.ToCStr() && GetSize() >= value.GetSize();
  1.1180 +    }
  1.1181 +    // value is a suffix of this string
  1.1182 +    // Character's values are not compared.
  1.1183 +    bool        IsSuffix(const StringDataPtr& value) const
  1.1184 +    {
  1.1185 +        return ToCStr() <= value.ToCStr() && (End()) == (value.End());
  1.1186 +    }
  1.1187 +
  1.1188 +    // Find first character.
  1.1189 +    // init_ind - initial index.
  1.1190 +    SPInt       FindChar(char c, UPInt init_ind = 0) const 
  1.1191 +    {
  1.1192 +        for (UPInt i = init_ind; i < GetSize(); ++i)
  1.1193 +            if (pStr[i] == c)
  1.1194 +                return static_cast<SPInt>(i);
  1.1195 +
  1.1196 +        return -1; 
  1.1197 +    }
  1.1198 +
  1.1199 +    // Find last character.
  1.1200 +    // init_ind - initial index.
  1.1201 +    SPInt       FindLastChar(char c, UPInt init_ind = ~0) const 
  1.1202 +    {
  1.1203 +        if (init_ind == (UPInt)~0 || init_ind > GetSize())
  1.1204 +            init_ind = GetSize();
  1.1205 +        else
  1.1206 +            ++init_ind;
  1.1207 +
  1.1208 +        for (UPInt i = init_ind; i > 0; --i)
  1.1209 +            if (pStr[i - 1] == c)
  1.1210 +                return static_cast<SPInt>(i - 1);
  1.1211 +
  1.1212 +        return -1; 
  1.1213 +    }
  1.1214 +
  1.1215 +    // Create new object and trim size bytes from the left.
  1.1216 +    StringDataPtr  GetTrimLeft(UPInt size) const
  1.1217 +    {
  1.1218 +        // Limit trim size to the size of the string.
  1.1219 +        size = Alg::PMin(GetSize(), size);
  1.1220 +
  1.1221 +        return StringDataPtr(ToCStr() + size, GetSize() - size);
  1.1222 +    }
  1.1223 +    // Create new object and trim size bytes from the right.
  1.1224 +    StringDataPtr  GetTrimRight(UPInt size) const
  1.1225 +    {
  1.1226 +        // Limit trim to the size of the string.
  1.1227 +        size = Alg::PMin(GetSize(), size);
  1.1228 +
  1.1229 +        return StringDataPtr(ToCStr(), GetSize() - size);
  1.1230 +    }
  1.1231 +
  1.1232 +    // Create new object, which contains next token.
  1.1233 +    // Useful for parsing.
  1.1234 +    StringDataPtr GetNextToken(char separator = ':') const
  1.1235 +    {
  1.1236 +        UPInt cur_pos = 0;
  1.1237 +        const char* cur_str = ToCStr();
  1.1238 +
  1.1239 +        for (; cur_pos < GetSize() && cur_str[cur_pos]; ++cur_pos)
  1.1240 +        {
  1.1241 +            if (cur_str[cur_pos] == separator)
  1.1242 +            {
  1.1243 +                break;
  1.1244 +            }
  1.1245 +        }
  1.1246 +
  1.1247 +        return StringDataPtr(ToCStr(), cur_pos);
  1.1248 +    }
  1.1249 +
  1.1250 +    // Trim size bytes from the left.
  1.1251 +    StringDataPtr& TrimLeft(UPInt size)
  1.1252 +    {
  1.1253 +        // Limit trim size to the size of the string.
  1.1254 +        size = Alg::PMin(GetSize(), size);
  1.1255 +        pStr += size;
  1.1256 +        Size -= size;
  1.1257 +
  1.1258 +        return *this;
  1.1259 +    }
  1.1260 +    // Trim size bytes from the right.
  1.1261 +    StringDataPtr& TrimRight(UPInt size)
  1.1262 +    {
  1.1263 +        // Limit trim to the size of the string.
  1.1264 +        size = Alg::PMin(GetSize(), size);
  1.1265 +        Size -= size;
  1.1266 +
  1.1267 +        return *this;
  1.1268 +    }
  1.1269 +
  1.1270 +    const char* Begin() const { return ToCStr(); }
  1.1271 +    const char* End() const { return ToCStr() + GetSize(); }
  1.1272 +
  1.1273 +    // Hash functor used string data pointers
  1.1274 +    struct HashFunctor
  1.1275 +    {    
  1.1276 +        UPInt operator()(const StringDataPtr& data) const
  1.1277 +        {
  1.1278 +            return String::BernsteinHashFunction(data.ToCStr(), data.GetSize());
  1.1279 +        }        
  1.1280 +    };
  1.1281 +
  1.1282 +    bool operator== (const StringDataPtr& data) const 
  1.1283 +    {
  1.1284 +        return (OVR_strncmp(pStr, data.pStr, data.Size) == 0);
  1.1285 +    }
  1.1286 +
  1.1287 +protected:
  1.1288 +    const char* pStr;
  1.1289 +    UPInt       Size;
  1.1290 +};
  1.1291 +
  1.1292 +} // OVR
  1.1293 +
  1.1294 +#endif