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(); } };