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

Side by Side 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.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #pragma once
2
3 #include <cstddef>
4 #include <cstring>
5 #include <algorithm>
6
7 #include "debug.h"
8
9 inline void String_assert_readonly(bool readOnly);
10
11 class String
12 {
13 friend class DependentString;
14 friend class OwnedString;
15
16 public:
17 typedef char16_t value_type;
18 typedef size_t size_type;
19
20 // Type flags, stored in the top 2 bits of the mLen member
21 static constexpr size_type INVALID = 0xC0000000;
22 static constexpr size_type DELETED = 0x80000000;
23 static constexpr size_type READ_ONLY = 0x40000000;
24 static constexpr size_type READ_WRITE = 0x00000000;
25
26 static constexpr size_type FLAGS_MASK = 0xC0000000;
27 static constexpr size_type LENGTH_MASK = 0x3FFFFFFF;
28
29 static constexpr size_type npos = -1;
30
31 protected:
32 value_type* mBuf;
33 size_type mLen;
34
35 String(value_type* buf, size_type len, size_type flags)
36 : mBuf(buf), mLen((len & LENGTH_MASK) | flags)
37 {
38 }
39
40 void reset(value_type* buf, size_type len, size_type flags)
41 {
42 mBuf = buf;
43 mLen = (len & LENGTH_MASK) | flags;
44 }
45
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
46 public:
47 size_type length() const
48 {
49 return mLen & LENGTH_MASK;
50 }
51
52 bool empty() const
53 {
54 return !(mLen & LENGTH_MASK);
55 }
56
57 const value_type* data() const
58 {
59 return mBuf;
60 }
61
62 value_type* data()
63 {
64 String_assert_readonly(is_readOnly());
65 return mBuf;
66 }
67
68 const value_type& operator[](size_type pos) const
69 {
70 return mBuf[pos];
71 }
72
73 value_type& operator[](size_type pos)
74 {
75 String_assert_readonly(is_readOnly());
76 return mBuf[pos];
77 }
78
79 bool is_readOnly() const
80 {
81 return (mLen & FLAGS_MASK) != READ_WRITE;
82 }
83
84 bool equals(const String& other) const
85 {
86 if (length() != other.length())
87 return false;
88
89 return std::memcmp(mBuf, other.mBuf, sizeof(value_type) * length()) == 0;
90 }
91
92 size_type find(value_type c, size_type pos = 0) const
93 {
94 for (size_type i = pos; i < length(); ++i)
95 if (mBuf[i] == c)
96 return i;
97 return npos;
98 }
99
100 size_type find(const String& str, size_type pos = 0) const
101 {
102 if (!str.length())
103 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.
104
105 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.
106 return npos;
107
108 for (; pos < length() - str.length(); ++pos)
109 {
110 if (mBuf[pos] == str[0] &&
111 std::memcmp(mBuf + pos, str.mBuf, sizeof(value_type) * str.length()) = = 0)
112 {
113 return pos;
114 }
115 }
116
117 return npos;
118 }
119
120 size_type rfind(value_type c, size_type pos = npos) const
121 {
122 if (length() == 0)
123 return npos;
124
125 if (pos == npos)
126 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.
127
128 for (int i = pos; i >= 0; --i)
129 if (mBuf[i] == c)
130 return i;
131 return npos;
132 }
133 };
134
135 class DependentString : public String
136 {
137 public:
138 DependentString()
139 : String(nullptr, 0, INVALID)
140 {
141 }
142
143 DependentString(value_type* buf, size_type len)
144 : String(buf, len, READ_WRITE)
145 {
146 }
147
148 DependentString(const value_type* buf, size_type len)
149 : String(const_cast<value_type*>(buf), len, READ_ONLY)
150 {
151 }
152
153 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
154 : String(
155 str.mBuf + std::min(pos, str.length()),
156 std::min(len, str.length() - std::min(pos, str.length())),
157 READ_WRITE
158 )
159 {
160 }
161
162 DependentString(const String& str, size_type pos = 0, size_type len = npos)
163 : String(
164 str.mBuf + std::min(pos, str.length()),
165 std::min(len, str.length() - std::min(pos, str.length())),
166 READ_ONLY
167 )
168 {
169 }
170
171 void reset(value_type* buf, size_type len)
172 {
173 *this = DependentString(buf, len);
174 }
175
176 void reset(const value_type* buf, size_type len)
177 {
178 *this = DependentString(buf, len);
179 }
180
181 void reset(String& str, size_type pos = 0, size_type len = npos)
182 {
183 *this = DependentString(str, pos, len);
184 }
185
186 void reset(const String& str, size_type pos = 0, size_type len = npos)
187 {
188 *this = DependentString(str, pos, len);
189 }
190
191 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.
192 {
193 return (mLen & FLAGS_MASK) == INVALID;
194 }
195
196 bool is_deleted() const
197 {
198 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.
199 }
200 };
201
202 class OwnedString : public String
203 {
204 private:
205 value_type* allocate(size_type len)
206 {
207 if (len)
208 return new value_type[len];
209 else
210 return nullptr;
211 }
212
213 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.
214 {
215 size_type oldLength = length();
216 value_type* oldBuffer = mBuf;
217
218 reset(nullptr, newLength, READ_WRITE);
219 newLength = length();
220 mBuf = allocate(newLength);
221 annotate_address(mBuf, "String");
222
223 if (copy && oldLength)
224 std::memcpy(mBuf, oldBuffer, sizeof(value_type) * std::min(oldLength, newL ength));
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.
225 if (oldBuffer)
226 delete[] oldBuffer;
227 }
228
229 public:
230 OwnedString(size_type len = 0)
231 : String(nullptr, len, READ_WRITE)
232 {
233 mBuf = allocate(length());
234 annotate_address(mBuf, "String");
235 }
236
237 OwnedString(const String& str)
238 : OwnedString(str.length())
239 {
240 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.
241 }
242
243 OwnedString(const OwnedString& str)
244 : OwnedString(static_cast<const String&>(str))
245 {
246 }
247
248 OwnedString(const value_type* str, size_type len)
249 : OwnedString(DependentString(str, len))
250 {
251 }
252
253 OwnedString(OwnedString&& str)
254 : OwnedString(str.length())
255 {
256 mBuf = str.mBuf;
257 str.mBuf = nullptr;
258 str.mLen = READ_WRITE | 0;
259 }
260
261 OwnedString(const char* source, size_type len)
262 : OwnedString(len)
263 {
264 for (size_type i = 0; i < len; i++)
265 mBuf[i] = source[i];
266 }
267
268 ~OwnedString()
269 {
270 if (mBuf)
271 delete[] mBuf;
272 }
273
274 OwnedString& operator=(const String& str)
275 {
276 *this = std::move(OwnedString(str));
277 return *this;
278 }
279
280 OwnedString& operator=(const OwnedString& str)
281 {
282 *this = std::move(OwnedString(str));
283 return *this;
284 }
285
286 OwnedString& operator=(OwnedString&& str)
287 {
288 mBuf = str.mBuf;
289 mLen = str.mLen;
290 str.mBuf = nullptr;
291 str.mLen = READ_WRITE | 0;
292 return *this;
293 }
294
295 void append(const value_type* source, size_type sourceLen)
296 {
297 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.
298 return;
299
300 size_t oldLength = length();
301 resize(oldLength + sourceLen, true);
302 std::memcpy(mBuf + oldLength, source, sizeof(value_type) * sourceLen);
303 }
304
305 void append(const String& str)
306 {
307 append(str.mBuf, str.length());
308 }
309
310 void append(value_type c)
311 {
312 append(&c, 1);
313 }
314 };
315
316 inline DependentString operator "" _str(const String::value_type* str,
317 String::size_type len)
318 {
319 return DependentString(str, len);
320 }
321
322 inline void String_assert_readonly(bool readOnly)
323 {
324 assert(!readOnly, u"Writing access to a read-only string"_str);
325 }
OLDNEW

Powered by Google App Engine
This is Rietveld