Prepare QpackHeaderTable::InsertEntry() for non-stable container.

My plan is to split QpackHeaderTable: the decoder does not need
FindHeaderField(), or static_index_, static_name_index, dynamic_index_,
dynamic_index_name_ methods, therefore it does not need iterator stability for
the underlying container, but it needs random access.  QuicCircularDeque would
be a good choice.  This CL prepares InsertEntry() for that.

Since copy is done in a separate step before insertion, now it is safe to evict
before insertion, potentially saving on a little bit of memory.

PiperOrigin-RevId: 365609653
Change-Id: I55b6a95168d7a6bca32b9f35c2bf8d3c08472635
diff --git a/quic/core/qpack/qpack_header_table.cc b/quic/core/qpack/qpack_header_table.cc
index bd6c6d0..da3636d 100644
--- a/quic/core/qpack/qpack_header_table.cc
+++ b/quic/core/qpack/qpack_header_table.cc
@@ -103,35 +103,43 @@
   QUICHE_DCHECK(EntryFitsDynamicTableCapacity(name, value));
 
   const uint64_t index = dropped_entry_count_ + dynamic_entries_.size();
-  dynamic_entries_.push_back({name, value});
-  QpackEntry* const new_entry = &dynamic_entries_.back();
 
-  // Evict entries after inserting the new entry instead of before
-  // in order to avoid invalidating |name| and |value|.
-  dynamic_table_size_ += QpackEntry::Size(name, value);
-  EvictDownToCurrentCapacity();
+  // Copy name and value before modifying the container, because evicting
+  // entries or even inserting a new one might invalidate |name| or |value| if
+  // they point to an entry.
+  QpackEntry new_entry((std::string(name)), (std::string(value)));
+  const size_t entry_size = new_entry.Size();
 
-  auto index_result = dynamic_index_.insert(std::make_pair(
-      QpackLookupEntry{new_entry->name(), new_entry->value()}, index));
+  EvictDownToCapacity(dynamic_table_capacity_ - entry_size);
+
+  dynamic_table_size_ += entry_size;
+  dynamic_entries_.push_back(std::move(new_entry));
+
+  // Make name and value point to the new entry.
+  name = dynamic_entries_.back().name();
+  value = dynamic_entries_.back().value();
+
+  auto index_result = dynamic_index_.insert(
+      std::make_pair(QpackLookupEntry{name, value}, index));
   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(index, index_result.first->second);
     dynamic_index_.erase(index_result.first);
-    auto result = dynamic_index_.insert(std::make_pair(
-        QpackLookupEntry{new_entry->name(), new_entry->value()}, index));
+    auto result = dynamic_index_.insert(
+        std::make_pair(QpackLookupEntry{name, value}, index));
     QUICHE_CHECK(result.second);
   }
 
-  auto name_result = dynamic_name_index_.insert({new_entry->name(), index});
+  auto name_result = dynamic_name_index_.insert({name, index});
   if (!name_result.second) {
     // An entry with the same name already exists.  It needs to be replaced,
     // because |dynamic_name_index_| tracks the most recent entry for a given
     // name.
     QUICHE_DCHECK_GT(index, name_result.first->second);
     dynamic_name_index_.erase(name_result.first);
-    auto result = dynamic_name_index_.insert({new_entry->name(), index});
+    auto result = dynamic_name_index_.insert({name, index});
     QUICHE_CHECK(result.second);
   }
 
@@ -179,7 +187,7 @@
   }
 
   dynamic_table_capacity_ = capacity;
-  EvictDownToCurrentCapacity();
+  EvictDownToCapacity(capacity);
 
   QUICHE_DCHECK_LE(dynamic_table_size_, dynamic_table_capacity_);
 
@@ -245,8 +253,8 @@
   return entry_index;
 }
 
-void QpackHeaderTable::EvictDownToCurrentCapacity() {
-  while (dynamic_table_size_ > dynamic_table_capacity_) {
+void QpackHeaderTable::EvictDownToCapacity(uint64_t capacity) {
+  while (dynamic_table_size_ > capacity) {
     QUICHE_DCHECK(!dynamic_entries_.empty());
 
     QpackEntry* const entry = &dynamic_entries_.front();
diff --git a/quic/core/qpack/qpack_header_table.h b/quic/core/qpack/qpack_header_table.h
index 6a5e15a..a5d6c5d 100644
--- a/quic/core/qpack/qpack_header_table.h
+++ b/quic/core/qpack/qpack_header_table.h
@@ -83,8 +83,12 @@
                                      absl::string_view value) const;
 
   // Inserts (name, value) into the dynamic table.  Entry must not be larger
-  // than the capacity of the dynamic table.  May evict entries.  Returns the
-  // absolute index of the inserted dynamic table entry.
+  // than the capacity of the dynamic table.  May evict entries.  |name| and
+  // |value| are copied first, therefore it is safe for them to point to an
+  // entry in the dynamic table, even if it is about to be evicted, or even if
+  // the underlying container might move entries around when resizing for
+  // insertion.
+  // Returns the absolute index of the inserted dynamic table entry.
   uint64_t InsertEntry(absl::string_view name, absl::string_view value);
 
   // Returns the size of the largest entry that could be inserted into the
@@ -156,8 +160,8 @@
   friend class test::QpackHeaderTablePeer;
 
   // Evict entries from the dynamic table until table size is less than or equal
-  // to current value of |dynamic_table_capacity_|.
-  void EvictDownToCurrentCapacity();
+  // to |capacity|.
+  void EvictDownToCapacity(uint64_t capacity);
 
   // Static Table