Skip to content

Commit 4183089

Browse files
committed
Refactor serializer
Improvements: * User-provided buffers are now type-erased and used directly, rather than being copied into a flat buffer. This enables efficient handling of buffer sequences with many elements. * Chunk encoding now occurs within the main buffers, allowing serialization of multiple chunks. This also improves buffer consumption efficiency by reducing the total number of buffers. * The number of internal states maintained by the serializer has been reduced. This lowers memory overhead and simplifies reasoning about the implementation.
1 parent 5427839 commit 4183089

7 files changed

Lines changed: 723 additions & 607 deletions

File tree

doc/local-playbook.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ content:
1414

1515
ui:
1616
bundle:
17-
url: https://github.com/boostorg/website-v2-docs/releases/download/ui-master/ui-bundle.zip
17+
url: https://github.com/boostorg/website-v2-docs/releases/download/ui-develop/ui-bundle.zip
1818
snapshot: true
1919

2020
antora:

include/boost/http_proto/detail/impl/array_of_buffers.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,6 @@ reset(std::size_t n)
124124
BOOST_ASSERT(n <= capacity());
125125
p_ = o_;
126126
n_ = n;
127-
for( auto p = p_; p < p_ + n; ++p )
128-
*p = value_type();
129127
}
130128

131129
} // detail

include/boost/http_proto/serializer.hpp

Lines changed: 144 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,26 @@
1717
#include <boost/http_proto/detail/header.hpp>
1818
#include <boost/http_proto/detail/workspace.hpp>
1919
#include <boost/http_proto/source.hpp>
20+
2021
#include <boost/buffers/circular_buffer.hpp>
2122
#include <boost/buffers/const_buffer_span.hpp>
2223
#include <boost/buffers/range.hpp>
2324
#include <boost/buffers/type_traits.hpp>
2425
#include <boost/system/result.hpp>
25-
#include <cstdint>
26+
2627
#include <memory>
28+
#include <numeric>
2729
#include <type_traits>
2830
#include <utility>
2931

3032
namespace boost {
3133
namespace http_proto {
3234

3335
#ifndef BOOST_HTTP_PROTO_DOCS
34-
class request;
35-
class response;
36-
class request_view;
37-
class response_view;
3836
class message_view_base;
3937
namespace detail {
4038
class filter;
41-
} // detail
39+
} // namespace detail
4240
#endif
4341

4442
/** A serializer for HTTP/1 messages
@@ -68,7 +66,8 @@ class filter;
6866
class serializer
6967
{
7068
public:
71-
using const_buffers_type = buffers::const_buffer_span;
69+
using const_buffers_type =
70+
buffers::const_buffer_span;
7271

7372
struct stream;
7473

@@ -219,36 +218,14 @@ class serializer
219218
void
220219
consume(std::size_t n);
221220

222-
/** Applies deflate compression to the current message
223-
224-
After @ref reset is called, compression is not
225-
applied to the next message.
226-
227-
Must be called before any calls to @ref start.
228-
*/
229-
BOOST_HTTP_PROTO_DECL
230-
void
231-
use_deflate_encoding();
232-
233-
/** Applies gzip compression to the current message
234-
235-
After @ref reset is called, compression is not
236-
applied to the next message.
221+
private:
222+
class const_buf_gen_base;
237223

238-
Must be called before any calls to @ref start.
239-
*/
240-
BOOST_HTTP_PROTO_DECL
241-
void
242-
use_gzip_encoding();
224+
template<class>
225+
class const_buf_gen;
243226

244-
private:
245-
static void copy(
246-
buffers::const_buffer*,
247-
buffers::const_buffer const*,
248-
std::size_t n) noexcept;
249-
auto
250-
make_array(std::size_t n) ->
251-
detail::array_of_const_buffers;
227+
detail::array_of_const_buffers
228+
make_array(std::size_t n);
252229

253230
template<
254231
class Source,
@@ -279,10 +256,25 @@ class serializer
279256
ws_, std::forward<Args>(args)...);
280257
}
281258

