Add ImmutableString to encapsulate some compiler strings

The new ImmutableString class is intended to be used instead of plain
const char pointers to pool-allocated or static memory.

It has the following advantages over using plain const char pointers:

1. It makes it clear when a string is guaranteed to be safe to pass
   around inside the compiler.
2. It can be compared with a comparison operator rather than using
   strcmp, which is easier to read.
3. It records the length of the stored string, which enables faster
   copies and comparisons in some cases.
4. ImmutableStrings could be implicitly converted from std::strings
   when a pool-allocated string is required. This is robust and
   convenient.

C++17 has a similar class std::string_view, but our code style doesn't
allow it yet. We also couldn't use it as is if we require properties
1 and 4 from above, but would rather need to inherit or wrap it in a
custom class.

Eventually all current usage of TString could be replaced with
ImmutableString. For now, use it for unmangled built-in names.

TEST=angle_unittests
BUG=angleproject:2267

Change-Id: Id60c7b544032e06460e1b99837e429bc84dc4367
Reviewed-on: https://chromium-review.googlesource.com/881020
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/ImmutableString.h b/src/compiler/translator/ImmutableString.h
new file mode 100644
index 0000000..2957944
--- /dev/null
+++ b/src/compiler/translator/ImmutableString.h
@@ -0,0 +1,73 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ImmutableString.h: Wrapper for static or pool allocated char arrays, that are guaranteed to be
+// valid and unchanged for the duration of the compilation.
+//
+
+#ifndef COMPILER_TRANSLATOR_IMMUTABLESTRING_H_
+#define COMPILER_TRANSLATOR_IMMUTABLESTRING_H_
+
+#include <string>
+
+#include "compiler/translator/Common.h"
+
+namespace sh
+{
+
+namespace
+{
+constexpr size_t constStrlen(const char *str)
+{
+    if (str == nullptr)
+    {
+        return 0u;
+    }
+    size_t len = 0u;
+    while (*(str + len) != '\0')
+    {
+        ++len;
+    }
+    return len;
+}
+}
+
+class ImmutableString
+{
+  public:
+    // 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.
+    explicit constexpr ImmutableString(const char *data) : mData(data), mLength(constStrlen(data))
+    {
+    }
+
+    ImmutableString(const ImmutableString &) = default;
+    ImmutableString &operator=(const ImmutableString &) = default;
+
+    const char *data() const { return mData ? mData : ""; }
+
+    bool operator<(const ImmutableString &b) const
+    {
+        if (mLength < b.mLength)
+        {
+            return true;
+        }
+        if (mLength > b.mLength)
+        {
+            return false;
+        }
+        return (memcmp(data(), b.data(), mLength) < 0);
+    }
+
+  private:
+    const char *const mData;
+    const size_t mLength;
+};
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_IMMUTABLESTRING_H_
diff --git a/src/compiler/translator/SymbolTable.cpp b/src/compiler/translator/SymbolTable.cpp
index 53ba840..7548880 100644
--- a/src/compiler/translator/SymbolTable.cpp
+++ b/src/compiler/translator/SymbolTable.cpp
@@ -13,6 +13,7 @@
 
 #include "compiler/translator/SymbolTable.h"
 
+#include "compiler/translator/ImmutableString.h"
 #include "compiler/translator/IntermNode.h"
 
 #include <stdio.h>
@@ -54,11 +55,7 @@
     std::set<std::string> mInvariantVaryings;
     bool mGlobalInvariant;
 
-    struct CharArrayComparator
-    {
-        bool operator()(const char *a, const char *b) const { return strcmp(a, b) < 0; }
-    };
-    std::set<const char *, CharArrayComparator> mUnmangledBuiltInNames;
+    std::set<ImmutableString> mUnmangledBuiltInNames;
 };
 
 bool TSymbolTable::TSymbolTableLevel::insert(TSymbol *symbol)
@@ -88,12 +85,12 @@
 
 void TSymbolTable::TSymbolTableLevel::insertUnmangledBuiltInName(const char *name)
 {
-    mUnmangledBuiltInNames.insert(name);
+    mUnmangledBuiltInNames.insert(ImmutableString(name));
 }
 
 bool TSymbolTable::TSymbolTableLevel::hasUnmangledBuiltIn(const char *name) const
 {
-    return mUnmangledBuiltInNames.count(name) > 0;
+    return mUnmangledBuiltInNames.count(ImmutableString(name)) > 0;
 }
 
 void TSymbolTable::push()