Tidy up allocator usage

This commit is contained in:
Vinnie Falco
2017-08-08 09:17:24 -07:00
parent cf8182794a
commit 0175102151
8 changed files with 178 additions and 129 deletions

View File

@ -1,6 +1,7 @@
Version 103:
* Boost test matrix fixes
* Tidy up allocator usage
--------------------------------------------------------------------------------

View File

@ -0,0 +1,42 @@
//
// Copyright (c) 2016-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_ALLOCATOR_HPP
#define BOOST_BEAST_DETAIL_ALLOCATOR_HPP
#include <boost/config.hpp>
#if BOOST_NO_CXX11_ALLOCATOR
#include <boost/container/allocator_traits.hpp>
#else
#include <memory>
#endif
namespace boost {
namespace beast {
namespace detail {
// This is a workaround for allocator_traits
// implementations which falsely claim C++11
// compatibility.
#if BOOST_NO_CXX11_ALLOCATOR
template<class Alloc>
using allocator_traits = boost::container::allocator_traits<Alloc>;
#else
template<class Alloc>
using allocator_traits = std::allocator_traits<Alloc>;
#endif
} // detail
} // beast
} // boost
#endif

View File

@ -11,6 +11,7 @@
#define BOOST_BEAST_FLAT_BUFFER_HPP
#include <boost/beast/config.hpp>
#include <boost/beast/core/detail/allocator.hpp>
#include <boost/beast/core/detail/empty_base_optimization.hpp>
#include <boost/asio/buffer.hpp>
#include <limits>
@ -44,21 +45,10 @@ template<class Allocator>
class basic_flat_buffer
#if ! BOOST_BEAST_DOXYGEN
: private detail::empty_base_optimization<
typename std::allocator_traits<Allocator>::
typename detail::allocator_traits<Allocator>::
template rebind_alloc<char>>
#endif
{
public:
#if BOOST_BEAST_DOXYGEN
/// The type of allocator used.
using allocator_type = Allocator;
#else
using allocator_type = typename
std::allocator_traits<Allocator>::
template rebind_alloc<char>;
#endif
private:
enum
{
min_size = 512
@ -67,8 +57,12 @@ private:
template<class OtherAlloc>
friend class basic_flat_buffer;
using base_alloc_type = typename
detail::allocator_traits<Allocator>::
template rebind_alloc<char>;
using alloc_traits =
std::allocator_traits<allocator_type>;
detail::allocator_traits<base_alloc_type>;
static
inline
@ -86,6 +80,9 @@ private:
std::size_t max_;
public:
/// The type of allocator used.
using allocator_type = Allocator;
/// The type used to represent the input sequence as a list of buffers.
using const_buffers_type = boost::asio::const_buffers_1;

View File

@ -58,7 +58,7 @@ basic_flat_buffer(std::size_t limit)
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(Allocator const& alloc)
: detail::empty_base_optimization<allocator_type>(alloc)
: detail::empty_base_optimization<base_alloc_type>(alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
@ -71,7 +71,7 @@ basic_flat_buffer(Allocator const& alloc)
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(std::size_t limit, Allocator const& alloc)
: detail::empty_base_optimization<allocator_type>(alloc)
: detail::empty_base_optimization<base_alloc_type>(alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
@ -84,7 +84,7 @@ basic_flat_buffer(std::size_t limit, Allocator const& alloc)
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer&& other)
: detail::empty_base_optimization<allocator_type>(
: detail::empty_base_optimization<base_alloc_type>(
std::move(other.member()))
, begin_(other.begin_)
, in_(other.in_)
@ -104,7 +104,7 @@ template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer&& other,
Allocator const& alloc)
: detail::empty_base_optimization<allocator_type>(alloc)
: detail::empty_base_optimization<base_alloc_type>(alloc)
{
if(this->member() != other.member())
{
@ -136,7 +136,7 @@ basic_flat_buffer(basic_flat_buffer&& other,
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer const& other)
: detail::empty_base_optimization<allocator_type>(
: detail::empty_base_optimization<base_alloc_type>(
alloc_traits::select_on_container_copy_construction(
other.member()))
, begin_(nullptr)
@ -153,7 +153,7 @@ template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer const& other,
Allocator const& alloc)
: detail::empty_base_optimization<allocator_type>(alloc)
: detail::empty_base_optimization<base_alloc_type>(alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
@ -184,7 +184,7 @@ template<class OtherAlloc>
basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer<OtherAlloc> const& other,
Allocator const& alloc)
: detail::empty_base_optimization<allocator_type>(alloc)
: detail::empty_base_optimization<base_alloc_type>(alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
@ -202,8 +202,8 @@ operator=(basic_flat_buffer&& other) ->
basic_flat_buffer&
{
if(this != &other)
move_assign(other,
typename alloc_traits::propagate_on_container_move_assignment{});
move_assign(other, std::integral_constant<bool,
alloc_traits::propagate_on_container_move_assignment::value>{});
return *this;
}
@ -214,8 +214,8 @@ operator=(basic_flat_buffer const& other) ->
basic_flat_buffer&
{
if(this != &other)
copy_assign(other,
typename alloc_traits::propagate_on_container_copy_assignment{});
copy_assign(other, std::integral_constant<bool,
alloc_traits::propagate_on_container_copy_assignment::value>{});
return *this;
}

View File

@ -92,7 +92,8 @@ class basic_multi_buffer<Allocator>::element
boost::intrusive::link_mode<
boost::intrusive::normal_link>>
{
using size_type = typename std::allocator_traits<Allocator>::size_type;
using size_type =
typename detail::allocator_traits<Allocator>::size_type;
size_type const size_;
@ -439,8 +440,9 @@ basic_multi_buffer(std::size_t limit)
template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer(Allocator const& alloc)
: out_(list_.end())
, alloc_(alloc)
: detail::empty_base_optimization<
base_alloc_type>(alloc)
, out_(list_.end())
{
}
@ -448,21 +450,23 @@ template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer(std::size_t limit,
Allocator const& alloc)
: max_(limit)
: detail::empty_base_optimization<
base_alloc_type>(alloc)
, max_(limit)
, out_(list_.end())
, alloc_(alloc)
{
}
template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer(basic_multi_buffer&& other)
: max_(other.max_)
: detail::empty_base_optimization<
base_alloc_type>(std::move(other.member()))
, max_(other.max_)
, in_size_(other.in_size_)
, in_pos_(other.in_pos_)
, out_pos_(other.out_pos_)
, out_end_(other.out_end_)
, alloc_(std::move(other.alloc_))
{
auto const at_end =
other.out_ == other.list_.end();
@ -479,10 +483,11 @@ template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer(basic_multi_buffer&& other,
Allocator const& alloc)
: max_(other.max_)
, alloc_(alloc)
: detail::empty_base_optimization<
base_alloc_type>(alloc)
, max_(other.max_)
{
if(alloc_ != other.alloc_)
if(this->member() != other.member())
{
out_ = list_.end();
copy_from(other);
@ -509,11 +514,12 @@ basic_multi_buffer(basic_multi_buffer&& other,
template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer(basic_multi_buffer const& other)
: max_(other.max_)
, out_(list_.end())
, alloc_(alloc_traits::
: detail::empty_base_optimization<
base_alloc_type>(alloc_traits::
select_on_container_copy_construction(
other.alloc_))
other.member()))
, max_(other.max_)
, out_(list_.end())
{
copy_from(other);
}
@ -522,9 +528,10 @@ template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer(basic_multi_buffer const& other,
Allocator const& alloc)
: max_(other.max_)
: detail::empty_base_optimization<
base_alloc_type>(alloc)
, max_(other.max_)
, out_(list_.end())
, alloc_(alloc)
{
copy_from(other);
}
@ -545,9 +552,10 @@ basic_multi_buffer<Allocator>::
basic_multi_buffer(
basic_multi_buffer<OtherAlloc> const& other,
allocator_type const& alloc)
: max_(other.max_)
: detail::empty_base_optimization<
base_alloc_type>(alloc)
, max_(other.max_)
, out_(list_.end())
, alloc_(alloc)
{
copy_from(other);
}
@ -562,8 +570,8 @@ operator=(basic_multi_buffer&& other) ->
return *this;
reset();
max_ = other.max_;
move_assign(other, typename
alloc_traits::propagate_on_container_move_assignment{});
move_assign(other, std::integral_constant<bool,
alloc_traits::propagate_on_container_move_assignment::value>{});
return *this;
}
@ -575,8 +583,8 @@ basic_multi_buffer&
{
if(this == &other)
return *this;
copy_assign(other, typename
alloc_traits::propagate_on_container_copy_assignment{});
copy_assign(other, std::integral_constant<bool,
alloc_traits::propagate_on_container_copy_assignment::value>{});
return *this;
}
@ -678,34 +686,40 @@ prepare(size_type n) ->
#endif
}
BOOST_ASSERT(total <= max_);
for(auto it = reuse.begin(); it != reuse.end();)
if(! reuse.empty() || n > 0)
{
auto& e = *it++;
reuse.erase(list_.iterator_to(e));
delete_element(e);
}
if(n > 0)
{
static auto const growth_factor = 2.0f;
auto const size =
std::min<std::size_t>(
max_ - total,
std::max<std::size_t>({
static_cast<std::size_t>(
in_size_ * growth_factor - in_size_),
512,
n}));
auto& e = *reinterpret_cast<element*>(static_cast<
void*>(alloc_traits::allocate(alloc_,
sizeof(element) + size)));
alloc_traits::construct(alloc_, &e, size);
list_.push_back(e);
if(out_ == list_.end())
out_ = list_.iterator_to(e);
out_end_ = n;
#if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
debug_check();
#endif
for(auto it = reuse.begin(); it != reuse.end();)
{
auto& e = *it++;
reuse.erase(list_.iterator_to(e));
auto const len = sizeof(e) + e.size();
alloc_traits::destroy(this->member(), &e);
alloc_traits::deallocate(this->member(),
reinterpret_cast<char*>(&e), len);
}
if(n > 0)
{
static auto const growth_factor = 2.0f;
auto const size =
std::min<std::size_t>(
max_ - total,
std::max<std::size_t>({
static_cast<std::size_t>(
in_size_ * growth_factor - in_size_),
512,
n}));
auto& e = *reinterpret_cast<element*>(static_cast<
void*>(alloc_traits::allocate(this->member(),
sizeof(element) + size)));
alloc_traits::construct(this->member(), &e, size);
list_.push_back(e);
if(out_ == list_.end())
out_ = list_.iterator_to(e);
out_end_ = n;
#if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
debug_check();
#endif
}
}
return mutable_buffers_type(*this);
}
@ -784,7 +798,10 @@ consume(size_type n)
in_pos_ = 0;
auto& e = list_.front();
list_.erase(list_.iterator_to(e));
delete_element(e);
auto const len = sizeof(e) + e.size();
alloc_traits::destroy(this->member(), &e);
alloc_traits::deallocate(this->member(),
reinterpret_cast<char*>(&e), len);
#if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
debug_check();
#endif
@ -822,18 +839,6 @@ consume(size_type n)
}
}
template<class Allocator>
inline
void
basic_multi_buffer<Allocator>::
delete_element(element& e)
{
auto const len = sizeof(e) + e.size();
alloc_traits::destroy(alloc_, &e);
alloc_traits::deallocate(alloc_,
reinterpret_cast<char*>(&e), len);
}
template<class Allocator>
inline
void
@ -841,7 +846,13 @@ basic_multi_buffer<Allocator>::
delete_list()
{
for(auto iter = list_.begin(); iter != list_.end();)
delete_element(*iter++);
{
auto& e = *iter++;
auto const len = sizeof(e) + e.size();
alloc_traits::destroy(this->member(), &e);
alloc_traits::deallocate(this->member(),
reinterpret_cast<char*>(&e), len);
}
}
template<class Allocator>
@ -879,7 +890,7 @@ void
basic_multi_buffer<Allocator>::
move_assign(basic_multi_buffer& other, std::false_type)
{
if(alloc_ != other.alloc_)
if(this->member() != other.member())
{
copy_from(other);
other.reset();
@ -896,7 +907,7 @@ void
basic_multi_buffer<Allocator>::
move_assign(basic_multi_buffer& other, std::true_type)
{
alloc_ = std::move(alloc_);
this->member() = std::move(other.member());
auto const at_end =
other.out_ == other.list_.end();
list_ = std::move(other.list_);
@ -935,7 +946,7 @@ copy_assign(
{
reset();
max_ = other.max_;
alloc_ = other.alloc_;
this->member() = other.member();
copy_from(other);
}
@ -960,7 +971,7 @@ swap(basic_multi_buffer& other, std::true_type)
out_ == list_.end();
auto const at_end1 =
other.out_ == other.list_.end();
swap(alloc_, other.alloc_);
swap(this->member(), other.member());
swap(list_, other.list_);
swap(out_, other.out_);
if(at_end1)
@ -979,7 +990,7 @@ void
basic_multi_buffer<Allocator>::
swap(basic_multi_buffer& other, std::false_type)
{
BOOST_ASSERT(alloc_ == other.alloc_);
BOOST_ASSERT(this->member() == other.member());
using std::swap;
auto const at_end0 =
out_ == list_.end();

View File

@ -11,6 +11,8 @@
#define BOOST_BEAST_MULTI_BUFFER_HPP
#include <boost/beast/config.hpp>
#include <boost/beast/core/detail/allocator.hpp>
#include <boost/beast/core/detail/empty_base_optimization.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/intrusive/list.hpp>
#include <iterator>
@ -34,30 +36,28 @@ namespace beast {
*/
template<class Allocator>
class basic_multi_buffer
{
public:
#if BOOST_BEAST_DOXYGEN
/// The type of allocator used.
using allocator_type = Allocator;
#else
using allocator_type = typename
std::allocator_traits<Allocator>::
template rebind_alloc<char>;
#if ! BOOST_BEAST_DOXYGEN
: private detail::empty_base_optimization<
typename detail::allocator_traits<Allocator>::
template rebind_alloc<char>>
#endif
{
using base_alloc_type = typename
detail::allocator_traits<Allocator>::
template rebind_alloc<char>;
private:
// Storage for the list of buffers representing the input
// and output sequences. The allocation for each element
// contains `element` followed by raw storage bytes.
class element;
using alloc_traits = std::allocator_traits<allocator_type>;
using alloc_traits = detail::allocator_traits<base_alloc_type>;
using list_type = typename boost::intrusive::make_list<element,
boost::intrusive::constant_time_size<true>>::type;
using iter = typename list_type::iterator;
using const_iter = typename list_type::const_iterator;
using size_type = typename std::allocator_traits<Allocator>::size_type;
using size_type = typename alloc_traits::size_type;
using const_buffer = boost::asio::const_buffer;
using mutable_buffer = boost::asio::mutable_buffer;
@ -77,9 +77,11 @@ private:
size_type in_pos_ = 0; // input offset in list_.front()
size_type out_pos_ = 0; // output offset in *out_
size_type out_end_ = 0; // output end offset in list_.back()
allocator_type alloc_; // the allocator
public:
/// The type of allocator used.
using allocator_type = Allocator;
#if BOOST_BEAST_DOXYGEN
/// The type used to represent the input sequence as a list of buffers.
using const_buffers_type = implementation_defined;
@ -215,7 +217,7 @@ public:
allocator_type
get_allocator() const
{
return alloc_;
return this->member();
}
/// Returns the size of the input sequence.
@ -274,9 +276,6 @@ private:
template<class OtherAlloc>
friend class basic_multi_buffer;
void
delete_element(element& e);
void
delete_list();

View File

@ -13,6 +13,7 @@
#include <boost/beast/config.hpp>
#include <boost/beast/core/string_param.hpp>
#include <boost/beast/core/string.hpp>
#include <boost/beast/core/detail/allocator.hpp>
#include <boost/beast/http/field.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/intrusive/list.hpp>
@ -259,9 +260,7 @@ public:
allocator_type
get_allocator() const
{
return typename std::allocator_traits<
Allocator>::template rebind_alloc<
value_type>(alloc_);
return alloc_;
}
//--------------------------------------------------------------------------
@ -675,15 +674,15 @@ private:
template<class OtherAlloc>
friend class basic_fields;
using alloc_type = typename
std::allocator_traits<Allocator>::
using base_alloc_type = typename
beast::detail::allocator_traits<Allocator>::
template rebind_alloc<value_type>;
using alloc_traits =
std::allocator_traits<alloc_type>;
beast::detail::allocator_traits<base_alloc_type>;
using size_type =
typename std::allocator_traits<Allocator>::size_type;
using size_type = typename
beast::detail::allocator_traits<Allocator>::size_type;
value_type&
new_element(field name,
@ -730,7 +729,7 @@ private:
void
swap(basic_fields& other, std::false_type);
alloc_type alloc_;
base_alloc_type alloc_;
set_t set_;
list_t list_;
string_view method_;

View File

@ -432,8 +432,8 @@ operator=(basic_fields&& other) ->
{
if(this == &other)
return *this;
move_assign(other, typename alloc_traits::
propagate_on_container_move_assignment{});
move_assign(other, std::integral_constant<bool,
alloc_traits:: propagate_on_container_move_assignment::value>{});
return *this;
}
@ -443,8 +443,8 @@ basic_fields<Allocator>::
operator=(basic_fields const& other) ->
basic_fields&
{
copy_assign(other, typename alloc_traits::
propagate_on_container_copy_assignment{});
copy_assign(other, std::integral_constant<bool,
alloc_traits::propagate_on_container_copy_assignment::value>{});
return *this;
}
@ -645,8 +645,8 @@ void
basic_fields<Allocator>::
swap(basic_fields<Allocator>& other)
{
swap(other, typename alloc_traits::
propagate_on_container_swap{});
swap(other, std::integral_constant<bool,
alloc_traits::propagate_on_container_swap::value>{});
}
template<class Allocator>
@ -1009,7 +1009,7 @@ set_chunked_impl(bool value)
std::string s;
#else
using rebind_type =
typename std::allocator_traits<
typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc<char>;
std::basic_string<
char,
@ -1046,7 +1046,7 @@ set_chunked_impl(bool value)
std::string s;
#else
using rebind_type =
typename std::allocator_traits<
typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc<char>;
std::basic_string<
char,
@ -1103,7 +1103,7 @@ set_keep_alive_impl(
std::string s;
#else
using rebind_type =
typename std::allocator_traits<
typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc<char>;
std::basic_string<
char,
@ -1199,7 +1199,7 @@ realloc_string(string_view& dest, string_view s)
{
if(dest.empty() && s.empty())
return;
auto a = typename std::allocator_traits<
auto a = typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc<
char>(alloc_);
if(! dest.empty())
@ -1227,7 +1227,7 @@ realloc_target(
// the reader class.
if(dest.empty() && s.empty())
return;
auto a = typename std::allocator_traits<
auto a = typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc<
char>(alloc_);
if(! dest.empty())