diff --git a/CHANGELOG.md b/CHANGELOG.md index d0543353..80cd15e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +Version 186: + +* basic_fields uses intrusive base hooks + +-------------------------------------------------------------------------------- + Version 185: * Remove extraneous function diff --git a/doc/qbk/09_releases.qbk b/doc/qbk/09_releases.qbk index 98a1e77f..1f571531 100644 --- a/doc/qbk/09_releases.qbk +++ b/doc/qbk/09_releases.qbk @@ -27,6 +27,8 @@ * ([issue 1091]) Fix timer on websocket upgrade in examples +* ([issue 1270]) `basic_fields` uses intrusive base hooks + * Workaround for http-server-fast and libstdc++ diff --git a/include/boost/beast/http/fields.hpp b/include/boost/beast/http/fields.hpp index f0b99893..8d526867 100644 --- a/include/boost/beast/http/fields.hpp +++ b/include/boost/beast/http/fields.hpp @@ -65,6 +65,8 @@ class basic_fields static std::size_t constexpr max_static_buffer = 4096; + struct element; + using off_t = std::uint16_t; public: @@ -76,24 +78,20 @@ public: { friend class basic_fields; - boost::asio::const_buffer - buffer() const; - - value_type(field name, - string_view sname, string_view value); - - boost::intrusive::list_member_hook< - boost::intrusive::link_mode< - boost::intrusive::normal_link>> - list_hook_; - boost::intrusive::set_member_hook< - boost::intrusive::link_mode< - boost::intrusive::normal_link>> - set_hook_; off_t off_; off_t len_; field f_; + char* + data() const; + + boost::asio::const_buffer + buffer() const; + + protected: + value_type(field name, + string_view sname, string_view value); + public: /// Constructor (deleted) value_type(value_type const&) = delete; @@ -118,13 +116,16 @@ public: The case-comparison operation is defined only for low-ASCII characters. */ +#if BOOST_BEAST_DOXYGEN + using key_compare = implementation_defined; +#else struct key_compare : beast::iless +#endif { /// Returns `true` if lhs is less than rhs using a strict ordering - template bool operator()( - String const& lhs, + string_view lhs, value_type const& rhs) const noexcept { if(lhs.size() < rhs.name_string().size()) @@ -135,11 +136,10 @@ public: } /// Returns `true` if lhs is less than rhs using a strict ordering - template bool operator()( value_type const& lhs, - String const& rhs) const noexcept + string_view rhs) const noexcept { if(lhs.name_string().size() < rhs.size()) return true; @@ -170,30 +170,36 @@ public: #endif private: + struct element + : public boost::intrusive::list_base_hook< + boost::intrusive::link_mode< + boost::intrusive::normal_link>> + , public boost::intrusive::set_base_hook< + boost::intrusive::link_mode< + boost::intrusive::normal_link>> + , public value_type + { + element(field name, + string_view sname, string_view value); + }; + using list_t = typename boost::intrusive::make_list< - value_type, boost::intrusive::member_hook< - value_type, boost::intrusive::list_member_hook< - boost::intrusive::link_mode< - boost::intrusive::normal_link>>, - &value_type::list_hook_>, - boost::intrusive::constant_time_size< - false>>::type; + element, + boost::intrusive::constant_time_size + >::type; using set_t = typename boost::intrusive::make_multiset< - value_type, boost::intrusive::member_hook>, - &value_type::set_hook_>, - boost::intrusive::constant_time_size, - boost::intrusive::compare>::type; + element, + boost::intrusive::constant_time_size, + boost::intrusive::compare + >::type; using align_type = typename - boost::type_with_alignment::type; + boost::type_with_alignment::type; using rebind_type = typename beast::detail::allocator_traits:: - template rebind_alloc; + template rebind_alloc; using alloc_traits = beast::detail::allocator_traits; @@ -704,15 +710,15 @@ private: template friend class basic_fields; - value_type& + element& new_element(field name, string_view sname, string_view value); void - delete_element(value_type& e); + delete_element(element& e); void - set_element(value_type& e); + set_element(element& e); void realloc_string(string_view& dest, string_view s); diff --git a/include/boost/beast/http/impl/fields.ipp b/include/boost/beast/http/impl/fields.ipp index e8f8a21a..f34a8e74 100644 --- a/include/boost/beast/http/impl/fields.ipp +++ b/include/boost/beast/http/impl/fields.ipp @@ -271,19 +271,38 @@ writer(basic_fields const& f, //------------------------------------------------------------------------------ template +char* basic_fields:: value_type:: -value_type( - field name, - string_view sname, - string_view value) +data() const +{ + return const_cast( + reinterpret_cast( + static_cast(this) + 1)); +} + +template +boost::asio::const_buffer +basic_fields:: +value_type:: +buffer() const +{ + return boost::asio::const_buffer{data(), + static_cast(off_) + len_ + 2}; +} + +template +basic_fields:: +value_type:: +value_type(field name, + string_view sname, string_view value) : off_(static_cast(sname.size() + 2)) , len_(static_cast(value.size())) , f_(name) { //BOOST_ASSERT(name == field::unknown || // iequals(sname, to_string(name))); - char* p = reinterpret_cast(this + 1); + char* p = data(); p[off_-2] = ':'; p[off_-1] = ' '; p[off_ + len_] = '\r'; @@ -293,7 +312,6 @@ value_type( } template -inline field basic_fields:: value_type:: @@ -303,39 +321,32 @@ name() const } template -inline string_view const basic_fields:: value_type:: name_string() const { - return {reinterpret_cast< - char const*>(this + 1), - static_cast(off_ - 2)}; + return {data(), + static_cast(off_ - 2)}; } template -inline string_view const basic_fields:: value_type:: value() const { - return {reinterpret_cast< - char const*>(this + 1) + off_, - static_cast(len_)}; + return {data() + off_, + static_cast(len_)}; } template -inline -boost::asio::const_buffer basic_fields:: -value_type:: -buffer() const +element:: +element(field name, + string_view sname, string_view value) + : value_type(name, sname, value) { - return boost::asio::const_buffer{ - reinterpret_cast(this + 1), - static_cast(off_) + len_ + 2}; } //------------------------------------------------------------------------------ @@ -614,7 +625,7 @@ erase(const_iterator pos) -> auto& e = *next++; set_.erase(e); list_.erase(pos); - delete_element(const_cast(e)); + delete_element(const_cast(e)); return next; } @@ -634,7 +645,7 @@ erase(string_view name) { std::size_t n =0; set_.erase_and_dispose(name, key_compare{}, - [&](value_type* e) + [&](element* e) { ++n; list_.erase(list_.iterator_to(*e)); @@ -1138,7 +1149,7 @@ auto basic_fields:: new_element(field name, string_view sname, string_view value) -> - value_type& + element& { if(sname.size() + 2 > (std::numeric_limits::max)()) @@ -1155,33 +1166,29 @@ new_element(field name, static_cast(value.size()); auto a = rebind_type{this->get()}; auto const p = alloc_traits::allocate(a, - (sizeof(value_type) + off + len + 2 + sizeof(align_type) - 1) / + (sizeof(element) + off + len + 2 + sizeof(align_type) - 1) / sizeof(align_type)); - // VFALCO allocator can't call the constructor because its private - //alloc_traits::construct(a, p, name, sname, value); - new(p) value_type{name, sname, value}; - return *reinterpret_cast(p); + return *(new(p) element(name, sname, value)); } template void basic_fields:: -delete_element(value_type& e) +delete_element(element& e) { auto a = rebind_type{this->get()}; auto const n = - (sizeof(value_type) + e.off_ + e.len_ + 2 + sizeof(align_type) - 1) / + (sizeof(element) + e.off_ + e.len_ + 2 + sizeof(align_type) - 1) / sizeof(align_type); - //alloc_traits::destroy(a, &e); - e.~value_type(); - alloc_traits::deallocate(a, - reinterpret_cast(&e), n); + e.~element(); + alloc_traits::deallocate(a, &e, n); + //reinterpret_cast(&e), n); } template void basic_fields:: -set_element(value_type& e) +set_element(element& e) { auto it = set_.lower_bound( e.name_string(), key_compare{});