Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: compiled/String.h

Issue 29333474: Issue 4125 - [emscripten] Convert filter classes to C++ (Closed)
Patch Set: Optimized hash lookup performance a bit Created Feb. 8, 2016, 7:11 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: compiled/String.h
===================================================================
new file mode 100644
--- /dev/null
+++ b/compiled/String.h
@@ -0,0 +1,325 @@
+#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)
+ {
+ }
+
+ void reset(value_type* buf, size_type len, size_type flags)
+ {
+ mBuf = buf;
+ mLen = (len & LENGTH_MASK) | flags;
+ }
+
sergei 2016/02/17 12:54:53 What about adding protected destructor or virtual
Wladimir Palant 2016/02/18 16:06:53 Nice one, I thought that having a protected constr
+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 (!str.length())
+ return pos;
sergei 2016/02/17 12:54:39 Strictly speaking, if `pos > this->length()` then
Wladimir Palant 2016/02/18 16:06:58 Done.
+
+ if (length() - pos < str.length())
sergei 2016/02/17 12:54:42 We also should check whether `this->length()` is n
Wladimir Palant 2016/02/18 16:06:47 If length() is 0 then length() - pos will be at mo
sergei 2016/02/22 12:45:46 I wanted to have at the beginning of the method th
Wladimir Palant 2016/02/23 12:37:21 Yes, in our case an integer overflow is luckily im
sergei 2016/02/23 15:07:27 As a matter of form we still need to check that `p
Wladimir Palant 2016/02/23 21:34:54 True, done.
+ return npos;
+
+ for (; pos < length() - str.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 == npos)
+ pos = length() - 1;
sergei 2016/02/17 12:54:54 It seems safer to use something like `pos = min(po
Wladimir Palant 2016/02/18 16:06:46 Done.
+
+ for (int i = pos; i >= 0; --i)
+ if (mBuf[i] == c)
+ return i;
+ return npos;
+ }
+};
+
+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)
+ {
+ }
+
+ DependentString(String& str, size_type pos = 0, size_type len = npos)
sergei 2016/02/17 12:54:51 I would add `explicit` for this particular method.
Wladimir Palant 2016/02/18 16:06:51 Why? I think that passing OwnedString to a functio
sergei 2016/02/22 12:45:45 May be it's desired. It seems it's not actually us
Wladimir Palant 2016/02/23 12:37:26 It's being used in various getters, e.g. Filter::G
sergei 2016/02/23 15:07:26 Yes, the variant with const, but this constructor
Wladimir Palant 2016/02/23 21:34:54 bindings.h currently enforces the return value to
+ : String(
+ str.mBuf + std::min(pos, str.length()),
+ std::min(len, str.length() - std::min(pos, str.length())),
+ READ_WRITE
+ )
+ {
+ }
+
+ 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);
+ }
+
+ bool is_invalid() const
sergei 2016/02/17 12:54:52 what about moving it into base class String?
Wladimir Palant 2016/02/18 16:06:52 Given that it is only necessary for StringMap - wh
sergei 2016/02/22 12:45:49 Because flag values are defined in `String`, flag
Wladimir Palant 2016/02/23 12:37:24 Done.
+ {
+ return (mLen & FLAGS_MASK) == INVALID;
+ }
+
+ bool is_deleted() const
+ {
+ return (mLen & FLAGS_MASK) == DELETED;
sergei 2016/02/17 12:54:49 How can it actually happen? It seems it is never s
Wladimir Palant 2016/02/18 16:06:55 No, it's not - yet. The reason is that StringMap c
sergei 2016/02/22 12:45:50 Acknowledged.
+ }
+};
+
+class OwnedString : public String
+{
+private:
+ value_type* allocate(size_type len)
+ {
+ if (len)
+ return new value_type[len];
+ else
+ return nullptr;
+ }
+
+ void resize(size_type newLength, bool copy)
sergei 2016/02/17 12:54:43 I'm not sure about `copy` argument, it's called on
Wladimir Palant 2016/02/18 16:06:49 Indeed, not any more - removed that parameter.
+ {
+ size_type oldLength = length();
+ value_type* oldBuffer = mBuf;
+
+ reset(nullptr, newLength, READ_WRITE);
+ newLength = length();
+ mBuf = allocate(newLength);
+ annotate_address(mBuf, "String");
+
+ if (copy && oldLength)
+ std::memcpy(mBuf, oldBuffer, sizeof(value_type) * std::min(oldLength, newLength));
sergei 2016/02/17 12:54:41 If either destination or source buffer is nullptr
Wladimir Palant 2016/02/18 16:06:57 oldLength is non-zero so oldBuffer cannot be nullp
sergei 2016/02/22 12:45:38 Acknowledged, sorry, overlooked.
+ 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())
+ {
+ std::memcpy(mBuf, str.mBuf, sizeof(value_type) * length());
sergei 2016/02/17 12:54:40 Here both mBuf and str.mBuf can be nullptr.
Wladimir Palant 2016/02/18 16:06:54 Should be fine as length() will be 0 in that case?
sergei 2016/02/22 12:45:48 According to http://en.cppreference.com/w/cpp/stri
Wladimir Palant 2016/02/23 12:37:23 Done.
+ }
+
+ 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(str.length())
+ {
+ mBuf = str.mBuf;
+ str.mBuf = nullptr;
+ str.mLen = READ_WRITE | 0;
+ }
+
+ OwnedString(const char* source, size_type len)
+ : OwnedString(len)
+ {
+ for (size_type i = 0; i < len; i++)
+ mBuf[i] = source[i];
+ }
+
+ ~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)
sergei 2016/02/17 12:54:50 it would be also good to check that source is not
Wladimir Palant 2016/02/18 16:06:50 That would be a bug in the caller - meaning that w
sergei 2016/02/22 12:45:39 Good.
+ return;
+
+ size_t oldLength = length();
+ resize(oldLength + sourceLen, true);
+ 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);
+ }
+};
+
+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);
+}

Powered by Google App Engine
This is Rietveld