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