Fix Label::hash() computation.

This CL fixes a subtle bug where the hash_ member of a Label
instance was not properly initialized after a call to ::Resolve()
in label.cc, and a few other trivial cases. This prevented the
proper use of std::unordered_map<Label, ...> types.

+ Slightly speed up Label::ComputeHash() by avoiding string hashing
  whenever possible, using the newly-introduced StringAtom::ptr_hash()
  method (which replicates std::hash<StringAtom>()()).

Measurements show no impact on performance or RAM usage.

Change-Id: I11b6645709cc8c8ff266bb5174c1bdd102919332
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/12580
Commit-Queue: David Turner <digit@google.com>
Reviewed-by: Brett Wilson <brettw@chromium.org>
diff --git a/src/gn/label.cc b/src/gn/label.cc
index c78b00e..6914962 100644
--- a/src/gn/label.cc
+++ b/src/gn/label.cc
@@ -289,6 +289,8 @@
                  input_string, &ret.dir_, &ret.name_, &ret.toolchain_dir_,
                  &ret.toolchain_name_, err))
     return Label();
+
+  ret.hash_ = ret.ComputeHash();
   return ret;
 }
 
diff --git a/src/gn/label.h b/src/gn/label.h
index 1458fcc..e2a0281 100644
--- a/src/gn/label.h
+++ b/src/gn/label.h
@@ -70,8 +70,8 @@
   std::string GetUserVisibleName(const Label& default_toolchain) const;
 
   bool operator==(const Label& other) const {
-    return name_.SameAs(other.name_) && dir_ == other.dir_ &&
-           toolchain_dir_ == other.toolchain_dir_ &&
+    return hash_ == other.hash_ && name_.SameAs(other.name_) &&
+           dir_ == other.dir_ && toolchain_dir_ == other.toolchain_dir_ &&
            toolchain_name_.SameAs(other.toolchain_name_);
   }
   bool operator!=(const Label& other) const { return !operator==(other); }
@@ -101,7 +101,8 @@
   size_t hash() const { return hash_; }
 
  private:
-  Label(SourceDir dir, StringAtom name) : dir_(dir), name_(name) {}
+  Label(SourceDir dir, StringAtom name)
+      : dir_(dir), name_(name), hash_(ComputeHash()) {}
 
   Label(SourceDir dir,
         StringAtom name,
@@ -110,13 +111,14 @@
       : dir_(dir),
         name_(name),
         toolchain_dir_(toolchain_dir),
-        toolchain_name_(toolchain_name) {}
+        toolchain_name_(toolchain_name),
+        hash_(ComputeHash()) {}
 
   size_t ComputeHash() const {
     size_t h0 = dir_.hash();
-    size_t h1 = name_.hash();
+    size_t h1 = name_.ptr_hash();
     size_t h2 = toolchain_dir_.hash();
-    size_t h3 = toolchain_name_.hash();
+    size_t h3 = toolchain_name_.ptr_hash();
     return ((h3 * 131 + h2) * 131 + h1) * 131 + h0;
   }
 
diff --git a/src/gn/source_dir.h b/src/gn/source_dir.h
index d8b3c28..2a694cf 100644
--- a/src/gn/source_dir.h
+++ b/src/gn/source_dir.h
@@ -128,7 +128,7 @@
   bool operator!=(const SourceDir& other) const { return !operator==(other); }
   bool operator<(const SourceDir& other) const { return value_ < other.value_; }
 
-  size_t hash() const { return value_.hash(); }
+  size_t hash() const { return value_.ptr_hash(); }
 
  private:
   friend class SourceFile;
diff --git a/src/gn/source_file.h b/src/gn/source_file.h
index b13a400..467c119 100644
--- a/src/gn/source_file.h
+++ b/src/gn/source_file.h
@@ -98,7 +98,7 @@
   }
 
   bool operator==(const SourceFile& other) const {
-    return value_ == other.value_;
+    return value_.SameAs(other.value_);
   }
   bool operator!=(const SourceFile& other) const { return !operator==(other); }
   bool operator<(const SourceFile& other) const {
diff --git a/src/gn/string_atom.h b/src/gn/string_atom.h
index 541399e..c590e0b 100644
--- a/src/gn/string_atom.h
+++ b/src/gn/string_atom.h
@@ -119,8 +119,10 @@
 
   size_t hash() const { return std::hash<std::string>()(value_); }
 
-  // Use the following structs to implement containers that use StringAtom
-  // values as keys, but only compare/hash the pointer values for speed.
+  // Use the following method and structs to implement containers that
+  // use StringAtom values as keys, but only compare/hash the pointer
+  // values for speed.
+  //
   // E.g.:
   //    using FastSet = std::unordered_set<StringAtom, PtrHash, PtrEqual>;
   //    using FastMap = std::map<StringAtom, Value, PtrCompare>;
@@ -128,9 +130,11 @@
   // IMPORTANT: Note that FastMap above is ordered based in the StringAtom
   //            pointer value, not the string content.
   //
+  size_t ptr_hash() const { return std::hash<const std::string*>()(&value_); }
+
   struct PtrHash {
     size_t operator()(const StringAtom& key) const noexcept {
-      return std::hash<const std::string*>()(&key.value_);
+      return key.ptr_hash();
     }
   };