Provide absl::Span<QuicMemSlice> version of WriteMemSlices()

The goal is to eventually deprecate QuicMemSliceSpan, thus reducing the amount of platform code we need to carry around.

PiperOrigin-RevId: 378444535
diff --git a/quic/core/quic_stream.cc b/quic/core/quic_stream.cc
index 3f1b7d9..9744ed3 100644
--- a/quic/core/quic_stream.cc
+++ b/quic/core/quic_stream.cc
@@ -19,6 +19,7 @@
 #include "quic/platform/api/quic_flag_utils.h"
 #include "quic/platform/api/quic_flags.h"
 #include "quic/platform/api/quic_logging.h"
+#include "quic/platform/api/quic_mem_slice.h"
 
 using spdy::SpdyPriority;
 
@@ -759,6 +760,16 @@
 }
 
 QuicConsumedData QuicStream::WriteMemSlices(QuicMemSliceSpan span, bool fin) {
+  return WriteMemSlicesInner(MemSliceSpanWrapper(span), fin);
+}
+
+QuicConsumedData QuicStream::WriteMemSlices(absl::Span<QuicMemSlice> span,
+                                            bool fin) {
+  return WriteMemSlicesInner(MemSliceSpanWrapper(span), fin);
+}
+
+QuicConsumedData QuicStream::WriteMemSlicesInner(MemSliceSpanWrapper span,
+                                                 bool fin) {
   QuicConsumedData consumed_data(0, false);
   if (span.empty() && !fin) {
     QUIC_BUG(quic_bug_10586_6) << "span.empty() && !fin";
@@ -786,7 +797,7 @@
     if (!span.empty()) {
       // Buffer all data if buffered data size is below limit.
       QuicStreamOffset offset = send_buffer_.stream_offset();
-      consumed_data.bytes_consumed = send_buffer_.SaveMemSliceSpan(span);
+      consumed_data.bytes_consumed = span.SaveTo(send_buffer_);
       if (offset > send_buffer_.stream_offset() ||
           kMaxStreamLength < send_buffer_.stream_offset()) {
         QUIC_BUG(quic_bug_10586_8) << "Write too many data via stream " << id_;
diff --git a/quic/core/quic_stream.h b/quic/core/quic_stream.h
index 6e6e623..ca20eb4 100644
--- a/quic/core/quic_stream.h
+++ b/quic/core/quic_stream.h
@@ -24,6 +24,7 @@
 
 #include "absl/strings/string_view.h"
 #include "absl/types/optional.h"
+#include "absl/types/span.h"
 #include "quic/core/quic_flow_controller.h"
 #include "quic/core/quic_packets.h"
 #include "quic/core/quic_stream_send_buffer.h"
@@ -32,6 +33,7 @@
 #include "quic/core/session_notifier_interface.h"
 #include "quic/core/stream_delegate_interface.h"
 #include "quic/platform/api/quic_export.h"
+#include "quic/platform/api/quic_mem_slice.h"
 #include "quic/platform/api/quic_mem_slice_span.h"
 #include "quic/platform/api/quic_reference_counted.h"
 #include "spdy/core/spdy_protocol.h"
@@ -343,9 +345,13 @@
   // succeeds.
   bool MaybeSetTtl(QuicTime::Delta ttl);
 
-  // Same as WritevData except data is provided in reference counted memory so
-  // that data copy is avoided.
+  // Commits data into the stream write buffer, and potentially sends it over
+  // the wire.  This method has all-or-nothing semantics: if the write buffer is
+  // not full, all of the memslices in |span| are moved into it; otherwise,
+  // nothing happens.
+  // TODO(vasilvv): deprecate and remove QuicMemSliceSpan version.
   QuicConsumedData WriteMemSlices(QuicMemSliceSpan span, bool fin);
+  QuicConsumedData WriteMemSlices(absl::Span<QuicMemSlice> span, bool fin);
 
   // Returns true if any stream data is lost (including fin) and needs to be
   // retransmitted.
@@ -464,6 +470,26 @@
   friend class test::QuicStreamPeer;
   friend class QuicStreamUtils;
 
+  // Wraps around either QuicMemSliceSpan or absl::Span<QuicMemSlice>.
+  // TODO(vasilvv): delete this after QuicMemSliceSpan is gone.
+  class QUIC_EXPORT_PRIVATE MemSliceSpanWrapper {
+   public:
+    explicit MemSliceSpanWrapper(QuicMemSliceSpan span) : old_(span) {}
+    explicit MemSliceSpanWrapper(absl::Span<QuicMemSlice> span) : new_(span) {}
+
+    bool empty() { return old_.has_value() ? old_->empty() : new_.empty(); }
+    size_t SaveTo(QuicStreamSendBuffer& send_buffer) {
+      if (old_.has_value()) {
+        return send_buffer.SaveMemSliceSpan(*old_);
+      }
+      return send_buffer.SaveMemSliceSpan(new_);
+    }
+
+   private:
+    absl::optional<QuicMemSliceSpan> old_;
+    absl::Span<QuicMemSlice> new_;
+  };
+
   QuicStream(QuicStreamId id,
              QuicSession* session,
              QuicStreamSequencer sequencer,
@@ -502,6 +528,8 @@
   // Returns true if deadline_ has passed.
   bool HasDeadlinePassed() const;
 
+  QuicConsumedData WriteMemSlicesInner(MemSliceSpanWrapper span, bool fin);
+
   QuicStreamSequencer sequencer_;
   QuicStreamId id_;
   // Pointer to the owning QuicSession object.
diff --git a/quic/core/quic_stream_send_buffer.cc b/quic/core/quic_stream_send_buffer.cc
index 3b1b37b..1e32e54 100644
--- a/quic/core/quic_stream_send_buffer.cc
+++ b/quic/core/quic_stream_send_buffer.cc
@@ -12,6 +12,7 @@
 #include "quic/platform/api/quic_flag_utils.h"
 #include "quic/platform/api/quic_flags.h"
 #include "quic/platform/api/quic_logging.h"
+#include "quic/platform/api/quic_mem_slice.h"
 
 namespace quic {
 
@@ -96,6 +97,20 @@
       [&](QuicMemSlice slice) { SaveMemSlice(std::move(slice)); });
 }
 
+QuicByteCount QuicStreamSendBuffer::SaveMemSliceSpan(
+    absl::Span<QuicMemSlice> span) {
+  QuicByteCount total = 0;
+  for (QuicMemSlice& slice : span) {
+    if (slice.length() == 0) {
+      // Skip empty slices.
+      continue;
+    }
+    total += slice.length();
+    SaveMemSlice(std::move(slice));
+  }
+  return total;
+}
+
 void QuicStreamSendBuffer::OnStreamDataConsumed(size_t bytes_consumed) {
   stream_bytes_written_ += bytes_consumed;
   stream_bytes_outstanding_ += bytes_consumed;
diff --git a/quic/core/quic_stream_send_buffer.h b/quic/core/quic_stream_send_buffer.h
index 4b23d3d..f91e476 100644
--- a/quic/core/quic_stream_send_buffer.h
+++ b/quic/core/quic_stream_send_buffer.h
@@ -5,6 +5,7 @@
 #ifndef QUICHE_QUIC_CORE_QUIC_STREAM_SEND_BUFFER_H_
 #define QUICHE_QUIC_CORE_QUIC_STREAM_SEND_BUFFER_H_
 
+#include "absl/types/span.h"
 #include "quic/core/frames/quic_stream_frame.h"
 #include "quic/core/quic_interval_deque.h"
 #include "quic/core/quic_interval_set.h"
@@ -80,6 +81,7 @@
 
   // Save all slices in |span| to send buffer. Return total bytes saved.
   QuicByteCount SaveMemSliceSpan(QuicMemSliceSpan span);
+  QuicByteCount SaveMemSliceSpan(absl::Span<QuicMemSlice> span);
 
   // Called when |bytes_consumed| bytes has been consumed by the stream.
   void OnStreamDataConsumed(size_t bytes_consumed);
diff --git a/quic/core/quic_stream_test.cc b/quic/core/quic_stream_test.cc
index 2d3298b..e69b657 100644
--- a/quic/core/quic_stream_test.cc
+++ b/quic/core/quic_stream_test.cc
@@ -1178,14 +1178,17 @@
   SetQuicFlag(FLAGS_quic_buffered_data_threshold, 100);
 
   Initialize();
-  char data[1024];
-  std::vector<std::pair<char*, size_t>> buffers;
-  buffers.push_back(std::make_pair(data, ABSL_ARRAYSIZE(data)));
-  buffers.push_back(std::make_pair(data, ABSL_ARRAYSIZE(data)));
-  QuicTestMemSliceVector vector1(buffers);
-  QuicTestMemSliceVector vector2(buffers);
-  QuicMemSliceSpan span1 = vector1.span();
-  QuicMemSliceSpan span2 = vector2.span();
+  constexpr QuicByteCount kDataSize = 1024;
+  QuicBufferAllocator* allocator =
+      connection_->helper()->GetStreamSendBufferAllocator();
+  std::vector<QuicMemSlice> vector1;
+  vector1.push_back(QuicMemSlice(QuicBuffer(allocator, kDataSize)));
+  vector1.push_back(QuicMemSlice(QuicBuffer(allocator, kDataSize)));
+  std::vector<QuicMemSlice> vector2;
+  vector2.push_back(QuicMemSlice(QuicBuffer(allocator, kDataSize)));
+  vector2.push_back(QuicMemSlice(QuicBuffer(allocator, kDataSize)));
+  absl::Span<QuicMemSlice> span1(vector1);
+  absl::Span<QuicMemSlice> span2(vector2);
 
   EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
@@ -1196,7 +1199,7 @@
   QuicConsumedData consumed = stream_->WriteMemSlices(span1, false);
   EXPECT_EQ(2048u, consumed.bytes_consumed);
   EXPECT_FALSE(consumed.fin_consumed);
-  EXPECT_EQ(2 * ABSL_ARRAYSIZE(data) - 100, stream_->BufferedDataBytes());
+  EXPECT_EQ(2 * kDataSize - 100, stream_->BufferedDataBytes());
   EXPECT_FALSE(stream_->fin_buffered());
 
   EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(0);
@@ -1204,12 +1207,11 @@
   consumed = stream_->WriteMemSlices(span2, true);
   EXPECT_EQ(0u, consumed.bytes_consumed);
   EXPECT_FALSE(consumed.fin_consumed);
-  EXPECT_EQ(2 * ABSL_ARRAYSIZE(data) - 100, stream_->BufferedDataBytes());
+  EXPECT_EQ(2 * kDataSize - 100, stream_->BufferedDataBytes());
   EXPECT_FALSE(stream_->fin_buffered());
 
   QuicByteCount data_to_write =
-      2 * ABSL_ARRAYSIZE(data) - 100 -
-      GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1;
+      2 * kDataSize - 100 - GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1;
   EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this, data_to_write]() {
         return session_->ConsumeData(stream_->id(), data_to_write, 100u, NO_FIN,
@@ -1225,8 +1227,7 @@
   consumed = stream_->WriteMemSlices(span2, true);
   EXPECT_EQ(2048u, consumed.bytes_consumed);
   EXPECT_TRUE(consumed.fin_consumed);
-  EXPECT_EQ(2 * ABSL_ARRAYSIZE(data) +
-                GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1,
+  EXPECT_EQ(2 * kDataSize + GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1,
             stream_->BufferedDataBytes());
   EXPECT_TRUE(stream_->fin_buffered());