1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "common/base-str.h"
24 #include "common/hash-str.h"
25 #include "common/list.h"
26 #include "common/memorypool.h"
27 #include "common/textconsole.h"
28 #include "common/util.h"
29 #include "common/mutex.h"
30
31 namespace Common {
32
33 #define TEMPLATE template<class T>
34 #define BASESTRING BaseString<T>
35
36 MemoryPool *g_refCountPool = nullptr; // FIXME: This is never freed right now
37 #ifndef SCUMMVM_UTIL
38 Mutex *g_refCountPoolMutex = nullptr;
39
lockMemoryPoolMutex()40 void lockMemoryPoolMutex() {
41 // The Mutex class can only be used once g_system is set and initialized,
42 // but we may use the String class earlier than that (it is for example
43 // used in the OSystem_POSIX constructor). However in those early stages
44 // we can hope we don't have multiple threads either.
45 if (!g_system || !g_system->backendInitialized())
46 return;
47 if (!g_refCountPoolMutex)
48 g_refCountPoolMutex = new Mutex();
49 g_refCountPoolMutex->lock();
50 }
51
unlockMemoryPoolMutex()52 void unlockMemoryPoolMutex() {
53 if (g_refCountPoolMutex)
54 g_refCountPoolMutex->unlock();
55 }
56
releaseMemoryPoolMutex()57 TEMPLATE void BASESTRING::releaseMemoryPoolMutex() {
58 if (g_refCountPoolMutex){
59 delete g_refCountPoolMutex;
60 g_refCountPoolMutex = nullptr;
61 }
62 }
63
64 #endif
65
computeCapacity(uint32 len)66 static uint32 computeCapacity(uint32 len) {
67 // By default, for the capacity we use the next multiple of 32
68 return ((len + 32 - 1) & ~0x1F);
69 }
70
71 TEMPLATE
BaseString(const BASESTRING & str)72 BASESTRING::BaseString(const BASESTRING &str)
73 : _size(str._size) {
74 if (str.isStorageIntern()) {
75 // String in internal storage: just copy it
76 memcpy(_storage, str._storage, _builtinCapacity * sizeof(value_type));
77 _str = _storage;
78 } else {
79 // String in external storage: use refcount mechanism
80 str.incRefCount();
81 _extern._refCount = str._extern._refCount;
82 _extern._capacity = str._extern._capacity;
83 _str = str._str;
84 }
85 assert(_str != nullptr);
86 }
87
BaseString(const value_type * str)88 TEMPLATE BASESTRING::BaseString(const value_type *str) : _size(0), _str(_storage) {
89 if (str == nullptr) {
90 _storage[0] = 0;
91 _size = 0;
92 } else {
93 uint32 len = 0;
94 const value_type *s = str;
95 while (*s++) {
96 ++len;
97 }
98 initWithValueTypeStr(str, len);
99 }
100 }
101
BaseString(const value_type * str,uint32 len)102 TEMPLATE BASESTRING::BaseString(const value_type *str, uint32 len) : _size(0), _str(_storage) {
103 initWithValueTypeStr(str, len);
104 }
105
BaseString(const value_type * beginP,const value_type * endP)106 TEMPLATE BASESTRING::BaseString(const value_type *beginP, const value_type *endP) : _size(0), _str(_storage) {
107 assert(endP >= beginP);
108 initWithValueTypeStr(beginP, endP - beginP);
109 }
110
~BaseString()111 TEMPLATE BASESTRING::~BaseString() {
112 decRefCount(_extern._refCount);
113 }
114
makeUnique()115 TEMPLATE void BASESTRING::makeUnique() {
116 ensureCapacity(_size, true);
117 }
118
ensureCapacity(uint32 new_size,bool keep_old)119 TEMPLATE void BASESTRING::ensureCapacity(uint32 new_size, bool keep_old) {
120 bool isShared;
121 uint32 curCapacity, newCapacity;
122 value_type *newStorage;
123 int *oldRefCount = _extern._refCount;
124
125 if (isStorageIntern()) {
126 isShared = false;
127 curCapacity = _builtinCapacity;
128 } else {
129 isShared = (oldRefCount && *oldRefCount > 1);
130 curCapacity = _extern._capacity;
131 }
132
133 // Special case: If there is enough space, and we do not share
134 // the storage, then there is nothing to do.
135 if (!isShared && new_size < curCapacity)
136 return;
137
138 if (isShared && new_size < _builtinCapacity) {
139 // We share the storage, but there is enough internal storage: Use that.
140 newStorage = _storage;
141 newCapacity = _builtinCapacity;
142 } else {
143 // We need to allocate storage on the heap!
144
145 // Compute a suitable new capacity limit
146 // If the current capacity is sufficient we use the same capacity
147 if (new_size < curCapacity)
148 newCapacity = curCapacity;
149 else
150 newCapacity = MAX(curCapacity * 2, computeCapacity(new_size + 1));
151
152 // Allocate new storage
153 newStorage = new value_type[newCapacity];
154 assert(newStorage);
155 }
156
157 // Copy old data if needed, elsewise reset the new storage.
158 if (keep_old) {
159 assert(_size < newCapacity);
160 memcpy(newStorage, _str, (_size + 1) * sizeof(value_type));
161 } else {
162 _size = 0;
163 newStorage[0] = 0;
164 }
165
166 // Release hold on the old storage ...
167 decRefCount(oldRefCount);
168
169 // ... in favor of the new storage
170 _str = newStorage;
171
172 if (!isStorageIntern()) {
173 // Set the ref count & capacity if we use an external storage.
174 // It is important to do this *after* copying any old content,
175 // else we would override data that has not yet been copied!
176 _extern._refCount = nullptr;
177 _extern._capacity = newCapacity;
178 }
179 }
180
181 TEMPLATE
incRefCount() const182 void BASESTRING::incRefCount() const {
183 assert(!isStorageIntern());
184 if (_extern._refCount == nullptr) {
185 #ifndef SCUMMVM_UTIL
186 lockMemoryPoolMutex();
187 #endif
188 if (g_refCountPool == nullptr) {
189 g_refCountPool = new MemoryPool(sizeof(int));
190 assert(g_refCountPool);
191 }
192
193 _extern._refCount = (int *)g_refCountPool->allocChunk();
194 #ifndef SCUMMVM_UTIL
195 unlockMemoryPoolMutex();
196 #endif
197 *_extern._refCount = 2;
198 } else {
199 ++(*_extern._refCount);
200 }
201 }
202
203 TEMPLATE
decRefCount(int * oldRefCount)204 void BASESTRING::decRefCount(int *oldRefCount) {
205 if (isStorageIntern())
206 return;
207
208 if (oldRefCount) {
209 --(*oldRefCount);
210 }
211 if (!oldRefCount || *oldRefCount <= 0) {
212 // The ref count reached zero, so we free the string storage
213 // and the ref count storage.
214 if (oldRefCount) {
215 #ifndef SCUMMVM_UTIL
216 lockMemoryPoolMutex();
217 #endif
218 assert(g_refCountPool);
219 g_refCountPool->freeChunk(oldRefCount);
220 #ifndef SCUMMVM_UTIL
221 unlockMemoryPoolMutex();
222 #endif
223 }
224 // Coverity thinks that we always free memory, as it assumes
225 // (correctly) that there are cases when oldRefCount == 0
226 // Thus, DO NOT COMPILE, trick it and shut tons of false positives
227 #ifndef __COVERITY__
228 delete[] _str;
229 #endif
230
231 // Even though _str points to a freed memory block now,
232 // we do not change its value, because any code that calls
233 // decRefCount will have to do this afterwards anyway.
234 }
235 }
236
initWithValueTypeStr(const value_type * str,uint32 len)237 TEMPLATE void BASESTRING::initWithValueTypeStr(const value_type *str, uint32 len) {
238 assert(str);
239
240 _storage[0] = 0;
241
242 _size = len;
243
244 if (len >= _builtinCapacity) {
245 // Not enough internal storage, so allocate more
246 _extern._capacity = computeCapacity(len + 1);
247 _extern._refCount = nullptr;
248 _str = new value_type[_extern._capacity];
249 assert(_str != nullptr);
250 }
251
252 // Copy the string into the storage area
253 memmove(_str, str, len * sizeof(value_type));
254 _str[len] = 0;
255 }
256
equals(const BaseString & x) const257 TEMPLATE bool BASESTRING::equals(const BaseString &x) const {
258 if (this == &x || _str == x._str) {
259 return true;
260 }
261
262 if (x.size() != _size) {
263 return false;
264 }
265
266 return !memcmp(_str, x._str, _size * sizeof(value_type));
267 }
268
equals(const value_type * ptr) const269 TEMPLATE bool BASESTRING::equals(const value_type *ptr) const {
270 if (_str == ptr) {
271 return true;
272 }
273
274 uint i = 0;
275
276 for (; i < _size && *ptr; i++, ptr++) {
277 if (_str[i] != *ptr)
278 return false;
279 }
280
281 if (i == _size && *ptr == 0) {
282 return true;
283 }
284
285 return false;
286 }
287
equalsC(const char * ptr) const288 TEMPLATE bool BASESTRING::equalsC(const char *ptr) const {
289 uint i = 0;
290
291 for (; i < _size && *ptr; i++, ptr++) {
292 if (_str[i] != (T)*ptr)
293 return false;
294 }
295
296 if (i == _size && *ptr == 0) {
297 return true;
298 }
299
300 return false;
301 }
302
operator ==(const BaseString & x) const303 TEMPLATE bool BASESTRING::operator==(const BaseString &x) const {
304 return equals(x);
305 }
306
operator ==(const value_type * x) const307 TEMPLATE bool BASESTRING::operator==(const value_type *x) const {
308 return equals(x);
309 }
310
operator !=(const BaseString & x) const311 TEMPLATE bool BASESTRING::operator!=(const BaseString &x) const {
312 return !equals(x);
313 }
314
operator !=(const value_type * x) const315 TEMPLATE bool BASESTRING::operator!=(const value_type *x) const {
316 return !equals(x);
317 }
318
compareTo(const BaseString & x) const319 TEMPLATE int BASESTRING::compareTo(const BaseString &x) const {
320 for (uint32 i = 0, n = x.size(); i < _size && i < n; ++i) {
321 uint32 sc = _str[i];
322 uint32 xc = x[i];
323 if (sc < xc)
324 return -1;
325 else if (sc > xc)
326 return +1;
327 }
328 if (_size < x.size())
329 return -1;
330 if (_size == x.size())
331 return 0;
332 return +1;
333 }
334
compareTo(const value_type * ptr) const335 TEMPLATE int BASESTRING::compareTo(const value_type *ptr) const {
336 uint32 i = 0;
337 for (; i < _size && *ptr; ++i, ptr++) {
338 uint32 sc = _str[i];
339 uint32 xc = *ptr;
340 if (sc < xc)
341 return -1;
342 else if (sc > xc)
343 return +1;
344 }
345 if (i == _size && *ptr == 0)
346 return 0;
347 if (*ptr == 0)
348 return +1;
349 return -1;
350 }
351
compareToC(const char * ptr) const352 TEMPLATE int BASESTRING::compareToC(const char *ptr) const {
353 uint32 i = 0;
354 for (; i < _size && *ptr; ++i, ptr++) {
355 uint32 sc = _str[i];
356 uint32 xc = *ptr;
357 if (sc < xc)
358 return -1;
359 else if (sc > xc)
360 return +1;
361 }
362 if (i == _size && *ptr == 0)
363 return 0;
364 if (*ptr == 0)
365 return +1;
366 return -1;
367 }
368
operator <(const BaseString & x) const369 TEMPLATE bool BASESTRING::operator<(const BaseString &x) const {
370 return compareTo(x) < 0;
371 }
372
operator <=(const BaseString & x) const373 TEMPLATE bool BASESTRING::operator<=(const BaseString &x) const {
374 return compareTo(x) <= 0;
375 }
376
operator >(const BaseString & x) const377 TEMPLATE bool BASESTRING::operator>(const BaseString &x) const {
378 return compareTo(x) > 0;
379 }
380
operator >=(const BaseString & x) const381 TEMPLATE bool BASESTRING::operator>=(const BaseString &x) const {
382 return compareTo(x) >= 0;
383 }
384
operator <(const value_type * x) const385 TEMPLATE bool BASESTRING::operator<(const value_type *x) const {
386 return compareTo(x) < 0;
387 }
388
operator <=(const value_type * x) const389 TEMPLATE bool BASESTRING::operator<=(const value_type *x) const {
390 return compareTo(x) <= 0;
391 }
392
operator >(const value_type * x) const393 TEMPLATE bool BASESTRING::operator>(const value_type *x) const {
394 return compareTo(x) > 0;
395 }
396
operator >=(const value_type * x) const397 TEMPLATE bool BASESTRING::operator>=(const value_type *x) const {
398 return compareTo(x) >= 0;
399 }
400
contains(value_type x) const401 TEMPLATE bool BASESTRING::contains(value_type x) const {
402 for (uint32 i = 0; i < _size; ++i) {
403 if (_str[i] == x) {
404 return true;
405 }
406 }
407
408 return false;
409 }
410
contains(const BaseString & otherString) const411 TEMPLATE bool BASESTRING::contains(const BaseString &otherString) const {
412 if (empty() || otherString.empty() || _size < otherString.size()) {
413 return false;
414 }
415
416 for (const_iterator cur = begin(); cur != end(); ++cur) {
417 uint i = 0;
418 while (true) {
419 if (i == otherString.size()) {
420 return true;
421 }
422
423 if (cur[i] != otherString[i]) {
424 break;
425 }
426
427 ++i;
428 }
429 }
430
431 return false;
432 }
433
insertChar(value_type c,uint32 p)434 TEMPLATE void BASESTRING::insertChar(value_type c, uint32 p) {
435 assert(p <= _size);
436
437 ensureCapacity(_size + 1, true);
438 _size++;
439 for (uint32 i = _size; i > p; --i)
440 _str[i] = _str[i - 1];
441 _str[p] = c;
442 }
443
deleteChar(uint32 p)444 TEMPLATE void BASESTRING::deleteChar(uint32 p) {
445 assert(p < _size);
446
447 makeUnique();
448 while (p++ < _size)
449 _str[p - 1] = _str[p];
450 _size--;
451 }
452
deleteLastChar()453 TEMPLATE void BASESTRING::deleteLastChar() {
454 if (_size > 0)
455 deleteChar(_size - 1);
456 }
457
erase(uint32 p,uint32 len)458 TEMPLATE void BASESTRING::erase(uint32 p, uint32 len) {
459 if (len == 0)
460 return;
461
462 assert(p < _size);
463
464 makeUnique();
465 // If len == npos or p + len is over the end, remove all the way to the end
466 if (len == npos || p + len >= _size) {
467 // Delete char at p as well. So _size = (p - 1) + 1
468 _size = p;
469 // Null terminate
470 _str[_size] = 0;
471 return;
472 }
473
474 for ( ; p + len <= _size; p++) {
475 _str[p] = _str[p + len];
476 }
477 _size -= len;
478 }
479
erase(iterator it)480 TEMPLATE typename BASESTRING::iterator BASESTRING::erase(iterator it) {
481 this->deleteChar(it - _str);
482 return it;
483 }
484
clear()485 TEMPLATE void BASESTRING::clear() {
486 decRefCount(_extern._refCount);
487
488 _size = 0;
489 _str = _storage;
490 _storage[0] = 0;
491 }
492
493
setChar(value_type c,uint32 p)494 TEMPLATE void BASESTRING::setChar(value_type c, uint32 p) {
495 assert(p < _size);
496
497 makeUnique();
498 _str[p] = c;
499 }
500
assign(const BaseString & str)501 TEMPLATE void BASESTRING::assign(const BaseString &str) {
502 if (&str == this)
503 return;
504
505 if (str.isStorageIntern()) {
506 decRefCount(_extern._refCount);
507 _size = str._size;
508 _str = _storage;
509 memcpy(_str, str._str, (_size + 1) * sizeof(value_type));
510 } else {
511 str.incRefCount();
512 decRefCount(_extern._refCount);
513
514 _extern._refCount = str._extern._refCount;
515 _extern._capacity = str._extern._capacity;
516 _size = str._size;
517 _str = str._str;
518 }
519 }
520
assign(value_type c)521 TEMPLATE void BASESTRING::assign(value_type c) {
522 decRefCount(_extern._refCount);
523 _str = _storage;
524
525 _str[0] = c;
526 _str[1] = 0;
527
528 _size = (c == 0) ? 0 : 1;
529 }
530
insertString(const value_type * s,uint32 p)531 TEMPLATE void BASESTRING::insertString(const value_type *s, uint32 p) {
532 while (*s != '\0') {
533 BaseString::insertChar(*s++, p++);
534 }
535 }
536
insertString(const BaseString & s,uint32 p)537 TEMPLATE void BASESTRING::insertString(const BaseString &s, uint32 p) {
538 for (uint i = 0; i < s._size; i++) {
539 BaseString::insertChar(s[i], p+i);
540 }
541 }
542
find(value_type x,uint32 pos) const543 TEMPLATE uint32 BASESTRING::find(value_type x, uint32 pos) const {
544 for (uint32 i = pos; i < _size; ++i) {
545 if (_str[i] == x) {
546 return i;
547 }
548 }
549
550 return npos;
551 }
552
find(const BaseString & str,uint32 pos) const553 TEMPLATE uint32 BASESTRING::find(const BaseString &str, uint32 pos) const {
554 if (pos >= _size) {
555 return npos;
556 }
557
558 const value_type *strP = str.c_str();
559
560 for (const_iterator cur = begin() + pos; cur != end(); ++cur) {
561 uint i = 0;
562 while (true) {
563 if (!strP[i]) {
564 return cur - begin();
565 }
566
567 if (cur[i] != strP[i]) {
568 break;
569 }
570
571 ++i;
572 }
573 }
574
575 return npos;
576 }
577
find(const value_type * strP,uint32 pos) const578 TEMPLATE size_t BASESTRING::find(const value_type *strP, uint32 pos) const {
579 if (pos >= _size) {
580 return npos;
581 }
582
583 for (const_iterator cur = begin() + pos; cur != end(); ++cur) {
584 uint i = 0;
585 while (true) {
586 if (!strP[i]) {
587 return cur - begin();
588 }
589
590 if (cur[i] != strP[i]) {
591 break;
592 }
593
594 ++i;
595 }
596 }
597
598 return npos;
599 }
600
asUint64() const601 TEMPLATE uint64 BASESTRING::asUint64() const {
602 uint64 result = 0;
603 for (uint32 i = 0; i < _size; ++i) {
604 if (_str[i] < '0' || _str[i] > '9') break;
605 result = result * 10L + (_str[i] - '0');
606 }
607 return result;
608 }
609
asUint64Ext() const610 TEMPLATE uint64 BASESTRING::asUint64Ext() const {
611 uint64 result = 0;
612 uint64 base = 10;
613 uint32 skip = 0;
614
615 if (_size >= 3 && _str[0] == '0' && _str[1] == 'x') {
616 base = 16;
617 skip = 2;
618 } else if (_size >= 2 && _str[0] == '0') {
619 base = 8;
620 skip = 1;
621 } else {
622 base = 10;
623 skip = 0;
624 }
625 for (uint32 i = skip; i < _size; ++i) {
626 char digit = _str[i];
627 uint64 digitval = 17; // sentinel
628 if (digit >= '0' && digit <= '9')
629 digitval = digit - '0';
630 else if (digit >= 'a' && digit <= 'f')
631 digitval = digit - 'a' + 10;
632 else if (digit >= 'A' && digit <= 'F')
633 digitval = digit - 'A' + 10;
634 if (digitval > base)
635 break;
636 result = result * base + digitval;
637 }
638 return result;
639 }
640
641 #ifndef SCUMMVM_UTIL
642
wordWrap(const uint32 maxLength)643 TEMPLATE void BASESTRING::wordWrap(const uint32 maxLength) {
644 if (_size < maxLength) {
645 return;
646 }
647
648 makeUnique();
649
650 const uint32 kNoSpace = 0xFFFFFFFF;
651
652 uint32 i = 0;
653 while (i < _size) {
654 uint32 lastSpace = kNoSpace;
655 uint32 x = 0;
656 while (i < _size && x <= maxLength) {
657 const char c = _str[i];
658 if (c == '\n') {
659 lastSpace = kNoSpace;
660 x = 0;
661 } else {
662 if (Common::isSpace(c)) {
663 lastSpace = i;
664 }
665 ++x;
666 }
667 ++i;
668 }
669
670 if (x > maxLength) {
671 if (lastSpace == kNoSpace) {
672 insertChar('\n', i - 1);
673 } else {
674 setChar('\n', lastSpace);
675 i = lastSpace + 1;
676 }
677 }
678 }
679 }
680
681 #endif
682
toLowercase()683 TEMPLATE void BASESTRING::toLowercase() {
684 makeUnique();
685 for (uint32 i = 0; i < _size; ++i) {
686 if (_str[i] > 0 && _str[i] < 128) {
687 _str[i] = tolower(_str[i]);
688 }
689 }
690 }
691
toUppercase()692 TEMPLATE void BASESTRING::toUppercase() {
693 makeUnique();
694 for (uint32 i = 0; i < _size; ++i) {
695 if (_str[i] > 0 && _str[i] < 128) {
696 _str[i] = toupper(_str[i]);
697 }
698 }
699 }
700
701 #ifndef SCUMMVM_UTIL
702
trim()703 TEMPLATE void BASESTRING::trim() {
704 if (_size == 0)
705 return;
706
707 makeUnique();
708
709 // Trim trailing whitespace
710 while (_size >= 1 && isSpace(_str[_size - 1]))
711 --_size;
712 _str[_size] = 0;
713
714 // Trim leading whitespace
715 value_type *t = _str;
716 while (isSpace(*t))
717 t++;
718
719 if (t != _str) {
720 _size -= t - _str;
721 memmove(_str, t, (_size + 1) * sizeof(_str[0]));
722 }
723 }
724 #endif
725
assignAppend(value_type c)726 TEMPLATE void BASESTRING::assignAppend(value_type c) {
727 if (c == 0) {
728 #ifndef SCUMMVM_UTIL
729 warning("Adding \\0 to String. This is permitted, but can have unwanted consequences. (This warning will be removed later.)");
730 #endif
731 }
732 ensureCapacity(_size + 1, true);
733
734 _str[_size++] = c;
735 _str[_size] = 0;
736 }
737
assignAppend(const BaseString & str)738 TEMPLATE void BASESTRING::assignAppend(const BaseString &str) {
739 if (&str == this) {
740 assignAppend(BaseString(str));
741 return;
742 }
743
744 int len = str._size;
745 if (len > 0) {
746 ensureCapacity(_size + len, true);
747
748 memcpy(_str + _size, str._str, (len + 1) * sizeof(value_type));
749 _size += len;
750 }
751 }
752
pointerInOwnBuffer(const value_type * str) const753 TEMPLATE bool BASESTRING::pointerInOwnBuffer(const value_type *str) const {
754 //compared pointers must be in the same array or UB
755 //cast to intptr however is IB
756 //which includes comparision of the values
757 uintptr ownBuffStart = (uintptr)_str;
758 uintptr ownBuffEnd = (uintptr)(_str + _size);
759 uintptr candidateAddr = (uintptr)str;
760 return ownBuffStart <= candidateAddr && candidateAddr <= ownBuffEnd;
761 }
762
assignAppend(const value_type * str)763 TEMPLATE void BASESTRING::assignAppend(const value_type *str) {
764 if (pointerInOwnBuffer(str)) {
765 assignAppend(BaseString(str));
766 return;
767 }
768
769 uint32 len;
770 for (len = 0; str[len]; len++);
771 if (len > 0) {
772 ensureCapacity(_size + len, true);
773
774 memcpy(_str + _size, str, (len + 1) * sizeof(value_type));
775 _size += len;
776 }
777 }
778
assign(const value_type * str)779 TEMPLATE void BASESTRING::assign(const value_type *str) {
780 uint32 len;
781 for (len = 0; str[len]; len++);
782 ensureCapacity(len, false);
783 _size = len;
784 memmove(_str, str, (len + 1) * sizeof(value_type));
785 }
786
getUnsignedValue(uint pos) const787 TEMPLATE uint BASESTRING::getUnsignedValue(uint pos) const {
788 const int shift = (sizeof(uint) - sizeof(value_type)) * 8;
789 return ((uint)_str[pos]) << shift >> shift;
790 }
791
792 // Hash function for strings, taken from CPython.
hash() const793 TEMPLATE uint BASESTRING::hash() const {
794 uint hashResult = getUnsignedValue(0) << 7;
795 for (uint i = 0; i < _size; i++) {
796 hashResult = (1000003 * hashResult) ^ getUnsignedValue(i);
797 }
798 return hashResult ^ _size;
799 }
800
801 template class BaseString<char>;
802 template class BaseString<u32char_type_t>;
803
804 }
805