282-
BOOST_HTTP_PROTO_DECL void start_init(message_view_base const&);
283-
BOOST_HTTP_PROTO_DECL void start_empty(message_view_base const&);
284-
BOOST_HTTP_PROTO_DECL void start_buffers(message_view_base const&);
285-
BOOST_HTTP_PROTO_DECL void start_source(message_view_base const&, source*);
259+
BOOST_HTTP_PROTO_DECL
260+
void
261+
start_init(
262+
message_view_base const&);
263+
264+
BOOST_HTTP_PROTO_DECL
265+
void
266+
start_empty(
267+
message_view_base const&);
268+
269+
BOOST_HTTP_PROTO_DECL
270+
void
271+
start_buffers(
272+
message_view_base const&);
273+
274+
BOOST_HTTP_PROTO_DECL
275+
void
276+
start_source(
277+
message_view_base const&);
286278

287279
enum class style
288280
{
@@ -292,68 +284,25 @@ class serializer
292284
stream
293285
};
294286

295-
// chunked-body = *chunk
296-
// last-chunk
297-
// trailer-section
298-
// CRLF
299-
300-
static
301-
constexpr
302-
std::size_t
303-
crlf_len_ = 2;
304-
305-
// chunk = chunk-size [ chunk-ext ] CRLF
306-
// chunk-data CRLF
307-
static
308-
constexpr
309-
std::size_t
310-
chunk_header_len_ =
311-
16 + // 16 hex digits => 64 bit number
312-
crlf_len_;
313-
314-
// last-chunk = 1*("0") [ chunk-ext ] CRLF
315-
static
316-
constexpr
317-
std::size_t
318-
last_chunk_len_ =
319-
1 + // "0"
320-
crlf_len_ +
321-
crlf_len_; // chunked-body termination requires an extra CRLF
322-
323-
static
324-
constexpr
325-
std::size_t
326-
chunked_overhead_ =
327-
chunk_header_len_ +
328-
crlf_len_ + // closing chunk data
329-
last_chunk_len_;
330-
331-
detail::workspace ws_;
332-
detail::array_of_const_buffers buf_;
333-
detail::filter* filter_ = nullptr;
334-
source* src_;
335287
context& ctx_;
336-
buffers::circular_buffer tmp0_;
337-
buffers::circular_buffer tmp1_;
338-
detail::array_of_const_buffers prepped_;
339-
340-
buffers::mutable_buffer chunk_header_;
341-
buffers::mutable_buffer chunk_close_;
342-
buffers::mutable_buffer last_chunk_;
288+
detail::workspace ws_;
343289

344-
buffers::circular_buffer* in_ = nullptr;
345-
buffers::circular_buffer* out_ = nullptr;
290+
const_buf_gen_base* buf_gen_;
291+
detail::filter* filter_;
292+
source* source_;
346293

347-
buffers::const_buffer* hp_; // header
294+
buffers::circular_buffer cb0_;
295+
buffers::circular_buffer cb1_;
296+
detail::array_of_const_buffers prepped_;
297+
buffers::const_buffer tmp_;
348298

349299
style st_;
350-
bool more_;
300+
bool more_input_;
351301
bool is_done_;
352302
bool is_header_done_;
353303
bool is_chunked_;
354-
bool is_expect_continue_;
355-
bool is_compressed_ = false;
356-
bool filter_done_ = false;
304+
bool needs_exp100_continue_;
305+
bool filter_done_;
357306
};
358307

359308
//------------------------------------------------
@@ -422,17 +371,6 @@ struct serializer::stream
422371
std::size_t
423372
capacity() const noexcept;
424373

