From 7317bd0de9e53a3e1f550cc429499053060a1c08 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Thu, 20 Jul 2017 22:54:54 -0700 Subject: [PATCH] Use custom variant --- .travis.yml | 1 - CHANGELOG.md | 1 + appveyor.yml | 1 - .../boost/beast/core/detail/bind_handler.hpp | 4 +- include/boost/beast/core/detail/variant.hpp | 184 ++++++++++++++++++ include/boost/beast/http/impl/serializer.ipp | 153 +++++++-------- include/boost/beast/http/serializer.hpp | 39 ++-- include/boost/beast/http/write.hpp | 1 - 8 files changed, 275 insertions(+), 109 deletions(-) create mode 100644 include/boost/beast/core/detail/variant.hpp diff --git a/.travis.yml b/.travis.yml index 35a9c076..80bd2613 100644 --- a/.travis.yml +++ b/.travis.yml @@ -201,7 +201,6 @@ install: - git submodule update --init libs/typeof - git submodule update --init libs/unordered - git submodule update --init libs/utility - - git submodule update --init libs/variant - git submodule update --init libs/winapi - rm -rf libs/beast - mkdir libs/beast diff --git a/CHANGELOG.md b/CHANGELOG.md index e3ebacb9..8ee4f4af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Version 86: * Boost prep * Remove use of lexical_cast +* Use custom variant -------------------------------------------------------------------------------- diff --git a/appveyor.yml b/appveyor.yml index e19318e4..b8aab6aa 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -87,7 +87,6 @@ install: - git submodule update --init libs/typeof - git submodule update --init libs/unordered - git submodule update --init libs/utility - - git submodule update --init libs/variant - git submodule update --init libs/winapi - bootstrap - b2 headers diff --git a/include/boost/beast/core/detail/bind_handler.hpp b/include/boost/beast/core/detail/bind_handler.hpp index 536c53b8..21563d37 100644 --- a/include/boost/beast/core/detail/bind_handler.hpp +++ b/include/boost/beast/core/detail/bind_handler.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_BIND_DETAIL_HANDLER_HPP -#define BOOST_BEAST_BIND_DETAIL_HANDLER_HPP +#ifndef BOOST_BEAST_DETAIL_BIND_HANDLER_HPP +#define BOOST_BEAST_DETAIL_BIND_HANDLER_HPP #include #include diff --git a/include/boost/beast/core/detail/variant.hpp b/include/boost/beast/core/detail/variant.hpp new file mode 100644 index 00000000..fda11e99 --- /dev/null +++ b/include/boost/beast/core/detail/variant.hpp @@ -0,0 +1,184 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_DETAIL_VARIANT_HPP +#define BOOST_BEAST_DETAIL_VARIANT_HPP + +#include +#include +#include +#include +#include + +namespace boost { +namespace beast { +namespace detail { + +// This simple variant gets the job done without +// causing too much trouble with template depth: +// +// * Always allows an empty state I==0 +// * emplace() and get() support 1-based indexes only +// * Basic exception guarantee +// * Max 255 types +// +template +class variant +{ + typename std::aligned_storage< + max_sizeof()>::type buf_; + unsigned char i_ = 0; + + template + using type = typename std::tuple_element< + I , std::tuple>::type; + + template + using C = std::integral_constant; + +public: + variant() = default; + + ~variant() + { + if(i_) + destroy(C<0>{}); + } + + variant(variant&& other) + { + i_ = other.move(&buf_, C<0>{}); + } + + variant(variant const& other) + { + i_ = other.copy(&buf_, C<0>{}); + } + + variant& operator=(variant&& other) + { + if(i_ != 0) + destroy(C<0>{}); + i_ = other.move(&buf_, C<0>{}); + return *this; + } + + variant& operator=(variant const& other) + { + if(i_ != 0) + destroy(C<0>{}); + i_ = other.copy(&buf_, C<0>{}); + return *this; + } + + template + void + emplace(Args&&... args) + { + if(i_ != 0) + destroy(C<0>{}); + i_ = 0; + new(&buf_) type( + std::forward(args)...); + i_ = I; + } + + template + type& + get() + { + BOOST_ASSERT(i_ == I); + return *reinterpret_cast< + type*>(&buf_); + } + + template + type& + get() const + { + BOOST_ASSERT(i_ == I); + return *reinterpret_cast< + type const*>(&buf_); + } + + void + reset() + { + if(i_ == 0) + return; + destroy(C<0>{}); + } + +private: + void + destroy(C) + { + return; + } + + template + void + destroy(C) + { + if(i_ == I+1) + { + using T = type; + get().~T(); + return; + } + destroy(C{}); + } + + unsigned char + move(void*, C) + { + return 0; + } + + template + unsigned char + move(void* dest, C) + { + if(i_ == I+1) + { + using T = type; + new(dest) T{std::move(get())}; + get().~T(); + i_ = 0; + return I+1; + } + move(C{}); + } + + unsigned char + copy(void*, C) const + { + return 0; + } + + template + unsigned char + copy(void* dest, C) const + { + if(i_ == I+1) + { + using T = type; + auto const& t = get(); + new(dest) T{t}; + return I+1; + } + copy(C{}); + } +}; + +} // detail +} // beast +} // boost + +#endif diff --git a/include/boost/beast/http/impl/serializer.ipp b/include/boost/beast/http/impl/serializer.ipp index 2d963a0c..0ae87ee9 100644 --- a/include/boost/beast/http/impl/serializer.ipp +++ b/include/boost/beast/http/impl/serializer.ipp @@ -41,18 +41,16 @@ frdinit(std::false_type) template< bool isRequest, class Body, class Fields> -template +template inline void serializer:: do_visit(error_code& ec, Visit& visit) { - // VFALCO work-around for missing variant::emplace - pv_.~variant(); - new(&pv_) decltype(pv_){ - T1{limit_, boost::get(v_)}}; - visit(ec, beast::detail::make_buffers_ref( - boost::get(pv_))); + pv_.template emplace(limit_, v_.template get()); + visit(ec, + beast::detail::make_buffers_ref( + pv_.template get())); } //------------------------------------------------------------------------------ @@ -104,23 +102,23 @@ next(error_code& ec, Visit&& visit) if(! result) goto go_header_only; more_ = result->second; - v_ = cb2_t{ + v_.template emplace<2>( boost::in_place_init, frd_->get(), - result->first}; + result->first); s_ = do_header; BOOST_BEAST_FALLTHROUGH; } case do_header: - do_visit(ec, visit); + do_visit<2>(ec, visit); break; go_header_only: - v_ = cb1_t{frd_->get()}; + v_.template emplace<1>(frd_->get()); s_ = do_header_only; case do_header_only: - do_visit(ec, visit); + do_visit<1>(ec, visit); break; case do_body: @@ -135,13 +133,13 @@ next(error_code& ec, Visit&& visit) if(! result) goto go_complete; more_ = result->second; - v_ = cb3_t{result->first}; + v_.template emplace<3>(result->first); s_ = do_body + 2; BOOST_BEAST_FALLTHROUGH; } case do_body + 2: - do_visit(ec, visit); + do_visit<3>(ec, visit); break; //---------------------------------------------------------------------- @@ -163,11 +161,10 @@ next(error_code& ec, Visit&& visit) if(! result) goto go_header_only_c; more_ = result->second; - #ifndef BOOST_BEAST_NO_BIG_VARIANTS if(! more_) { // do it all in one buffer - v_ = cb7_t{ + v_.template emplace<7>( boost::in_place_init, frd_->get(), buffer_size(result->first), @@ -177,31 +174,30 @@ next(error_code& ec, Visit&& visit) chunk_crlf{}, detail::chunk_last(), boost::asio::const_buffers_1{nullptr, 0}, - chunk_crlf{}}; + chunk_crlf{}); goto go_all_c; } - #endif - v_ = cb4_t{ + v_.template emplace<4>( boost::in_place_init, frd_->get(), buffer_size(result->first), boost::asio::const_buffers_1{nullptr, 0}, chunk_crlf{}, result->first, - chunk_crlf{}}; + chunk_crlf{}); s_ = do_header_c; BOOST_BEAST_FALLTHROUGH; } case do_header_c: - do_visit(ec, visit); + do_visit<4>(ec, visit); break; go_header_only_c: - v_ = cb1_t{frd_->get()}; + v_.template emplace<1>(frd_->get()); s_ = do_header_only_c; case do_header_only_c: - do_visit(ec, visit); + do_visit<1>(ec, visit); break; case do_body_c: @@ -216,11 +212,10 @@ next(error_code& ec, Visit&& visit) if(! result) goto go_final_c; more_ = result->second; - #ifndef BOOST_BEAST_NO_BIG_VARIANTS if(! more_) { // do it all in one buffer - v_ = cb6_t{ + v_.template emplace<6>( boost::in_place_init, buffer_size(result->first), boost::asio::const_buffers_1{nullptr, 0}, @@ -229,51 +224,48 @@ next(error_code& ec, Visit&& visit) chunk_crlf{}, detail::chunk_last(), boost::asio::const_buffers_1{nullptr, 0}, - chunk_crlf{}}; + chunk_crlf{}); goto go_body_final_c; } - #endif - v_ = cb5_t{ + v_.template emplace<5>( boost::in_place_init, buffer_size(result->first), boost::asio::const_buffers_1{nullptr, 0}, chunk_crlf{}, result->first, - chunk_crlf{}}; + chunk_crlf{}); s_ = do_body_c + 2; BOOST_BEAST_FALLTHROUGH; } case do_body_c + 2: - do_visit(ec, visit); + do_visit<5>(ec, visit); break; -#ifndef BOOST_BEAST_NO_BIG_VARIANTS go_body_final_c: s_ = do_body_final_c; case do_body_final_c: - do_visit(ec, visit); + do_visit<6>(ec, visit); break; go_all_c: s_ = do_all_c; case do_all_c: - do_visit(ec, visit); + do_visit<7>(ec, visit); break; -#endif go_final_c: case do_final_c: - v_ = cb8_t{ + v_.template emplace<8>( boost::in_place_init, detail::chunk_last(), boost::asio::const_buffers_1{nullptr, 0}, - chunk_crlf{}}; + chunk_crlf{}); s_ = do_final_c + 1; BOOST_BEAST_FALLTHROUGH; case do_final_c + 1: - do_visit(ec, visit); + do_visit<8>(ec, visit); break; //---------------------------------------------------------------------- @@ -299,23 +291,23 @@ consume(std::size_t n) switch(s_) { case do_header: - BOOST_ASSERT(n <= buffer_size( - boost::get(v_))); - boost::get(v_).consume(n); - if(buffer_size(boost::get(v_)) > 0) + BOOST_ASSERT( + n <= buffer_size(v_.template get<2>())); + v_.template get<2>().consume(n); + if(buffer_size(v_.template get<2>()) > 0) break; header_done_ = true; - v_ = boost::blank{}; + v_.reset(); if(! more_) goto go_complete; s_ = do_body + 1; break; case do_header_only: - BOOST_ASSERT(n <= buffer_size( - boost::get(v_))); - boost::get(v_).consume(n); - if(buffer_size(boost::get(v_)) > 0) + BOOST_ASSERT( + n <= buffer_size(v_.template get<1>())); + v_.template get<1>().consume(n); + if(buffer_size(v_.template get<1>()) > 0) break; frd_ = boost::none; header_done_ = true; @@ -326,12 +318,12 @@ consume(std::size_t n) case do_body + 2: { - BOOST_ASSERT(n <= buffer_size( - boost::get(v_))); - boost::get(v_).consume(n); - if(buffer_size(boost::get(v_)) > 0) + BOOST_ASSERT( + n <= buffer_size(v_.template get<3>())); + v_.template get<3>().consume(n); + if(buffer_size(v_.template get<3>()) > 0) break; - v_ = boost::blank{}; + v_.reset(); if(! more_) goto go_complete; s_ = do_body + 1; @@ -341,13 +333,13 @@ consume(std::size_t n) //---------------------------------------------------------------------- case do_header_c: - BOOST_ASSERT(n <= buffer_size( - boost::get(v_))); - boost::get(v_).consume(n); - if(buffer_size(boost::get(v_)) > 0) + BOOST_ASSERT( + n <= buffer_size(v_.template get<4>())); + v_.template get<4>().consume(n); + if(buffer_size(v_.template get<4>()) > 0) break; header_done_ = true; - v_ = boost::blank{}; + v_.reset(); if(more_) s_ = do_body_c + 1; else @@ -356,10 +348,10 @@ consume(std::size_t n) case do_header_only_c: { - BOOST_ASSERT(n <= buffer_size( - boost::get(v_))); - boost::get(v_).consume(n); - if(buffer_size(boost::get(v_)) > 0) + BOOST_ASSERT( + n <= buffer_size(v_.template get<1>())); + v_.template get<1>().consume(n); + if(buffer_size(v_.template get<1>()) > 0) break; frd_ = boost::none; header_done_ = true; @@ -373,52 +365,49 @@ consume(std::size_t n) } case do_body_c + 2: - BOOST_ASSERT(n <= buffer_size( - boost::get(v_))); - boost::get(v_).consume(n); - if(buffer_size(boost::get(v_)) > 0) + BOOST_ASSERT( + n <= buffer_size(v_.template get<5>())); + v_.template get<5>().consume(n); + if(buffer_size(v_.template get<5>()) > 0) break; - v_ = boost::blank{}; + v_.reset(); if(more_) s_ = do_body_c + 1; else s_ = do_final_c; break; -#ifndef BOOST_BEAST_NO_BIG_VARIANTS case do_body_final_c: { - auto& b = boost::get(v_); - BOOST_ASSERT(n <= buffer_size(b)); - b.consume(n); - if(buffer_size(b) > 0) + BOOST_ASSERT( + n <= buffer_size(v_.template get<6>())); + v_.template get<6>().consume(n); + if(buffer_size(v_.template get<6>()) > 0) break; - v_ = boost::blank{}; + v_.reset(); s_ = do_complete; break; } case do_all_c: { - auto& b = boost::get(v_); - BOOST_ASSERT(n <= buffer_size(b)); - b.consume(n); - if(buffer_size(b) > 0) + BOOST_ASSERT( + n <= buffer_size(v_.template get<7>())); + v_.template get<7>().consume(n); + if(buffer_size(v_.template get<7>()) > 0) break; header_done_ = true; - v_ = boost::blank{}; + v_.reset(); s_ = do_complete; break; } -#endif case do_final_c + 1: - BOOST_ASSERT(buffer_size( - boost::get(v_))); - boost::get(v_).consume(n); - if(buffer_size(boost::get(v_)) > 0) + BOOST_ASSERT(buffer_size(v_.template get<8>())); + v_.template get<8>().consume(n); + if(buffer_size(v_.template get<8>()) > 0) break; - v_ = boost::blank{}; + v_.reset(); goto go_complete; //---------------------------------------------------------------------- diff --git a/include/boost/beast/http/serializer.hpp b/include/boost/beast/http/serializer.hpp index 3b0e6f25..16c0d071 100644 --- a/include/boost/beast/http/serializer.hpp +++ b/include/boost/beast/http/serializer.hpp @@ -16,17 +16,11 @@ #include #include #include +#include #include #include #include #include -#include - -#ifndef BOOST_BEAST_NO_BIG_VARIANTS -# if defined(BOOST_GCC) && BOOST_GCC < 50000 && BOOST_VERSION < 106600 -# define BOOST_BEAST_NO_BIG_VARIANTS -# endif -#endif namespace boost { namespace beast { @@ -116,7 +110,7 @@ private: void frdinit(std::true_type); void frdinit(std::false_type); - template + template void do_visit(error_code& ec, Visit& visit); @@ -152,7 +146,6 @@ private: chunk_crlf>>; // crlf using pcb5_t = buffer_prefix_view; -#ifndef BOOST_BEAST_NO_BIG_VARIANTS using cb6_t = consuming_buffers>; // crlf using pcb7_t = buffer_prefix_view; -#endif using cb8_t = consuming_buffers frd_; - boost::variant v_; - boost::variant pv_; + beast::detail::variant< + cb1_t, cb2_t, cb3_t, cb4_t, + cb5_t ,cb6_t, cb7_t, cb8_t> v_; + beast::detail::variant< + pcb1_t, pcb2_t, pcb3_t, pcb4_t, + pcb5_t ,pcb6_t, pcb7_t, pcb8_t> pv_; std::size_t limit_ = (std::numeric_limits::max)(); int s_ = do_construct; @@ -208,6 +194,15 @@ private: bool more_; public: + /// Constructor + serializer(serializer&&) = default; + + /// Constructor + serializer(serializer const&) = default; + + /// Assignment + serializer& operator=(serializer const&) = delete; + /** Constructor The implementation guarantees that the message passed on diff --git a/include/boost/beast/http/write.hpp b/include/boost/beast/http/write.hpp index 9d6b15c1..bf9ccc55 100644 --- a/include/boost/beast/http/write.hpp +++ b/include/boost/beast/http/write.hpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include