Updates QpackHeaderTable to use QuicheCircularDeque rather than std::deque.

This required adding a pointer indirection, as the QPACK encoder assumes pointer stability of individual entries.

Protected by data structure change, not possible to protect.

PiperOrigin-RevId: 441062105
diff --git a/quiche/quic/core/qpack/qpack_header_table.cc b/quiche/quic/core/qpack/qpack_header_table.cc
index 5ee41f6..fb2c76b 100644
--- a/quiche/quic/core/qpack/qpack_header_table.cc
+++ b/quiche/quic/core/qpack/qpack_header_table.cc
@@ -20,8 +20,8 @@
       QpackHeaderTableBase<QpackEncoderDynamicTable>::InsertEntry(name, value);
 
   // Make name and value point to the new entry.
-  name = dynamic_entries().back().name();
-  value = dynamic_entries().back().value();
+  name = dynamic_entries().back()->name();
+  value = dynamic_entries().back()->value();
 
   auto index_result = dynamic_index_.insert(
       std::make_pair(QpackLookupEntry{name, value}, index));
@@ -110,7 +110,7 @@
       break;
     }
     ++entry_index;
-    max_insert_size += entry.Size();
+    max_insert_size += entry->Size();
   }
 
   return max_insert_size;
@@ -133,7 +133,7 @@
   auto it = dynamic_entries().begin();
   uint64_t entry_index = dropped_entry_count();
   while (space_above_draining_index < required_space) {
-    space_above_draining_index += it->Size();
+    space_above_draining_index += (*it)->Size();
     ++it;
     ++entry_index;
     if (it == dynamic_entries().end()) {
@@ -145,7 +145,7 @@
 }
 
 void QpackEncoderHeaderTable::RemoveEntryFromEnd() {
-  const QpackEntry* const entry = &dynamic_entries().front();
+  const QpackEntry* const entry = dynamic_entries().front().get();
   const uint64_t index = dropped_entry_count();
 
   auto index_it = dynamic_index_.find({entry->name(), entry->value()});
diff --git a/quiche/quic/core/qpack/qpack_header_table.h b/quiche/quic/core/qpack/qpack_header_table.h
index 75b66a4..2bbce45 100644
--- a/quiche/quic/core/qpack/qpack_header_table.h
+++ b/quiche/quic/core/qpack/qpack_header_table.h
@@ -22,8 +22,8 @@
 
 // Encoder needs pointer stability for |dynamic_index_| and
 // |dynamic_name_index_|.  However, it does not need random access.
-// TODO(b/182349990): Change to a more memory efficient container.
-using QpackEncoderDynamicTable = std::deque<QpackEntry>;
+using QpackEncoderDynamicTable =
+    quiche::QuicheCircularDeque<std::unique_ptr<QpackEntry>>;
 
 // Decoder needs random access for LookupEntry().
 // However, it does not need pointer stability.
@@ -154,6 +154,28 @@
   return QpackEntry::Size(name, value) <= dynamic_table_capacity_;
 }
 
+namespace internal {
+
+QUIC_NO_EXPORT inline size_t GetSize(const QpackEntry& entry) {
+  return entry.Size();
+}
+
+QUIC_NO_EXPORT inline size_t GetSize(const std::unique_ptr<QpackEntry>& entry) {
+  return entry->Size();
+}
+
+QUIC_NO_EXPORT inline std::unique_ptr<QpackEntry> NewEntry(
+    std::string name, std::string value, QpackEncoderDynamicTable& /*t*/) {
+  return std::make_unique<QpackEntry>(std::move(name), std::move(value));
+}
+
+QUIC_NO_EXPORT inline QpackEntry NewEntry(std::string name, std::string value,
+                                          QpackDecoderDynamicTable& /*t*/) {
+  return QpackEntry{std::move(name), std::move(value)};
+}
+
+}  // namespace internal
+
 template <typename DynamicEntryTable>
 uint64_t QpackHeaderTableBase<DynamicEntryTable>::InsertEntry(
     absl::string_view name,
@@ -165,9 +187,9 @@
   // 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 new_entry = internal::NewEntry(std::string(name), std::string(value),
+                                      dynamic_entries_);
+  const size_t entry_size = internal::GetSize(new_entry);
   EvictDownToCapacity(dynamic_table_capacity_ - entry_size);
 
   dynamic_table_size_ += entry_size;
@@ -205,7 +227,7 @@
 
 template <typename DynamicEntryTable>
 void QpackHeaderTableBase<DynamicEntryTable>::RemoveEntryFromEnd() {
-  const uint64_t entry_size = dynamic_entries_.front().Size();
+  const uint64_t entry_size = internal::GetSize(dynamic_entries_.front());
   QUICHE_DCHECK_GE(dynamic_table_size_, entry_size);
   dynamic_table_size_ -= entry_size;