oculus1

annotate libovr/Src/Kernel/OVR_String.cpp @ 29:9a973ef0e2a3

fixed the performance issue under MacOSX by replacing glutSolidTeapot (which uses glEvalMesh) with my own teapot generator.
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 27 Oct 2013 06:31:18 +0200
parents e2f9e4603129
children
rev   line source
nuclear@3 1 /************************************************************************************
nuclear@3 2
nuclear@3 3 Filename : OVR_String.cpp
nuclear@3 4 Content : String UTF8 string implementation with copy-on-write semantics
nuclear@3 5 (thread-safe for assignment but not modification).
nuclear@3 6 Created : September 19, 2012
nuclear@3 7 Notes :
nuclear@3 8
nuclear@3 9 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
nuclear@3 10
nuclear@3 11 Use of this software is subject to the terms of the Oculus license
nuclear@3 12 agreement provided at the time of installation or download, or which
nuclear@3 13 otherwise accompanies this software in either electronic or hard copy form.
nuclear@3 14
nuclear@3 15 ************************************************************************************/
nuclear@3 16
nuclear@3 17 #include "OVR_String.h"
nuclear@3 18
nuclear@3 19 #include <stdlib.h>
nuclear@3 20 #include <ctype.h>
nuclear@3 21
nuclear@3 22 #ifdef OVR_OS_QNX
nuclear@3 23 # include <strings.h>
nuclear@3 24 #endif
nuclear@3 25
nuclear@3 26 namespace OVR {
nuclear@3 27
nuclear@3 28 #define String_LengthIsSize (UPInt(1) << String::Flag_LengthIsSizeShift)
nuclear@3 29
nuclear@3 30 String::DataDesc String::NullData = {String_LengthIsSize, 1, {0} };
nuclear@3 31
nuclear@3 32
nuclear@3 33 String::String()
nuclear@3 34 {
nuclear@3 35 pData = &NullData;
nuclear@3 36 pData->AddRef();
nuclear@3 37 };
nuclear@3 38
nuclear@3 39 String::String(const char* pdata)
nuclear@3 40 {
nuclear@3 41 // Obtain length in bytes; it doesn't matter if _data is UTF8.
nuclear@3 42 UPInt size = pdata ? OVR_strlen(pdata) : 0;
nuclear@3 43 pData = AllocDataCopy1(size, 0, pdata, size);
nuclear@3 44 };
nuclear@3 45
nuclear@3 46 String::String(const char* pdata1, const char* pdata2, const char* pdata3)
nuclear@3 47 {
nuclear@3 48 // Obtain length in bytes; it doesn't matter if _data is UTF8.
nuclear@3 49 UPInt size1 = pdata1 ? OVR_strlen(pdata1) : 0;
nuclear@3 50 UPInt size2 = pdata2 ? OVR_strlen(pdata2) : 0;
nuclear@3 51 UPInt size3 = pdata3 ? OVR_strlen(pdata3) : 0;
nuclear@3 52
nuclear@3 53 DataDesc *pdataDesc = AllocDataCopy2(size1 + size2 + size3, 0,
nuclear@3 54 pdata1, size1, pdata2, size2);
nuclear@3 55 memcpy(pdataDesc->Data + size1 + size2, pdata3, size3);
nuclear@3 56 pData = pdataDesc;
nuclear@3 57 }
nuclear@3 58
nuclear@3 59 String::String(const char* pdata, UPInt size)
nuclear@3 60 {
nuclear@3 61 OVR_ASSERT((size == 0) || (pdata != 0));
nuclear@3 62 pData = AllocDataCopy1(size, 0, pdata, size);
nuclear@3 63 };
nuclear@3 64
nuclear@3 65
nuclear@3 66 String::String(const InitStruct& src, UPInt size)
nuclear@3 67 {
nuclear@3 68 pData = AllocData(size, 0);
nuclear@3 69 src.InitString(GetData()->Data, size);
nuclear@3 70 }
nuclear@3 71
nuclear@3 72 String::String(const String& src)
nuclear@3 73 {
nuclear@3 74 pData = src.GetData();
nuclear@3 75 pData->AddRef();
nuclear@3 76 }
nuclear@3 77
nuclear@3 78 String::String(const StringBuffer& src)
nuclear@3 79 {
nuclear@3 80 pData = AllocDataCopy1(src.GetSize(), 0, src.ToCStr(), src.GetSize());
nuclear@3 81 }
nuclear@3 82
nuclear@3 83 String::String(const wchar_t* data)
nuclear@3 84 {
nuclear@3 85 pData = &NullData;
nuclear@3 86 pData->AddRef();
nuclear@3 87 // Simplified logic for wchar_t constructor.
nuclear@3 88 if (data)
nuclear@3 89 *this = data;
nuclear@3 90 }
nuclear@3 91
nuclear@3 92
nuclear@3 93 String::DataDesc* String::AllocData(UPInt size, UPInt lengthIsSize)
nuclear@3 94 {
nuclear@3 95 String::DataDesc* pdesc;
nuclear@3 96
nuclear@3 97 if (size == 0)
nuclear@3 98 {
nuclear@3 99 pdesc = &NullData;
nuclear@3 100 pdesc->AddRef();
nuclear@3 101 return pdesc;
nuclear@3 102 }
nuclear@3 103
nuclear@3 104 pdesc = (DataDesc*)OVR_ALLOC(sizeof(DataDesc)+ size);
nuclear@3 105 pdesc->Data[size] = 0;
nuclear@3 106 pdesc->RefCount = 1;
nuclear@3 107 pdesc->Size = size | lengthIsSize;
nuclear@3 108 return pdesc;
nuclear@3 109 }
nuclear@3 110
nuclear@3 111
nuclear@3 112 String::DataDesc* String::AllocDataCopy1(UPInt size, UPInt lengthIsSize,
nuclear@3 113 const char* pdata, UPInt copySize)
nuclear@3 114 {
nuclear@3 115 String::DataDesc* pdesc = AllocData(size, lengthIsSize);
nuclear@3 116 memcpy(pdesc->Data, pdata, copySize);
nuclear@3 117 return pdesc;
nuclear@3 118 }
nuclear@3 119
nuclear@3 120 String::DataDesc* String::AllocDataCopy2(UPInt size, UPInt lengthIsSize,
nuclear@3 121 const char* pdata1, UPInt copySize1,
nuclear@3 122 const char* pdata2, UPInt copySize2)
nuclear@3 123 {
nuclear@3 124 String::DataDesc* pdesc = AllocData(size, lengthIsSize);
nuclear@3 125 memcpy(pdesc->Data, pdata1, copySize1);
nuclear@3 126 memcpy(pdesc->Data + copySize1, pdata2, copySize2);
nuclear@3 127 return pdesc;
nuclear@3 128 }
nuclear@3 129
nuclear@3 130
nuclear@3 131 UPInt String::GetLength() const
nuclear@3 132 {
nuclear@3 133 // Optimize length accesses for non-UTF8 character strings.
nuclear@3 134 DataDesc* pdata = GetData();
nuclear@3 135 UPInt length, size = pdata->GetSize();
nuclear@3 136
nuclear@3 137 if (pdata->LengthIsSize())
nuclear@3 138 return size;
nuclear@3 139
nuclear@3 140 length = (UPInt)UTF8Util::GetLength(pdata->Data, (UPInt)size);
nuclear@3 141
nuclear@3 142 if (length == size)
nuclear@3 143 pdata->Size |= String_LengthIsSize;
nuclear@3 144
nuclear@3 145 return length;
nuclear@3 146 }
nuclear@3 147
nuclear@3 148
nuclear@3 149 //static UInt32 String_CharSearch(const char* buf, )
nuclear@3 150
nuclear@3 151
nuclear@3 152 UInt32 String::GetCharAt(UPInt index) const
nuclear@3 153 {
nuclear@3 154 SPInt i = (SPInt) index;
nuclear@3 155 DataDesc* pdata = GetData();
nuclear@3 156 const char* buf = pdata->Data;
nuclear@3 157 UInt32 c;
nuclear@3 158
nuclear@3 159 if (pdata->LengthIsSize())
nuclear@3 160 {
nuclear@3 161 OVR_ASSERT(index < pdata->GetSize());
nuclear@3 162 buf += i;
nuclear@3 163 return UTF8Util::DecodeNextChar_Advance0(&buf);
nuclear@3 164 }
nuclear@3 165
nuclear@3 166 c = UTF8Util::GetCharAt(index, buf, pdata->GetSize());
nuclear@3 167 return c;
nuclear@3 168 }
nuclear@3 169
nuclear@3 170 UInt32 String::GetFirstCharAt(UPInt index, const char** offset) const
nuclear@3 171 {
nuclear@3 172 DataDesc* pdata = GetData();
nuclear@3 173 SPInt i = (SPInt) index;
nuclear@3 174 const char* buf = pdata->Data;
nuclear@3 175 const char* end = buf + pdata->GetSize();
nuclear@3 176 UInt32 c;
nuclear@3 177
nuclear@3 178 do
nuclear@3 179 {
nuclear@3 180 c = UTF8Util::DecodeNextChar_Advance0(&buf);
nuclear@3 181 i--;
nuclear@3 182
nuclear@3 183 if (buf >= end)
nuclear@3 184 {
nuclear@3 185 // We've hit the end of the string; don't go further.
nuclear@3 186 OVR_ASSERT(i == 0);
nuclear@3 187 return c;
nuclear@3 188 }
nuclear@3 189 } while (i >= 0);
nuclear@3 190
nuclear@3 191 *offset = buf;
nuclear@3 192
nuclear@3 193 return c;
nuclear@3 194 }
nuclear@3 195
nuclear@3 196 UInt32 String::GetNextChar(const char** offset) const
nuclear@3 197 {
nuclear@3 198 return UTF8Util::DecodeNextChar(offset);
nuclear@3 199 }
nuclear@3 200
nuclear@3 201
nuclear@3 202
nuclear@3 203 void String::AppendChar(UInt32 ch)
nuclear@3 204 {
nuclear@3 205 DataDesc* pdata = GetData();
nuclear@3 206 UPInt size = pdata->GetSize();
nuclear@3 207 char buff[8];
nuclear@3 208 SPInt encodeSize = 0;
nuclear@3 209
nuclear@3 210 // Converts ch into UTF8 string and fills it into buff.
nuclear@3 211 UTF8Util::EncodeChar(buff, &encodeSize, ch);
nuclear@3 212 OVR_ASSERT(encodeSize >= 0);
nuclear@3 213
nuclear@3 214 SetData(AllocDataCopy2(size + (UPInt)encodeSize, 0,
nuclear@3 215 pdata->Data, size, buff, (UPInt)encodeSize));
nuclear@3 216 pdata->Release();
nuclear@3 217 }
nuclear@3 218
nuclear@3 219
nuclear@3 220 void String::AppendString(const wchar_t* pstr, SPInt len)
nuclear@3 221 {
nuclear@3 222 if (!pstr)
nuclear@3 223 return;
nuclear@3 224
nuclear@3 225 DataDesc* pdata = GetData();
nuclear@3 226 UPInt oldSize = pdata->GetSize();
nuclear@3 227 UPInt encodeSize = (UPInt)UTF8Util::GetEncodeStringSize(pstr, len);
nuclear@3 228
nuclear@3 229 DataDesc* pnewData = AllocDataCopy1(oldSize + (UPInt)encodeSize, 0,
nuclear@3 230 pdata->Data, oldSize);
nuclear@3 231 UTF8Util::EncodeString(pnewData->Data + oldSize, pstr, len);
nuclear@3 232
nuclear@3 233 SetData(pnewData);
nuclear@3 234 pdata->Release();
nuclear@3 235 }
nuclear@3 236
nuclear@3 237
nuclear@3 238 void String::AppendString(const char* putf8str, SPInt utf8StrSz)
nuclear@3 239 {
nuclear@3 240 if (!putf8str || !utf8StrSz)
nuclear@3 241 return;
nuclear@3 242 if (utf8StrSz == -1)
nuclear@3 243 utf8StrSz = (SPInt)OVR_strlen(putf8str);
nuclear@3 244
nuclear@3 245 DataDesc* pdata = GetData();
nuclear@3 246 UPInt oldSize = pdata->GetSize();
nuclear@3 247
nuclear@3 248 SetData(AllocDataCopy2(oldSize + (UPInt)utf8StrSz, 0,
nuclear@3 249 pdata->Data, oldSize, putf8str, (UPInt)utf8StrSz));
nuclear@3 250 pdata->Release();
nuclear@3 251 }
nuclear@3 252
nuclear@3 253 void String::AssignString(const InitStruct& src, UPInt size)
nuclear@3 254 {
nuclear@3 255 DataDesc* poldData = GetData();
nuclear@3 256 DataDesc* pnewData = AllocData(size, 0);
nuclear@3 257 src.InitString(pnewData->Data, size);
nuclear@3 258 SetData(pnewData);
nuclear@3 259 poldData->Release();
nuclear@3 260 }
nuclear@3 261
nuclear@3 262 void String::AssignString(const char* putf8str, UPInt size)
nuclear@3 263 {
nuclear@3 264 DataDesc* poldData = GetData();
nuclear@3 265 SetData(AllocDataCopy1(size, 0, putf8str, size));
nuclear@3 266 poldData->Release();
nuclear@3 267 }
nuclear@3 268
nuclear@3 269 void String::operator = (const char* pstr)
nuclear@3 270 {
nuclear@3 271 AssignString(pstr, pstr ? OVR_strlen(pstr) : 0);
nuclear@3 272 }
nuclear@3 273
nuclear@3 274 void String::operator = (const wchar_t* pwstr)
nuclear@3 275 {
nuclear@3 276 DataDesc* poldData = GetData();
nuclear@3 277 UPInt size = pwstr ? (UPInt)UTF8Util::GetEncodeStringSize(pwstr) : 0;
nuclear@3 278
nuclear@3 279 DataDesc* pnewData = AllocData(size, 0);
nuclear@3 280 UTF8Util::EncodeString(pnewData->Data, pwstr);
nuclear@3 281 SetData(pnewData);
nuclear@3 282 poldData->Release();
nuclear@3 283 }
nuclear@3 284
nuclear@3 285
nuclear@3 286 void String::operator = (const String& src)
nuclear@3 287 {
nuclear@3 288 DataDesc* psdata = src.GetData();
nuclear@3 289 DataDesc* pdata = GetData();
nuclear@3 290
nuclear@3 291 SetData(psdata);
nuclear@3 292 psdata->AddRef();
nuclear@3 293 pdata->Release();
nuclear@3 294 }
nuclear@3 295
nuclear@3 296
nuclear@3 297 void String::operator = (const StringBuffer& src)
nuclear@3 298 {
nuclear@3 299 DataDesc* polddata = GetData();
nuclear@3 300 SetData(AllocDataCopy1(src.GetSize(), 0, src.ToCStr(), src.GetSize()));
nuclear@3 301 polddata->Release();
nuclear@3 302 }
nuclear@3 303
nuclear@3 304 void String::operator += (const String& src)
nuclear@3 305 {
nuclear@3 306 DataDesc *pourData = GetData(),
nuclear@3 307 *psrcData = src.GetData();
nuclear@3 308 UPInt ourSize = pourData->GetSize(),
nuclear@3 309 srcSize = psrcData->GetSize();
nuclear@3 310 UPInt lflag = pourData->GetLengthFlag() & psrcData->GetLengthFlag();
nuclear@3 311
nuclear@3 312 SetData(AllocDataCopy2(ourSize + srcSize, lflag,
nuclear@3 313 pourData->Data, ourSize, psrcData->Data, srcSize));
nuclear@3 314 pourData->Release();
nuclear@3 315 }
nuclear@3 316
nuclear@3 317
nuclear@3 318 String String::operator + (const char* str) const
nuclear@3 319 {
nuclear@3 320 String tmp1(*this);
nuclear@3 321 tmp1 += (str ? str : "");
nuclear@3 322 return tmp1;
nuclear@3 323 }
nuclear@3 324
nuclear@3 325 String String::operator + (const String& src) const
nuclear@3 326 {
nuclear@3 327 String tmp1(*this);
nuclear@3 328 tmp1 += src;
nuclear@3 329 return tmp1;
nuclear@3 330 }
nuclear@3 331
nuclear@3 332 void String::Remove(UPInt posAt, SPInt removeLength)
nuclear@3 333 {
nuclear@3 334 DataDesc* pdata = GetData();
nuclear@3 335 UPInt oldSize = pdata->GetSize();
nuclear@3 336 // Length indicates the number of characters to remove.
nuclear@3 337 UPInt length = GetLength();
nuclear@3 338
nuclear@3 339 // If index is past the string, nothing to remove.
nuclear@3 340 if (posAt >= length)
nuclear@3 341 return;
nuclear@3 342 // Otherwise, cap removeLength to the length of the string.
nuclear@3 343 if ((posAt + removeLength) > length)
nuclear@3 344 removeLength = length - posAt;
nuclear@3 345
nuclear@3 346 // Get the byte position of the UTF8 char at position posAt.
nuclear@3 347 SPInt bytePos = UTF8Util::GetByteIndex(posAt, pdata->Data, oldSize);
nuclear@3 348 SPInt removeSize = UTF8Util::GetByteIndex(removeLength, pdata->Data + bytePos, oldSize-bytePos);
nuclear@3 349
nuclear@3 350 SetData(AllocDataCopy2(oldSize - removeSize, pdata->GetLengthFlag(),
nuclear@3 351 pdata->Data, bytePos,
nuclear@3 352 pData->Data + bytePos + removeSize, (oldSize - bytePos - removeSize)));
nuclear@3 353 pdata->Release();
nuclear@3 354 }
nuclear@3 355
nuclear@3 356
nuclear@3 357 String String::Substring(UPInt start, UPInt end) const
nuclear@3 358 {
nuclear@3 359 UPInt length = GetLength();
nuclear@3 360 if ((start >= length) || (start >= end))
nuclear@3 361 return String();
nuclear@3 362
nuclear@3 363 DataDesc* pdata = GetData();
nuclear@3 364
nuclear@3 365 // If size matches, we know the exact index range.
nuclear@3 366 if (pdata->LengthIsSize())
nuclear@3 367 return String(pdata->Data + start, end - start);
nuclear@3 368
nuclear@3 369 // Get position of starting character.
nuclear@3 370 SPInt byteStart = UTF8Util::GetByteIndex(start, pdata->Data, pdata->GetSize());
nuclear@3 371 SPInt byteSize = UTF8Util::GetByteIndex(end - start, pdata->Data + byteStart, pdata->GetSize()-byteStart);
nuclear@3 372 return String(pdata->Data + byteStart, (UPInt)byteSize);
nuclear@3 373 }
nuclear@3 374
nuclear@3 375 void String::Clear()
nuclear@3 376 {
nuclear@3 377 NullData.AddRef();
nuclear@3 378 GetData()->Release();
nuclear@3 379 SetData(&NullData);
nuclear@3 380 }
nuclear@3 381
nuclear@3 382
nuclear@3 383 String String::ToUpper() const
nuclear@3 384 {
nuclear@3 385 UInt32 c;
nuclear@3 386 const char* psource = GetData()->Data;
nuclear@3 387 const char* pend = psource + GetData()->GetSize();
nuclear@3 388 String str;
nuclear@3 389 SPInt bufferOffset = 0;
nuclear@3 390 char buffer[512];
nuclear@3 391
nuclear@3 392 while(psource < pend)
nuclear@3 393 {
nuclear@3 394 do {
nuclear@3 395 c = UTF8Util::DecodeNextChar_Advance0(&psource);
nuclear@3 396 UTF8Util::EncodeChar(buffer, &bufferOffset, OVR_towupper(wchar_t(c)));
nuclear@3 397 } while ((psource < pend) && (bufferOffset < SPInt(sizeof(buffer)-8)));
nuclear@3 398
nuclear@3 399 // Append string a piece at a time.
nuclear@3 400 str.AppendString(buffer, bufferOffset);
nuclear@3 401 bufferOffset = 0;
nuclear@3 402 }
nuclear@3 403
nuclear@3 404 return str;
nuclear@3 405 }
nuclear@3 406
nuclear@3 407 String String::ToLower() const
nuclear@3 408 {
nuclear@3 409 UInt32 c;
nuclear@3 410 const char* psource = GetData()->Data;
nuclear@3 411 const char* pend = psource + GetData()->GetSize();
nuclear@3 412 String str;
nuclear@3 413 SPInt bufferOffset = 0;
nuclear@3 414 char buffer[512];
nuclear@3 415
nuclear@3 416 while(psource < pend)
nuclear@3 417 {
nuclear@3 418 do {
nuclear@3 419 c = UTF8Util::DecodeNextChar_Advance0(&psource);
nuclear@3 420 UTF8Util::EncodeChar(buffer, &bufferOffset, OVR_towlower(wchar_t(c)));
nuclear@3 421 } while ((psource < pend) && (bufferOffset < SPInt(sizeof(buffer)-8)));
nuclear@3 422
nuclear@3 423 // Append string a piece at a time.
nuclear@3 424 str.AppendString(buffer, bufferOffset);
nuclear@3 425 bufferOffset = 0;
nuclear@3 426 }
nuclear@3 427
nuclear@3 428 return str;
nuclear@3 429 }
nuclear@3 430
nuclear@3 431
nuclear@3 432
nuclear@3 433 String& String::Insert(const char* substr, UPInt posAt, SPInt strSize)
nuclear@3 434 {
nuclear@3 435 DataDesc* poldData = GetData();
nuclear@3 436 UPInt oldSize = poldData->GetSize();
nuclear@3 437 UPInt insertSize = (strSize < 0) ? OVR_strlen(substr) : (UPInt)strSize;
nuclear@3 438 UPInt byteIndex = (poldData->LengthIsSize()) ?
nuclear@3 439 posAt : (UPInt)UTF8Util::GetByteIndex(posAt, poldData->Data, oldSize);
nuclear@3 440
nuclear@3 441 OVR_ASSERT(byteIndex <= oldSize);
nuclear@3 442
nuclear@3 443 DataDesc* pnewData = AllocDataCopy2(oldSize + insertSize, 0,
nuclear@3 444 poldData->Data, byteIndex, substr, insertSize);
nuclear@3 445 memcpy(pnewData->Data + byteIndex + insertSize,
nuclear@3 446 poldData->Data + byteIndex, oldSize - byteIndex);
nuclear@3 447 SetData(pnewData);
nuclear@3 448 poldData->Release();
nuclear@3 449 return *this;
nuclear@3 450 }
nuclear@3 451
nuclear@3 452 /*
nuclear@3 453 String& String::Insert(const UInt32* substr, UPInt posAt, SPInt len)
nuclear@3 454 {
nuclear@3 455 for (SPInt i = 0; i < len; ++i)
nuclear@3 456 {
nuclear@3 457 UPInt charw = InsertCharAt(substr[i], posAt);
nuclear@3 458 posAt += charw;
nuclear@3 459 }
nuclear@3 460 return *this;
nuclear@3 461 }
nuclear@3 462 */
nuclear@3 463
nuclear@3 464 UPInt String::InsertCharAt(UInt32 c, UPInt posAt)
nuclear@3 465 {
nuclear@3 466 char buf[8];
nuclear@3 467 SPInt index = 0;
nuclear@3 468 UTF8Util::EncodeChar(buf, &index, c);
nuclear@3 469 OVR_ASSERT(index >= 0);
nuclear@3 470 buf[(UPInt)index] = 0;
nuclear@3 471
nuclear@3 472 Insert(buf, posAt, index);
nuclear@3 473 return (UPInt)index;
nuclear@3 474 }
nuclear@3 475
nuclear@3 476
nuclear@3 477 int String::CompareNoCase(const char* a, const char* b)
nuclear@3 478 {
nuclear@3 479 return OVR_stricmp(a, b);
nuclear@3 480 }
nuclear@3 481
nuclear@3 482 int String::CompareNoCase(const char* a, const char* b, SPInt len)
nuclear@3 483 {
nuclear@3 484 if (len)
nuclear@3 485 {
nuclear@3 486 SPInt f,l;
nuclear@3 487 SPInt slen = len;
nuclear@3 488 const char *s = b;
nuclear@3 489 do {
nuclear@3 490 f = (SPInt)OVR_tolower((int)(*(a++)));
nuclear@3 491 l = (SPInt)OVR_tolower((int)(*(b++)));
nuclear@3 492 } while (--len && f && (f == l) && *b != 0);
nuclear@3 493
nuclear@3 494 if (f == l && (len != 0 || *b != 0))
nuclear@3 495 {
nuclear@3 496 f = (SPInt)slen;
nuclear@3 497 l = (SPInt)OVR_strlen(s);
nuclear@3 498 return int(f - l);
nuclear@3 499 }
nuclear@3 500
nuclear@3 501 return int(f - l);
nuclear@3 502 }
nuclear@3 503 else
nuclear@3 504 return (0-(int)OVR_strlen(b));
nuclear@3 505 }
nuclear@3 506
nuclear@3 507 // ***** Implement hash static functions
nuclear@3 508
nuclear@3 509 // Hash function
nuclear@3 510 UPInt String::BernsteinHashFunction(const void* pdataIn, UPInt size, UPInt seed)
nuclear@3 511 {
nuclear@3 512 const UByte* pdata = (const UByte*) pdataIn;
nuclear@3 513 UPInt h = seed;
nuclear@3 514 while (size > 0)
nuclear@3 515 {
nuclear@3 516 size--;
nuclear@3 517 h = ((h << 5) + h) ^ (unsigned) pdata[size];
nuclear@3 518 }
nuclear@3 519
nuclear@3 520 return h;
nuclear@3 521 }
nuclear@3 522
nuclear@3 523 // Hash function, case-insensitive
nuclear@3 524 UPInt String::BernsteinHashFunctionCIS(const void* pdataIn, UPInt size, UPInt seed)
nuclear@3 525 {
nuclear@3 526 const UByte* pdata = (const UByte*) pdataIn;
nuclear@3 527 UPInt h = seed;
nuclear@3 528 while (size > 0)
nuclear@3 529 {
nuclear@3 530 size--;
nuclear@3 531 h = ((h << 5) + h) ^ OVR_tolower(pdata[size]);
nuclear@3 532 }
nuclear@3 533
nuclear@3 534 // Alternative: "sdbm" hash function, suggested at same web page above.
nuclear@3 535 // h = 0;
nuclear@3 536 // for bytes { h = (h << 16) + (h << 6) - hash + *p; }
nuclear@3 537 return h;
nuclear@3 538 }
nuclear@3 539
nuclear@3 540
nuclear@3 541
nuclear@3 542 // ***** String Buffer used for Building Strings
nuclear@3 543
nuclear@3 544
nuclear@3 545 #define OVR_SBUFF_DEFAULT_GROW_SIZE 512
nuclear@3 546 // Constructors / Destructor.
nuclear@3 547 StringBuffer::StringBuffer()
nuclear@3 548 : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
nuclear@3 549 {
nuclear@3 550 }
nuclear@3 551
nuclear@3 552 StringBuffer::StringBuffer(UPInt growSize)
nuclear@3 553 : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
nuclear@3 554 {
nuclear@3 555 SetGrowSize(growSize);
nuclear@3 556 }
nuclear@3 557
nuclear@3 558 StringBuffer::StringBuffer(const char* data)
nuclear@3 559 : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
nuclear@3 560 {
nuclear@3 561 *this = data;
nuclear@3 562 }
nuclear@3 563
nuclear@3 564 StringBuffer::StringBuffer(const char* data, UPInt dataSize)
nuclear@3 565 : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
nuclear@3 566 {
nuclear@3 567 AppendString(data, dataSize);
nuclear@3 568 }
nuclear@3 569
nuclear@3 570 StringBuffer::StringBuffer(const String& src)
nuclear@3 571 : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
nuclear@3 572 {
nuclear@3 573 AppendString(src.ToCStr(), src.GetSize());
nuclear@3 574 }
nuclear@3 575
nuclear@3 576 StringBuffer::StringBuffer(const StringBuffer& src)
nuclear@3 577 : pData(NULL), Size(0), BufferSize(src.GetGrowSize()), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
nuclear@3 578 {
nuclear@3 579 AppendString(src.ToCStr(), src.GetSize());
nuclear@3 580 LengthIsSize = src.LengthIsSize;
nuclear@3 581 }
nuclear@3 582
nuclear@3 583 StringBuffer::StringBuffer(const wchar_t* data)
nuclear@3 584 : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
nuclear@3 585 {
nuclear@3 586 *this = data;
nuclear@3 587 }
nuclear@3 588
nuclear@3 589 StringBuffer::~StringBuffer()
nuclear@3 590 {
nuclear@3 591 if (pData)
nuclear@3 592 OVR_FREE(pData);
nuclear@3 593 }
nuclear@3 594 void StringBuffer::SetGrowSize(UPInt growSize)
nuclear@3 595 {
nuclear@3 596 if (growSize <= 16)
nuclear@3 597 GrowSize = 16;
nuclear@3 598 else
nuclear@3 599 {
nuclear@3 600 UByte bits = Alg::UpperBit(UInt32(growSize-1));
nuclear@3 601 UPInt size = 1<<bits;
nuclear@3 602 GrowSize = size == growSize ? growSize : size;
nuclear@3 603 }
nuclear@3 604 }
nuclear@3 605
nuclear@3 606 UPInt StringBuffer::GetLength() const
nuclear@3 607 {
nuclear@3 608 UPInt length, size = GetSize();
nuclear@3 609 if (LengthIsSize)
nuclear@3 610 return size;
nuclear@3 611
nuclear@3 612 length = (UPInt)UTF8Util::GetLength(pData, (UPInt)GetSize());
nuclear@3 613
nuclear@3 614 if (length == GetSize())
nuclear@3 615 LengthIsSize = true;
nuclear@3 616 return length;
nuclear@3 617 }
nuclear@3 618
nuclear@3 619 void StringBuffer::Reserve(UPInt _size)
nuclear@3 620 {
nuclear@3 621 if (_size >= BufferSize) // >= because of trailing zero! (!AB)
nuclear@3 622 {
nuclear@3 623 BufferSize = (_size + 1 + GrowSize - 1)& ~(GrowSize-1);
nuclear@3 624 if (!pData)
nuclear@3 625 pData = (char*)OVR_ALLOC(BufferSize);
nuclear@3 626 else
nuclear@3 627 pData = (char*)OVR_REALLOC(pData, BufferSize);
nuclear@3 628 }
nuclear@3 629 }
nuclear@3 630 void StringBuffer::Resize(UPInt _size)
nuclear@3 631 {
nuclear@3 632 Reserve(_size);
nuclear@3 633 LengthIsSize = false;
nuclear@3 634 Size = _size;
nuclear@3 635 if (pData)
nuclear@3 636 pData[Size] = 0;
nuclear@3 637 }
nuclear@3 638
nuclear@3 639 void StringBuffer::Clear()
nuclear@3 640 {
nuclear@3 641 Resize(0);
nuclear@3 642 /*
nuclear@3 643 if (pData != pEmptyNullData)
nuclear@3 644 {
nuclear@3 645 OVR_FREE(pHeap, pData);
nuclear@3 646 pData = pEmptyNullData;
nuclear@3 647 Size = BufferSize = 0;
nuclear@3 648 LengthIsSize = false;
nuclear@3 649 }
nuclear@3 650 */
nuclear@3 651 }
nuclear@3 652 // Appends a character
nuclear@3 653 void StringBuffer::AppendChar(UInt32 ch)
nuclear@3 654 {
nuclear@3 655 char buff[8];
nuclear@3 656 UPInt origSize = GetSize();
nuclear@3 657
nuclear@3 658 // Converts ch into UTF8 string and fills it into buff. Also increments index according to the number of bytes
nuclear@3 659 // in the UTF8 string.
nuclear@3 660 SPInt srcSize = 0;
nuclear@3 661 UTF8Util::EncodeChar(buff, &srcSize, ch);
nuclear@3 662 OVR_ASSERT(srcSize >= 0);
nuclear@3 663
nuclear@3 664 UPInt size = origSize + srcSize;
nuclear@3 665 Resize(size);
nuclear@3 666 memcpy(pData + origSize, buff, srcSize);
nuclear@3 667 }
nuclear@3 668
nuclear@3 669 // Append a string
nuclear@3 670 void StringBuffer::AppendString(const wchar_t* pstr, SPInt len)
nuclear@3 671 {
nuclear@3 672 if (!pstr)
nuclear@3 673 return;
nuclear@3 674
nuclear@3 675 SPInt srcSize = UTF8Util::GetEncodeStringSize(pstr, len);
nuclear@3 676 UPInt origSize = GetSize();
nuclear@3 677 UPInt size = srcSize + origSize;
nuclear@3 678
nuclear@3 679 Resize(size);
nuclear@3 680 UTF8Util::EncodeString(pData + origSize, pstr, len);
nuclear@3 681 }
nuclear@3 682
nuclear@3 683 void StringBuffer::AppendString(const char* putf8str, SPInt utf8StrSz)
nuclear@3 684 {
nuclear@3 685 if (!putf8str || !utf8StrSz)
nuclear@3 686 return;
nuclear@3 687 if (utf8StrSz == -1)
nuclear@3 688 utf8StrSz = (SPInt)OVR_strlen(putf8str);
nuclear@3 689
nuclear@3 690 UPInt origSize = GetSize();
nuclear@3 691 UPInt size = utf8StrSz + origSize;
nuclear@3 692
nuclear@3 693 Resize(size);
nuclear@3 694 memcpy(pData + origSize, putf8str, utf8StrSz);
nuclear@3 695 }
nuclear@3 696
nuclear@3 697
nuclear@3 698 void StringBuffer::operator = (const char* pstr)
nuclear@3 699 {
nuclear@3 700 pstr = pstr ? pstr : "";
nuclear@3 701 UPInt size = OVR_strlen(pstr);
nuclear@3 702 Resize(size);
nuclear@3 703 memcpy(pData, pstr, size);
nuclear@3 704 }
nuclear@3 705
nuclear@3 706 void StringBuffer::operator = (const wchar_t* pstr)
nuclear@3 707 {
nuclear@3 708 pstr = pstr ? pstr : L"";
nuclear@3 709 UPInt size = (UPInt)UTF8Util::GetEncodeStringSize(pstr);
nuclear@3 710 Resize(size);
nuclear@3 711 UTF8Util::EncodeString(pData, pstr);
nuclear@3 712 }
nuclear@3 713
nuclear@3 714 void StringBuffer::operator = (const String& src)
nuclear@3 715 {
nuclear@3 716 Resize(src.GetSize());
nuclear@3 717 memcpy(pData, src.ToCStr(), src.GetSize());
nuclear@3 718 }
nuclear@3 719
nuclear@3 720
nuclear@3 721 // Inserts substr at posAt
nuclear@3 722 void StringBuffer::Insert(const char* substr, UPInt posAt, SPInt len)
nuclear@3 723 {
nuclear@3 724 UPInt oldSize = Size;
nuclear@3 725 UPInt insertSize = (len < 0) ? OVR_strlen(substr) : (UPInt)len;
nuclear@3 726 UPInt byteIndex = LengthIsSize ? posAt :
nuclear@3 727 (UPInt)UTF8Util::GetByteIndex(posAt, pData, (SPInt)Size);
nuclear@3 728
nuclear@3 729 OVR_ASSERT(byteIndex <= oldSize);
nuclear@3 730 Reserve(oldSize + insertSize);
nuclear@3 731
nuclear@3 732 memmove(pData + byteIndex + insertSize, pData + byteIndex, oldSize - byteIndex + 1);
nuclear@3 733 memcpy (pData + byteIndex, substr, insertSize);
nuclear@3 734 LengthIsSize = false;
nuclear@3 735 Size = oldSize + insertSize;
nuclear@3 736 pData[Size] = 0;
nuclear@3 737 }
nuclear@3 738
nuclear@3 739 // Inserts character at posAt
nuclear@3 740 UPInt StringBuffer::InsertCharAt(UInt32 c, UPInt posAt)
nuclear@3 741 {
nuclear@3 742 char buf[8];
nuclear@3 743 SPInt len = 0;
nuclear@3 744 UTF8Util::EncodeChar(buf, &len, c);
nuclear@3 745 OVR_ASSERT(len >= 0);
nuclear@3 746 buf[(UPInt)len] = 0;
nuclear@3 747
nuclear@3 748 Insert(buf, posAt, len);
nuclear@3 749 return (UPInt)len;
nuclear@3 750 }
nuclear@3 751
nuclear@3 752 } // OVR