Refactor basic_fields allocator internals:

fix #857

* Use empty base optimization to store the allocator

* Rebind to a smaller aligned type to reduce waste
This commit is contained in:
Vinnie Falco
2017-11-18 12:29:54 -08:00
parent a55e67b94f
commit 5ae15432b8
4 changed files with 55 additions and 38 deletions

View File

@@ -1,6 +1,7 @@
Version 145: Version 145:
* Rename some detail functions * Rename some detail functions
* Refactor basic_fields allocator internals
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -14,6 +14,7 @@
#include <boost/beast/core/string_param.hpp> #include <boost/beast/core/string_param.hpp>
#include <boost/beast/core/string.hpp> #include <boost/beast/core/string.hpp>
#include <boost/beast/core/detail/allocator.hpp> #include <boost/beast/core/detail/allocator.hpp>
#include <boost/beast/core/detail/empty_base_optimization.hpp>
#include <boost/beast/http/field.hpp> #include <boost/beast/http/field.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/intrusive/list.hpp> #include <boost/intrusive/list.hpp>
@@ -51,6 +52,9 @@ namespace http {
*/ */
template<class Allocator> template<class Allocator>
class basic_fields class basic_fields
#ifndef BOOST_BEAST_DOXYGEN
: private beast::detail::empty_base_optimization<Allocator>
#endif
{ {
friend class fields_test; // for `header` friend class fields_test; // for `header`
@@ -260,7 +264,7 @@ public:
allocator_type allocator_type
get_allocator() const get_allocator() const
{ {
return alloc_; return this->member();
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
@@ -681,12 +685,15 @@ private:
template<class OtherAlloc> template<class OtherAlloc>
friend class basic_fields; friend class basic_fields;
using base_alloc_type = typename using align_type = typename
boost::type_with_alignment<alignof(value_type)>::type;
using rebind_type = typename
beast::detail::allocator_traits<Allocator>:: beast::detail::allocator_traits<Allocator>::
template rebind_alloc<value_type>; template rebind_alloc<align_type>;
using alloc_traits = using alloc_traits =
beast::detail::allocator_traits<base_alloc_type>; beast::detail::allocator_traits<rebind_type>;
using size_type = typename using size_type = typename
beast::detail::allocator_traits<Allocator>::size_type; beast::detail::allocator_traits<Allocator>::size_type;
@@ -736,7 +743,6 @@ private:
void void
swap(basic_fields& other, std::false_type); swap(basic_fields& other, std::false_type);
base_alloc_type alloc_;
set_t set_; set_t set_;
list_t list_; list_t list_;
string_view method_; string_view method_;

View File

@@ -350,14 +350,15 @@ basic_fields<Allocator>::
template<class Allocator> template<class Allocator>
basic_fields<Allocator>:: basic_fields<Allocator>::
basic_fields(Allocator const& alloc) basic_fields(Allocator const& alloc)
: alloc_(alloc) : beast::detail::empty_base_optimization<Allocator>(alloc)
{ {
} }
template<class Allocator> template<class Allocator>
basic_fields<Allocator>:: basic_fields<Allocator>::
basic_fields(basic_fields&& other) basic_fields(basic_fields&& other)
: alloc_(std::move(other.alloc_)) : beast::detail::empty_base_optimization<Allocator>(
std::move(other.member()))
, set_(std::move(other.set_)) , set_(std::move(other.set_))
, list_(std::move(other.list_)) , list_(std::move(other.list_))
, method_(other.method_) , method_(other.method_)
@@ -370,9 +371,9 @@ basic_fields(basic_fields&& other)
template<class Allocator> template<class Allocator>
basic_fields<Allocator>:: basic_fields<Allocator>::
basic_fields(basic_fields&& other, Allocator const& alloc) basic_fields(basic_fields&& other, Allocator const& alloc)
: alloc_(alloc) : beast::detail::empty_base_optimization<Allocator>(alloc)
{ {
if(alloc_ != other.alloc_) if(this->member() != other.member())
{ {
copy_all(other); copy_all(other);
other.clear_all(); other.clear_all();
@@ -389,8 +390,8 @@ basic_fields(basic_fields&& other, Allocator const& alloc)
template<class Allocator> template<class Allocator>
basic_fields<Allocator>:: basic_fields<Allocator>::
basic_fields(basic_fields const& other) basic_fields(basic_fields const& other)
: alloc_(alloc_traits:: : beast::detail::empty_base_optimization<Allocator>(alloc_traits::
select_on_container_copy_construction(other.alloc_)) select_on_container_copy_construction(other.member()))
{ {
copy_all(other); copy_all(other);
} }
@@ -399,7 +400,7 @@ template<class Allocator>
basic_fields<Allocator>:: basic_fields<Allocator>::
basic_fields(basic_fields const& other, basic_fields(basic_fields const& other,
Allocator const& alloc) Allocator const& alloc)
: alloc_(alloc) : beast::detail::empty_base_optimization<Allocator>(alloc)
{ {
copy_all(other); copy_all(other);
} }
@@ -417,7 +418,7 @@ template<class OtherAlloc>
basic_fields<Allocator>:: basic_fields<Allocator>::
basic_fields(basic_fields<OtherAlloc> const& other, basic_fields(basic_fields<OtherAlloc> const& other,
Allocator const& alloc) Allocator const& alloc)
: alloc_(alloc) : beast::detail::empty_base_optimization<Allocator>(alloc)
{ {
copy_all(other); copy_all(other);
} }
@@ -1014,13 +1015,13 @@ set_chunked_impl(bool value)
// Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437 // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
std::string s; std::string s;
#else #else
using rebind_type = using A =
typename beast::detail::allocator_traits< typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc<char>; Allocator>::template rebind_alloc<char>;
std::basic_string< std::basic_string<
char, char,
std::char_traits<char>, std::char_traits<char>,
rebind_type> s{rebind_type{alloc_}}; A> s{A{this->member()}};
#endif #endif
s.reserve(it->value().size() + 9); s.reserve(it->value().size() + 9);
s.append(it->value().data(), it->value().size()); 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 // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
std::string s; std::string s;
#else #else
using rebind_type = using A =
typename beast::detail::allocator_traits< typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc<char>; Allocator>::template rebind_alloc<char>;
std::basic_string< std::basic_string<
char, char,
std::char_traits<char>, std::char_traits<char>,
rebind_type> s{rebind_type{alloc_}}; A> s{A{this->member()}};
#endif #endif
s.reserve(it->value().size()); s.reserve(it->value().size());
detail::filter_token_list_last(s, it->value(), 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 // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
std::string s; std::string s;
#else #else
using rebind_type = using A =
typename beast::detail::allocator_traits< typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc<char>; Allocator>::template rebind_alloc<char>;
std::basic_string< std::basic_string<
char, char,
std::char_traits<char>, std::char_traits<char>,
rebind_type> s{rebind_type{alloc_}}; A> s{A{this->member()}};
#endif #endif
s.reserve(value.size()); s.reserve(value.size());
detail::keep_alive_impl( detail::keep_alive_impl(
@@ -1148,13 +1149,14 @@ new_element(field name,
static_cast<off_t>(sname.size() + 2); static_cast<off_t>(sname.size() + 2);
std::uint16_t const len = std::uint16_t const len =
static_cast<off_t>(value.size()); static_cast<off_t>(value.size());
auto const p = alloc_traits::allocate(alloc_, auto a = rebind_type{this->member()};
1 + (off + len + 2 + sizeof(value_type) - 1) / auto const p = alloc_traits::allocate(a,
sizeof(value_type)); (sizeof(value_type) + off + len + 2 + sizeof(align_type) - 1) /
sizeof(align_type));
// VFALCO allocator can't call the constructor because its private // 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}; new(p) value_type{name, sname, value};
return *p; return *reinterpret_cast<value_type*>(p);
} }
template<class Allocator> template<class Allocator>
@@ -1162,10 +1164,14 @@ void
basic_fields<Allocator>:: basic_fields<Allocator>::
delete_element(value_type& e) delete_element(value_type& e)
{ {
auto const n = 1 + (e.off_ + e.len_ + 2 + auto a = rebind_type{this->member()};
sizeof(value_type) - 1) / sizeof(value_type); auto const n =
alloc_traits::destroy(alloc_, &e); (sizeof(value_type) + e.off_ + e.len_ + 2 + sizeof(align_type) - 1) /
alloc_traits::deallocate(alloc_, &e, n); sizeof(align_type);
//alloc_traits::destroy(a, &e);
e.~value_type();
alloc_traits::deallocate(a,
reinterpret_cast<align_type*>(&e), n);
} }
template<class Allocator> template<class Allocator>
@@ -1207,7 +1213,7 @@ realloc_string(string_view& dest, string_view s)
return; return;
auto a = typename beast::detail::allocator_traits< auto a = typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc< Allocator>::template rebind_alloc<
char>(alloc_); char>(this->member());
if(! dest.empty()) if(! dest.empty())
{ {
a.deallocate(const_cast<char*>( a.deallocate(const_cast<char*>(
@@ -1235,7 +1241,7 @@ realloc_target(
return; return;
auto a = typename beast::detail::allocator_traits< auto a = typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc< Allocator>::template rebind_alloc<
char>(alloc_); char>(this->member());
if(! dest.empty()) if(! dest.empty())
{ {
a.deallocate(const_cast<char*>( a.deallocate(const_cast<char*>(
@@ -1298,7 +1304,7 @@ move_assign(basic_fields& other, std::true_type)
target_or_reason_ = other.target_or_reason_; target_or_reason_ = other.target_or_reason_;
other.method_.clear(); other.method_.clear();
other.target_or_reason_.clear(); other.target_or_reason_.clear();
alloc_ = other.alloc_; this->member() = other.member();
} }
template<class Allocator> template<class Allocator>
@@ -1308,7 +1314,7 @@ basic_fields<Allocator>::
move_assign(basic_fields& other, std::false_type) move_assign(basic_fields& other, std::false_type)
{ {
clear_all(); clear_all();
if(alloc_ != other.alloc_) if(this->member() != other.member())
{ {
copy_all(other); copy_all(other);
other.clear_all(); other.clear_all();
@@ -1331,7 +1337,7 @@ basic_fields<Allocator>::
copy_assign(basic_fields const& other, std::true_type) copy_assign(basic_fields const& other, std::true_type)
{ {
clear_all(); clear_all();
alloc_ = other.alloc_; this->member() = other.member();
copy_all(other); copy_all(other);
} }
@@ -1352,7 +1358,7 @@ basic_fields<Allocator>::
swap(basic_fields& other, std::true_type) swap(basic_fields& other, std::true_type)
{ {
using std::swap; using std::swap;
swap(alloc_, other.alloc_); swap(this->member(), other.member());
swap(set_, other.set_); swap(set_, other.set_);
swap(list_, other.list_); swap(list_, other.list_);
swap(method_, other.method_); swap(method_, other.method_);
@@ -1365,7 +1371,7 @@ void
basic_fields<Allocator>:: basic_fields<Allocator>::
swap(basic_fields& other, std::false_type) swap(basic_fields& other, std::false_type)
{ {
BOOST_ASSERT(alloc_ == other.alloc_); BOOST_ASSERT(this->member() == other.member());
using std::swap; using std::swap;
swap(set_, other.set_); swap(set_, other.set_);
swap(list_, other.list_); swap(list_, other.list_);

View File

@@ -862,7 +862,8 @@ struct message
#endif #endif
body()& noexcept body()& noexcept
{ {
return this->member(); return this->beast::detail::empty_base_optimization<
typename Body::value_type>::member();
} }
/// Returns the body /// Returns the body
@@ -873,7 +874,9 @@ struct message
#endif #endif
body()&& noexcept body()&& noexcept
{ {
return std::move(this->member()); return std::move(
this->beast::detail::empty_base_optimization<
typename Body::value_type>::member());
} }
/// Returns the body /// Returns the body
@@ -884,7 +887,8 @@ struct message
#endif #endif
body() const& noexcept body() const& noexcept
{ {
return this->member(); return this->beast::detail::empty_base_optimization<
typename Body::value_type>::member();
} }
private: private: