Store symbol names as a ImmutableString

This will enable compile-time initialization of built-in symbols as
well as reducing copying strings.

Most of the code that deals with names is changed to use
ImmutableString where it makes sense to avoid conversions.

The lexer/parser now allocate const char pointers into pool memory
instead of allocating TStrings. These are then converted to
ImmutableString upon entering TParseContext.

BUG=angleproject:2267
TEST=angle_unittests, angle_end2end_tests

Change-Id: I244d6271ea1ecf7150d4f89dfa388a7745a1150c
Reviewed-on: https://chromium-review.googlesource.com/881561
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/ImmutableString.h b/src/compiler/translator/ImmutableString.h
index a33fec9..2caef8d 100644
--- a/src/compiler/translator/ImmutableString.h
+++ b/src/compiler/translator/ImmutableString.h
@@ -12,6 +12,7 @@
 
 #include <string>
 
+#include "common/string_utils.h"
 #include "compiler/translator/Common.h"
 
 namespace sh
@@ -40,20 +41,60 @@
     // The data pointer passed in must be one of:
     //  1. nullptr (only valid with length 0).
     //  2. a null-terminated static char array like a string literal.
-    //  3. a null-terminated pool allocated char array.
+    //  3. a null-terminated pool allocated char array. This can't be c_str() of a local TString,
+    //     since when a TString goes out of scope it clears its first character.
     explicit constexpr ImmutableString(const char *data) : mData(data), mLength(constStrlen(data))
     {
     }
 
     constexpr ImmutableString(const char *data, size_t length) : mData(data), mLength(length) {}
 
+    ImmutableString(const std::string &str)
+        : mData(AllocatePoolCharArray(str.c_str(), str.size())), mLength(str.size())
+    {
+    }
+
     ImmutableString(const ImmutableString &) = default;
     ImmutableString &operator=(const ImmutableString &) = default;
 
-    const char *data() const { return mData ? mData : ""; }
-    size_t length() const { return mLength; }
+    constexpr const char *data() const { return mData ? mData : ""; }
+    constexpr size_t length() const { return mLength; }
 
-    bool operator<(const ImmutableString &b) const
+    char operator[](size_t index) const { return data()[index]; }
+
+    constexpr bool empty() const { return mLength == 0; }
+    bool beginsWith(const char *prefix) const { return angle::BeginsWith(data(), prefix); }
+    constexpr bool beginsWith(const ImmutableString &prefix) const
+    {
+        return mLength >= prefix.length() && memcmp(data(), prefix.data(), prefix.length()) == 0;
+    }
+    bool contains(const char *substr) const { return strstr(data(), substr) != nullptr; }
+
+    constexpr bool operator==(const ImmutableString &b) const
+    {
+        if (mLength != b.mLength)
+        {
+            return false;
+        }
+        return memcmp(data(), b.data(), mLength) == 0;
+    }
+    constexpr bool operator!=(const ImmutableString &b) const { return !(*this == b); }
+    constexpr bool operator==(const char *b) const
+    {
+        if (b == nullptr)
+        {
+            return empty();
+        }
+        return strcmp(data(), b) == 0;
+    }
+    constexpr bool operator!=(const char *b) const { return !(*this == b); }
+    bool operator==(const std::string &b) const
+    {
+        return mLength == b.length() && memcmp(data(), b.c_str(), mLength) == 0;
+    }
+    bool operator!=(const std::string &b) const { return !(*this == b); }
+
+    constexpr bool operator<(const ImmutableString &b) const
     {
         if (mLength < b.mLength)
         {
@@ -66,6 +107,26 @@
         return (memcmp(data(), b.data(), mLength) < 0);
     }
 
+    template <size_t hashBytes>
+    struct FowlerNollVoHash
+    {
+        static const size_t kFnvOffsetBasis;
+        static const size_t kFnvPrime;
+
+        constexpr size_t operator()(const ImmutableString &a) const
+        {
+            const char *data = a.data();
+            size_t hash      = kFnvOffsetBasis;
+            while ((*data) != '\0')
+            {
+                hash = hash ^ (*data);
+                hash = hash * kFnvPrime;
+                ++data;
+            }
+            return hash;
+        }
+    };
+
   private:
     const char *mData;
     size_t mLength;