| Index: compiled/String.h |
| =================================================================== |
| new file mode 100644 |
| --- /dev/null |
| +++ b/compiled/String.h |
| @@ -0,0 +1,327 @@ |
| +#pragma once |
| + |
| +#include <cstddef> |
| +#include <cstring> |
| +#include <algorithm> |
| + |
| +#include "debug.h" |
| + |
| +inline void String_assert_readonly(bool readOnly); |
| + |
| +class String |
| +{ |
| + friend class DependentString; |
| + friend class OwnedString; |
| + |
| +public: |
| + typedef char16_t value_type; |
| + typedef size_t size_type; |
| + |
| + // Type flags, stored in the top 2 bits of the mLen member |
| + static constexpr size_type INVALID = 0xC0000000; |
| + static constexpr size_type DELETED = 0x80000000; |
| + static constexpr size_type READ_ONLY = 0x40000000; |
| + static constexpr size_type READ_WRITE = 0x00000000; |
| + |
| + static constexpr size_type FLAGS_MASK = 0xC0000000; |
| + static constexpr size_type LENGTH_MASK = 0x3FFFFFFF; |
| + |
| + static constexpr size_type npos = -1; |
| + |
| +protected: |
| + value_type* mBuf; |
| + size_type mLen; |
| + |
| + String(value_type* buf, size_type len, size_type flags) |
| + : mBuf(buf), mLen((len & LENGTH_MASK) | flags) |
| + { |
| + } |
| + |
| + ~String() |
| + { |
| + } |
| + |
| + void reset(value_type* buf, size_type len, size_type flags) |
| + { |
| + mBuf = buf; |
| + mLen = (len & LENGTH_MASK) | flags; |
| + } |
| + |
| +public: |
| + size_type length() const |
| + { |
| + return mLen & LENGTH_MASK; |
| + } |
| + |
| + bool empty() const |
| + { |
| + return !(mLen & LENGTH_MASK); |
| + } |
| + |
| + const value_type* data() const |
| + { |
| + return mBuf; |
| + } |
| + |
| + value_type* data() |
| + { |
| + String_assert_readonly(is_readOnly()); |
| + return mBuf; |
| + } |
| + |
| + const value_type& operator[](size_type pos) const |
| + { |
| + return mBuf[pos]; |
| + } |
| + |
| + value_type& operator[](size_type pos) |
| + { |
| + String_assert_readonly(is_readOnly()); |
| + return mBuf[pos]; |
| + } |
| + |
| + bool is_readOnly() const |
| + { |
| + return (mLen & FLAGS_MASK) != READ_WRITE; |
| + } |
| + |
| + bool equals(const String& other) const |
| + { |
| + if (length() != other.length()) |
| + return false; |
| + |
| + return std::memcmp(mBuf, other.mBuf, sizeof(value_type) * length()) == 0; |
| + } |
| + |
| + size_type find(value_type c, size_type pos = 0) const |
| + { |
| + for (size_type i = pos; i < length(); ++i) |
| + if (mBuf[i] == c) |
| + return i; |
| + return npos; |
| + } |
| + |
| + size_type find(const String& str, size_type pos = 0) const |
| + { |
| + if (pos > LENGTH_MASK || pos + str.length() > length()) |
| + return npos; |
| + |
| + if (!str.length()) |
| + return pos; |
| + |
| + for (; pos + str.length() <= length(); ++pos) |
| + { |
| + if (mBuf[pos] == str[0] && |
| + std::memcmp(mBuf + pos, str.mBuf, sizeof(value_type) * str.length()) == 0) |
| + { |
| + return pos; |
| + } |
| + } |
| + |
| + return npos; |
| + } |
| + |
| + size_type rfind(value_type c, size_type pos = npos) const |
| + { |
| + if (length() == 0) |
| + return npos; |
| + |
| + if (pos >= length()) |
| + pos = length() - 1; |
| + |
| + for (int i = pos; i >= 0; --i) |
| + if (mBuf[i] == c) |
| + return i; |
| + return npos; |
| + } |
| + |
| + bool is_invalid() const |
| + { |
| + return (mLen & FLAGS_MASK) == INVALID; |
| + } |
| + |
| + bool is_deleted() const |
| + { |
| + return (mLen & FLAGS_MASK) == DELETED; |
| + } |
| +}; |
| + |
| +class DependentString : public String |
| +{ |
| +public: |
| + DependentString() |
| + : String(nullptr, 0, INVALID) |
| + { |
| + } |
| + |
| + DependentString(value_type* buf, size_type len) |
| + : String(buf, len, READ_WRITE) |
| + { |
| + } |
| + |
| + DependentString(const value_type* buf, size_type len) |
| + : String(const_cast<value_type*>(buf), len, READ_ONLY) |
| + { |
| + } |
| + |
| + explicit DependentString(String& str, size_type pos = 0, size_type len = npos) |
| + : String( |
| + str.mBuf + std::min(pos, str.length()), |
| + std::min(len, str.length() - std::min(pos, str.length())), |
| + str.is_readOnly() ? READ_ONLY : READ_WRITE |
| + ) |
| + { |
| + } |
| + |
| + explicit DependentString(const String& str, size_type pos = 0, |
| + size_type len = npos) |
| + : String( |
| + str.mBuf + std::min(pos, str.length()), |
| + std::min(len, str.length() - std::min(pos, str.length())), |
| + READ_ONLY |
| + ) |
| + { |
| + } |
| + |
| + void reset(value_type* buf, size_type len) |
| + { |
| + *this = DependentString(buf, len); |
| + } |
| + |
| + void reset(const value_type* buf, size_type len) |
| + { |
| + *this = DependentString(buf, len); |
| + } |
| + |
| + void reset(String& str, size_type pos = 0, size_type len = npos) |
| + { |
| + *this = DependentString(str, pos, len); |
| + } |
| + |
| + void reset(const String& str, size_type pos = 0, size_type len = npos) |
| + { |
| + *this = DependentString(str, pos, len); |
| + } |
| +}; |
| + |
| +inline DependentString operator "" _str(const String::value_type* str, |
| + String::size_type len) |
| +{ |
| + return DependentString(str, len); |
| +} |
| + |
| +inline void String_assert_readonly(bool readOnly) |
| +{ |
| + assert(!readOnly, u"Writing access to a read-only string"_str); |
| +} |
| + |
| +class OwnedString : public String |
| +{ |
| +private: |
| + value_type* allocate(size_type len) |
| + { |
| + if (len) |
| + return new value_type[len]; |
| + else |
| + return nullptr; |
| + } |
| + |
| + void grow(size_type additionalSize) |
| + { |
| + size_type oldLength = length(); |
| + size_type newLength = oldLength + additionalSize; |
| + value_type* oldBuffer = mBuf; |
| + |
| + reset(nullptr, newLength, READ_WRITE); |
| + newLength = length(); |
| + mBuf = allocate(newLength); |
| + annotate_address(mBuf, "String"); |
| + |
| + if (oldLength) |
| + std::memcpy(mBuf, oldBuffer, sizeof(value_type) * oldLength); |
| + if (oldBuffer) |
| + delete[] oldBuffer; |
| + } |
| + |
| +public: |
| + OwnedString(size_type len = 0) |
| + : String(nullptr, len, READ_WRITE) |
| + { |
| + mBuf = allocate(length()); |
| + annotate_address(mBuf, "String"); |
| + } |
| + |
| + OwnedString(const String& str) |
| + : OwnedString(str.length()) |
| + { |
| + if (length()) |
| + std::memcpy(mBuf, str.mBuf, sizeof(value_type) * length()); |
| + } |
| + |
| + OwnedString(const OwnedString& str) |
| + : OwnedString(static_cast<const String&>(str)) |
| + { |
| + } |
| + |
| + OwnedString(const value_type* str, size_type len) |
| + : OwnedString(DependentString(str, len)) |
| + { |
| + } |
| + |
| + OwnedString(OwnedString&& str) |
| + : OwnedString(0) |
| + { |
| + mBuf = str.mBuf; |
| + mLen = str.mLen; |
| + str.mBuf = nullptr; |
| + str.mLen = READ_WRITE | 0; |
| + } |
| + |
| + ~OwnedString() |
| + { |
| + if (mBuf) |
| + delete[] mBuf; |
| + } |
| + |
| + OwnedString& operator=(const String& str) |
| + { |
| + *this = std::move(OwnedString(str)); |
| + return *this; |
| + } |
| + |
| + OwnedString& operator=(const OwnedString& str) |
| + { |
| + *this = std::move(OwnedString(str)); |
| + return *this; |
| + } |
| + |
| + OwnedString& operator=(OwnedString&& str) |
| + { |
| + mBuf = str.mBuf; |
| + mLen = str.mLen; |
| + str.mBuf = nullptr; |
| + str.mLen = READ_WRITE | 0; |
| + return *this; |
| + } |
| + |
| + void append(const value_type* source, size_type sourceLen) |
| + { |
| + if (!sourceLen) |
| + return; |
| + |
| + assert(source, u"Null buffer passed to OwnedString.append()"_str); |
| + size_t oldLength = length(); |
| + grow(sourceLen); |
| + std::memcpy(mBuf + oldLength, source, sizeof(value_type) * sourceLen); |
| + } |
| + |
| + void append(const String& str) |
| + { |
| + append(str.mBuf, str.length()); |
| + } |
| + |
| + void append(value_type c) |
| + { |
| + append(&c, 1); |
| + } |
| +}; |