ovr_sdk

diff LibOVR/Src/Kernel/OVR_String.h @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/LibOVR/Src/Kernel/OVR_String.h	Wed Jan 14 06:51:16 2015 +0200
     1.3 @@ -0,0 +1,658 @@
     1.4 +/************************************************************************************
     1.5 +
     1.6 +PublicHeader:   OVR_Kernel.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 2014 Oculus VR, LLC All Rights reserved.
    1.14 +
    1.15 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 
    1.16 +you may not use the Oculus VR Rift SDK except in compliance with the License, 
    1.17 +which is provided at the time of installation or download, or which 
    1.18 +otherwise accompanies this software in either electronic or hard copy form.
    1.19 +
    1.20 +You may obtain a copy of the License at
    1.21 +
    1.22 +http://www.oculusvr.com/licenses/LICENSE-3.2 
    1.23 +
    1.24 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 
    1.25 +distributed under the License is distributed on an "AS IS" BASIS,
    1.26 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.27 +See the License for the specific language governing permissions and
    1.28 +limitations under the License.
    1.29 +
    1.30 +************************************************************************************/
    1.31 +
    1.32 +#ifndef OVR_String_h
    1.33 +#define OVR_String_h
    1.34 +
    1.35 +#include "OVR_Types.h"
    1.36 +#include "OVR_Allocator.h"
    1.37 +#include "OVR_UTF8Util.h"
    1.38 +#include "OVR_Atomic.h"
    1.39 +#include "OVR_Std.h"
    1.40 +#include "OVR_Alg.h"
    1.41 +
    1.42 +namespace OVR {
    1.43 +
    1.44 +// ***** Classes
    1.45 +
    1.46 +class String;
    1.47 +class StringBuffer;
    1.48 +
    1.49 +
    1.50 +//-----------------------------------------------------------------------------------
    1.51 +// ***** String Class 
    1.52 +
    1.53 +// String is UTF8 based string class with copy-on-write implementation
    1.54 +// for assignment.
    1.55 +
    1.56 +class String
    1.57 +{
    1.58 +protected:
    1.59 +
    1.60 +    enum FlagConstants
    1.61 +    {
    1.62 +        //Flag_GetLength      = 0x7FFFFFFF,
    1.63 +        // This flag is set if GetLength() == GetSize() for a string.
    1.64 +        // Avoid extra scanning is Substring and indexing logic.
    1.65 +        Flag_LengthIsSizeShift   = (sizeof(size_t)*8 - 1)
    1.66 +    };
    1.67 +
    1.68 +
    1.69 +    // Internal structure to hold string data
    1.70 +    struct DataDesc
    1.71 +    {
    1.72 +        // Number of bytes. Will be the same as the number of chars if the characters
    1.73 +        // are ascii, may not be equal to number of chars in case string data is UTF8.
    1.74 +        size_t  Size;       
    1.75 +        volatile int32_t RefCount;
    1.76 +        char    Data[1];
    1.77 +
    1.78 +        void    AddRef()
    1.79 +        {
    1.80 +            AtomicOps<int32_t>::ExchangeAdd_NoSync(&RefCount, 1);
    1.81 +        }
    1.82 +        // Decrement ref count. This needs to be thread-safe, since
    1.83 +        // a different thread could have also decremented the ref count.
    1.84 +        // For example, if u start off with a ref count = 2. Now if u
    1.85 +        // decrement the ref count and check against 0 in different
    1.86 +        // statements, a different thread can also decrement the ref count
    1.87 +        // in between our decrement and checking against 0 and will find
    1.88 +        // the ref count = 0 and delete the object. This will lead to a crash
    1.89 +        // when context switches to our thread and we'll be trying to delete
    1.90 +        // an already deleted object. Hence decrementing the ref count and
    1.91 +        // checking against 0 needs to made an atomic operation.
    1.92 +        void    Release()
    1.93 +        {
    1.94 +            if ((AtomicOps<int32_t>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
    1.95 +                OVR_FREE(this);
    1.96 +        }
    1.97 +
    1.98 +        static size_t GetLengthFlagBit()     { return size_t(1) << Flag_LengthIsSizeShift; }
    1.99 +        size_t      GetSize() const         { return Size & ~GetLengthFlagBit() ; }
   1.100 +        size_t      GetLengthFlag()  const  { return Size & GetLengthFlagBit(); }
   1.101 +        bool        LengthIsSize() const    { return GetLengthFlag() != 0; }
   1.102 +    };
   1.103 +
   1.104 +    // Heap type of the string is encoded in the lower bits.
   1.105 +    enum HeapType
   1.106 +    {
   1.107 +        HT_Global   = 0,    // Heap is global.
   1.108 +        HT_Local    = 1,    // SF::String_loc: Heap is determined based on string's address.
   1.109 +        HT_Dynamic  = 2,    // SF::String_temp: Heap is stored as a part of the class.
   1.110 +        HT_Mask     = 3
   1.111 +    };
   1.112 +
   1.113 +    union {
   1.114 +        DataDesc* pData;
   1.115 +        size_t    HeapTypeBits;
   1.116 +    };
   1.117 +    typedef union {
   1.118 +        DataDesc* pData;
   1.119 +        size_t    HeapTypeBits;
   1.120 +    } DataDescUnion;
   1.121 +
   1.122 +    inline HeapType    GetHeapType() const { return (HeapType) (HeapTypeBits & HT_Mask); }
   1.123 +
   1.124 +    inline DataDesc*   GetData() const
   1.125 +    {
   1.126 +        DataDescUnion u;
   1.127 +        u.pData    = pData;
   1.128 +        u.HeapTypeBits = (u.HeapTypeBits & ~(size_t)HT_Mask);
   1.129 +        return u.pData;
   1.130 +    }
   1.131 +    
   1.132 +    inline void        SetData(DataDesc* pdesc)
   1.133 +    {
   1.134 +        HeapType ht = GetHeapType();
   1.135 +        pData = pdesc;
   1.136 +        OVR_ASSERT((HeapTypeBits & HT_Mask) == 0);
   1.137 +        HeapTypeBits |= ht;        
   1.138 +    }
   1.139 +
   1.140 +    
   1.141 +    DataDesc*   AllocData(size_t size, size_t lengthIsSize);
   1.142 +    DataDesc*   AllocDataCopy1(size_t size, size_t lengthIsSize,
   1.143 +                               const char* pdata, size_t copySize);
   1.144 +    DataDesc*   AllocDataCopy2(size_t size, size_t lengthIsSize,
   1.145 +                               const char* pdata1, size_t copySize1,
   1.146 +                               const char* pdata2, size_t copySize2);
   1.147 +
   1.148 +    // Special constructor to avoid data initalization when used in derived class.
   1.149 +    struct NoConstructor { };
   1.150 +    String(const NoConstructor&) { }
   1.151 +
   1.152 +public:
   1.153 +
   1.154 +    // For initializing string with dynamic buffer
   1.155 +    struct InitStruct
   1.156 +    {
   1.157 +        virtual ~InitStruct() { }
   1.158 +        virtual void InitString(char* pbuffer, size_t size) const = 0;
   1.159 +    };
   1.160 +
   1.161 +
   1.162 +    // Constructors / Destructors.
   1.163 +    String();
   1.164 +    String(const char* data);
   1.165 +    String(const char* data1, const char* pdata2, const char* pdata3 = 0);
   1.166 +    String(const char* data, size_t buflen);
   1.167 +    String(const String& src);
   1.168 +    String(const StringBuffer& src);
   1.169 +    String(const InitStruct& src, size_t size);
   1.170 +    explicit String(const wchar_t* data);      
   1.171 +
   1.172 +    // Destructor (Captain Obvious guarantees!)
   1.173 +    ~String()
   1.174 +    {
   1.175 +        GetData()->Release();
   1.176 +    }
   1.177 +
   1.178 +    // Declaration of NullString
   1.179 +    static DataDesc NullData;
   1.180 +
   1.181 +
   1.182 +    // *** General Functions
   1.183 +
   1.184 +    void        Clear();
   1.185 +
   1.186 +    // For casting to a pointer to char.
   1.187 +    operator const char*() const        { return GetData()->Data; }
   1.188 +    // Pointer to raw buffer.
   1.189 +    const char* ToCStr() const          { return GetData()->Data; }
   1.190 +
   1.191 +    // Returns number of bytes
   1.192 +    size_t      GetSize() const         { return GetData()->GetSize() ; }
   1.193 +    // Tells whether or not the string is empty
   1.194 +    bool        IsEmpty() const         { return GetSize() == 0; }
   1.195 +
   1.196 +    // Returns  number of characters
   1.197 +    size_t      GetLength() const;
   1.198 +    int         GetLengthI() const      { return (int)GetLength(); }
   1.199 +
   1.200 +    // Returns  character at the specified index
   1.201 +    uint32_t    GetCharAt(size_t index) const;
   1.202 +    uint32_t    GetFirstCharAt(size_t index, const char** offset) const;
   1.203 +    uint32_t    GetNextChar(const char** offset) const;
   1.204 +
   1.205 +    // Appends a character
   1.206 +    void        AppendChar(uint32_t ch);
   1.207 +
   1.208 +    // Append a string
   1.209 +    void        AppendString(const wchar_t* pstr, intptr_t len = -1);
   1.210 +    void        AppendString(const char* putf8str, intptr_t utf8StrSz = -1);
   1.211 +
   1.212 +    // Assigned a string with dynamic data (copied through initializer).
   1.213 +    void        AssignString(const InitStruct& src, size_t size);
   1.214 +    // Assigns string with known size.
   1.215 +    void        AssignString(const char* putf8str, size_t size);
   1.216 +
   1.217 +    //  Resize the string to the new size
   1.218 +//  void        Resize(size_t _size);
   1.219 +
   1.220 +    // Removes the character at posAt
   1.221 +    void        Remove(size_t posAt, intptr_t len = 1);
   1.222 +
   1.223 +    // Returns a String that's a substring of this.
   1.224 +    //  -start is the index of the first UTF8 character you want to include.
   1.225 +    //  -end is the index one past the last UTF8 character you want to include.
   1.226 +    String   Substring(size_t start, size_t end) const;
   1.227 +
   1.228 +    // Case-conversion
   1.229 +    String   ToUpper() const;
   1.230 +    String   ToLower() const;
   1.231 +
   1.232 +    // Inserts substr at posAt
   1.233 +    String&    Insert (const char* substr, size_t posAt, intptr_t len = -1);
   1.234 +
   1.235 +    // Inserts character at posAt
   1.236 +    size_t      InsertCharAt(uint32_t c, size_t posAt);
   1.237 +
   1.238 +    // Inserts substr at posAt, which is an index of a character (not byte).
   1.239 +    // Of size is specified, it is in bytes.
   1.240 +//  String&    Insert(const uint32_t* substr, size_t posAt, intptr_t size = -1);
   1.241 +
   1.242 +    // Get Byte index of the character at position = index
   1.243 +    size_t      GetByteIndex(size_t index) const { return (size_t)UTF8Util::GetByteIndex(index, GetData()->Data); }
   1.244 +
   1.245 +    // Utility: case-insensitive string compare.  stricmp() & strnicmp() are not
   1.246 +    // ANSI or POSIX, do not seem to appear in Linux.
   1.247 +    static int OVR_STDCALL   CompareNoCase(const char* a, const char* b);
   1.248 +    static int OVR_STDCALL   CompareNoCase(const char* a, const char* b, intptr_t len);
   1.249 +
   1.250 +    // Hash function, case-insensitive
   1.251 +    static size_t OVR_STDCALL BernsteinHashFunctionCIS(const void* pdataIn, size_t size, size_t seed = 5381);
   1.252 +
   1.253 +    // Hash function, case-sensitive
   1.254 +    static size_t OVR_STDCALL BernsteinHashFunction(const void* pdataIn, size_t size, size_t seed = 5381);
   1.255 +
   1.256 +
   1.257 +    // ***** File path parsing helper functions.
   1.258 +    // Implemented in OVR_String_FilePath.cpp.
   1.259 +
   1.260 +    // Absolute paths can star with:
   1.261 +    //  - protocols:        'file://', 'http://'
   1.262 +    //  - windows drive:    'c:\'
   1.263 +    //  - UNC share name:   '\\share'
   1.264 +    //  - unix root         '/'
   1.265 +    static bool HasAbsolutePath(const char* path);
   1.266 +    static bool HasExtension(const char* path);
   1.267 +    static bool HasProtocol(const char* path);
   1.268 +
   1.269 +    bool    HasAbsolutePath() const { return HasAbsolutePath(ToCStr()); }
   1.270 +    bool    HasExtension() const    { return HasExtension(ToCStr()); }
   1.271 +    bool    HasProtocol() const     { return HasProtocol(ToCStr()); }
   1.272 +
   1.273 +    String  GetProtocol() const;    // Returns protocol, if any, with trailing '://'.
   1.274 +    String  GetPath() const;        // Returns path with trailing '/'.
   1.275 +    String  GetFilename() const;    // Returns filename, including extension.
   1.276 +    String  GetExtension() const;   // Returns extension with a dot.
   1.277 +
   1.278 +    void    StripProtocol();        // Strips front protocol, if any, from the string.
   1.279 +    void    StripExtension();       // Strips off trailing extension.
   1.280 +    
   1.281 +
   1.282 +    // Operators
   1.283 +    // Assignment
   1.284 +    void        operator =  (const char* str);
   1.285 +    void        operator =  (const wchar_t* str);
   1.286 +    void        operator =  (const String& src);
   1.287 +    void        operator =  (const StringBuffer& src);
   1.288 +
   1.289 +    // Addition
   1.290 +    void        operator += (const String& src);
   1.291 +    void        operator += (const char* psrc)       { AppendString(psrc); }
   1.292 +    void        operator += (const wchar_t* psrc)    { AppendString(psrc); }
   1.293 +    void        operator += (char  ch)               { AppendChar(ch); }
   1.294 +    String      operator +  (const char* str) const;
   1.295 +    String      operator +  (const String& src)  const;
   1.296 +
   1.297 +    // Comparison
   1.298 +    bool        operator == (const String& str) const
   1.299 +    {
   1.300 +        return (OVR_strcmp(GetData()->Data, str.GetData()->Data)== 0);
   1.301 +    }
   1.302 +
   1.303 +    bool        operator != (const String& str) const
   1.304 +    {
   1.305 +        return !operator == (str);
   1.306 +    }
   1.307 +
   1.308 +    bool        operator == (const char* str) const
   1.309 +    {
   1.310 +        return OVR_strcmp(GetData()->Data, str) == 0;
   1.311 +    }
   1.312 +
   1.313 +    bool        operator != (const char* str) const
   1.314 +    {
   1.315 +        return !operator == (str);
   1.316 +    }
   1.317 +
   1.318 +    bool        operator <  (const char* pstr) const
   1.319 +    {
   1.320 +        return OVR_strcmp(GetData()->Data, pstr) < 0;
   1.321 +    }
   1.322 +
   1.323 +    bool        operator <  (const String& str) const
   1.324 +    {
   1.325 +        return *this < str.GetData()->Data;
   1.326 +    }
   1.327 +
   1.328 +    bool        operator >  (const char* pstr) const
   1.329 +    {
   1.330 +        return OVR_strcmp(GetData()->Data, pstr) > 0;
   1.331 +    }
   1.332 +
   1.333 +    bool        operator >  (const String& str) const
   1.334 +    {
   1.335 +        return *this > str.GetData()->Data;
   1.336 +    }
   1.337 +
   1.338 +    int CompareNoCase(const char* pstr) const
   1.339 +    {
   1.340 +        return CompareNoCase(GetData()->Data, pstr);
   1.341 +    }
   1.342 +    int CompareNoCase(const String& str) const
   1.343 +    {
   1.344 +        return CompareNoCase(GetData()->Data, str.ToCStr());
   1.345 +    }
   1.346 +
   1.347 +    // Accesses raw bytes
   1.348 +    const char&     operator [] (int index) const
   1.349 +    {
   1.350 +        OVR_ASSERT(index >= 0 && (size_t)index < GetSize());
   1.351 +        return GetData()->Data[index];
   1.352 +    }
   1.353 +    const char&     operator [] (size_t index) const
   1.354 +    {
   1.355 +        OVR_ASSERT(index < GetSize());
   1.356 +        return GetData()->Data[index];
   1.357 +    }
   1.358 +
   1.359 +
   1.360 +    // Case insensitive keys are used to look up insensitive string in hash tables
   1.361 +    // for SWF files with version before SWF 7.
   1.362 +    struct NoCaseKey
   1.363 +    {   
   1.364 +        const String* pStr;
   1.365 +        NoCaseKey(const String &str) : pStr(&str){};
   1.366 +    };
   1.367 +
   1.368 +    bool    operator == (const NoCaseKey& strKey) const
   1.369 +    {
   1.370 +        return (CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
   1.371 +    }
   1.372 +    bool    operator != (const NoCaseKey& strKey) const
   1.373 +    {
   1.374 +        return !(CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
   1.375 +    }
   1.376 +
   1.377 +    // Hash functor used for strings.
   1.378 +    struct HashFunctor
   1.379 +    {    
   1.380 +        size_t operator()(const String& data) const
   1.381 +        {
   1.382 +            size_t size = data.GetSize();
   1.383 +            return String::BernsteinHashFunction((const char*)data, size);
   1.384 +        }        
   1.385 +    };
   1.386 +    // Case-insensitive hash functor used for strings. Supports additional
   1.387 +    // lookup based on NoCaseKey.
   1.388 +    struct NoCaseHashFunctor
   1.389 +    {    
   1.390 +        size_t operator()(const String& data) const
   1.391 +        {
   1.392 +            size_t size = data.GetSize();
   1.393 +            return String::BernsteinHashFunctionCIS((const char*)data, size);
   1.394 +        }
   1.395 +        size_t operator()(const NoCaseKey& data) const
   1.396 +        {       
   1.397 +            size_t size = data.pStr->GetSize();
   1.398 +            return String::BernsteinHashFunctionCIS((const char*)data.pStr->ToCStr(), size);
   1.399 +        }
   1.400 +    };
   1.401 +
   1.402 +};
   1.403 +
   1.404 +
   1.405 +//-----------------------------------------------------------------------------------
   1.406 +// ***** String Buffer used for Building Strings
   1.407 +
   1.408 +class StringBuffer
   1.409 +{
   1.410 +    char*           pData;
   1.411 +    size_t          Size;
   1.412 +    size_t          BufferSize;
   1.413 +    size_t          GrowSize;    
   1.414 +    mutable bool    LengthIsSize;    
   1.415 +
   1.416 +public:
   1.417 +
   1.418 +    // Constructors / Destructor.    
   1.419 +    StringBuffer();
   1.420 +    explicit StringBuffer(size_t growSize);
   1.421 +    StringBuffer(const char* data);
   1.422 +    StringBuffer(const char* data, size_t buflen);
   1.423 +    StringBuffer(const String& src);
   1.424 +    StringBuffer(const StringBuffer& src);
   1.425 +    explicit StringBuffer(const wchar_t* data);
   1.426 +    ~StringBuffer();
   1.427 +    
   1.428 +
   1.429 +    // Modify grow size used for growing/shrinking the buffer.
   1.430 +    size_t      GetGrowSize() const         { return GrowSize; }
   1.431 +    void        SetGrowSize(size_t growSize);
   1.432 +    
   1.433 +
   1.434 +    // *** General Functions
   1.435 +    // Does not release memory, just sets Size to 0
   1.436 +    void        Clear();
   1.437 +
   1.438 +    // For casting to a pointer to char.
   1.439 +    operator const char*() const        { return (pData) ? pData : ""; }
   1.440 +    // Pointer to raw buffer.
   1.441 +    const char* ToCStr() const          { return (pData) ? pData : ""; }
   1.442 +
   1.443 +    // Returns number of bytes.
   1.444 +    size_t      GetSize() const         { return Size ; }
   1.445 +    // Tells whether or not the string is empty.
   1.446 +    bool        IsEmpty() const         { return GetSize() == 0; }
   1.447 +
   1.448 +    // Returns  number of characters
   1.449 +    size_t      GetLength() const;
   1.450 +
   1.451 +    // Returns  character at the specified index
   1.452 +    uint32_t    GetCharAt(size_t index) const;
   1.453 +    uint32_t    GetFirstCharAt(size_t index, const char** offset) const;
   1.454 +    uint32_t    GetNextChar(const char** offset) const;
   1.455 +
   1.456 +
   1.457 +    //  Resize the string to the new size
   1.458 +    void        Resize(size_t _size);
   1.459 +    void        Reserve(size_t _size);
   1.460 +
   1.461 +    // Appends a character
   1.462 +    void        AppendChar(uint32_t ch);
   1.463 +
   1.464 +    // Append a string
   1.465 +    void        AppendString(const wchar_t* pstr, intptr_t len = -1);
   1.466 +    void        AppendString(const char* putf8str, intptr_t utf8StrSz = -1);
   1.467 +    void        AppendFormat(const char* format, ...);
   1.468 +
   1.469 +    // Assigned a string with dynamic data (copied through initializer).
   1.470 +    //void        AssignString(const InitStruct& src, size_t size);
   1.471 +
   1.472 +    // Inserts substr at posAt
   1.473 +    void        Insert (const char* substr, size_t posAt, intptr_t len = -1);
   1.474 +    // Inserts character at posAt
   1.475 +    size_t      InsertCharAt(uint32_t c, size_t posAt);
   1.476 +
   1.477 +    // Assignment
   1.478 +    void        operator =  (const char* str);
   1.479 +    void        operator =  (const wchar_t* str);
   1.480 +    void        operator =  (const String& src);
   1.481 +    void        operator =  (const StringBuffer& src);
   1.482 +
   1.483 +    // Addition
   1.484 +    void        operator += (const String& src)      { AppendString(src.ToCStr(),src.GetSize()); }
   1.485 +    void        operator += (const char* psrc)       { AppendString(psrc); }
   1.486 +    void        operator += (const wchar_t* psrc)    { AppendString(psrc); }
   1.487 +    void        operator += (char  ch)               { AppendChar(ch); }
   1.488 +    //String   operator +  (const char* str) const ;
   1.489 +    //String   operator +  (const String& src)  const ;
   1.490 +
   1.491 +    // Accesses raw bytes
   1.492 +    char&       operator [] (int index)
   1.493 +    {
   1.494 +        OVR_ASSERT(((size_t)index) < GetSize());
   1.495 +        return pData[index];
   1.496 +    }
   1.497 +    char&       operator [] (size_t index)
   1.498 +    {
   1.499 +        OVR_ASSERT(index < GetSize());
   1.500 +        return pData[index];
   1.501 +    }
   1.502 +
   1.503 +    const char&     operator [] (int index) const 
   1.504 +    {
   1.505 +        OVR_ASSERT(((size_t)index) < GetSize());
   1.506 +        return pData[index];
   1.507 +    }
   1.508 +    const char&     operator [] (size_t index) const
   1.509 +    {
   1.510 +        OVR_ASSERT(index < GetSize());
   1.511 +        return pData[index];
   1.512 +    }
   1.513 +};
   1.514 +
   1.515 +
   1.516 +//
   1.517 +// Wrapper for string data. The data must have a guaranteed 
   1.518 +// lifespan throughout the usage of the wrapper. Not intended for 
   1.519 +// cached usage. Not thread safe.
   1.520 +//
   1.521 +class StringDataPtr
   1.522 +{
   1.523 +public:
   1.524 +    StringDataPtr() : pStr(NULL), Size(0) {}
   1.525 +    StringDataPtr(const StringDataPtr& p)
   1.526 +        : pStr(p.pStr), Size(p.Size) {}
   1.527 +    StringDataPtr(const char* pstr, size_t sz)
   1.528 +        : pStr(pstr), Size(sz) {}
   1.529 +    StringDataPtr(const char* pstr)
   1.530 +        : pStr(pstr), Size((pstr != NULL) ? OVR_strlen(pstr) : 0) {}
   1.531 +    explicit StringDataPtr(const String& str)
   1.532 +        : pStr(str.ToCStr()), Size(str.GetSize()) {}
   1.533 +    template <typename T, int N> 
   1.534 +    StringDataPtr(const T (&v)[N])
   1.535 +        : pStr(v), Size(N) {}
   1.536 +
   1.537 +public:
   1.538 +    const char* ToCStr() const { return pStr; }
   1.539 +    size_t      GetSize() const { return Size; }
   1.540 +    bool        IsEmpty() const { return GetSize() == 0; }
   1.541 +
   1.542 +    // value is a prefix of this string
   1.543 +    // Character's values are not compared.
   1.544 +    bool        IsPrefix(const StringDataPtr& value) const
   1.545 +    {
   1.546 +        return ToCStr() == value.ToCStr() && GetSize() >= value.GetSize();
   1.547 +    }
   1.548 +    // value is a suffix of this string
   1.549 +    // Character's values are not compared.
   1.550 +    bool        IsSuffix(const StringDataPtr& value) const
   1.551 +    {
   1.552 +        return ToCStr() <= value.ToCStr() && (End()) == (value.End());
   1.553 +    }
   1.554 +
   1.555 +    // Find first character.
   1.556 +    // init_ind - initial index.
   1.557 +    intptr_t    FindChar(char c, size_t init_ind = 0) const 
   1.558 +    {
   1.559 +        for (size_t i = init_ind; i < GetSize(); ++i)
   1.560 +            if (pStr[i] == c)
   1.561 +                return static_cast<intptr_t>(i);
   1.562 +
   1.563 +        return -1; 
   1.564 +    }
   1.565 +
   1.566 +    // Find last character.
   1.567 +    // init_ind - initial index.
   1.568 +    intptr_t    FindLastChar(char c, size_t init_ind = ~0) const 
   1.569 +    {
   1.570 +        if (init_ind == (size_t)~0 || init_ind > GetSize())
   1.571 +            init_ind = GetSize();
   1.572 +        else
   1.573 +            ++init_ind;
   1.574 +
   1.575 +        for (size_t i = init_ind; i > 0; --i)
   1.576 +            if (pStr[i - 1] == c)
   1.577 +                return static_cast<intptr_t>(i - 1);
   1.578 +
   1.579 +        return -1; 
   1.580 +    }
   1.581 +
   1.582 +    // Create new object and trim size bytes from the left.
   1.583 +    StringDataPtr  GetTrimLeft(size_t size) const
   1.584 +    {
   1.585 +        // Limit trim size to the size of the string.
   1.586 +        size = Alg::PMin(GetSize(), size);
   1.587 +
   1.588 +        return StringDataPtr(ToCStr() + size, GetSize() - size);
   1.589 +    }
   1.590 +    // Create new object and trim size bytes from the right.
   1.591 +    StringDataPtr  GetTrimRight(size_t size) const
   1.592 +    {
   1.593 +        // Limit trim to the size of the string.
   1.594 +        size = Alg::PMin(GetSize(), size);
   1.595 +
   1.596 +        return StringDataPtr(ToCStr(), GetSize() - size);
   1.597 +    }
   1.598 +
   1.599 +    // Create new object, which contains next token.
   1.600 +    // Useful for parsing.
   1.601 +    StringDataPtr GetNextToken(char separator = ':') const
   1.602 +    {
   1.603 +        size_t cur_pos = 0;
   1.604 +        const char* cur_str = ToCStr();
   1.605 +
   1.606 +        for (; cur_pos < GetSize() && cur_str[cur_pos]; ++cur_pos)
   1.607 +        {
   1.608 +            if (cur_str[cur_pos] == separator)
   1.609 +            {
   1.610 +                break;
   1.611 +            }
   1.612 +        }
   1.613 +
   1.614 +        return StringDataPtr(ToCStr(), cur_pos);
   1.615 +    }
   1.616 +
   1.617 +    // Trim size bytes from the left.
   1.618 +    StringDataPtr& TrimLeft(size_t size)
   1.619 +    {
   1.620 +        // Limit trim size to the size of the string.
   1.621 +        size = Alg::PMin(GetSize(), size);
   1.622 +        pStr += size;
   1.623 +        Size -= size;
   1.624 +
   1.625 +        return *this;
   1.626 +    }
   1.627 +    // Trim size bytes from the right.
   1.628 +    StringDataPtr& TrimRight(size_t size)
   1.629 +    {
   1.630 +        // Limit trim to the size of the string.
   1.631 +        size = Alg::PMin(GetSize(), size);
   1.632 +        Size -= size;
   1.633 +
   1.634 +        return *this;
   1.635 +    }
   1.636 +
   1.637 +    const char* Begin() const { return ToCStr(); }
   1.638 +    const char* End() const { return ToCStr() + GetSize(); }
   1.639 +
   1.640 +    // Hash functor used string data pointers
   1.641 +    struct HashFunctor
   1.642 +    {    
   1.643 +        size_t operator()(const StringDataPtr& data) const
   1.644 +        {
   1.645 +            return String::BernsteinHashFunction(data.ToCStr(), data.GetSize());
   1.646 +        }        
   1.647 +    };
   1.648 +
   1.649 +    bool operator== (const StringDataPtr& data) const 
   1.650 +    {
   1.651 +        return (OVR_strncmp(pStr, data.pStr, data.Size) == 0);
   1.652 +    }
   1.653 +
   1.654 +protected:
   1.655 +    const char* pStr;
   1.656 +    size_t      Size;
   1.657 +};
   1.658 +
   1.659 +} // OVR
   1.660 +
   1.661 +#endif