rev |
line source |
nuclear@1
|
1 /************************************************************************************
|
nuclear@1
|
2
|
nuclear@1
|
3 PublicHeader: OVR.h
|
nuclear@1
|
4 Filename : OVR_String.h
|
nuclear@1
|
5 Content : String UTF8 string implementation with copy-on-write semantics
|
nuclear@1
|
6 (thread-safe for assignment but not modification).
|
nuclear@1
|
7 Created : September 19, 2012
|
nuclear@1
|
8 Notes :
|
nuclear@1
|
9
|
nuclear@1
|
10 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
|
nuclear@1
|
11
|
nuclear@1
|
12 Use of this software is subject to the terms of the Oculus license
|
nuclear@1
|
13 agreement provided at the time of installation or download, or which
|
nuclear@1
|
14 otherwise accompanies this software in either electronic or hard copy form.
|
nuclear@1
|
15
|
nuclear@1
|
16 ************************************************************************************/
|
nuclear@1
|
17
|
nuclear@1
|
18 #ifndef OVR_String_h
|
nuclear@1
|
19 #define OVR_String_h
|
nuclear@1
|
20
|
nuclear@1
|
21 #include "OVR_Types.h"
|
nuclear@1
|
22 #include "OVR_Allocator.h"
|
nuclear@1
|
23 #include "OVR_UTF8Util.h"
|
nuclear@1
|
24 #include "OVR_Atomic.h"
|
nuclear@1
|
25 #include "OVR_Std.h"
|
nuclear@1
|
26 #include "OVR_Alg.h"
|
nuclear@1
|
27
|
nuclear@1
|
28 namespace OVR {
|
nuclear@1
|
29
|
nuclear@1
|
30 // ***** Classes
|
nuclear@1
|
31
|
nuclear@1
|
32 class String;
|
nuclear@1
|
33 class StringBuffer;
|
nuclear@1
|
34
|
nuclear@1
|
35
|
nuclear@1
|
36 //-----------------------------------------------------------------------------------
|
nuclear@1
|
37 // ***** String Class
|
nuclear@1
|
38
|
nuclear@1
|
39 // String is UTF8 based string class with copy-on-write implementation
|
nuclear@1
|
40 // for assignment.
|
nuclear@1
|
41
|
nuclear@1
|
42 class String
|
nuclear@1
|
43 {
|
nuclear@1
|
44 protected:
|
nuclear@1
|
45
|
nuclear@1
|
46 enum FlagConstants
|
nuclear@1
|
47 {
|
nuclear@1
|
48 //Flag_GetLength = 0x7FFFFFFF,
|
nuclear@1
|
49 // This flag is set if GetLength() == GetSize() for a string.
|
nuclear@1
|
50 // Avoid extra scanning is Substring and indexing logic.
|
nuclear@1
|
51 Flag_LengthIsSizeShift = (sizeof(UPInt)*8 - 1)
|
nuclear@1
|
52 };
|
nuclear@1
|
53
|
nuclear@1
|
54
|
nuclear@1
|
55 // Internal structure to hold string data
|
nuclear@1
|
56 struct DataDesc
|
nuclear@1
|
57 {
|
nuclear@1
|
58 // Number of bytes. Will be the same as the number of chars if the characters
|
nuclear@1
|
59 // are ascii, may not be equal to number of chars in case string data is UTF8.
|
nuclear@1
|
60 UPInt Size;
|
nuclear@1
|
61 volatile SInt32 RefCount;
|
nuclear@1
|
62 char Data[1];
|
nuclear@1
|
63
|
nuclear@1
|
64 void AddRef()
|
nuclear@1
|
65 {
|
nuclear@1
|
66 AtomicOps<SInt32>::ExchangeAdd_NoSync(&RefCount, 1);
|
nuclear@1
|
67 }
|
nuclear@1
|
68 // Decrement ref count. This needs to be thread-safe, since
|
nuclear@1
|
69 // a different thread could have also decremented the ref count.
|
nuclear@1
|
70 // For example, if u start off with a ref count = 2. Now if u
|
nuclear@1
|
71 // decrement the ref count and check against 0 in different
|
nuclear@1
|
72 // statements, a different thread can also decrement the ref count
|
nuclear@1
|
73 // in between our decrement and checking against 0 and will find
|
nuclear@1
|
74 // the ref count = 0 and delete the object. This will lead to a crash
|
nuclear@1
|
75 // when context switches to our thread and we'll be trying to delete
|
nuclear@1
|
76 // an already deleted object. Hence decrementing the ref count and
|
nuclear@1
|
77 // checking against 0 needs to made an atomic operation.
|
nuclear@1
|
78 void Release()
|
nuclear@1
|
79 {
|
nuclear@1
|
80 if ((AtomicOps<SInt32>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
|
nuclear@1
|
81 OVR_FREE(this);
|
nuclear@1
|
82 }
|
nuclear@1
|
83
|
nuclear@1
|
84 static UPInt GetLengthFlagBit() { return UPInt(1) << Flag_LengthIsSizeShift; }
|
nuclear@1
|
85 UPInt GetSize() const { return Size & ~GetLengthFlagBit() ; }
|
nuclear@1
|
86 UPInt GetLengthFlag() const { return Size & GetLengthFlagBit(); }
|
nuclear@1
|
87 bool LengthIsSize() const { return GetLengthFlag() != 0; }
|
nuclear@1
|
88 };
|
nuclear@1
|
89
|
nuclear@1
|
90 // Heap type of the string is encoded in the lower bits.
|
nuclear@1
|
91 enum HeapType
|
nuclear@1
|
92 {
|
nuclear@1
|
93 HT_Global = 0, // Heap is global.
|
nuclear@1
|
94 HT_Local = 1, // SF::String_loc: Heap is determined based on string's address.
|
nuclear@1
|
95 HT_Dynamic = 2, // SF::String_temp: Heap is stored as a part of the class.
|
nuclear@1
|
96 HT_Mask = 3
|
nuclear@1
|
97 };
|
nuclear@1
|
98
|
nuclear@1
|
99 union {
|
nuclear@1
|
100 DataDesc* pData;
|
nuclear@1
|
101 UPInt HeapTypeBits;
|
nuclear@1
|
102 };
|
nuclear@1
|
103 typedef union {
|
nuclear@1
|
104 DataDesc* pData;
|
nuclear@1
|
105 UPInt HeapTypeBits;
|
nuclear@1
|
106 } DataDescUnion;
|
nuclear@1
|
107
|
nuclear@1
|
108 inline HeapType GetHeapType() const { return (HeapType) (HeapTypeBits & HT_Mask); }
|
nuclear@1
|
109
|
nuclear@1
|
110 inline DataDesc* GetData() const
|
nuclear@1
|
111 {
|
nuclear@1
|
112 DataDescUnion u;
|
nuclear@1
|
113 u.pData = pData;
|
nuclear@1
|
114 u.HeapTypeBits = (u.HeapTypeBits & ~(UPInt)HT_Mask);
|
nuclear@1
|
115 return u.pData;
|
nuclear@1
|
116 }
|
nuclear@1
|
117
|
nuclear@1
|
118 inline void SetData(DataDesc* pdesc)
|
nuclear@1
|
119 {
|
nuclear@1
|
120 HeapType ht = GetHeapType();
|
nuclear@1
|
121 pData = pdesc;
|
nuclear@1
|
122 OVR_ASSERT((HeapTypeBits & HT_Mask) == 0);
|
nuclear@1
|
123 HeapTypeBits |= ht;
|
nuclear@1
|
124 }
|
nuclear@1
|
125
|
nuclear@1
|
126
|
nuclear@1
|
127 DataDesc* AllocData(UPInt size, UPInt lengthIsSize);
|
nuclear@1
|
128 DataDesc* AllocDataCopy1(UPInt size, UPInt lengthIsSize,
|
nuclear@1
|
129 const char* pdata, UPInt copySize);
|
nuclear@1
|
130 DataDesc* AllocDataCopy2(UPInt size, UPInt lengthIsSize,
|
nuclear@1
|
131 const char* pdata1, UPInt copySize1,
|
nuclear@1
|
132 const char* pdata2, UPInt copySize2);
|
nuclear@1
|
133
|
nuclear@1
|
134 // Special constructor to avoid data initalization when used in derived class.
|
nuclear@1
|
135 struct NoConstructor { };
|
nuclear@1
|
136 String(const NoConstructor&) { }
|
nuclear@1
|
137
|
nuclear@1
|
138 public:
|
nuclear@1
|
139
|
nuclear@1
|
140 // For initializing string with dynamic buffer
|
nuclear@1
|
141 struct InitStruct
|
nuclear@1
|
142 {
|
nuclear@1
|
143 virtual ~InitStruct() { }
|
nuclear@1
|
144 virtual void InitString(char* pbuffer, UPInt size) const = 0;
|
nuclear@1
|
145 };
|
nuclear@1
|
146
|
nuclear@1
|
147
|
nuclear@1
|
148 // Constructors / Destructors.
|
nuclear@1
|
149 String();
|
nuclear@1
|
150 String(const char* data);
|
nuclear@1
|
151 String(const char* data1, const char* pdata2, const char* pdata3 = 0);
|
nuclear@1
|
152 String(const char* data, UPInt buflen);
|
nuclear@1
|
153 String(const String& src);
|
nuclear@1
|
154 String(const StringBuffer& src);
|
nuclear@1
|
155 String(const InitStruct& src, UPInt size);
|
nuclear@1
|
156 explicit String(const wchar_t* data);
|
nuclear@1
|
157
|
nuclear@1
|
158 // Destructor (Captain Obvious guarantees!)
|
nuclear@1
|
159 ~String()
|
nuclear@1
|
160 {
|
nuclear@1
|
161 GetData()->Release();
|
nuclear@1
|
162 }
|
nuclear@1
|
163
|
nuclear@1
|
164 // Declaration of NullString
|
nuclear@1
|
165 static DataDesc NullData;
|
nuclear@1
|
166
|
nuclear@1
|
167
|
nuclear@1
|
168 // *** General Functions
|
nuclear@1
|
169
|
nuclear@1
|
170 void Clear();
|
nuclear@1
|
171
|
nuclear@1
|
172 // For casting to a pointer to char.
|
nuclear@1
|
173 operator const char*() const { return GetData()->Data; }
|
nuclear@1
|
174 // Pointer to raw buffer.
|
nuclear@1
|
175 const char* ToCStr() const { return GetData()->Data; }
|
nuclear@1
|
176
|
nuclear@1
|
177 // Returns number of bytes
|
nuclear@1
|
178 UPInt GetSize() const { return GetData()->GetSize() ; }
|
nuclear@1
|
179 // Tells whether or not the string is empty
|
nuclear@1
|
180 bool IsEmpty() const { return GetSize() == 0; }
|
nuclear@1
|
181
|
nuclear@1
|
182 // Returns number of characters
|
nuclear@1
|
183 UPInt GetLength() const;
|
nuclear@1
|
184
|
nuclear@1
|
185 // Returns character at the specified index
|
nuclear@1
|
186 UInt32 GetCharAt(UPInt index) const;
|
nuclear@1
|
187 UInt32 GetFirstCharAt(UPInt index, const char** offset) const;
|
nuclear@1
|
188 UInt32 GetNextChar(const char** offset) const;
|
nuclear@1
|
189
|
nuclear@1
|
190 // Appends a character
|
nuclear@1
|
191 void AppendChar(UInt32 ch);
|
nuclear@1
|
192
|
nuclear@1
|
193 // Append a string
|
nuclear@1
|
194 void AppendString(const wchar_t* pstr, SPInt len = -1);
|
nuclear@1
|
195 void AppendString(const char* putf8str, SPInt utf8StrSz = -1);
|
nuclear@1
|
196
|
nuclear@1
|
197 // Assigned a string with dynamic data (copied through initializer).
|
nuclear@1
|
198 void AssignString(const InitStruct& src, UPInt size);
|
nuclear@1
|
199 // Assigns string with known size.
|
nuclear@1
|
200 void AssignString(const char* putf8str, UPInt size);
|
nuclear@1
|
201
|
nuclear@1
|
202 // Resize the string to the new size
|
nuclear@1
|
203 // void Resize(UPInt _size);
|
nuclear@1
|
204
|
nuclear@1
|
205 // Removes the character at posAt
|
nuclear@1
|
206 void Remove(UPInt posAt, SPInt len = 1);
|
nuclear@1
|
207
|
nuclear@1
|
208 // Returns a String that's a substring of this.
|
nuclear@1
|
209 // -start is the index of the first UTF8 character you want to include.
|
nuclear@1
|
210 // -end is the index one past the last UTF8 character you want to include.
|
nuclear@1
|
211 String Substring(UPInt start, UPInt end) const;
|
nuclear@1
|
212
|
nuclear@1
|
213 // Case-conversion
|
nuclear@1
|
214 String ToUpper() const;
|
nuclear@1
|
215 String ToLower() const;
|
nuclear@1
|
216
|
nuclear@1
|
217 // Inserts substr at posAt
|
nuclear@1
|
218 String& Insert (const char* substr, UPInt posAt, SPInt len = -1);
|
nuclear@1
|
219
|
nuclear@1
|
220 // Inserts character at posAt
|
nuclear@1
|
221 UPInt InsertCharAt(UInt32 c, UPInt posAt);
|
nuclear@1
|
222
|
nuclear@1
|
223 // Inserts substr at posAt, which is an index of a character (not byte).
|
nuclear@1
|
224 // Of size is specified, it is in bytes.
|
nuclear@1
|
225 // String& Insert(const UInt32* substr, UPInt posAt, SPInt size = -1);
|
nuclear@1
|
226
|
nuclear@1
|
227 // Get Byte index of the character at position = index
|
nuclear@1
|
228 UPInt GetByteIndex(UPInt index) const { return (UPInt)UTF8Util::GetByteIndex(index, GetData()->Data); }
|
nuclear@1
|
229
|
nuclear@1
|
230 // Utility: case-insensitive string compare. stricmp() & strnicmp() are not
|
nuclear@1
|
231 // ANSI or POSIX, do not seem to appear in Linux.
|
nuclear@1
|
232 static int OVR_STDCALL CompareNoCase(const char* a, const char* b);
|
nuclear@1
|
233 static int OVR_STDCALL CompareNoCase(const char* a, const char* b, SPInt len);
|
nuclear@1
|
234
|
nuclear@1
|
235 // Hash function, case-insensitive
|
nuclear@1
|
236 static UPInt OVR_STDCALL BernsteinHashFunctionCIS(const void* pdataIn, UPInt size, UPInt seed = 5381);
|
nuclear@1
|
237
|
nuclear@1
|
238 // Hash function, case-sensitive
|
nuclear@1
|
239 static UPInt OVR_STDCALL BernsteinHashFunction(const void* pdataIn, UPInt size, UPInt seed = 5381);
|
nuclear@1
|
240
|
nuclear@1
|
241
|
nuclear@1
|
242 // ***** File path parsing helper functions.
|
nuclear@1
|
243 // Implemented in OVR_String_FilePath.cpp.
|
nuclear@1
|
244
|
nuclear@1
|
245 // Absolute paths can star with:
|
nuclear@1
|
246 // - protocols: 'file://', 'http://'
|
nuclear@1
|
247 // - windows drive: 'c:\'
|
nuclear@1
|
248 // - UNC share name: '\\share'
|
nuclear@1
|
249 // - unix root '/'
|
nuclear@1
|
250 static bool HasAbsolutePath(const char* path);
|
nuclear@1
|
251 static bool HasExtension(const char* path);
|
nuclear@1
|
252 static bool HasProtocol(const char* path);
|
nuclear@1
|
253
|
nuclear@1
|
254 bool HasAbsolutePath() const { return HasAbsolutePath(ToCStr()); }
|
nuclear@1
|
255 bool HasExtension() const { return HasExtension(ToCStr()); }
|
nuclear@1
|
256 bool HasProtocol() const { return HasProtocol(ToCStr()); }
|
nuclear@1
|
257
|
nuclear@1
|
258 String GetProtocol() const; // Returns protocol, if any, with trailing '://'.
|
nuclear@1
|
259 String GetPath() const; // Returns path with trailing '/'.
|
nuclear@1
|
260 String GetFilename() const; // Returns filename, including extension.
|
nuclear@1
|
261 String GetExtension() const; // Returns extension with a dot.
|
nuclear@1
|
262
|
nuclear@1
|
263 void StripProtocol(); // Strips front protocol, if any, from the string.
|
nuclear@1
|
264 void StripExtension(); // Strips off trailing extension.
|
nuclear@1
|
265
|
nuclear@1
|
266
|
nuclear@1
|
267 // Operators
|
nuclear@1
|
268 // Assignment
|
nuclear@1
|
269 void operator = (const char* str);
|
nuclear@1
|
270 void operator = (const wchar_t* str);
|
nuclear@1
|
271 void operator = (const String& src);
|
nuclear@1
|
272 void operator = (const StringBuffer& src);
|
nuclear@1
|
273
|
nuclear@1
|
274 // Addition
|
nuclear@1
|
275 void operator += (const String& src);
|
nuclear@1
|
276 void operator += (const char* psrc) { AppendString(psrc); }
|
nuclear@1
|
277 void operator += (const wchar_t* psrc) { AppendString(psrc); }
|
nuclear@1
|
278 void operator += (char ch) { AppendChar(ch); }
|
nuclear@1
|
279 String operator + (const char* str) const;
|
nuclear@1
|
280 String operator + (const String& src) const;
|
nuclear@1
|
281
|
nuclear@1
|
282 // Comparison
|
nuclear@1
|
283 bool operator == (const String& str) const
|
nuclear@1
|
284 {
|
nuclear@1
|
285 return (OVR_strcmp(GetData()->Data, str.GetData()->Data)== 0);
|
nuclear@1
|
286 }
|
nuclear@1
|
287
|
nuclear@1
|
288 bool operator != (const String& str) const
|
nuclear@1
|
289 {
|
nuclear@1
|
290 return !operator == (str);
|
nuclear@1
|
291 }
|
nuclear@1
|
292
|
nuclear@1
|
293 bool operator == (const char* str) const
|
nuclear@1
|
294 {
|
nuclear@1
|
295 return OVR_strcmp(GetData()->Data, str) == 0;
|
nuclear@1
|
296 }
|
nuclear@1
|
297
|
nuclear@1
|
298 bool operator != (const char* str) const
|
nuclear@1
|
299 {
|
nuclear@1
|
300 return !operator == (str);
|
nuclear@1
|
301 }
|
nuclear@1
|
302
|
nuclear@1
|
303 bool operator < (const char* pstr) const
|
nuclear@1
|
304 {
|
nuclear@1
|
305 return OVR_strcmp(GetData()->Data, pstr) < 0;
|
nuclear@1
|
306 }
|
nuclear@1
|
307
|
nuclear@1
|
308 bool operator < (const String& str) const
|
nuclear@1
|
309 {
|
nuclear@1
|
310 return *this < str.GetData()->Data;
|
nuclear@1
|
311 }
|
nuclear@1
|
312
|
nuclear@1
|
313 bool operator > (const char* pstr) const
|
nuclear@1
|
314 {
|
nuclear@1
|
315 return OVR_strcmp(GetData()->Data, pstr) > 0;
|
nuclear@1
|
316 }
|
nuclear@1
|
317
|
nuclear@1
|
318 bool operator > (const String& str) const
|
nuclear@1
|
319 {
|
nuclear@1
|
320 return *this > str.GetData()->Data;
|
nuclear@1
|
321 }
|
nuclear@1
|
322
|
nuclear@1
|
323 int CompareNoCase(const char* pstr) const
|
nuclear@1
|
324 {
|
nuclear@1
|
325 return CompareNoCase(GetData()->Data, pstr);
|
nuclear@1
|
326 }
|
nuclear@1
|
327 int CompareNoCase(const String& str) const
|
nuclear@1
|
328 {
|
nuclear@1
|
329 return CompareNoCase(GetData()->Data, str.ToCStr());
|
nuclear@1
|
330 }
|
nuclear@1
|
331
|
nuclear@1
|
332 // Accesses raw bytes
|
nuclear@1
|
333 const char& operator [] (int index) const
|
nuclear@1
|
334 {
|
nuclear@1
|
335 OVR_ASSERT(index >= 0 && (UPInt)index < GetSize());
|
nuclear@1
|
336 return GetData()->Data[index];
|
nuclear@1
|
337 }
|
nuclear@1
|
338 const char& operator [] (UPInt index) const
|
nuclear@1
|
339 {
|
nuclear@1
|
340 OVR_ASSERT(index < GetSize());
|
nuclear@1
|
341 return GetData()->Data[index];
|
nuclear@1
|
342 }
|
nuclear@1
|
343
|
nuclear@1
|
344
|
nuclear@1
|
345 // Case insensitive keys are used to look up insensitive string in hash tables
|
nuclear@1
|
346 // for SWF files with version before SWF 7.
|
nuclear@1
|
347 struct NoCaseKey
|
nuclear@1
|
348 {
|
nuclear@1
|
349 const String* pStr;
|
nuclear@1
|
350 NoCaseKey(const String &str) : pStr(&str){};
|
nuclear@1
|
351 };
|
nuclear@1
|
352
|
nuclear@1
|
353 bool operator == (const NoCaseKey& strKey) const
|
nuclear@1
|
354 {
|
nuclear@1
|
355 return (CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
|
nuclear@1
|
356 }
|
nuclear@1
|
357 bool operator != (const NoCaseKey& strKey) const
|
nuclear@1
|
358 {
|
nuclear@1
|
359 return !(CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
|
nuclear@1
|
360 }
|
nuclear@1
|
361
|
nuclear@1
|
362 // Hash functor used for strings.
|
nuclear@1
|
363 struct HashFunctor
|
nuclear@1
|
364 {
|
nuclear@1
|
365 UPInt operator()(const String& data) const
|
nuclear@1
|
366 {
|
nuclear@1
|
367 UPInt size = data.GetSize();
|
nuclear@1
|
368 return String::BernsteinHashFunction((const char*)data, size);
|
nuclear@1
|
369 }
|
nuclear@1
|
370 };
|
nuclear@1
|
371 // Case-insensitive hash functor used for strings. Supports additional
|
nuclear@1
|
372 // lookup based on NoCaseKey.
|
nuclear@1
|
373 struct NoCaseHashFunctor
|
nuclear@1
|
374 {
|
nuclear@1
|
375 UPInt operator()(const String& data) const
|
nuclear@1
|
376 {
|
nuclear@1
|
377 UPInt size = data.GetSize();
|
nuclear@1
|
378 return String::BernsteinHashFunctionCIS((const char*)data, size);
|
nuclear@1
|
379 }
|
nuclear@1
|
380 UPInt operator()(const NoCaseKey& data) const
|
nuclear@1
|
381 {
|
nuclear@1
|
382 UPInt size = data.pStr->GetSize();
|
nuclear@1
|
383 return String::BernsteinHashFunctionCIS((const char*)data.pStr->ToCStr(), size);
|
nuclear@1
|
384 }
|
nuclear@1
|
385 };
|
nuclear@1
|
386
|
nuclear@1
|
387 };
|
nuclear@1
|
388
|
nuclear@1
|
389
|
nuclear@1
|
390 //-----------------------------------------------------------------------------------
|
nuclear@1
|
391 // ***** String Buffer used for Building Strings
|
nuclear@1
|
392
|
nuclear@1
|
393 class StringBuffer
|
nuclear@1
|
394 {
|
nuclear@1
|
395 char* pData;
|
nuclear@1
|
396 UPInt Size;
|
nuclear@1
|
397 UPInt BufferSize;
|
nuclear@1
|
398 UPInt GrowSize;
|
nuclear@1
|
399 mutable bool LengthIsSize;
|
nuclear@1
|
400
|
nuclear@1
|
401 public:
|
nuclear@1
|
402
|
nuclear@1
|
403 // Constructors / Destructor.
|
nuclear@1
|
404 StringBuffer();
|
nuclear@1
|
405 explicit StringBuffer(UPInt growSize);
|
nuclear@1
|
406 StringBuffer(const char* data);
|
nuclear@1
|
407 StringBuffer(const char* data, UPInt buflen);
|
nuclear@1
|
408 StringBuffer(const String& src);
|
nuclear@1
|
409 StringBuffer(const StringBuffer& src);
|
nuclear@1
|
410 explicit StringBuffer(const wchar_t* data);
|
nuclear@1
|
411 ~StringBuffer();
|
nuclear@1
|
412
|
nuclear@1
|
413
|
nuclear@1
|
414 // Modify grow size used for growing/shrinking the buffer.
|
nuclear@1
|
415 UPInt GetGrowSize() const { return GrowSize; }
|
nuclear@1
|
416 void SetGrowSize(UPInt growSize);
|
nuclear@1
|
417
|
nuclear@1
|
418
|
nuclear@1
|
419 // *** General Functions
|
nuclear@1
|
420 // Does not release memory, just sets Size to 0
|
nuclear@1
|
421 void Clear();
|
nuclear@1
|
422
|
nuclear@1
|
423 // For casting to a pointer to char.
|
nuclear@1
|
424 operator const char*() const { return (pData) ? pData : ""; }
|
nuclear@1
|
425 // Pointer to raw buffer.
|
nuclear@1
|
426 const char* ToCStr() const { return (pData) ? pData : ""; }
|
nuclear@1
|
427
|
nuclear@1
|
428 // Returns number of bytes.
|
nuclear@1
|
429 UPInt GetSize() const { return Size ; }
|
nuclear@1
|
430 // Tells whether or not the string is empty.
|
nuclear@1
|
431 bool IsEmpty() const { return GetSize() == 0; }
|
nuclear@1
|
432
|
nuclear@1
|
433 // Returns number of characters
|
nuclear@1
|
434 UPInt GetLength() const;
|
nuclear@1
|
435
|
nuclear@1
|
436 // Returns character at the specified index
|
nuclear@1
|
437 UInt32 GetCharAt(UPInt index) const;
|
nuclear@1
|
438 UInt32 GetFirstCharAt(UPInt index, const char** offset) const;
|
nuclear@1
|
439 UInt32 GetNextChar(const char** offset) const;
|
nuclear@1
|
440
|
nuclear@1
|
441
|
nuclear@1
|
442 // Resize the string to the new size
|
nuclear@1
|
443 void Resize(UPInt _size);
|
nuclear@1
|
444 void Reserve(UPInt _size);
|
nuclear@1
|
445
|
nuclear@1
|
446 // Appends a character
|
nuclear@1
|
447 void AppendChar(UInt32 ch);
|
nuclear@1
|
448
|
nuclear@1
|
449 // Append a string
|
nuclear@1
|
450 void AppendString(const wchar_t* pstr, SPInt len = -1);
|
nuclear@1
|
451 void AppendString(const char* putf8str, SPInt utf8StrSz = -1);
|
nuclear@1
|
452 void AppendFormat(const char* format, ...);
|
nuclear@1
|
453
|
nuclear@1
|
454 // Assigned a string with dynamic data (copied through initializer).
|
nuclear@1
|
455 //void AssignString(const InitStruct& src, UPInt size);
|
nuclear@1
|
456
|
nuclear@1
|
457 // Inserts substr at posAt
|
nuclear@1
|
458 void Insert (const char* substr, UPInt posAt, SPInt len = -1);
|
nuclear@1
|
459 // Inserts character at posAt
|
nuclear@1
|
460 UPInt InsertCharAt(UInt32 c, UPInt posAt);
|
nuclear@1
|
461
|
nuclear@1
|
462 // Assignment
|
nuclear@1
|
463 void operator = (const char* str);
|
nuclear@1
|
464 void operator = (const wchar_t* str);
|
nuclear@1
|
465 void operator = (const String& src);
|
nuclear@1
|
466
|
nuclear@1
|
467 // Addition
|
nuclear@1
|
468 void operator += (const String& src) { AppendString(src.ToCStr(),src.GetSize()); }
|
nuclear@1
|
469 void operator += (const char* psrc) { AppendString(psrc); }
|
nuclear@1
|
470 void operator += (const wchar_t* psrc) { AppendString(psrc); }
|
nuclear@1
|
471 void operator += (char ch) { AppendChar(ch); }
|
nuclear@1
|
472 //String operator + (const char* str) const ;
|
nuclear@1
|
473 //String operator + (const String& src) const ;
|
nuclear@1
|
474
|
nuclear@1
|
475 // Accesses raw bytes
|
nuclear@1
|
476 char& operator [] (int index)
|
nuclear@1
|
477 {
|
nuclear@1
|
478 OVR_ASSERT(((UPInt)index) < GetSize());
|
nuclear@1
|
479 return pData[index];
|
nuclear@1
|
480 }
|
nuclear@1
|
481 char& operator [] (UPInt index)
|
nuclear@1
|
482 {
|
nuclear@1
|
483 OVR_ASSERT(index < GetSize());
|
nuclear@1
|
484 return pData[index];
|
nuclear@1
|
485 }
|
nuclear@1
|
486
|
nuclear@1
|
487 const char& operator [] (int index) const
|
nuclear@1
|
488 {
|
nuclear@1
|
489 OVR_ASSERT(((UPInt)index) < GetSize());
|
nuclear@1
|
490 return pData[index];
|
nuclear@1
|
491 }
|
nuclear@1
|
492 const char& operator [] (UPInt index) const
|
nuclear@1
|
493 {
|
nuclear@1
|
494 OVR_ASSERT(index < GetSize());
|
nuclear@1
|
495 return pData[index];
|
nuclear@1
|
496 }
|
nuclear@1
|
497 };
|
nuclear@1
|
498
|
nuclear@1
|
499
|
nuclear@1
|
500 //
|
nuclear@1
|
501 // Wrapper for string data. The data must have a guaranteed
|
nuclear@1
|
502 // lifespan throughout the usage of the wrapper. Not intended for
|
nuclear@1
|
503 // cached usage. Not thread safe.
|
nuclear@1
|
504 //
|
nuclear@1
|
505 class StringDataPtr
|
nuclear@1
|
506 {
|
nuclear@1
|
507 public:
|
nuclear@1
|
508 StringDataPtr() : pStr(NULL), Size(0) {}
|
nuclear@1
|
509 StringDataPtr(const StringDataPtr& p)
|
nuclear@1
|
510 : pStr(p.pStr), Size(p.Size) {}
|
nuclear@1
|
511 StringDataPtr(const char* pstr, UPInt sz)
|
nuclear@1
|
512 : pStr(pstr), Size(sz) {}
|
nuclear@1
|
513 StringDataPtr(const char* pstr)
|
nuclear@1
|
514 : pStr(pstr), Size((pstr != NULL) ? OVR_strlen(pstr) : 0) {}
|
nuclear@1
|
515 explicit StringDataPtr(const String& str)
|
nuclear@1
|
516 : pStr(str.ToCStr()), Size(str.GetSize()) {}
|
nuclear@1
|
517 template <typename T, int N>
|
nuclear@1
|
518 StringDataPtr(const T (&v)[N])
|
nuclear@1
|
519 : pStr(v), Size(N) {}
|
nuclear@1
|
520
|
nuclear@1
|
521 public:
|
nuclear@1
|
522 const char* ToCStr() const { return pStr; }
|
nuclear@1
|
523 UPInt GetSize() const { return Size; }
|
nuclear@1
|
524 bool IsEmpty() const { return GetSize() == 0; }
|
nuclear@1
|
525
|
nuclear@1
|
526 // value is a prefix of this string
|
nuclear@1
|
527 // Character's values are not compared.
|
nuclear@1
|
528 bool IsPrefix(const StringDataPtr& value) const
|
nuclear@1
|
529 {
|
nuclear@1
|
530 return ToCStr() == value.ToCStr() && GetSize() >= value.GetSize();
|
nuclear@1
|
531 }
|
nuclear@1
|
532 // value is a suffix of this string
|
nuclear@1
|
533 // Character's values are not compared.
|
nuclear@1
|
534 bool IsSuffix(const StringDataPtr& value) const
|
nuclear@1
|
535 {
|
nuclear@1
|
536 return ToCStr() <= value.ToCStr() && (End()) == (value.End());
|
nuclear@1
|
537 }
|
nuclear@1
|
538
|
nuclear@1
|
539 // Find first character.
|
nuclear@1
|
540 // init_ind - initial index.
|
nuclear@1
|
541 SPInt FindChar(char c, UPInt init_ind = 0) const
|
nuclear@1
|
542 {
|
nuclear@1
|
543 for (UPInt i = init_ind; i < GetSize(); ++i)
|
nuclear@1
|
544 if (pStr[i] == c)
|
nuclear@1
|
545 return static_cast<SPInt>(i);
|
nuclear@1
|
546
|
nuclear@1
|
547 return -1;
|
nuclear@1
|
548 }
|
nuclear@1
|
549
|
nuclear@1
|
550 // Find last character.
|
nuclear@1
|
551 // init_ind - initial index.
|
nuclear@1
|
552 SPInt FindLastChar(char c, UPInt init_ind = ~0) const
|
nuclear@1
|
553 {
|
nuclear@1
|
554 if (init_ind == (UPInt)~0 || init_ind > GetSize())
|
nuclear@1
|
555 init_ind = GetSize();
|
nuclear@1
|
556 else
|
nuclear@1
|
557 ++init_ind;
|
nuclear@1
|
558
|
nuclear@1
|
559 for (UPInt i = init_ind; i > 0; --i)
|
nuclear@1
|
560 if (pStr[i - 1] == c)
|
nuclear@1
|
561 return static_cast<SPInt>(i - 1);
|
nuclear@1
|
562
|
nuclear@1
|
563 return -1;
|
nuclear@1
|
564 }
|
nuclear@1
|
565
|
nuclear@1
|
566 // Create new object and trim size bytes from the left.
|
nuclear@1
|
567 StringDataPtr GetTrimLeft(UPInt size) const
|
nuclear@1
|
568 {
|
nuclear@1
|
569 // Limit trim size to the size of the string.
|
nuclear@1
|
570 size = Alg::PMin(GetSize(), size);
|
nuclear@1
|
571
|
nuclear@1
|
572 return StringDataPtr(ToCStr() + size, GetSize() - size);
|
nuclear@1
|
573 }
|
nuclear@1
|
574 // Create new object and trim size bytes from the right.
|
nuclear@1
|
575 StringDataPtr GetTrimRight(UPInt size) const
|
nuclear@1
|
576 {
|
nuclear@1
|
577 // Limit trim to the size of the string.
|
nuclear@1
|
578 size = Alg::PMin(GetSize(), size);
|
nuclear@1
|
579
|
nuclear@1
|
580 return StringDataPtr(ToCStr(), GetSize() - size);
|
nuclear@1
|
581 }
|
nuclear@1
|
582
|
nuclear@1
|
583 // Create new object, which contains next token.
|
nuclear@1
|
584 // Useful for parsing.
|
nuclear@1
|
585 StringDataPtr GetNextToken(char separator = ':') const
|
nuclear@1
|
586 {
|
nuclear@1
|
587 UPInt cur_pos = 0;
|
nuclear@1
|
588 const char* cur_str = ToCStr();
|
nuclear@1
|
589
|
nuclear@1
|
590 for (; cur_pos < GetSize() && cur_str[cur_pos]; ++cur_pos)
|
nuclear@1
|
591 {
|
nuclear@1
|
592 if (cur_str[cur_pos] == separator)
|
nuclear@1
|
593 {
|
nuclear@1
|
594 break;
|
nuclear@1
|
595 }
|
nuclear@1
|
596 }
|
nuclear@1
|
597
|
nuclear@1
|
598 return StringDataPtr(ToCStr(), cur_pos);
|
nuclear@1
|
599 }
|
nuclear@1
|
600
|
nuclear@1
|
601 // Trim size bytes from the left.
|
nuclear@1
|
602 StringDataPtr& TrimLeft(UPInt size)
|
nuclear@1
|
603 {
|
nuclear@1
|
604 // Limit trim size to the size of the string.
|
nuclear@1
|
605 size = Alg::PMin(GetSize(), size);
|
nuclear@1
|
606 pStr += size;
|
nuclear@1
|
607 Size -= size;
|
nuclear@1
|
608
|
nuclear@1
|
609 return *this;
|
nuclear@1
|
610 }
|
nuclear@1
|
611 // Trim size bytes from the right.
|
nuclear@1
|
612 StringDataPtr& TrimRight(UPInt size)
|
nuclear@1
|
613 {
|
nuclear@1
|
614 // Limit trim to the size of the string.
|
nuclear@1
|
615 size = Alg::PMin(GetSize(), size);
|
nuclear@1
|
616 Size -= size;
|
nuclear@1
|
617
|
nuclear@1
|
618 return *this;
|
nuclear@1
|
619 }
|
nuclear@1
|
620
|
nuclear@1
|
621 const char* Begin() const { return ToCStr(); }
|
nuclear@1
|
622 const char* End() const { return ToCStr() + GetSize(); }
|
nuclear@1
|
623
|
nuclear@1
|
624 // Hash functor used string data pointers
|
nuclear@1
|
625 struct HashFunctor
|
nuclear@1
|
626 {
|
nuclear@1
|
627 UPInt operator()(const StringDataPtr& data) const
|
nuclear@1
|
628 {
|
nuclear@1
|
629 return String::BernsteinHashFunction(data.ToCStr(), data.GetSize());
|
nuclear@1
|
630 }
|
nuclear@1
|
631 };
|
nuclear@1
|
632
|
nuclear@1
|
633 bool operator== (const StringDataPtr& data) const
|
nuclear@1
|
634 {
|
nuclear@1
|
635 return (OVR_strncmp(pStr, data.pStr, data.Size) == 0);
|
nuclear@1
|
636 }
|
nuclear@1
|
637
|
nuclear@1
|
638 protected:
|
nuclear@1
|
639 const char* pStr;
|
nuclear@1
|
640 UPInt Size;
|
nuclear@1
|
641 };
|
nuclear@1
|
642
|
nuclear@1
|
643 } // OVR
|
nuclear@1
|
644
|
nuclear@1
|
645 #endif
|