425-
/** Returns the number of octets serialized by this
426-
stream.
427-
428-
The associated serializer stores stream output in its
429-
internal buffers. The stream returns the size of this
430-
output.
431-
*/
432-
BOOST_HTTP_PROTO_DECL
433-
std::size_t
434-
size() const noexcept;
435-
436374
/** Return true if the stream cannot currently hold
437375
additional output data.
438376
@@ -503,29 +441,115 @@ struct serializer::stream
503441

504442
//---------------------------------------------------------
505443

444+
class serializer::const_buf_gen_base
445+
{
446+
public:
447+
// Next non-empty buffer
448+
virtual
449+
buffers::const_buffer
450+
operator()() = 0;
451+
452+
// Size of remaining buffers
453+
virtual
454+
std::size_t
455+
size() const = 0;
456+
457+
// Count of remaining non-empty buffers
458+
virtual
459+
std::size_t
460+
count() const = 0;
461+
462+
// Returns true when there is no buffer or
463+
// the remaining buffers are empty
464+
virtual
465+
bool
466+
is_empty() const = 0;
467+
};
468+
469+
template<class ConstBufferSequence>
470+
class serializer::const_buf_gen
471+
: public const_buf_gen_base
472+
{
473+
using it_t = decltype(buffers::begin(
474+
std::declval<ConstBufferSequence>()));
475+
476+
ConstBufferSequence cbs_;
477+
it_t current_;
478+
public:
479+
using const_buffer =
480+
buffers::const_buffer;
481+
482+
explicit
483+
const_buf_gen(ConstBufferSequence cbs)
484+
: cbs_(std::move(cbs))
485+
, current_(buffers::begin(cbs_))
486+
{
487+
}
488+
489+
const_buffer
490+
operator()() override
491+
{
492+
while(current_ != buffers::end(cbs_))
493+
{
494+
const_buffer buf = *current_++;
495+
if(buf.size() != 0)
496+
return buf;
497+
}
498+
return {};
499+
}
500+
501+
std::size_t
502+
size() const override
503+
{
504+
return std::accumulate(
505+
current_,
506+
buffers::end(cbs_),
507+
std::size_t{},
508+
[](std::size_t sum, const_buffer cb) {
509+
return sum + cb.size(); });
510+
}
511+
512+
std::size_t
513+
count() const override
514+
{
515+
return std::count_if(
516+
current_,
517+
buffers::end(cbs_),
518+
[](const_buffer cb) {
519+
return cb.size() != 0; });
520+
}
521+
522+
bool
523+
is_empty() const override
524+
{
525+
return std::all_of(
526+
current_,
527+
buffers::end(cbs_),
528+
[](const_buffer cb) {
529+
return cb.size() == 0; });
530+
}
531+
};
532+
533+
//---------------------------------------------------------
534+
506535
template<
507536
class ConstBufferSequence,
508537
class>
509538
void
510539
serializer::
511540
start(
512541
message_view_base const& m,
513-
ConstBufferSequence&& body)
542+
ConstBufferSequence&& cbs)
514543
{
515-
start_init(m);
516-
auto const& bs =
517-
ws_.emplace<ConstBufferSequence>(
518-
std::forward<ConstBufferSequence>(body));
519-
520-
std::size_t n = std::distance(
521-
buffers::begin(bs),
522-
buffers::end(bs));
523-
524-
buf_ = make_array(n);
525-
auto p = buf_.data();
526-
for(buffers::const_buffer b : buffers::range(bs))
527-
*p++ = b;
544+
static_assert(buffers::is_const_buffer_sequence<
545+
ConstBufferSequence>::value,
546+
"ConstBufferSequence type requirements not met");
528547

548+
start_init(m);
549+
buf_gen_ = std::addressof(
550+
ws_.emplace<const_buf_gen<typename
551+
std::decay<ConstBufferSequence>::type>>(
552+
std::forward<ConstBufferSequence>(cbs)));
529553
start_buffers(m);
530554
}
531555

@@ -549,24 +573,11 @@ start(
549573
start_init(m);
550574
auto& src = construct_source<Source>(
551575
std::forward<Args>(args)...);
552-
start_source(m, std::addressof(src));
576+
source_ = std::addressof(src);
577+
start_source(m);
553578
return src;
554579
}
555580

556-
//------------------------------------------------
557-
558-
inline
559-
auto
560-
serializer::
561-
make_array(std::size_t n) ->
562-
detail::array_of_const_buffers
563-
{
564-
return {
565-
ws_.push_array(n,
566-
buffers::const_buffer{}),
567-
n };
568-
}
569-
570581
} // http_proto
571582
} // boost
572583

0 commit comments

Comments
 (0)