aboutsummaryrefslogtreecommitdiff
path: root/client/asmjit/core/string.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'client/asmjit/core/string.cpp')
-rw-r--r--client/asmjit/core/string.cpp551
1 files changed, 551 insertions, 0 deletions
diff --git a/client/asmjit/core/string.cpp b/client/asmjit/core/string.cpp
new file mode 100644
index 0000000..e059884
--- /dev/null
+++ b/client/asmjit/core/string.cpp
@@ -0,0 +1,551 @@
+// AsmJit - Machine code generation for C++
+//
+// * Official AsmJit Home Page: https://asmjit.com
+// * Official Github Repository: https://github.com/asmjit/asmjit
+//
+// Copyright (c) 2008-2020 The AsmJit Authors
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+#include "../core/api-build_p.h"
+#include "../core/string.h"
+#include "../core/support.h"
+
+ASMJIT_BEGIN_NAMESPACE
+
+// ============================================================================
+// [asmjit::String - Globals]
+// ============================================================================
+
+static const char String_baseN[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+constexpr size_t kMinAllocSize = 64;
+constexpr size_t kMaxAllocSize = SIZE_MAX - Globals::kGrowThreshold;
+
+// ============================================================================
+// [asmjit::String]
+// ============================================================================
+
+Error String::reset() noexcept {
+ if (_type == kTypeLarge)
+ ::free(_large.data);
+
+ _resetInternal();
+ return kErrorOk;
+}
+
+Error String::clear() noexcept {
+ if (isLarge()) {
+ _large.size = 0;
+ _large.data[0] = '\0';
+ }
+ else {
+ _raw.uptr[0] = 0;
+ }
+
+ return kErrorOk;
+}
+
+char* String::prepare(uint32_t op, size_t size) noexcept {
+ char* curData;
+ size_t curSize;
+ size_t curCapacity;
+
+ if (isLarge()) {
+ curData = this->_large.data;
+ curSize = this->_large.size;
+ curCapacity = this->_large.capacity;
+ }
+ else {
+ curData = this->_small.data;
+ curSize = this->_small.type;
+ curCapacity = kSSOCapacity;
+ }
+
+ if (op == kOpAssign) {
+ if (size > curCapacity) {
+ // Prevent arithmetic overflow.
+ if (ASMJIT_UNLIKELY(size >= kMaxAllocSize))
+ return nullptr;
+
+ size_t newCapacity = Support::alignUp<size_t>(size + 1, kMinAllocSize);
+ char* newData = static_cast<char*>(::malloc(newCapacity));
+
+ if (ASMJIT_UNLIKELY(!newData))
+ return nullptr;
+
+ if (_type == kTypeLarge)
+ ::free(curData);
+
+ _large.type = kTypeLarge;
+ _large.size = size;
+ _large.capacity = newCapacity - 1;
+ _large.data = newData;
+
+ newData[size] = '\0';
+ return newData;
+ }
+ else {
+ _setSize(size);
+ curData[size] = '\0';
+ return curData;
+ }
+ }
+ else {
+ // Prevent arithmetic overflow.
+ if (ASMJIT_UNLIKELY(size >= kMaxAllocSize - curSize))
+ return nullptr;
+
+ size_t newSize = size + curSize;
+ size_t newSizePlusOne = newSize + 1;
+
+ if (newSizePlusOne > curCapacity) {
+ size_t newCapacity = Support::max<size_t>(curCapacity + 1, kMinAllocSize);
+
+ if (newCapacity < newSizePlusOne && newCapacity < Globals::kGrowThreshold)
+ newCapacity = Support::alignUpPowerOf2(newCapacity);
+
+ if (newCapacity < newSizePlusOne)
+ newCapacity = Support::alignUp(newSizePlusOne, Globals::kGrowThreshold);
+
+ if (ASMJIT_UNLIKELY(newCapacity < newSizePlusOne))
+ return nullptr;
+
+ char* newData = static_cast<char*>(::malloc(newCapacity));
+ if (ASMJIT_UNLIKELY(!newData))
+ return nullptr;
+
+ memcpy(newData, curData, curSize);
+
+ if (_type == kTypeLarge)
+ ::free(curData);
+
+ _large.type = kTypeLarge;
+ _large.size = newSize;
+ _large.capacity = newCapacity - 1;
+ _large.data = newData;
+
+ newData[newSize] = '\0';
+ return newData + curSize;
+ }
+ else {
+ _setSize(newSize);
+ curData[newSize] = '\0';
+ return curData + curSize;
+ }
+ }
+}
+
+Error String::assign(const char* data, size_t size) noexcept {
+ char* dst = nullptr;
+
+ // Null terminated string without `size` specified.
+ if (size == SIZE_MAX)
+ size = data ? strlen(data) : size_t(0);
+
+ if (isLarge()) {
+ if (size <= _large.capacity) {
+ dst = _large.data;
+ _large.size = size;
+ }
+ else {
+ size_t capacityPlusOne = Support::alignUp(size + 1, 32);
+ if (ASMJIT_UNLIKELY(capacityPlusOne < size))
+ return DebugUtils::errored(kErrorOutOfMemory);
+
+ dst = static_cast<char*>(::malloc(capacityPlusOne));
+ if (ASMJIT_UNLIKELY(!dst))
+ return DebugUtils::errored(kErrorOutOfMemory);
+
+ if (!isExternal())
+ ::free(_large.data);
+
+ _large.type = kTypeLarge;
+ _large.data = dst;
+ _large.size = size;
+ _large.capacity = capacityPlusOne - 1;
+ }
+ }
+ else {
+ if (size <= kSSOCapacity) {
+ ASMJIT_ASSERT(size < 0xFFu);
+
+ dst = _small.data;
+ _small.type = uint8_t(size);
+ }
+ else {
+ dst = static_cast<char*>(::malloc(size + 1));
+ if (ASMJIT_UNLIKELY(!dst))
+ return DebugUtils::errored(kErrorOutOfMemory);
+
+ _large.type = kTypeLarge;
+ _large.data = dst;
+ _large.size = size;
+ _large.capacity = size;
+ }
+ }
+
+ // Optionally copy data from `data` and null-terminate.
+ if (data && size) {
+ // NOTE: It's better to use `memmove()`. If, for any reason, somebody uses
+ // this function to substring the same string it would work as expected.
+ ::memmove(dst, data, size);
+ }
+
+ dst[size] = '\0';
+ return kErrorOk;
+}
+
+// ============================================================================
+// [asmjit::String - Operations]
+// ============================================================================
+
+Error String::_opString(uint32_t op, const char* str, size_t size) noexcept {
+ if (size == SIZE_MAX)
+ size = str ? strlen(str) : size_t(0);
+
+ if (!size)
+ return kErrorOk;
+
+ char* p = prepare(op, size);
+ if (!p)
+ return DebugUtils::errored(kErrorOutOfMemory);
+
+ memcpy(p, str, size);
+ return kErrorOk;
+}
+
+Error String::_opChar(uint32_t op, char c) noexcept {
+ char* p = prepare(op, 1);
+ if (!p)
+ return DebugUtils::errored(kErrorOutOfMemory);
+
+ *p = c;
+ return kErrorOk;
+}
+
+Error String::_opChars(uint32_t op, char c, size_t n) noexcept {
+ if (!n)
+ return kErrorOk;
+
+ char* p = prepare(op, n);
+ if (!p)
+ return DebugUtils::errored(kErrorOutOfMemory);
+
+ memset(p, c, n);
+ return kErrorOk;
+}
+
+Error String::padEnd(size_t n, char c) noexcept {
+ size_t size = this->size();
+ return n > size ? appendChars(c, n - size) : kErrorOk;
+}
+
+Error String::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, uint32_t flags) noexcept {
+ if (base < 2 || base > 36)
+ base = 10;
+
+ char buf[128];
+ char* p = buf + ASMJIT_ARRAY_SIZE(buf);
+
+ uint64_t orig = i;
+ char sign = '\0';
+
+ // --------------------------------------------------------------------------
+ // [Sign]
+ // --------------------------------------------------------------------------
+
+ if ((flags & kFormatSigned) != 0 && int64_t(i) < 0) {
+ i = uint64_t(-int64_t(i));
+ sign = '-';
+ }
+ else if ((flags & kFormatShowSign) != 0) {
+ sign = '+';
+ }
+ else if ((flags & kFormatShowSpace) != 0) {
+ sign = ' ';
+ }
+
+ // --------------------------------------------------------------------------
+ // [Number]
+ // --------------------------------------------------------------------------
+
+ do {
+ uint64_t d = i / base;
+ uint64_t r = i % base;
+
+ *--p = String_baseN[r];
+ i = d;
+ } while (i);
+
+ size_t numberSize = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p);
+
+ // --------------------------------------------------------------------------
+ // [Alternate Form]
+ // --------------------------------------------------------------------------
+
+ if ((flags & kFormatAlternate) != 0) {
+ if (base == 8) {
+ if (orig != 0)
+ *--p = '0';
+ }
+ if (base == 16) {
+ *--p = 'x';
+ *--p = '0';
+ }
+ }
+
+ // --------------------------------------------------------------------------
+ // [Width]
+ // --------------------------------------------------------------------------
+
+ if (sign != 0)
+ *--p = sign;
+
+ if (width > 256)
+ width = 256;
+
+ if (width <= numberSize)
+ width = 0;
+ else
+ width -= numberSize;
+
+ // --------------------------------------------------------------------------
+ // Write]
+ // --------------------------------------------------------------------------
+
+ size_t prefixSize = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p) - numberSize;
+ char* data = prepare(op, prefixSize + width + numberSize);
+
+ if (!data)
+ return DebugUtils::errored(kErrorOutOfMemory);
+
+ memcpy(data, p, prefixSize);
+ data += prefixSize;
+
+ memset(data, '0', width);
+ data += width;
+
+ memcpy(data, p + prefixSize, numberSize);
+ return kErrorOk;
+}
+
+Error String::_opHex(uint32_t op, const void* data, size_t size, char separator) noexcept {
+ char* dst;
+ const uint8_t* src = static_cast<const uint8_t*>(data);
+
+ if (!size)
+ return kErrorOk;
+
+ if (separator) {
+ if (ASMJIT_UNLIKELY(size >= SIZE_MAX / 3))
+ return DebugUtils::errored(kErrorOutOfMemory);
+
+ dst = prepare(op, size * 3 - 1);
+ if (ASMJIT_UNLIKELY(!dst))
+ return DebugUtils::errored(kErrorOutOfMemory);
+
+ size_t i = 0;
+ for (;;) {
+ dst[0] = String_baseN[(src[0] >> 4) & 0xF];
+ dst[1] = String_baseN[(src[0] ) & 0xF];
+ if (++i == size)
+ break;
+ // This makes sure that the separator is only put between two hexadecimal bytes.
+ dst[2] = separator;
+ dst += 3;
+ src++;
+ }
+ }
+ else {
+ if (ASMJIT_UNLIKELY(size >= SIZE_MAX / 2))
+ return DebugUtils::errored(kErrorOutOfMemory);
+
+ dst = prepare(op, size * 2);
+ if (ASMJIT_UNLIKELY(!dst))
+ return DebugUtils::errored(kErrorOutOfMemory);
+
+ for (size_t i = 0; i < size; i++, dst += 2, src++) {
+ dst[0] = String_baseN[(src[0] >> 4) & 0xF];
+ dst[1] = String_baseN[(src[0] ) & 0xF];
+ }
+ }
+
+ return kErrorOk;
+}
+
+Error String::_opFormat(uint32_t op, const char* fmt, ...) noexcept {
+ Error err;
+ va_list ap;
+
+ va_start(ap, fmt);
+ err = _opVFormat(op, fmt, ap);
+ va_end(ap);
+
+ return err;
+}
+
+Error String::_opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept {
+ size_t startAt = (op == kOpAssign) ? size_t(0) : size();
+ size_t remainingCapacity = capacity() - startAt;
+
+ char buf[1024];
+ int fmtResult;
+ size_t outputSize;
+
+ va_list apCopy;
+ va_copy(apCopy, ap);
+
+ if (remainingCapacity >= 128) {
+ fmtResult = vsnprintf(data() + startAt, remainingCapacity, fmt, ap);
+ outputSize = size_t(fmtResult);
+
+ if (ASMJIT_LIKELY(outputSize <= remainingCapacity)) {
+ _setSize(startAt + outputSize);
+ return kErrorOk;
+ }
+ }
+ else {
+ fmtResult = vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap);
+ outputSize = size_t(fmtResult);
+
+ if (ASMJIT_LIKELY(outputSize < ASMJIT_ARRAY_SIZE(buf)))
+ return _opString(op, buf, outputSize);
+ }
+
+ if (ASMJIT_UNLIKELY(fmtResult < 0))
+ return DebugUtils::errored(kErrorInvalidState);
+
+ char* p = prepare(op, outputSize);
+ if (ASMJIT_UNLIKELY(!p))
+ return DebugUtils::errored(kErrorOutOfMemory);
+
+ fmtResult = vsnprintf(p, outputSize + 1, fmt, apCopy);
+ ASMJIT_ASSERT(size_t(fmtResult) == outputSize);
+
+ return kErrorOk;
+}
+
+Error String::truncate(size_t newSize) noexcept {
+ if (isLarge()) {
+ if (newSize < _large.size) {
+ _large.data[newSize] = '\0';
+ _large.size = newSize;
+ }
+ }
+ else {
+ if (newSize < _type) {
+ _small.data[newSize] = '\0';
+ _small.type = uint8_t(newSize);
+ }
+ }
+
+ return kErrorOk;
+}
+
+bool String::eq(const char* other, size_t size) const noexcept {
+ const char* aData = data();
+ const char* bData = other;
+
+ size_t aSize = this->size();
+ size_t bSize = size;
+
+ if (bSize == SIZE_MAX) {
+ size_t i;
+ for (i = 0; i < aSize; i++)
+ if (aData[i] != bData[i] || bData[i] == 0)
+ return false;
+ return bData[i] == 0;
+ }
+ else {
+ if (aSize != bSize)
+ return false;
+ return ::memcmp(aData, bData, aSize) == 0;
+ }
+}
+
+// ============================================================================
+// [asmjit::Support - Unit]
+// ============================================================================
+
+#if defined(ASMJIT_TEST)
+UNIT(core_string) {
+ String s;
+
+ EXPECT(s.isLarge() == false);
+ EXPECT(s.isExternal() == false);
+
+ EXPECT(s.assign('a') == kErrorOk);
+ EXPECT(s.size() == 1);
+ EXPECT(s.capacity() == String::kSSOCapacity);
+ EXPECT(s.data()[0] == 'a');
+ EXPECT(s.data()[1] == '\0');
+ EXPECT(s.eq("a") == true);
+ EXPECT(s.eq("a", 1) == true);
+
+ EXPECT(s.assignChars('b', 4) == kErrorOk);
+ EXPECT(s.size() == 4);
+ EXPECT(s.capacity() == String::kSSOCapacity);
+ EXPECT(s.data()[0] == 'b');
+ EXPECT(s.data()[1] == 'b');
+ EXPECT(s.data()[2] == 'b');
+ EXPECT(s.data()[3] == 'b');
+ EXPECT(s.data()[4] == '\0');
+ EXPECT(s.eq("bbbb") == true);
+ EXPECT(s.eq("bbbb", 4) == true);
+
+ EXPECT(s.assign("abc") == kErrorOk);
+ EXPECT(s.size() == 3);
+ EXPECT(s.capacity() == String::kSSOCapacity);
+ EXPECT(s.data()[0] == 'a');
+ EXPECT(s.data()[1] == 'b');
+ EXPECT(s.data()[2] == 'c');
+ EXPECT(s.data()[3] == '\0');
+ EXPECT(s.eq("abc") == true);
+ EXPECT(s.eq("abc", 3) == true);
+
+ const char* large = "Large string that will not fit into SSO buffer";
+ EXPECT(s.assign(large) == kErrorOk);
+ EXPECT(s.isLarge() == true);
+ EXPECT(s.size() == strlen(large));
+ EXPECT(s.capacity() > String::kSSOCapacity);
+ EXPECT(s.eq(large) == true);
+ EXPECT(s.eq(large, strlen(large)) == true);
+
+ const char* additional = " (additional content)";
+ EXPECT(s.isLarge() == true);
+ EXPECT(s.append(additional) == kErrorOk);
+ EXPECT(s.size() == strlen(large) + strlen(additional));
+
+ EXPECT(s.clear() == kErrorOk);
+ EXPECT(s.size() == 0);
+ EXPECT(s.empty() == true);
+ EXPECT(s.data()[0] == '\0');
+ EXPECT(s.isLarge() == true); // Clear should never release the memory.
+
+ EXPECT(s.appendUInt(1234) == kErrorOk);
+ EXPECT(s.eq("1234") == true);
+
+ StringTmp<64> sTmp;
+ EXPECT(sTmp.isLarge());
+ EXPECT(sTmp.isExternal());
+ EXPECT(sTmp.appendChars(' ', 1000) == kErrorOk);
+ EXPECT(!sTmp.isExternal());
+}
+#endif
+
+ASMJIT_END_NAMESPACE