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