Add QuicheCircularDeque::shrink_to_fit. Notes: 1. This is useful if the data structure (e.g., in a connection that has been idle for a long time) has excessive unused capacity. 2. quiche::QuicheCircularDeque cannot be replaced with absl::chunked_queue completely as the later is not a deque and does not offer random access. PiperOrigin-RevId: 873030800
diff --git a/quiche/common/quiche_circular_deque.h b/quiche/common/quiche_circular_deque.h index 5c8fc1f..28c32c7 100644 --- a/quiche/common/quiche_circular_deque.h +++ b/quiche/common/quiche_circular_deque.h
@@ -457,6 +457,15 @@ return num_elements_to_pop; } + // Requests the reduction of unused capacity. A bit headroom is still kept. + void shrink_to_fit() { + size_type new_capacity = + size() + std::max(MinCapacityIncrement, size() / 4); + if (capacity() > new_capacity) { + Relocate(new_capacity); + } + } + void swap(QuicheCircularDeque& other) { using std::swap; swap(begin_, other.begin_);
diff --git a/quiche/common/quiche_circular_deque_test.cc b/quiche/common/quiche_circular_deque_test.cc index 9278420..48fe474 100644 --- a/quiche/common/quiche_circular_deque_test.cc +++ b/quiche/common/quiche_circular_deque_test.cc
@@ -540,6 +540,84 @@ EXPECT_EQ(5, *(dq2.rbegin() + 1)); } +TEST_F(QuicheCircularDequeTest, ShrinkToFitOnEmptyDeque) { + QuicheCircularDeque<int> dq; + EXPECT_EQ(0u, dq.size()); + EXPECT_EQ(0u, dq.capacity()); + dq.shrink_to_fit(); + EXPECT_EQ(0u, dq.size()); + EXPECT_EQ(0u, dq.capacity()); +} + +TEST_F(QuicheCircularDequeTest, ShrinkToFitOnSmallDeque) { + QuicheCircularDeque<int> dq; + dq.push_back(1); + EXPECT_EQ(1u, dq.size()); + EXPECT_EQ(3u, dq.capacity()); + dq.shrink_to_fit(); + EXPECT_EQ(1u, dq.size()); + EXPECT_EQ(3u, dq.capacity()); + dq.clear(); + EXPECT_EQ(0u, dq.size()); + EXPECT_EQ(3u, dq.capacity()); + dq.shrink_to_fit(); + EXPECT_EQ(0u, dq.size()); + EXPECT_EQ(3u, dq.capacity()); +} + +TEST_F(QuicheCircularDequeTest, ShrinkToFitOnLargeDeque) { + QuicheCircularDeque<int> dq; + dq.assign(64, 1); + dq.push_back(2); + EXPECT_EQ(65u, dq.size()); + EXPECT_EQ(80u, dq.capacity()); + dq.shrink_to_fit(); + EXPECT_EQ(65u, dq.size()); + EXPECT_EQ(80u, dq.capacity()); + dq.pop_front_n(33); + EXPECT_EQ(32u, dq.size()); + EXPECT_EQ(80u, dq.capacity()); + dq.shrink_to_fit(); + EXPECT_EQ(32u, dq.size()); + EXPECT_EQ(40u, dq.capacity()); + dq.pop_front_n(16); + EXPECT_EQ(16u, dq.size()); + EXPECT_EQ(40u, dq.capacity()); + dq.shrink_to_fit(); + EXPECT_EQ(16u, dq.size()); + EXPECT_EQ(20u, dq.capacity()); + dq.pop_front_n(8); + EXPECT_EQ(8u, dq.size()); + EXPECT_EQ(20u, dq.capacity()); + dq.shrink_to_fit(); + EXPECT_EQ(8u, dq.size()); + EXPECT_EQ(11u, dq.capacity()); + dq.pop_front_n(4); + EXPECT_EQ(4u, dq.size()); + EXPECT_EQ(11u, dq.capacity()); + dq.shrink_to_fit(); + EXPECT_EQ(4u, dq.size()); + EXPECT_EQ(7u, dq.capacity()); + dq.pop_front_n(2); + EXPECT_EQ(2u, dq.size()); + EXPECT_EQ(7u, dq.capacity()); + dq.shrink_to_fit(); + EXPECT_EQ(2u, dq.size()); + EXPECT_EQ(5u, dq.capacity()); + dq.pop_front(); + EXPECT_EQ(1u, dq.size()); + EXPECT_EQ(5u, dq.capacity()); + dq.shrink_to_fit(); + EXPECT_EQ(1u, dq.size()); + EXPECT_EQ(4u, dq.capacity()); + dq.pop_front(); + EXPECT_EQ(0u, dq.size()); + EXPECT_EQ(4u, dq.capacity()); + dq.shrink_to_fit(); + EXPECT_EQ(0u, dq.size()); + EXPECT_EQ(3u, dq.capacity()); +} + namespace { class Foo { public: