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

Delta Between Two Patch Sets: compiled/String.h

Issue 29722755: Issue 6378 - [emscripten] Make DependentString constexpr
Left Patch Set: More tests, made operator[] and default ctor constexpr. Created March 14, 2018, 5:11 p.m.
Right Patch Set: Added missing '*'. Created March 19, 2018, 1:39 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | test/compiled/String.cpp » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH 3 * Copyright (C) 2006-present eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
(...skipping 19 matching lines...) Expand all
30 #include <limits> 30 #include <limits>
31 31
32 #include "base.h" 32 #include "base.h"
33 #include "debug.h" 33 #include "debug.h"
34 #include "library.h" 34 #include "library.h"
35 35
36 ABP_NS_BEGIN 36 ABP_NS_BEGIN
37 37
38 inline void String_assert_writable(bool isWritable); 38 inline void String_assert_writable(bool isWritable);
39 39
40 // hacky because without templates
41 #ifdef ABP_UTF8_STRING
42 #define ABP_TEXT(val) val
43 struct StringTraits
44 {
45 typedef char char_type;
46 };
47 #else
48 #define ABP_TEXT(val) u##val
49 struct StringTraits
50 {
51 typedef char16_t char_type;
52 };
53 #endif
54
40 class String 55 class String
41 { 56 {
42 friend class DependentString; 57 friend class DependentString;
43 friend class OwnedString; 58 friend class OwnedString;
44 59
45 public: 60 public:
46 typedef char16_t value_type; 61 typedef StringTraits::char_type value_type;
47 typedef size_t size_type; 62 typedef size_t size_type;
48 63
49 // Type flags, stored in the top 2 bits of the mLen member 64 // Type flags, stored in the top 2 bits of the mLen member
50 static constexpr size_type INVALID = 0xC0000000; 65 static constexpr size_type INVALID = 0xC0000000;
51 static constexpr size_type DELETED = 0x80000000; 66 static constexpr size_type DELETED = 0x80000000;
52 static constexpr size_type READ_ONLY = 0x40000000; 67 static constexpr size_type READ_ONLY = 0x40000000;
53 static constexpr size_type READ_WRITE = 0x00000000; 68 static constexpr size_type READ_WRITE = 0x00000000;
54 69
55 static constexpr size_type FLAGS_MASK = 0xC0000000; 70 static constexpr size_type FLAGS_MASK = 0xC0000000;
56 static constexpr size_type LENGTH_MASK = 0x3FFFFFFF; 71 static constexpr size_type LENGTH_MASK = 0x3FFFFFFF;
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 { 120 {
106 String_assert_writable(is_writable()); 121 String_assert_writable(is_writable());
107 return mBuf[pos]; 122 return mBuf[pos];
108 } 123 }
109 124
110 constexpr bool is_writable() const 125 constexpr bool is_writable() const
111 { 126 {
112 return (mLen & FLAGS_MASK) == READ_WRITE; 127 return (mLen & FLAGS_MASK) == READ_WRITE;
113 } 128 }
114 129
115 bool equals(const String& other) const 130 constexpr bool equals(const String& other) const
116 { 131 {
117 if (length() != other.length()) 132 if (length() != other.length())
118 return false; 133 return false;
119 134
120 return std::memcmp(mBuf, other.mBuf, sizeof(value_type) * length()) == 0; 135 return std::memcmp(mBuf, other.mBuf, sizeof(value_type) * length()) == 0;
121 } 136 }
122 137
123 bool operator==(const String& other) const 138 constexpr bool operator==(const String& other) const
124 { 139 {
125 return equals(other); 140 return equals(other);
126 } 141 }
127 142
128 bool operator!=(const String& other) const 143 constexpr bool operator!=(const String& other) const
129 { 144 {
130 return !equals(other); 145 return !equals(other);
131 } 146 }
132 147
133 size_type find(value_type c, size_type pos = 0) const 148 constexpr size_type find(value_type c, size_type pos = 0) const
134 { 149 {
135 for (size_type i = pos; i < length(); ++i) 150 for (size_type i = pos; i < length(); ++i)
136 if (mBuf[i] == c) 151 if (mBuf[i] == c)
137 return i; 152 return i;
138 return npos; 153 return npos;
139 } 154 }
140 155
141 size_type find(const String& str, size_type pos = 0) const 156 constexpr size_type find(const String& str, size_type pos = 0) const
142 { 157 {
143 return find(str.mBuf, pos, str.length()); 158 return find(str.mBuf, pos, str.length());
144 } 159 }
145 160
146 size_type find(const value_type* str, size_type pos, size_type count) const 161 constexpr size_type find(const value_type* str, size_type pos, size_type count ) const
147 { 162 {
148 if (pos > LENGTH_MASK || pos + count > length()) 163 if (pos > LENGTH_MASK || pos + count > length())
149 return npos; 164 return npos;
150 165
151 if (!count) 166 if (!count)
152 return pos; 167 return pos;
153 168
154 for (; pos + count <= length(); ++pos) 169 for (; pos + count <= length(); ++pos)
155 { 170 {
156 if (mBuf[pos] == str[0] && 171 if (mBuf[pos] == str[0] &&
157 std::memcmp(mBuf + pos, str, sizeof(value_type) * count) == 0) 172 std::memcmp(mBuf + pos, str, sizeof(value_type) * count) == 0)
158 { 173 {
159 return pos; 174 return pos;
160 } 175 }
161 } 176 }
162 177
163 return npos; 178 return npos;
164 } 179 }
165 180
166 size_type rfind(value_type c, size_type pos = npos) const 181 constexpr size_type rfind(value_type c, size_type pos = npos) const
167 { 182 {
168 if (length() == 0) 183 if (length() == 0)
169 return npos; 184 return npos;
170 185
171 if (pos >= length()) 186 if (pos >= length())
172 pos = length() - 1; 187 pos = length() - 1;
173 188
174 for (int i = pos; i >= 0; --i) 189 for (int i = pos; i >= 0; --i)
175 if (mBuf[i] == c) 190 if (mBuf[i] == c)
176 return i; 191 return i;
(...skipping 12 matching lines...) Expand all
189 204
190 void toLower() 205 void toLower()
191 { 206 {
192 size_type len = length(); 207 size_type len = length();
193 for (size_type i = 0; i < len; ++i) 208 for (size_type i = 0; i < len; ++i)
194 { 209 {
195 value_type currChar = mBuf[i]; 210 value_type currChar = mBuf[i];
196 211
197 // This should be more efficient with a lookup table but I couldn't measur e 212 // This should be more efficient with a lookup table but I couldn't measur e
198 // any performance difference. 213 // any performance difference.
199 if (currChar >= u'A' && currChar <= u'Z') 214 if (currChar >= ABP_TEXT('A') && currChar <= ABP_TEXT('Z'))
200 mBuf[i] = currChar + u'a' - u'A'; 215 mBuf[i] = currChar + ABP_TEXT('a') - ABP_TEXT('A');
201 else if (currChar >= 128) 216 else if (currChar >= 128)
202 { 217 {
203 mBuf[i] = CharToLower(currChar); 218 mBuf[i] = CharToLower(currChar);
204 } 219 }
205 } 220 }
206 } 221 }
207 }; 222 };
208 223
209 #ifdef INSIDE_TESTS 224 #ifdef INSIDE_TESTS
210 inline std::ostream& operator<<(std::ostream& os, const String& str) 225 inline std::ostream& operator<<(std::ostream& os, const String& str)
211 { 226 {
227 #ifdef ABP_UTF8_STRING
228 os.write(str.data(), str.length());
229 #else
212 #if _MSC_VER >= 1900 230 #if _MSC_VER >= 1900
213 std::wstring_convert<std::codecvt_utf8_utf16<int16_t>, int16_t> converter; 231 std::wstring_convert<std::codecvt_utf8_utf16<int16_t>, int16_t> converter;
214 auto p = reinterpret_cast<const int16_t *>(str.data()); 232 auto p = reinterpret_cast<const int16_t *>(str.data());
215 os << converter.to_bytes(p, p + str.length()); 233 os << converter.to_bytes(p, p + str.length());
216 #else 234 #else
217 std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> converter; 235 std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> converter;
218 os << converter.to_bytes(str.data(), str.data() + str.length()); 236 os << converter.to_bytes(str.data(), str.data() + str.length());
219 #endif 237 #endif // _MSC_VER >= 1900
238 #endif // ABP_UTF8_STRING
220 return os; 239 return os;
221 } 240 }
222 #endif 241 #endif // INSIDE_TESTS
223 242
224 class DependentString : public String 243 class DependentString : public String
225 { 244 {
226 public: 245 public:
227 constexpr explicit DependentString() 246 constexpr explicit DependentString()
228 : String(nullptr, 0, INVALID) 247 : String(nullptr, 0, INVALID)
229 { 248 {
230 } 249 }
231 250
232 template <int N1> 251 template <int N1>
233 constexpr explicit DependentString(const value_type (&buf)[N1]) 252 constexpr explicit DependentString(const value_type (&buf)[N1])
234 : String(const_cast<value_type*>(buf), N1 - 1, READ_ONLY) 253 : String(const_cast<value_type*>(buf), N1 - 1, READ_ONLY)
235 { 254 {
236 } 255 }
237 256
238 explicit DependentString(value_type* buf, size_type len) 257 explicit DependentString(value_type* buf, size_type len)
239 : String(buf, len, READ_WRITE) 258 : String(buf, len, READ_WRITE)
240 { 259 {
241 } 260 }
242 261
243 explicit DependentString(const value_type* buf, size_type len) 262 constexpr explicit DependentString(const value_type* buf, size_type len)
244 : String(const_cast<value_type*>(buf), len, READ_ONLY) 263 : String(const_cast<value_type*>(buf), len, READ_ONLY)
245 { 264 {
246 } 265 }
247 266
248 explicit DependentString(String& str, size_type pos = 0, size_type len = npos) 267 explicit DependentString(String& str, size_type pos = 0, size_type len = npos)
249 : String( 268 : String(
250 str.mBuf + std::min(pos, str.length()), 269 str.mBuf + std::min(pos, str.length()),
251 std::min(len, str.length() - std::min(pos, str.length())), 270 std::min(len, str.length() - std::min(pos, str.length())),
252 str.is_writable() ? READ_WRITE: READ_ONLY 271 str.is_writable() ? READ_WRITE: READ_ONLY
253 ) 272 )
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 } 310 }
292 }; 311 };
293 312
294 #ifdef INSIDE_TESTS 313 #ifdef INSIDE_TESTS
295 inline std::ostream& operator<<(std::ostream& os, const DependentString& str) 314 inline std::ostream& operator<<(std::ostream& os, const DependentString& str)
296 { 315 {
297 return os << static_cast<const String&>(str); 316 return os << static_cast<const String&>(str);
298 } 317 }
299 #endif 318 #endif
300 319
301 inline DependentString operator "" _str(const String::value_type* str, 320 constexpr DependentString operator "" _str(const String::value_type* str,
sergei 2018/03/15 15:58:37 Can it be constexpr too? http://en.cppreference.co
302 String::size_type len) 321 String::size_type len)
303 { 322 {
304 return DependentString(str, len); 323 return DependentString(str, len);
305 } 324 }
306 325
307 inline void String_assert_writable(bool isWritable) 326 inline void String_assert_writable(bool isWritable)
308 { 327 {
309 assert2(isWritable, u"Writing access to a read-only string"_str); 328 assert2(isWritable, ABP_TEXT("Writing access to a read-only string"_str));
310 } 329 }
311 330
312 class OwnedString : public String 331 class OwnedString : public String
313 { 332 {
314 private: 333 private:
315 void grow(size_type additionalSize) 334 void grow(size_type additionalSize)
316 { 335 {
317 OwnedString newValue(length() + additionalSize); 336 OwnedString newValue(length() + additionalSize);
318 if (length() > 0) 337 if (length() > 0)
319 std::memcpy(newValue.mBuf, mBuf, sizeof(value_type) * length()); 338 std::memcpy(newValue.mBuf, mBuf, sizeof(value_type) * length());
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 std::swap(mBuf, str.mBuf); 416 std::swap(mBuf, str.mBuf);
398 std::swap(mLen, str.mLen); 417 std::swap(mLen, str.mLen);
399 return *this; 418 return *this;
400 } 419 }
401 420
402 void append(const value_type* source, size_type sourceLen) 421 void append(const value_type* source, size_type sourceLen)
403 { 422 {
404 if (!sourceLen) 423 if (!sourceLen)
405 return; 424 return;
406 425
407 assert2(source, u"Null buffer passed to OwnedString.append()"_str); 426 assert2(source, ABP_TEXT("Null buffer passed to OwnedString.append()"_str));
408 size_t oldLength = length(); 427 size_t oldLength = length();
409 grow(sourceLen); 428 grow(sourceLen);
410 std::memcpy(mBuf + oldLength, source, sizeof(value_type) * sourceLen); 429 std::memcpy(mBuf + oldLength, source, sizeof(value_type) * sourceLen);
411 } 430 }
412 431
432 #ifndef ABP_UTF8_STRING
413 void append(const char* source, size_type sourceLen) 433 void append(const char* source, size_type sourceLen)
414 { 434 {
415 if (!sourceLen) 435 if (!sourceLen)
416 return; 436 return;
417 437
418 assert2(source, u"Null buffer passed to OwnedString.append()"_str); 438 assert2(source, ABP_TEXT("Null buffer passed to OwnedString.append()"_str));
419 size_t oldLength = length(); 439 size_t oldLength = length();
420 grow(sourceLen); 440 grow(sourceLen);
421 for (size_t i = 0; i < sourceLen; i++) 441 for (size_t i = 0; i < sourceLen; i++)
422 mBuf[oldLength + i] = source[i]; 442 mBuf[oldLength + i] = source[i];
423 } 443 }
444 #endif // !ABP_UTF8_STRING
424 445
425 void append(const String& str) 446 void append(const String& str)
426 { 447 {
427 append(str.mBuf, str.length()); 448 append(str.mBuf, str.length());
428 } 449 }
429 450
430 void append(value_type c) 451 void append(value_type c)
431 { 452 {
432 append(&c, 1); 453 append(&c, 1);
433 } 454 }
(...skipping 11 matching lines...) Expand all
445 466
446 size_type size = 0; 467 size_type size = 0;
447 for (T i = num; i; i /= 10) 468 for (T i = num; i; i /= 10)
448 size++; 469 size++;
449 size = (size ? size : 1); 470 size = (size ? size : 1);
450 471
451 size_type pos = length(); 472 size_type pos = length();
452 grow((negative ? 1 : 0) + size); 473 grow((negative ? 1 : 0) + size);
453 474
454 if (negative) 475 if (negative)
455 mBuf[pos++] = '-'; 476 mBuf[pos++] = ABP_TEXT('-');
456 477
457 for (int i = size - 1; i >= 0; i--) 478 for (int i = size - 1; i >= 0; i--)
458 { 479 {
459 mBuf[pos + i] = '0' + (num % 10); 480 mBuf[pos + i] = ABP_TEXT('0') + (num % 10);
460 num /= 10; 481 num /= 10;
461 } 482 }
462 } 483 }
463 }; 484 };
464 485
465 #ifdef INSIDE_TESTS 486 #ifdef INSIDE_TESTS
466 inline std::ostream& operator<<(std::ostream& os, const OwnedString& str) 487 inline std::ostream& operator<<(std::ostream& os, const OwnedString& str)
467 { 488 {
468 return os << static_cast<const String&>(str); 489 return os << static_cast<const String&>(str);
469 } 490 }
470 #endif 491 #endif
471 492
472 template<typename T> 493 template<typename T>
473 struct LexicalCastImpl; 494 struct LexicalCastImpl;
474 495
475 /// Performs common conversions of a text represented value. 496 /// Performs common conversions of a text represented value.
476 template<typename T> 497 template<typename T>
477 inline T lexical_cast(const String& value) 498 inline T lexical_cast(const String& value)
478 { 499 {
479 return LexicalCastImpl<T>::Convert(value); 500 return LexicalCastImpl<T>::Convert(value);
480 } 501 }
481 502
482 template<> 503 template<>
483 struct LexicalCastImpl<bool> 504 struct LexicalCastImpl<bool>
484 { 505 {
485 static bool Convert(const String& value) 506 static bool Convert(const String& value)
486 { 507 {
487 return value == u"true"_str; 508 return value == ABP_TEXT("true"_str);
488 } 509 }
489 }; 510 };
490 511
491 template<typename T> 512 template<typename T>
492 struct LexicalCastImpl 513 struct LexicalCastImpl
493 { 514 {
494 static_assert(std::is_integral<T>::value, "T should be a number"); 515 static_assert(std::is_integral<T>::value, "T should be a number");
495 static T Convert(const String& value) 516 static T Convert(const String& value)
496 { 517 {
497 String::size_type len = value.length(); 518 String::size_type len = value.length();
498 if (len == 0) 519 if (len == 0)
499 return 0; 520 return 0;
500 String::size_type pos = 0; 521 String::size_type pos = 0;
501 bool negative = std::numeric_limits<T>::is_signed && value[0] == u'-'; 522 bool negative = std::numeric_limits<T>::is_signed && value[0] == ABP_TEXT('- ');
502 if (negative) 523 if (negative)
503 { 524 {
504 ++pos; 525 ++pos;
505 } 526 }
506 T result = 0; 527 T result = 0;
507 for (; pos < len; ++pos) 528 for (; pos < len; ++pos)
508 { 529 {
509 auto c = value[pos]; 530 auto c = value[pos];
510 if (c < u'0' || c > u'9') 531 if (c < ABP_TEXT('0') || c > ABP_TEXT('9'))
511 return 0; 532 return 0;
512 // isDangerous is the optimization because there is no need for some check s 533 // isDangerous is the optimization because there is no need for some check s
513 // when the values are far from edge cases. 534 // when the values are far from edge cases.
514 // It targets the normal values, when a value is prefixed with several 535 // It targets the normal values, when a value is prefixed with several
515 // zeros additional checks start to work earlier than the actual value of 536 // zeros additional checks start to work earlier than the actual value of
516 // result reaches an edge case, but it does not affect the result. 537 // result reaches an edge case, but it does not affect the result.
517 bool isDangerous = pos >= std::numeric_limits<T>::digits10; 538 bool isDangerous = pos >= std::numeric_limits<T>::digits10;
518 // It also invalidates the parsing of too big numbers in comparison with 539 // It also invalidates the parsing of too big numbers in comparison with
519 // stopping when it encounters a non numerical character. 540 // stopping when it encounters a non numerical character.
520 // cast<uint8_t>(u"1230"_str) -> 0 541 // cast<uint8_t>(u"1230"_str) -> 0
521 // cast<uint8_t>(u"123E"_str) -> 123 542 // cast<uint8_t>(u"123E"_str) -> 123
522 if (isDangerous && std::numeric_limits<T>::max() / 10 < result) 543 if (isDangerous && std::numeric_limits<T>::max() / 10 < result)
523 { 544 {
524 return 0; 545 return 0;
525 } 546 }
526 result *= 10; 547 result *= 10;
527 uint8_t digit = c - u'0'; 548 uint8_t digit = c - ABP_TEXT('0');
528 if (isDangerous && (std::numeric_limits<T>::max() - digit < result - (nega tive ? 1 : 0))) 549 if (isDangerous && (std::numeric_limits<T>::max() - digit < result - (nega tive ? 1 : 0)))
529 { 550 {
530 return 0; 551 return 0;
531 } 552 }
532 result += digit; 553 result += digit;
533 } 554 }
534 return negative ? -result : result; 555 return negative ? -result : result;
535 } 556 }
536 }; 557 };
537 558
538 template<> 559 template<>
539 inline OwnedString lexical_cast<OwnedString>(const String& value) 560 inline OwnedString lexical_cast<OwnedString>(const String& value)
540 { 561 {
541 return OwnedString{value}; 562 return OwnedString{value};
542 } 563 }
543 564
544 DependentString TrimSpaces(const String& value); 565 DependentString TrimSpaces(const String& value);
545 566
546 // Splits the `value` string into two `DependentString`s excluding the character staying at `separatorPos`. 567 // Splits the `value` string into two `DependentString`s excluding the character staying at `separatorPos`.
547 // Useful for parsing. 568 // Useful for parsing.
548 std::pair<DependentString, DependentString> SplitString(const String& value, Str ing::size_type separatorPos); 569 std::pair<DependentString, DependentString> SplitString(const String& value, Str ing::size_type separatorPos);
549 570
550 ABP_NS_END 571 ABP_NS_END
LEFTRIGHT

Powered by Google App Engine
This is Rietveld