diff --git a/include/boost/http_proto/parser.hpp b/include/boost/http_proto/parser.hpp index c2552fa8..b87ddafb 100644 --- a/include/boost/http_proto/parser.hpp +++ b/include/boost/http_proto/parser.hpp @@ -614,16 +614,11 @@ class parser friend class response_parser; class impl; - BOOST_HTTP_PROTO_DECL - parser( - const rts::context&, - detail::kind); - - BOOST_HTTP_PROTO_DECL - parser(parser&& other) noexcept; - - BOOST_HTTP_PROTO_DECL - ~parser(); + BOOST_HTTP_PROTO_DECL ~parser(); + BOOST_HTTP_PROTO_DECL parser() noexcept; + BOOST_HTTP_PROTO_DECL parser(parser&& other) noexcept; + BOOST_HTTP_PROTO_DECL parser(rts::context const&, detail::kind); + BOOST_HTTP_PROTO_DECL void assign(parser&& other) noexcept; BOOST_HTTP_PROTO_DECL void diff --git a/include/boost/http_proto/request_parser.hpp b/include/boost/http_proto/request_parser.hpp index 7ad99bfb..f6cee2ee 100644 --- a/include/boost/http_proto/request_parser.hpp +++ b/include/boost/http_proto/request_parser.hpp @@ -43,6 +43,62 @@ class request_parser } }; + /** Destructor. + + Any views or buffers obtained from this + parser become invalid. + */ + ~request_parser() = default; + + /** Constructor. + + Default-constructed parsers do not reference any + implementation and therefore must be assigned to before using. + */ + request_parser() noexcept = default; + + /** Constructor. + + The states of `other` are transferred + to the newly constructed object, + including the allocated buffer. + After construction, the only valid + operations on the moved-from object + are destruction and assignment. + + Buffer sequences previously obtained + using @ref prepare or @ref pull_body + remain valid. + + @par Complexity + Constant. + + @param other The parser to move from. + */ + request_parser( + request_parser&& other) noexcept = default; + + /** Assignment. + The states of `other` are transferred + to this object, including the allocated + buffer. + After assignment, the only valid + operations on the moved-from object + are destruction and assignment. + Buffer sequences previously obtained + using @ref prepare or @ref pull_body + remain valid. + @par Complexity + Constant. + @param other The parser to move from. + */ + request_parser& + operator=(request_parser&& other) noexcept + { + assign(std::move(other)); + return *this; + } + /** Constructor. Constructs a parser that uses the @ref @@ -84,35 +140,7 @@ class request_parser */ BOOST_HTTP_PROTO_DECL explicit - request_parser(const rts::context& ctx); - - /** Constructor. - - The states of `other` are transferred - to the newly constructed object, - including the allocated buffer. - After construction, the only valid - operations on the moved-from object - are destruction and assignment. - - Buffer sequences previously obtained - using @ref prepare or @ref pull_body - remain valid. - - @par Complexity - Constant. - - @param other The parser to move from. - */ - request_parser( - request_parser&& other) noexcept = default; - - /** Destructor. - - Any views or buffers obtained from this - parser become invalid. - */ - ~request_parser() = default; + request_parser(rts::context const& ctx); /** Return a reference to the parsed request headers. diff --git a/include/boost/http_proto/response_parser.hpp b/include/boost/http_proto/response_parser.hpp index 6d3380e5..7e96b957 100644 --- a/include/boost/http_proto/response_parser.hpp +++ b/include/boost/http_proto/response_parser.hpp @@ -43,6 +43,62 @@ class response_parser } }; + /** Destructor. + + Any views or buffers obtained from this + parser become invalid. + */ + ~response_parser() = default; + + /** Constructor. + + Default-constructed parsers do not reference any + implementation and therefore must be assigned to before using. + */ + response_parser() = default; + + /** Constructor. + + The states of `other` are transferred + to the newly constructed object, + including the allocated buffer. + After construction, the only valid + operations on the moved-from object + are destruction and assignemt. + + Buffer sequences previously obtained + using @ref prepare or @ref pull_body + remain valid. + + @par Complexity + Constant. + + @param other The parser to move from. + */ + response_parser( + response_parser&& other) noexcept = default; + + /** Assignment. + The states of `other` are transferred + to this object, including the allocated + buffer. + After assignment, the only valid + operations on the moved-from object + are destruction and assignment. + Buffer sequences previously obtained + using @ref prepare or @ref pull_body + remain valid. + @par Complexity + Constant. + @param other The parser to move from. + */ + response_parser& + operator=(response_parser&& other) noexcept + { + assign(std::move(other)); + return *this; + } + /** Constructor. Constructs a parser that uses the @ref @@ -84,35 +140,7 @@ class response_parser */ BOOST_HTTP_PROTO_DECL explicit - response_parser(const rts::context& ctx); - - /** Constructor. - - The states of `other` are transferred - to the newly constructed object, - including the allocated buffer. - After construction, the only valid - operations on the moved-from object - are destruction and assignemt. - - Buffer sequences previously obtained - using @ref prepare or @ref pull_body - remain valid. - - @par Complexity - Constant. - - @param other The parser to move from. - */ - response_parser( - response_parser&& other) noexcept = default; - - /** Destructor. - - Any views or buffers obtained from this - parser become invalid. - */ - ~response_parser() = default; + response_parser(rts::context const& ctx); /** Prepare for the next message on the stream. diff --git a/include/boost/http_proto/serializer.hpp b/include/boost/http_proto/serializer.hpp index b28771c0..a0dce023 100644 --- a/include/boost/http_proto/serializer.hpp +++ b/include/boost/http_proto/serializer.hpp @@ -66,6 +66,63 @@ class serializer using const_buffers_type = boost::span; + /** Destructor + */ + BOOST_HTTP_PROTO_DECL + ~serializer(); + + /** Constructor + Default-constructed serializers do not reference any implementation; + the only valid operations are destruction and assignment. + */ + serializer() = default; + + /** Constructor. + + The states of `other` are transferred + to the newly constructed object, + which includes the allocated buffer. + After construction, the only valid + operations on the moved-from object + are destruction and assignment. + + Buffer sequences previously obtained + using @ref prepare or @ref stream::prepare + remain valid. + + @par Postconditions + @code + other.is_done() == true + @endcode + + @par Complexity + Constant. + + @param other The serializer to move from. + */ + BOOST_HTTP_PROTO_DECL + serializer( + serializer&& other) noexcept; + + /** Assignment. + The states of `other` are transferred + to this object, which includes the + allocated buffer. After assignment, + the only valid operations on the + moved-from object are destruction and + assignment. + Buffer sequences previously obtained + using @ref prepare or @ref stream::prepare + remain valid. + @par Complexity + Constant. + @param other The serializer to move from. + @return A reference to this object. + */ + BOOST_HTTP_PROTO_DECL + serializer& + operator=(serializer&& other) noexcept; + /** Constructor. Constructs a serializer that uses the @ref @@ -116,38 +173,6 @@ class serializer serializer( const rts::context& ctx); - /** Constructor. - - The states of `other` are transferred - to the newly constructed object, - which includes the allocated buffer. - After construction, the only valid - operations on the moved-from object - are destruction and assignment. - - Buffer sequences previously obtained - using @ref prepare or @ref stream::prepare - remain valid. - - @par Postconditions - @code - other.is_done() == true - @endcode - - @par Complexity - Constant. - - @param other The serializer to move from. - */ - BOOST_HTTP_PROTO_DECL - serializer( - serializer&& other) noexcept; - - /** Destructor - */ - BOOST_HTTP_PROTO_DECL - ~serializer(); - /** Reset the serializer for a new message. Aborts any ongoing serialization and @@ -536,7 +561,7 @@ class serializer message_base const&, source&); - impl* impl_; + impl* impl_ = nullptr; }; /** Serializer configuration settings. diff --git a/src/parser.cpp b/src/parser.cpp index 34ab4f12..9b31bcc6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1848,11 +1848,15 @@ class parser::impl //------------------------------------------------ parser:: -parser(const rts::context& ctx, detail::kind k) - : impl_(new impl(ctx, k)) +~parser() +{ + delete impl_; +} + +parser:: +parser() noexcept + : impl_(nullptr) { - // TODO: use a single allocation for - // impl and workspace buffer. } parser:: @@ -1863,9 +1867,24 @@ parser(parser&& other) noexcept } parser:: -~parser() +parser( + rts::context const& ctx, + detail::kind k) + : impl_(new impl(ctx, k)) +{ + // TODO: use a single allocation for + // impl and workspace buffer. +} + +void +parser:: +assign(parser&& other) noexcept { + if(this == &other) + return; delete impl_; + impl_ = other.impl_; + other.impl_ = nullptr; } //-------------------------------------------- diff --git a/src/serializer.cpp b/src/serializer.cpp index 179cddce..14ea4547 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -931,11 +931,9 @@ class serializer::impl //------------------------------------------------ serializer:: -serializer(const rts::context& ctx) - : impl_(new impl(ctx)) +~serializer() { - // TODO: use a single allocation for - // impl and workspace buffer. + delete impl_; } serializer:: @@ -945,10 +943,25 @@ serializer(serializer&& other) noexcept other.impl_ = nullptr; } +serializer& serializer:: -~serializer() +operator=(serializer&& other) noexcept { - delete impl_; + if(this != &other) + { + delete impl_; + impl_ = other.impl_; + other.impl_ = nullptr; + } + return *this; +} + +serializer:: +serializer(rts::context const& ctx) + : impl_(new impl(ctx)) +{ + // TODO: use a single allocation for + // impl and workspace buffer. } void diff --git a/test/unit/request_parser.cpp b/test/unit/request_parser.cpp index db960496..b9d93365 100644 --- a/test/unit/request_parser.cpp +++ b/test/unit/request_parser.cpp @@ -200,6 +200,26 @@ struct request_parser_test void testSpecial() { + // request_parser() + { + BOOST_TEST_NO_THROW(request_parser()); + } + + // operator=(request_parser&&) + { + request_parser pr; + BOOST_TEST_NO_THROW(pr = request_parser()); + } + { + request_parser pr; + + rts::context ctx; + request_parser::config cfg; + install_parser_service(ctx, cfg); + + BOOST_TEST_NO_THROW(pr = request_parser(ctx)); + } + // request_parser(rts::context&) { rts::context ctx; @@ -215,6 +235,10 @@ struct request_parser_test request_parser pr1(ctx); request_parser pr2(std::move(pr1)); } + { + BOOST_TEST_NO_THROW( + request_parser(request_parser())); + } } //-------------------------------------------- diff --git a/test/unit/response_parser.cpp b/test/unit/response_parser.cpp index a56b250d..c440eabc 100644 --- a/test/unit/response_parser.cpp +++ b/test/unit/response_parser.cpp @@ -23,6 +23,26 @@ class response_parser_test void testSpecial() { + // response_parser() + { + BOOST_TEST_NO_THROW(response_parser()); + } + + // operator=(response_parser&&) + { + response_parser pr; + + rts::context ctx; + response_parser::config cfg; + install_parser_service(ctx, cfg); + + BOOST_TEST_NO_THROW(pr = response_parser(ctx)); + } + { + response_parser pr; + BOOST_TEST_NO_THROW(pr = response_parser()); + } + // response_parser(rts::context&) { rts::context ctx; @@ -38,6 +58,10 @@ class response_parser_test response_parser pr1(ctx); response_parser pr2(std::move(pr1)); } + { + BOOST_TEST_NO_THROW( + response_parser(response_parser())); + } } void diff --git a/test/unit/serializer.cpp b/test/unit/serializer.cpp index 01943fb2..9aba02cd 100644 --- a/test/unit/serializer.cpp +++ b/test/unit/serializer.cpp @@ -211,7 +211,7 @@ struct serializer_test } void - testSpecialMembers() + testSpecial() { rts::context ctx; install_serializer_service(ctx, {}); @@ -222,6 +222,21 @@ struct serializer_test // empty body final chunk expected.append("0\r\n\r\n"); + // serializer() + { + BOOST_TEST_NO_THROW(serializer()); + } + + // operator=(serializer&&) + { + serializer sr; + BOOST_TEST_NO_THROW(sr = serializer()); + } + { + serializer sr; + BOOST_TEST_NO_THROW(sr = serializer(ctx)); + } + // serializer(serializer&&) { std::string message; @@ -956,7 +971,7 @@ struct serializer_test run() { testSyntax(); - testSpecialMembers(); + testSpecial(); testEmptyBody(); testOutput(); testExpect100Continue();