From 5ae15432b8726ace5521b88477fa995961396c25 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sat, 18 Nov 2017 12:29:54 -0800 Subject: [PATCH] Refactor basic_fields allocator internals: fix #857 * Use empty base optimization to store the allocator * Rebind to a smaller aligned type to reduce waste --- CHANGELOG.md | 1 + include/boost/beast/http/fields.hpp | 16 ++++-- include/boost/beast/http/impl/fields.ipp | 66 +++++++++++++----------- include/boost/beast/http/message.hpp | 10 ++-- 4 files changed, 55 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee72497e..da9cebd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ Version 145: * Rename some detail functions +* Refactor basic_fields allocator internals -------------------------------------------------------------------------------- diff --git a/include/boost/beast/http/fields.hpp b/include/boost/beast/http/fields.hpp index 06c950ee..4aa9ff71 100644 --- a/include/boost/beast/http/fields.hpp +++ b/include/boost/beast/http/fields.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,9 @@ namespace http { */ template class basic_fields +#ifndef BOOST_BEAST_DOXYGEN + : private beast::detail::empty_base_optimization +#endif { friend class fields_test; // for `header` @@ -260,7 +264,7 @@ public: allocator_type get_allocator() const { - return alloc_; + return this->member(); } //-------------------------------------------------------------------------- @@ -681,12 +685,15 @@ private: template friend class basic_fields; - using base_alloc_type = typename + using align_type = typename + 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; + beast::detail::allocator_traits; using size_type = typename beast::detail::allocator_traits::size_type; @@ -736,7 +743,6 @@ private: void swap(basic_fields& other, std::false_type); - base_alloc_type alloc_; set_t set_; list_t list_; string_view method_; diff --git a/include/boost/beast/http/impl/fields.ipp b/include/boost/beast/http/impl/fields.ipp index 67d7cc45..d0505f0b 100644 --- a/include/boost/beast/http/impl/fields.ipp +++ b/include/boost/beast/http/impl/fields.ipp @@ -350,14 +350,15 @@ basic_fields:: template basic_fields:: basic_fields(Allocator const& alloc) - : alloc_(alloc) + : beast::detail::empty_base_optimization(alloc) { } template basic_fields:: basic_fields(basic_fields&& other) - : alloc_(std::move(other.alloc_)) + : beast::detail::empty_base_optimization( + std::move(other.member())) , set_(std::move(other.set_)) , list_(std::move(other.list_)) , method_(other.method_) @@ -370,9 +371,9 @@ basic_fields(basic_fields&& other) template basic_fields:: basic_fields(basic_fields&& other, Allocator const& alloc) - : alloc_(alloc) + : beast::detail::empty_base_optimization(alloc) { - if(alloc_ != other.alloc_) + if(this->member() != other.member()) { copy_all(other); other.clear_all(); @@ -389,8 +390,8 @@ basic_fields(basic_fields&& other, Allocator const& alloc) template basic_fields:: basic_fields(basic_fields const& other) - : alloc_(alloc_traits:: - select_on_container_copy_construction(other.alloc_)) + : beast::detail::empty_base_optimization(alloc_traits:: + select_on_container_copy_construction(other.member())) { copy_all(other); } @@ -399,7 +400,7 @@ template basic_fields:: basic_fields(basic_fields const& other, Allocator const& alloc) - : alloc_(alloc) + : beast::detail::empty_base_optimization(alloc) { copy_all(other); } @@ -417,7 +418,7 @@ template basic_fields:: basic_fields(basic_fields const& other, Allocator const& alloc) - : alloc_(alloc) + : beast::detail::empty_base_optimization(alloc) { copy_all(other); } @@ -1014,13 +1015,13 @@ set_chunked_impl(bool value) // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437 std::string s; #else - using rebind_type = + using A = typename beast::detail::allocator_traits< Allocator>::template rebind_alloc; std::basic_string< char, std::char_traits, - rebind_type> s{rebind_type{alloc_}}; + A> s{A{this->member()}}; #endif s.reserve(it->value().size() + 9); s.append(it->value().data(), it->value().size()); @@ -1051,13 +1052,13 @@ set_chunked_impl(bool value) // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437 std::string s; #else - using rebind_type = + using A = typename beast::detail::allocator_traits< Allocator>::template rebind_alloc; std::basic_string< char, std::char_traits, - rebind_type> s{rebind_type{alloc_}}; + A> s{A{this->member()}}; #endif s.reserve(it->value().size()); detail::filter_token_list_last(s, it->value(), @@ -1108,13 +1109,13 @@ set_keep_alive_impl( // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437 std::string s; #else - using rebind_type = + using A = typename beast::detail::allocator_traits< Allocator>::template rebind_alloc; std::basic_string< char, std::char_traits, - rebind_type> s{rebind_type{alloc_}}; + A> s{A{this->member()}}; #endif s.reserve(value.size()); detail::keep_alive_impl( @@ -1148,13 +1149,14 @@ new_element(field name, static_cast(sname.size() + 2); std::uint16_t const len = static_cast(value.size()); - auto const p = alloc_traits::allocate(alloc_, - 1 + (off + len + 2 + sizeof(value_type) - 1) / - sizeof(value_type)); + auto a = rebind_type{this->member()}; + auto const p = alloc_traits::allocate(a, + (sizeof(value_type) + off + len + 2 + sizeof(align_type) - 1) / + sizeof(align_type)); // VFALCO allocator can't call the constructor because its private - //alloc_traits::construct(alloc_, p, name, sname, value); + //alloc_traits::construct(a, p, name, sname, value); new(p) value_type{name, sname, value}; - return *p; + return *reinterpret_cast(p); } template @@ -1162,10 +1164,14 @@ void basic_fields:: delete_element(value_type& e) { - auto const n = 1 + (e.off_ + e.len_ + 2 + - sizeof(value_type) - 1) / sizeof(value_type); - alloc_traits::destroy(alloc_, &e); - alloc_traits::deallocate(alloc_, &e, n); + auto a = rebind_type{this->member()}; + auto const n = + (sizeof(value_type) + 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); } template @@ -1207,7 +1213,7 @@ realloc_string(string_view& dest, string_view s) return; auto a = typename beast::detail::allocator_traits< Allocator>::template rebind_alloc< - char>(alloc_); + char>(this->member()); if(! dest.empty()) { a.deallocate(const_cast( @@ -1235,7 +1241,7 @@ realloc_target( return; auto a = typename beast::detail::allocator_traits< Allocator>::template rebind_alloc< - char>(alloc_); + char>(this->member()); if(! dest.empty()) { a.deallocate(const_cast( @@ -1298,7 +1304,7 @@ move_assign(basic_fields& other, std::true_type) target_or_reason_ = other.target_or_reason_; other.method_.clear(); other.target_or_reason_.clear(); - alloc_ = other.alloc_; + this->member() = other.member(); } template @@ -1308,7 +1314,7 @@ basic_fields:: move_assign(basic_fields& other, std::false_type) { clear_all(); - if(alloc_ != other.alloc_) + if(this->member() != other.member()) { copy_all(other); other.clear_all(); @@ -1331,7 +1337,7 @@ basic_fields:: copy_assign(basic_fields const& other, std::true_type) { clear_all(); - alloc_ = other.alloc_; + this->member() = other.member(); copy_all(other); } @@ -1352,7 +1358,7 @@ basic_fields:: swap(basic_fields& other, std::true_type) { using std::swap; - swap(alloc_, other.alloc_); + swap(this->member(), other.member()); swap(set_, other.set_); swap(list_, other.list_); swap(method_, other.method_); @@ -1365,7 +1371,7 @@ void basic_fields:: swap(basic_fields& other, std::false_type) { - BOOST_ASSERT(alloc_ == other.alloc_); + BOOST_ASSERT(this->member() == other.member()); using std::swap; swap(set_, other.set_); swap(list_, other.list_); diff --git a/include/boost/beast/http/message.hpp b/include/boost/beast/http/message.hpp index 5cf5d94d..04550427 100644 --- a/include/boost/beast/http/message.hpp +++ b/include/boost/beast/http/message.hpp @@ -862,7 +862,8 @@ struct message #endif body()& noexcept { - return this->member(); + return this->beast::detail::empty_base_optimization< + typename Body::value_type>::member(); } /// Returns the body @@ -873,7 +874,9 @@ struct message #endif body()&& noexcept { - return std::move(this->member()); + return std::move( + this->beast::detail::empty_base_optimization< + typename Body::value_type>::member()); } /// Returns the body @@ -884,7 +887,8 @@ struct message #endif body() const& noexcept { - return this->member(); + return this->beast::detail::empty_base_optimization< + typename Body::value_type>::member(); } private: