Refactor HPACK/QPACK lookup entry.

Before this CL, an HpackEntry could serve as a storage entry: to store strings
in a deque, for easy FIFO insertion and deletion; or as a reference entry used
for lookup: to point to strings stored in storage entries by means of
string_views, used in a set to allow convenient lookup by name and value without
having to store duplicate copies of strings.

This CL creates a dedicated HpackLookupEntry struct, so that the EntryType and
the string_view parts of HpackEntry can be removed in a future CL, substantially
reducing HpackEntry size and complexity.

Note that previously separate EntryHasher and EntriesEq functors were used,
mostly because until recently STL containers were used in Chromium and Absail
ones internally, and the hasher had to be defined as a template parameter to
work with both, and partially because conceptually two HpackEntries with same
string values were not equal, so operator==() would have been a lie.  Now both
obstacles have been removed, allowing HpackLookupEntry to define operator==()
and an Absail-style hasher, eliminating the need for extra container template
parameters.

Also remove unused HpackHeaderTable::DebugLogTableState().

PiperOrigin-RevId: 363679331
Change-Id: Iad2f198c57e8e60c2b6e0e679b391d50d1dbcf7a
diff --git a/quic/core/qpack/qpack_header_table.cc b/quic/core/qpack/qpack_header_table.cc
index e8d4c24..90b0d8b 100644
--- a/quic/core/qpack/qpack_header_table.cc
+++ b/quic/core/qpack/qpack_header_table.cc
@@ -55,22 +55,22 @@
     absl::string_view value,
     bool* is_static,
     uint64_t* index) const {
-  QpackEntry query(name, value);
+  QpackLookupEntry query{name, value};
 
   // Look for exact match in static table.
-  auto index_it = static_index_.find(&query);
+  auto index_it = static_index_.find(query);
   if (index_it != static_index_.end()) {
-    QUICHE_DCHECK((*index_it)->IsStatic());
-    *index = (*index_it)->InsertionIndex();
+    QUICHE_DCHECK(index_it->second->IsStatic());
+    *index = index_it->second->InsertionIndex();
     *is_static = true;
     return MatchType::kNameAndValue;
   }
 
   // Look for exact match in dynamic table.
-  index_it = dynamic_index_.find(&query);
+  index_it = dynamic_index_.find(query);
   if (index_it != dynamic_index_.end()) {
-    QUICHE_DCHECK(!(*index_it)->IsStatic());
-    *index = (*index_it)->InsertionIndex();
+    QUICHE_DCHECK(!index_it->second->IsStatic());
+    *index = index_it->second->InsertionIndex();
     *is_static = false;
     return MatchType::kNameAndValue;
   }
@@ -115,15 +115,17 @@
   dynamic_table_size_ += QpackEntry::Size(name, value);
   EvictDownToCurrentCapacity();
 
-  auto index_result = dynamic_index_.insert(new_entry);
+  auto index_result = dynamic_index_.insert(std::make_pair(
+      QpackLookupEntry{new_entry->name(), new_entry->value()}, new_entry));
   if (!index_result.second) {
     // An entry with the same name and value already exists.  It needs to be
     // replaced, because |dynamic_index_| tracks the most recent entry for a
     // given name and value.
     QUICHE_DCHECK_GT(new_entry->InsertionIndex(),
-                     (*index_result.first)->InsertionIndex());
+                     index_result.first->second->InsertionIndex());
     dynamic_index_.erase(index_result.first);
-    auto result = dynamic_index_.insert(new_entry);
+    auto result = dynamic_index_.insert(std::make_pair(
+        QpackLookupEntry{new_entry->name(), new_entry->value()}, new_entry));
     QUICHE_CHECK(result.second);
   }
 
@@ -255,13 +257,10 @@
     QUICHE_DCHECK_GE(dynamic_table_size_, entry_size);
     dynamic_table_size_ -= entry_size;
 
-    auto index_it = dynamic_index_.find(entry);
+    auto index_it = dynamic_index_.find({entry->name(), entry->value()});
     // Remove |dynamic_index_| entry only if it points to the same
-    // QpackEntry in |dynamic_entries_|.  Note that |dynamic_index_| has a
-    // comparison function that only considers name and value, not actual
-    // QpackEntry* address, so find() can return a different entry if name and
-    // value match.
-    if (index_it != dynamic_index_.end() && *index_it == entry) {
+    // QpackEntry in |dynamic_entries_|.
+    if (index_it != dynamic_index_.end() && index_it->second == entry) {
       dynamic_index_.erase(index_it);
     }
 
diff --git a/quic/core/qpack/qpack_header_table.h b/quic/core/qpack/qpack_header_table.h
index 90b0d4c..e2a1a9e 100644
--- a/quic/core/qpack/qpack_header_table.h
+++ b/quic/core/qpack/qpack_header_table.h
@@ -24,6 +24,7 @@
 }  // namespace test
 
 using QpackEntry = spdy::HpackEntry;
+using QpackLookupEntry = spdy::HpackLookupEntry;
 constexpr size_t kQpackEntrySizeOverhead = spdy::kHpackEntrySizeOverhead;
 
 // This class manages the QPACK static and dynamic tables.  For dynamic entries,
@@ -32,9 +33,7 @@
 class QUIC_EXPORT_PRIVATE QpackHeaderTable {
  public:
   using EntryTable = spdy::HpackHeaderTable::EntryTable;
-  using EntryHasher = spdy::HpackHeaderTable::EntryHasher;
-  using EntriesEq = spdy::HpackHeaderTable::EntriesEq;
-  using UnorderedEntrySet = spdy::HpackHeaderTable::UnorderedEntrySet;
+  using NameValueToEntryMap = spdy::HpackHeaderTable::NameValueToEntryMap;
   using NameToEntryMap = spdy::HpackHeaderTable::NameToEntryMap;
 
   // Result of header table lookup.
@@ -168,7 +167,7 @@
   const EntryTable& static_entries_;
 
   // Tracks the unique static entry for a given header name and value.
-  const UnorderedEntrySet& static_index_;
+  const NameValueToEntryMap& static_index_;
 
   // Tracks the first static entry for a given header name.
   const NameToEntryMap& static_name_index_;
@@ -183,7 +182,7 @@
   // only cares about name and value.  This allows fast lookup of the most
   // recently inserted dynamic entry for a given header name and value pair.
   // Entries point to entries owned by |dynamic_entries_|.
-  UnorderedEntrySet dynamic_index_;
+  NameValueToEntryMap dynamic_index_;
 
   // An unordered map of QpackEntry pointers keyed off header name.  This allows
   // fast lookup of the most recently inserted dynamic entry for a given header
diff --git a/quic/core/qpack/qpack_static_table_test.cc b/quic/core/qpack/qpack_static_table_test.cc
index 7c2818d..53ab0f4 100644
--- a/quic/core/qpack/qpack_static_table_test.cc
+++ b/quic/core/qpack/qpack_static_table_test.cc
@@ -32,9 +32,10 @@
   EXPECT_EQ(QpackStaticTableVector().size(), static_index.size());
 
   const auto& static_name_index = table.GetStaticNameIndex();
+  // Count distinct names in static table.
   std::set<absl::string_view> names;
-  for (auto entry : static_index) {
-    names.insert(entry->name());
+  for (const auto& entry : static_entries) {
+    names.insert(entry.name());
   }
   EXPECT_EQ(names.size(), static_name_index.size());
 }
diff --git a/spdy/core/hpack/hpack_entry.cc b/spdy/core/hpack/hpack_entry.cc
index e217d7f..252b826 100644
--- a/spdy/core/hpack/hpack_entry.cc
+++ b/spdy/core/hpack/hpack_entry.cc
@@ -21,9 +21,6 @@
       insertion_index_(insertion_index),
       type_(is_static ? STATIC : DYNAMIC) {}
 
-HpackEntry::HpackEntry(absl::string_view name, absl::string_view value)
-    : name_ref_(name), value_ref_(value), insertion_index_(0), type_(LOOKUP) {}
-
 HpackEntry::HpackEntry() : insertion_index_(0), type_(LOOKUP) {}
 
 HpackEntry::HpackEntry(const HpackEntry& other)
diff --git a/spdy/core/hpack/hpack_entry.h b/spdy/core/hpack/hpack_entry.h
index e395e33..0afcf5f 100644
--- a/spdy/core/hpack/hpack_entry.h
+++ b/spdy/core/hpack/hpack_entry.h
@@ -21,6 +21,22 @@
 // get the size of an HpackEntry as defined in 5.1.
 constexpr size_t kHpackEntrySizeOverhead = 32;
 
+// A structure for looking up entries in the static and dynamic tables.
+struct QUICHE_EXPORT_PRIVATE HpackLookupEntry {
+  absl::string_view name;
+  absl::string_view value;
+
+  bool operator==(const HpackLookupEntry& other) const {
+    return name == other.name && value == other.value;
+  }
+
+  // Absail hashing framework extension according to absl/hash/hash.h:
+  template <typename H>
+  friend H AbslHashValue(H h, const HpackLookupEntry& entry) {
+    return H::combine(std::move(h), entry.name, entry.value);
+  }
+};
+
 // A structure for an entry in the static table (3.3.1)
 // and the header table (3.3.2).
 class QUICHE_EXPORT_PRIVATE HpackEntry {
@@ -39,11 +55,6 @@
              bool is_static,
              size_t insertion_index);
 
-  // Create a 'lookup' entry (only) suitable for querying a HpackEntrySet. The
-  // instance InsertionIndex() always returns 0 and IsLookup() returns true.
-  // The memory backing |name| and |value| must outlive this object.
-  HpackEntry(absl::string_view name, absl::string_view value);
-
   HpackEntry(const HpackEntry& other);
   HpackEntry& operator=(const HpackEntry& other);
 
@@ -58,9 +69,11 @@
 
   // Returns whether this entry is a member of the static (as opposed to
   // dynamic) table.
+  // TODO(b/182789212): Remove.
   bool IsStatic() const { return type_ == STATIC; }
 
   // Returns whether this entry is a lookup-only entry.
+  // TODO(b/182789212): Remove.
   bool IsLookup() const { return type_ == LOOKUP; }
 
   // Used to compute the entry's index in the header table.
@@ -76,6 +89,7 @@
   size_t EstimateMemoryUsage() const;
 
  private:
+  // TODO(b/182789212): Remove.
   enum EntryType {
     LOOKUP,
     DYNAMIC,
@@ -88,6 +102,7 @@
 
   // These members are always valid. For DYNAMIC and STATIC entries, they
   // always point to |name_| and |value_|.
+  // TODO(b/182789212): Remove.
   absl::string_view name_ref_;
   absl::string_view value_ref_;
 
@@ -95,6 +110,7 @@
   // table.
   size_t insertion_index_;
 
+  // TODO(b/182789212): Remove.
   EntryType type_;
 };
 
diff --git a/spdy/core/hpack/hpack_entry_test.cc b/spdy/core/hpack/hpack_entry_test.cc
index ecd5565..11cbdd2 100644
--- a/spdy/core/hpack/hpack_entry_test.cc
+++ b/spdy/core/hpack/hpack_entry_test.cc
@@ -4,12 +4,40 @@
 
 #include "spdy/core/hpack/hpack_entry.h"
 
+#include "absl/hash/hash.h"
 #include "common/platform/api/quiche_test.h"
 
 namespace spdy {
 
 namespace {
 
+TEST(HpackLookupEntryTest, EntryNamesDiffer) {
+  HpackLookupEntry entry1{"header", "value"};
+  HpackLookupEntry entry2{"HEADER", "value"};
+
+  EXPECT_FALSE(entry1 == entry2);
+  EXPECT_NE(absl::Hash<HpackLookupEntry>()(entry1),
+            absl::Hash<HpackLookupEntry>()(entry2));
+}
+
+TEST(HpackLookupEntryTest, EntryValuesDiffer) {
+  HpackLookupEntry entry1{"header", "value"};
+  HpackLookupEntry entry2{"header", "VALUE"};
+
+  EXPECT_FALSE(entry1 == entry2);
+  EXPECT_NE(absl::Hash<HpackLookupEntry>()(entry1),
+            absl::Hash<HpackLookupEntry>()(entry2));
+}
+
+TEST(HpackLookupEntryTest, EntriesEqual) {
+  HpackLookupEntry entry1{"name", "value"};
+  HpackLookupEntry entry2{"name", "value"};
+
+  EXPECT_TRUE(entry1 == entry2);
+  EXPECT_EQ(absl::Hash<HpackLookupEntry>()(entry1),
+            absl::Hash<HpackLookupEntry>()(entry2));
+}
+
 class HpackEntryTest : public QuicheTest {
  protected:
   HpackEntryTest()
@@ -28,8 +56,8 @@
     size_t index = total_insertions_++;
     return HpackEntry(name_, value_, false, index);
   }
-  void DropEntry() { --table_size_; }
 
+  // TODO(b/182789212): More meaningful tests of Size().
   size_t Size() {
     return name_.size() + value_.size() + kHpackEntrySizeOverhead;
   }
@@ -60,15 +88,6 @@
   EXPECT_EQ(Size(), entry.Size());
 }
 
-TEST_F(HpackEntryTest, LookupConstructor) {
-  HpackEntry entry(name_, value_);
-
-  EXPECT_EQ(name_, entry.name());
-  EXPECT_EQ(value_, entry.value());
-  EXPECT_FALSE(entry.IsStatic());
-  EXPECT_EQ(Size(), entry.Size());
-}
-
 TEST_F(HpackEntryTest, DefaultConstructor) {
   HpackEntry entry;
 
diff --git a/spdy/core/hpack/hpack_header_table.cc b/spdy/core/hpack/hpack_header_table.cc
index 006618d..18ae9a8 100644
--- a/spdy/core/hpack/hpack_header_table.cc
+++ b/spdy/core/hpack/hpack_header_table.cc
@@ -14,23 +14,6 @@
 
 namespace spdy {
 
-size_t HpackHeaderTable::EntryHasher::operator()(
-    const HpackEntry* entry) const {
-  return absl::Hash<std::pair<absl::string_view, absl::string_view>>()(
-      std::make_pair(entry->name(), entry->value()));
-}
-
-bool HpackHeaderTable::EntriesEq::operator()(const HpackEntry* lhs,
-                                             const HpackEntry* rhs) const {
-  if (lhs == nullptr) {
-    return rhs == nullptr;
-  }
-  if (rhs == nullptr) {
-    return false;
-  }
-  return lhs->name() == rhs->name() && lhs->value() == rhs->value();
-}
-
 HpackHeaderTable::HpackHeaderTable()
     : static_entries_(ObtainHpackStaticTable().GetStaticEntries()),
       static_index_(ObtainHpackStaticTable().GetStaticIndex()),
@@ -76,17 +59,18 @@
 
 size_t HpackHeaderTable::GetByNameAndValue(absl::string_view name,
                                            absl::string_view value) {
-  HpackEntry query(name, value);
+  HpackLookupEntry query{name, value};
   {
-    auto it = static_index_.find(&query);
+    auto it = static_index_.find(query);
     if (it != static_index_.end()) {
-      return 1 + (*it)->InsertionIndex();
+      return 1 + it->second->InsertionIndex();
     }
   }
   {
-    auto it = dynamic_index_.find(&query);
+    auto it = dynamic_index_.find(query);
     if (it != dynamic_index_.end()) {
-      return total_insertions_ - (*it)->InsertionIndex() + kStaticTableSize;
+      return total_insertions_ - it->second->InsertionIndex() +
+             kStaticTableSize;
     }
   }
   return kHpackEntryNotFound;
@@ -143,12 +127,12 @@
     HpackEntry* entry = &dynamic_entries_.back();
 
     size_ -= entry->Size();
-    auto it = dynamic_index_.find(entry);
+    auto it = dynamic_index_.find({entry->name(), entry->value()});
     QUICHE_DCHECK(it != dynamic_index_.end());
     // Only remove an entry from the index if its insertion index matches;
     // otherwise, the index refers to another entry with the same name and
     // value.
-    if ((*it)->InsertionIndex() == entry->InsertionIndex()) {
+    if (it->second->InsertionIndex() == entry->InsertionIndex()) {
       dynamic_index_.erase(it);
     }
     auto name_it = dynamic_name_index_.find(entry->name());
@@ -178,17 +162,20 @@
                                  false,  // is_static
                                  total_insertions_);
   HpackEntry* new_entry = &dynamic_entries_.front();
-  auto index_result = dynamic_index_.insert(new_entry);
+  auto index_result = dynamic_index_.insert(std::make_pair(
+      HpackLookupEntry{new_entry->name(), new_entry->value()}, new_entry));
   if (!index_result.second) {
     // An entry with the same name and value already exists in the dynamic
     // index. We should replace it with the newly added entry.
     SPDY_DVLOG(1) << "Found existing entry: "
-                  << (*index_result.first)->GetDebugString()
+                  << index_result.first->second->GetDebugString()
                   << " replacing with: " << new_entry->GetDebugString();
     QUICHE_DCHECK_GT(new_entry->InsertionIndex(),
-                     (*index_result.first)->InsertionIndex());
+                     index_result.first->second->InsertionIndex());
     dynamic_index_.erase(index_result.first);
-    QUICHE_CHECK(dynamic_index_.insert(new_entry).second);
+    auto insert_result = dynamic_index_.insert(std::make_pair(
+        HpackLookupEntry{new_entry->name(), new_entry->value()}, new_entry));
+    QUICHE_CHECK(insert_result.second);
   }
 
   auto name_result =
@@ -213,29 +200,6 @@
   return &dynamic_entries_.front();
 }
 
-void HpackHeaderTable::DebugLogTableState() const {
-  SPDY_DVLOG(2) << "Dynamic table:";
-  for (auto it = dynamic_entries_.begin(); it != dynamic_entries_.end(); ++it) {
-    SPDY_DVLOG(2) << "  " << it->GetDebugString();
-  }
-  SPDY_DVLOG(2) << "Full Static Index:";
-  for (const auto* entry : static_index_) {
-    SPDY_DVLOG(2) << "  " << entry->GetDebugString();
-  }
-  SPDY_DVLOG(2) << "Full Static Name Index:";
-  for (const auto& it : static_name_index_) {
-    SPDY_DVLOG(2) << "  " << it.first << ": " << it.second->GetDebugString();
-  }
-  SPDY_DVLOG(2) << "Full Dynamic Index:";
-  for (const auto* entry : dynamic_index_) {
-    SPDY_DVLOG(2) << "  " << entry->GetDebugString();
-  }
-  SPDY_DVLOG(2) << "Full Dynamic Name Index:";
-  for (const auto& it : dynamic_name_index_) {
-    SPDY_DVLOG(2) << "  " << it.first << ": " << it.second->GetDebugString();
-  }
-}
-
 size_t HpackHeaderTable::EstimateMemoryUsage() const {
   return SpdyEstimateMemoryUsage(dynamic_entries_) +
          SpdyEstimateMemoryUsage(dynamic_index_) +
diff --git a/spdy/core/hpack/hpack_header_table.h b/spdy/core/hpack/hpack_header_table.h
index d6ea206..c057df9 100644
--- a/spdy/core/hpack/hpack_header_table.h
+++ b/spdy/core/hpack/hpack_header_table.h
@@ -46,14 +46,8 @@
   // which case |*_index_| can be trivially extended to map to list iterators.
   using EntryTable = std::deque<HpackEntry>;
 
-  struct QUICHE_EXPORT_PRIVATE EntryHasher {
-    size_t operator()(const HpackEntry* entry) const;
-  };
-  struct QUICHE_EXPORT_PRIVATE EntriesEq {
-    bool operator()(const HpackEntry* lhs, const HpackEntry* rhs) const;
-  };
-  using UnorderedEntrySet =
-      absl::flat_hash_set<HpackEntry*, EntryHasher, EntriesEq>;
+  using NameValueToEntryMap =
+      absl::flat_hash_map<HpackLookupEntry, const HpackEntry*>;
   using NameToEntryMap =
       absl::flat_hash_map<absl::string_view, const HpackEntry*>;
 
@@ -109,8 +103,6 @@
   const HpackEntry* TryAddEntry(absl::string_view name,
                                 absl::string_view value);
 
-  void DebugLogTableState() const ABSL_ATTRIBUTE_UNUSED;
-
   // Returns the estimate of dynamically allocated memory in bytes.
   size_t EstimateMemoryUsage() const;
 
@@ -133,16 +125,23 @@
   EntryTable dynamic_entries_;
 
   // Tracks the unique HpackEntry for a given header name and value.
-  const UnorderedEntrySet& static_index_;
+  // Entries consist of string_views that point to strings stored in
+  // |static_entries_|.
+  const NameValueToEntryMap& static_index_;
 
   // Tracks the first static entry for each name in the static table.
+  // Each entry has a string_view that points to the name strings stored in
+  // |static_entries_|.
   const NameToEntryMap& static_name_index_;
 
   // Tracks the most recently inserted HpackEntry for a given header name and
-  // value.
-  UnorderedEntrySet dynamic_index_;
+  // value.  Entries consist of string_views that point to strings stored in
+  // |dynamic_entries_|.
+  NameValueToEntryMap dynamic_index_;
 
   // Tracks the most recently inserted HpackEntry for a given header name.
+  // Each entry has a string_view that points to the name strings stored in
+  // |dynamic_entries_|.
   NameToEntryMap dynamic_name_index_;
 
   // Last acknowledged value for SETTINGS_HEADER_TABLE_SIZE.
diff --git a/spdy/core/hpack/hpack_header_table_test.cc b/spdy/core/hpack/hpack_header_table_test.cc
index 1b0f12b..c46f58f 100644
--- a/spdy/core/hpack/hpack_header_table_test.cc
+++ b/spdy/core/hpack/hpack_header_table_test.cc
@@ -393,50 +393,6 @@
   EXPECT_EQ(0u, peer_.dynamic_entries().size());
 }
 
-TEST_F(HpackHeaderTableTest, EntryNamesDiffer) {
-  HpackEntry entry1("header", "value");
-  HpackEntry entry2("HEADER", "value");
-
-  HpackHeaderTable::EntryHasher hasher;
-  EXPECT_NE(hasher(&entry1), hasher(&entry2));
-
-  HpackHeaderTable::EntriesEq eq;
-  EXPECT_FALSE(eq(&entry1, &entry2));
-}
-
-TEST_F(HpackHeaderTableTest, EntryValuesDiffer) {
-  HpackEntry entry1("header", "value");
-  HpackEntry entry2("header", "VALUE");
-
-  HpackHeaderTable::EntryHasher hasher;
-  EXPECT_NE(hasher(&entry1), hasher(&entry2));
-
-  HpackHeaderTable::EntriesEq eq;
-  EXPECT_FALSE(eq(&entry1, &entry2));
-}
-
-TEST_F(HpackHeaderTableTest, EntriesEqual) {
-  HpackEntry entry1(DynamicEntry("name", "value"));
-  HpackEntry entry2(DynamicEntry("name", "value"));
-
-  HpackHeaderTable::EntryHasher hasher;
-  EXPECT_EQ(hasher(&entry1), hasher(&entry2));
-
-  HpackHeaderTable::EntriesEq eq;
-  EXPECT_TRUE(eq(&entry1, &entry2));
-}
-
-TEST_F(HpackHeaderTableTest, StaticAndDynamicEntriesEqual) {
-  HpackEntry entry1("name", "value");
-  HpackEntry entry2(DynamicEntry("name", "value"));
-
-  HpackHeaderTable::EntryHasher hasher;
-  EXPECT_EQ(hasher(&entry1), hasher(&entry2));
-
-  HpackHeaderTable::EntriesEq eq;
-  EXPECT_TRUE(eq(&entry1, &entry2));
-}
-
 }  // namespace
 
 }  // namespace spdy
diff --git a/spdy/core/hpack/hpack_static_table.cc b/spdy/core/hpack/hpack_static_table.cc
index d977db1..09af550 100644
--- a/spdy/core/hpack/hpack_static_table.cc
+++ b/spdy/core/hpack/hpack_static_table.cc
@@ -23,14 +23,16 @@
   int total_insertions = 0;
   for (const HpackStaticEntry* it = static_entry_table;
        it != static_entry_table + static_entry_count; ++it) {
-    static_entries_.emplace_back(absl::string_view(it->name, it->name_len),
-                                 absl::string_view(it->value, it->value_len),
-                                 true,  // is_static
+    absl::string_view name(it->name, it->name_len);
+    absl::string_view value(it->value, it->value_len);
+    static_entries_.emplace_back(name, value, true,  // is_static
                                  total_insertions);
     HpackEntry* entry = &static_entries_.back();
-    QUICHE_CHECK(static_index_.insert(entry).second);
+    auto result = static_index_.insert(
+        std::make_pair(HpackLookupEntry{name, value}, entry));
+    QUICHE_CHECK(result.second);
     // Multiple static entries may have the same name, so inserts may fail.
-    static_name_index_.insert(std::make_pair(entry->name(), entry));
+    static_name_index_.insert(std::make_pair(name, entry));
 
     ++total_insertions;
   }
diff --git a/spdy/core/hpack/hpack_static_table.h b/spdy/core/hpack/hpack_static_table.h
index 09f9740..296e050 100644
--- a/spdy/core/hpack/hpack_static_table.h
+++ b/spdy/core/hpack/hpack_static_table.h
@@ -36,7 +36,7 @@
   const HpackHeaderTable::EntryTable& GetStaticEntries() const {
     return static_entries_;
   }
-  const HpackHeaderTable::UnorderedEntrySet& GetStaticIndex() const {
+  const HpackHeaderTable::NameValueToEntryMap& GetStaticIndex() const {
     return static_index_;
   }
   const HpackHeaderTable::NameToEntryMap& GetStaticNameIndex() const {
@@ -48,7 +48,9 @@
 
  private:
   HpackHeaderTable::EntryTable static_entries_;
-  HpackHeaderTable::UnorderedEntrySet static_index_;
+  // The following two members have string_views that point to strings stored in
+  // |static_entries_|.
+  HpackHeaderTable::NameValueToEntryMap static_index_;
   HpackHeaderTable::NameToEntryMap static_name_index_;
 };
 
diff --git a/spdy/core/hpack/hpack_static_table_test.cc b/spdy/core/hpack/hpack_static_table_test.cc
index 4e79d8f..0d0c74b 100644
--- a/spdy/core/hpack/hpack_static_table_test.cc
+++ b/spdy/core/hpack/hpack_static_table_test.cc
@@ -35,14 +35,16 @@
       table_.GetStaticEntries();
   EXPECT_EQ(kStaticTableSize, static_entries.size());
 
-  HpackHeaderTable::UnorderedEntrySet static_index = table_.GetStaticIndex();
+  const HpackHeaderTable::NameValueToEntryMap& static_index =
+      table_.GetStaticIndex();
   EXPECT_EQ(kStaticTableSize, static_index.size());
 
-  HpackHeaderTable::NameToEntryMap static_name_index =
+  const HpackHeaderTable::NameToEntryMap& static_name_index =
       table_.GetStaticNameIndex();
+  // Count distinct names in static table.
   std::set<absl::string_view> names;
-  for (auto* entry : static_index) {
-    names.insert(entry->name());
+  for (const auto& entry : static_entries) {
+    names.insert(entry.name());
   }
   EXPECT_EQ(names.size(), static_name_index.size());
 }