@@ -67,19 +67,24 @@ Stream::Stream(Connection& conn, StreamID id, size_t buffer_size)
6767void Stream::set_buffer_size (size_t size) {
6868 if (used () != 0 )
6969 throw std::runtime_error{" Cannot update buffer size while buffer is in use" };
70- if (size == 0 )
71- size = 64 *1024 ;
72- else if (size < 2048 )
70+ if (size > 0 && size < 2048 )
7371 size = 2048 ;
7472
7573 buffer.resize (size);
7674 buffer.shrink_to_fit ();
7775 start = size = unacked_size = 0 ;
7876}
7977
78+ size_t Stream::buffer_size () const {
79+ return buffer.empty ()
80+ ? size + start // start is the acked amount of the first buffer
81+ : buffer.size ();
82+ }
83+
8084bool Stream::append (bstring_view data) {
81- size_t avail = available ();
82- if (avail < data.size ())
85+ assert (!buffer.empty ());
86+
87+ if (data.size () > available ())
8388 return false ;
8489
8590 // When we are appending we have three cases:
@@ -107,14 +112,20 @@ bool Stream::append(bstring_view data) {
107112 return true ;
108113}
109114size_t Stream::append_any (bstring_view data) {
110- size_t avail = available ();
111- if (data.size () > avail)
115+ if (size_t avail = available (); data.size () > avail)
112116 data.remove_suffix (data.size () - avail);
113117 [[maybe_unused]] bool appended = append (data);
114118 assert (appended);
115119 return data.size ();
116120}
117121
122+ void Stream::append_buffer (const std::byte* buffer, size_t length) {
123+ assert (this ->buffer .empty ());
124+ user_buffers.emplace_back (buffer, length);
125+ size += length;
126+ conn.io_ready ();
127+ }
128+
118129void Stream::acknowledge (size_t bytes) {
119130 // Frees bytes; e.g. acknowledge(3) changes:
120131 // [ áaaaaarr ] to [ áaarr ]
@@ -128,21 +139,61 @@ void Stream::acknowledge(size_t bytes) {
128139
129140 unacked_size -= bytes;
130141 size -= bytes;
131- start = size == 0 ? 0 : (start + bytes) % buffer.size (); // reset start to 0 (to reduce wrapping buffers) if empty
142+ if (!buffer.empty ())
143+ start = size == 0 ? 0 : (start + bytes) % buffer.size (); // reset start to 0 (to reduce wrapping buffers) if empty
144+ else if (size == 0 ) {
145+ user_buffers.clear ();
146+ start = 0 ;
147+ } else {
148+ while (bytes) {
149+ assert (!user_buffers.empty ());
150+ assert (start < user_buffers.front ().second );
151+ if (size_t remaining = user_buffers.front ().second - start;
152+ bytes >= remaining) {
153+ user_buffers.pop_front ();
154+ start = 0 ;
155+ bytes -= remaining;
156+ } else {
157+ start += bytes;
158+ bytes = 0 ;
159+ }
160+ }
161+ }
162+
132163 if (!unblocked_callbacks.empty ())
133164 available_ready ();
134165}
135166
136- std::pair<bstring_view, bstring_view> Stream::pending () {
137- std::pair<bstring_view, bstring_view> bufs;
138- if (size_t rsize = unsent (); rsize > 0 ) {
167+ auto get_buffer_it (std::deque<std::pair<std::unique_ptr<const std::byte[]>, size_t >>& bufs, size_t offset) {
168+ auto it = bufs.begin ();
169+ while (offset >= it->second ) {
170+ offset -= it->second ;
171+ it++;
172+ }
173+ return std::make_pair (std::move (it), offset);
174+ }
175+
176+ std::vector<bstring_view> Stream::pending () {
177+ std::vector<bstring_view> bufs;
178+ size_t rsize = unsent ();
179+ if (!rsize) return bufs;
180+ if (!buffer.empty ()) {
139181 size_t rpos = (start + unacked_size) % buffer.size ();
140182 if (size_t rend = rpos + rsize; rend <= buffer.size ()) {
141- bufs.first = { buffer.data () + rpos, rsize} ;
183+ bufs.emplace_back ( buffer.data () + rpos, rsize) ;
142184 } else { // wrapping
143- bufs.first = {buffer.data () + rpos, buffer.size () - rpos};
144- bufs.second = {buffer.data (), rend % buffer.size ()};
185+ bufs.reserve (2 );
186+ bufs.emplace_back (buffer.data () + rpos, buffer.size () - rpos);
187+ bufs.emplace_back (buffer.data (), rend % buffer.size ());
145188 }
189+ } else {
190+ assert (!user_buffers.empty ()); // If empty then unsent() should have been 0
191+ auto [it, offset] = get_buffer_it (user_buffers, start + unacked_size);
192+ bufs.reserve (std::distance (it, user_buffers.end ()));
193+ assert (it != user_buffers.end ());
194+ bufs.emplace_back (it->first .get () + offset, it->second - offset);
195+ for (++it; it != user_buffers.end (); ++it)
196+ bufs.emplace_back (it->first .get (), it->second );
146197 }
147198 return bufs;
148199}
@@ -153,6 +204,10 @@ void Stream::when_available(unblocked_callback_t unblocked_cb) {
153204}
154205
155206void Stream::handle_unblocked () {
207+ if (buffer.empty ()) {
208+ while (!unblocked_callbacks.empty () && unblocked_callbacks.front ()(*this ))
209+ unblocked_callbacks.pop ();
210+ }
156211 while (!unblocked_callbacks.empty () && available () > 0 ) {
157212 if (unblocked_callbacks.front ()(*this ))
158213 unblocked_callbacks.pop ();
@@ -171,6 +226,7 @@ void Stream::wrote(size_t bytes) {
171226 // [ áaarrrrrr ] or [rr áaar]
172227 // to:
173228 // [ áaaaaarrr ] or [aa áaaa]
229+ Debug (" wrote " , bytes, " , unsent=" ,unsent ());
174230 assert (bytes <= unsent ());
175231 unacked_size += bytes;
176232}
0 commit comments