Index: compiled/String.h |
=================================================================== |
new file mode 100644 |
--- /dev/null |
+++ b/compiled/String.h |
@@ -0,0 +1,302 @@ |
+#ifndef ADBLOCK_PLUS_STRING_H |
+#define ADBLOCK_PLUS_STRING_H |
+ |
+#include <cstddef> |
+#include <cstring> |
+#include <algorithm> |
+ |
+#include "debug.h" |
+ |
+inline void String_assert_readonly(bool readOnly); |
+ |
+class String |
+{ |
+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 OWNBUFFER = 0xC0000000; |
+ static constexpr size_type INVALID = 0x80000000; |
+ static constexpr size_type DELETED = 0x40000000; |
+ static constexpr size_type DEPENDENT = 0x00000000; |
+ |
+ // Read-only flag (for debug asserts only) |
+ static constexpr size_type READ_ONLY = 0x20000000; |
+ static constexpr size_type READ_WRITE = 0x00000000; |
+ |
+ static constexpr size_type FLAGS_MASK = 0xE0000000; |
+ static constexpr size_type LENGTH_MASK = 0x1FFFFFFF; |
+ |
+ static constexpr size_type npos = -1; |
+ |
+private: |
+ value_type* mBuf; |
+ size_type mLen; |
+ |
+ value_type* allocate(size_type len) |
+ { |
+ if (len) |
+ return new value_type[len]; |
+ else |
+ return nullptr; |
+ } |
+ |
+ void resize(size_type newLength, bool copy) |
+ { |
+ bool owningOldBuffer = owns_buffer(); |
+ size_type oldLength = length(); |
+ value_type* oldBuffer = mBuf; |
+ |
+ newLength &= LENGTH_MASK; |
+ mBuf = allocate(newLength); |
+ annotate_address(mBuf, "String"); |
+ mLen = OWNBUFFER | READ_WRITE | newLength; |
+ |
+ if (copy && oldLength) |
+ memcpy(mBuf, oldBuffer, sizeof(value_type) * std::min(oldLength, newLength)); |
+ if (owningOldBuffer) |
+ delete[] oldBuffer; |
+ } |
+ |
+public: |
+ String() : mBuf(nullptr), mLen(INVALID) {} |
+ |
+ String(size_type len) |
+ : mBuf(allocate(len & LENGTH_MASK)), |
+ mLen(OWNBUFFER | READ_WRITE | (len & LENGTH_MASK)) |
+ { |
+ annotate_address(mBuf, "String"); |
+ } |
+ |
+ String(value_type* buf, size_type len) |
+ : mBuf(buf), mLen(DEPENDENT | READ_WRITE | (buf ? len & LENGTH_MASK: 0)) |
+ { |
+ } |
+ |
+ String(const value_type* buf, size_type len) |
+ : mBuf(const_cast<value_type*>(buf)), |
+ mLen(DEPENDENT | READ_ONLY | (buf ? len & LENGTH_MASK: 0)) |
+ { |
+ } |
+ |
+ String(String& str, size_type pos = 0, size_type len = npos) |
+ : mBuf(str.mBuf + std::min(pos, str.length())), |
+ mLen(DEPENDENT | READ_WRITE | std::min(len, str.length() - (mBuf - str.mBuf))) |
+ { |
+ } |
+ |
+ String(const String& str, size_type pos = 0, size_type len = npos) |
+ : mBuf(str.mBuf + std::min(pos, str.length())), |
+ mLen(DEPENDENT | READ_ONLY | std::min(len, str.length() - (mBuf - str.mBuf))) |
+ { |
+ } |
+ |
+ String(String&& str) |
+ { |
+ *this = std::move(str); |
+ } |
+ |
+ String(const char* source, size_type len) |
+ : String(len) |
+ { |
+ for (size_type i = 0; i < len; i++) |
+ mBuf[i] = source[i]; |
+ } |
+ |
+ String& operator=(const String& str) |
+ { |
+ reset(str); |
+ return *this; |
+ } |
+ |
+ String& operator=(String& str) |
+ { |
+ reset(str); |
+ return *this; |
+ } |
+ |
+ String& operator=(String&& str) |
+ { |
+ mBuf = str.mBuf; |
+ mLen = str.mLen; |
+ str.mBuf = nullptr; |
+ str.mLen = INVALID; |
+ return *this; |
+ } |
+ |
+ ~String() |
+ { |
+ if (owns_buffer()) |
+ delete[] mBuf; |
+ } |
+ |
+ void reset(value_type* buf, size_type len) |
+ { |
+ mBuf = buf; |
+ mLen = (DEPENDENT | READ_WRITE | (buf ? len & LENGTH_MASK: 0)); |
+ } |
+ |
+ void reset(const value_type* buf, size_type len) |
+ { |
+ mBuf = const_cast<value_type*>(buf); |
+ mLen = (DEPENDENT | READ_ONLY | (buf ? len & LENGTH_MASK: 0)); |
+ } |
+ |
+ void reset(String& str, size_type pos = 0, size_type len = npos) |
+ { |
+ pos = std::min(pos, str.length()); |
+ len = std::min(len, str.length() - pos); |
+ reset(str.mBuf + pos, len); |
+ } |
+ |
+ void reset(const String& str, size_type pos = 0, size_type len = npos) |
+ { |
+ pos = std::min(pos, str.length()); |
+ len = std::min(len, str.length() - pos); |
+ reset(const_cast<const value_type*>(str.mBuf + pos), len); |
+ } |
+ |
+ 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(mLen & READ_ONLY); |
+ return mBuf; |
+ } |
+ |
+ const value_type& operator[](size_type pos) const |
+ { |
+ return mBuf[pos]; |
+ } |
+ |
+ value_type& operator[](size_type pos) |
+ { |
+ String_assert_readonly(mLen & READ_ONLY); |
+ return mBuf[pos]; |
+ } |
+ |
+ bool equals(const String& other) const |
+ { |
+ if (length() != other.length()) |
+ return false; |
+ |
+ return 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 (!str.length()) |
+ return pos; |
+ |
+ if (length() - pos < str.length()) |
+ return npos; |
+ |
+ for (; pos < length() - str.length(); ++pos) |
+ { |
+ if (mBuf[pos] == str[0] && |
+ 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 == npos) |
+ pos = length() - 1; |
+ |
+ for (int i = pos; i >= 0; --i) |
+ if (mBuf[i] == c) |
+ return i; |
+ return npos; |
+ } |
+ |
+ void append(const value_type* source, size_type sourceLen) |
+ { |
+ if (!sourceLen) |
+ return; |
+ |
+ size_t oldLength = length(); |
+ resize(oldLength + sourceLen, true); |
+ 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); |
+ } |
+ |
+ bool owns_buffer() const |
+ { |
+ return mBuf && (mLen & FLAGS_MASK) == OWNBUFFER; |
+ } |
+ |
+ String& ensure_own_buffer() |
+ { |
+ size_type len = length(); |
+ if (len && !owns_buffer()) |
+ resize(len, true); |
+ return *this; |
+ } |
+ |
+ bool is_dependent() const |
+ { |
+ return (mLen & FLAGS_MASK) == DEPENDENT; |
+ } |
+ |
+ bool is_invalid() const |
+ { |
+ return (mLen & FLAGS_MASK) == INVALID; |
+ } |
+ |
+ bool is_deleted() const |
+ { |
+ return (mLen & FLAGS_MASK) == DELETED; |
+ } |
+}; |
+ |
+inline String operator "" _str(const String::value_type* str, |
+ String::size_type len) |
+{ |
+ return String(const_cast<String::value_type*>(str), len); |
+} |
+ |
+inline void String_assert_readonly(bool readOnly) |
+{ |
+ assert(!readOnly, u"Writing access to a read-only string"_str); |
+} |
+ |
+#endif |