flat_buffer is an AllocatorAwareContainer

fix #453
This commit is contained in:
Vinnie Falco
2017-06-09 17:36:45 -07:00
parent 44995bf071
commit 23863230de
4 changed files with 437 additions and 209 deletions

View File

@@ -1,5 +1,7 @@
Version 52: Version 52:
* flat_buffer is an AllocatorAwareContainer
API Changes: API Changes:
* `auto_fragment` is a member of `stream` * `auto_fragment` is a member of `stream`

View File

@@ -89,109 +89,120 @@ public:
/// The type used to represent the output sequence as a list of buffers. /// The type used to represent the output sequence as a list of buffers.
using mutable_buffers_type = boost::asio::mutable_buffers_1; using mutable_buffers_type = boost::asio::mutable_buffers_1;
/// Copy assignment (disallowed). /// Destructor
basic_flat_buffer&
operator=(basic_flat_buffer const&) = delete;
/// Destructor.
~basic_flat_buffer(); ~basic_flat_buffer();
/** Move constructor. /** Constructor
The new object will have the same input sequence Upon construction, capacity will be zero.
and an empty output sequence.
@note After the move, the moved-from object will
have a capacity of zero, an empty input sequence,
and an empty output sequence.
*/ */
basic_flat_buffer(basic_flat_buffer&&); basic_flat_buffer();
/** Move constructor. /** Constructor
The new object will have the same input sequence Upon construction, capacity will be zero.
and an empty output sequence.
@note After the move, the moved-from object will @param limit The setting for @ref max_size.
have a capacity of zero, an empty input sequence,
and an empty output sequence.
@param alloc The allocator to associate with the
stream buffer.
*/
basic_flat_buffer(basic_flat_buffer&&,
Allocator const& alloc);
/** Copy constructor.
The new object will have a copy of the input sequence
and an empty output sequence.
*/
basic_flat_buffer(basic_flat_buffer const&);
/** Copy constructor.
The new object will have a copy of the input sequence
and an empty output sequence.
@param alloc The allocator to associate with the
stream buffer.
*/
basic_flat_buffer(basic_flat_buffer const&,
Allocator const& alloc);
/** Copy constructor.
The new object will have a copy of the input sequence
and an empty output sequence.
*/
template<class OtherAlloc>
basic_flat_buffer(
basic_flat_buffer<OtherAlloc> const&);
/** Copy constructor.
The new object will have a copy of the input sequence
and an empty output sequence.
@param alloc The allocator to associate with the
stream buffer.
*/
template<class OtherAlloc>
basic_flat_buffer(
basic_flat_buffer<OtherAlloc> const&,
Allocator const& alloc);
/** Construct a flat stream buffer.
No allocation is performed; the buffer will have
empty input and output sequences.
@param limit An optional non-zero value specifying the
maximum of the sum of the input and output sequence sizes
that can be allocated. If unspecified, the largest
possible value of `std::size_t` is used.
*/ */
explicit explicit
basic_flat_buffer(std::size_t limit = ( basic_flat_buffer(std::size_t limit);
std::numeric_limits<std::size_t>::max)());
/** Construct a flat stream buffer. /** Constructor
No allocation is performed; the buffer will have Upon construction, capacity will be zero.
empty input and output sequences.
@param alloc The allocator to associate with the @param alloc The allocator to construct with.
stream buffer.
@param limit An optional non-zero value specifying the
maximum of the sum of the input and output sequence sizes
that can be allocated. If unspecified, the largest
possible value of `std::size_t` is used.
*/ */
basic_flat_buffer(Allocator const& alloc, explicit
std::size_t limit = ( basic_flat_buffer(Allocator const& alloc);
std::numeric_limits<std::size_t>::max)());
/** Constructor
Upon construction, capacity will be zero.
@param limit The setting for @ref max_size.
@param alloc The allocator to use.
*/
basic_flat_buffer(
std::size_t limit, Allocator const& alloc);
/** Move constructor
After the move, `*this` will have an empty output sequence.
@param other The object to move from. After the move,
The object's state will be as if constructed using
its current allocator and limit.
*/
basic_flat_buffer(basic_flat_buffer&& other);
/** Move constructor
After the move, `*this` will have an empty output sequence.
@param other The object to move from. After the move,
The object's state will be as if constructed using
its current allocator and limit.
@param alloc The allocator to use.
*/
basic_flat_buffer(
basic_flat_buffer&& other, Allocator const& alloc);
/** Copy constructor
@param other The object to copy from.
*/
basic_flat_buffer(basic_flat_buffer const& other);
/** Copy constructor
@param other The object to copy from.
@param alloc The allocator to use.
*/
basic_flat_buffer(basic_flat_buffer const& other,
Allocator const& alloc);
/** Copy constructor
@param other The object to copy from.
*/
template<class OtherAlloc>
basic_flat_buffer(
basic_flat_buffer<OtherAlloc> const& other);
/** Copy constructor
@param other The object to copy from.
@param alloc The allocator to use.
*/
template<class OtherAlloc>
basic_flat_buffer(
basic_flat_buffer<OtherAlloc> const& other,
Allocator const& alloc);
/** Move assignment
After the move, `*this` will have an empty output sequence.
@param other The object to move from. After the move,
The object's state will be as if constructed using
its current allocator and limit.
*/
basic_flat_buffer&
operator=(basic_flat_buffer&& other);
/** Copy assignment
After the copy, `*this` will have an empty output sequence.
@param other The object to copy from.
*/
basic_flat_buffer&
operator=(basic_flat_buffer const& other);
/// Returns a copy of the associated allocator. /// Returns a copy of the associated allocator.
allocator_type allocator_type
@@ -287,14 +298,41 @@ public:
void void
shrink_to_fit(); shrink_to_fit();
template<class Alloc>
friend
void
swap(
basic_flat_buffer<Alloc>& lhs,
basic_flat_buffer<Alloc>& rhs);
private: private:
void void
move_from(basic_flat_buffer& other); reset();
template<class OtherAlloc> template<class DynamicBuffer>
void void
copy_from(basic_flat_buffer< copy_from(DynamicBuffer const& other);
OtherAlloc> const& other);
void
move_assign(basic_flat_buffer&, std::true_type);
void
move_assign(basic_flat_buffer&, std::false_type);
void
copy_assign(basic_flat_buffer const&, std::true_type);
void
copy_assign(basic_flat_buffer const&, std::false_type);
void
swap(basic_flat_buffer&);
void
swap(basic_flat_buffer&, std::true_type);
void
swap(basic_flat_buffer&, std::false_type);
}; };
using flat_buffer = using flat_buffer =

View File

@@ -36,50 +36,7 @@ next_pow2(std::size_t x)
} // detail } // detail
template<class Allocator> //------------------------------------------------------------------------------
void
basic_flat_buffer<Allocator>::
move_from(basic_flat_buffer& other)
{
begin_ = other.begin_;
in_ = other.in_;
out_ = other.out_;
last_ = out_;
end_ = other.end_;
max_ = other.max_;
other.begin_ = nullptr;
other.in_ = nullptr;
other.out_ = nullptr;
other.last_ = nullptr;
other.end_ = nullptr;
}
template<class Allocator>
template<class OtherAlloc>
void
basic_flat_buffer<Allocator>::
copy_from(basic_flat_buffer<
OtherAlloc> const& other)
{
max_ = other.max_;
auto const n = other.size();
if(n > 0)
{
begin_ = alloc_traits::allocate(
this->member(), n);
in_ = begin_;
out_ = begin_ + n;
last_ = out_;
end_ = out_;
std::memcpy(in_, other.in_, n);
return;
}
begin_ = nullptr;
in_ = nullptr;
out_ = nullptr;
last_ = nullptr;
end_ = nullptr;
}
template<class Allocator> template<class Allocator>
basic_flat_buffer<Allocator>:: basic_flat_buffer<Allocator>::
@@ -92,69 +49,14 @@ basic_flat_buffer<Allocator>::
template<class Allocator> template<class Allocator>
basic_flat_buffer<Allocator>:: basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer&& other) basic_flat_buffer()
: detail::empty_base_optimization< : begin_(nullptr)
allocator_type>(std::move(other.member())) , in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_((std::numeric_limits<std::size_t>::max)())
{ {
move_from(other);
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer&& other,
Allocator const& alloc)
: detail::empty_base_optimization<
allocator_type>(alloc)
{
if(this->member() != other.member())
{
copy_from(other);
return;
}
move_from(other);
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
basic_flat_buffer const& other)
: detail::empty_base_optimization<allocator_type>(
alloc_traits::select_on_container_copy_construction(
other.member()))
{
copy_from(other);
}
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)
{
copy_from(other);
}
template<class Allocator>
template<class OtherAlloc>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
basic_flat_buffer<OtherAlloc> const& other)
{
copy_from(other);
}
template<class Allocator>
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)
{
copy_from(other);
} }
template<class Allocator> template<class Allocator>
@@ -167,15 +69,25 @@ basic_flat_buffer(std::size_t limit)
, end_(nullptr) , end_(nullptr)
, max_(limit) , max_(limit)
{ {
BOOST_ASSERT(limit >= 1);
} }
template<class Allocator> template<class Allocator>
basic_flat_buffer<Allocator>:: basic_flat_buffer<Allocator>::
basic_flat_buffer(Allocator const& alloc, basic_flat_buffer(Allocator const& alloc)
std::size_t limit) : detail::empty_base_optimization<allocator_type>(alloc)
: detail::empty_base_optimization< , begin_(nullptr)
allocator_type>(alloc) , in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_((std::numeric_limits<std::size_t>::max)())
{
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(std::size_t limit, Allocator const& alloc)
: detail::empty_base_optimization<allocator_type>(alloc)
, begin_(nullptr) , begin_(nullptr)
, in_(nullptr) , in_(nullptr)
, out_(nullptr) , out_(nullptr)
@@ -183,9 +95,148 @@ basic_flat_buffer(Allocator const& alloc,
, end_(nullptr) , end_(nullptr)
, max_(limit) , max_(limit)
{ {
BOOST_ASSERT(limit >= 1);
} }
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer&& other)
: detail::empty_base_optimization<allocator_type>(
std::move(other.member()))
, begin_(other.begin_)
, in_(other.in_)
, out_(other.out_)
, last_(out_)
, end_(other.end_)
, max_(other.max_)
{
other.begin_ = nullptr;
other.in_ = nullptr;
other.out_ = nullptr;
other.last_ = nullptr;
other.end_ = nullptr;
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer&& other,
Allocator const& alloc)
: detail::empty_base_optimization<allocator_type>(alloc)
{
if(this->member() != other.member())
{
begin_ = nullptr;
in_ = nullptr;
out_ = nullptr;
last_ = nullptr;
end_ = nullptr;
max_ = other.max_;
copy_from(other);
other.reset();
}
else
{
begin_ = other.begin_;
in_ = other.in_;
out_ = other.out_;
last_ = out_;
end_ = other.end_;
max_ = other.max_;
other.begin_ = nullptr;
other.in_ = nullptr;
other.out_ = nullptr;
other.last_ = nullptr;
other.end_ = nullptr;
}
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer const& other)
: detail::empty_base_optimization<allocator_type>(
alloc_traits::select_on_container_copy_construction(
other.member()))
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(other.max_)
{
copy_from(other);
}
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)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(other.max_)
{
copy_from(other);
}
template<class Allocator>
template<class OtherAlloc>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
basic_flat_buffer<OtherAlloc> const& other)
: begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(other.max_)
{
copy_from(other);
}
template<class Allocator>
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)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(other.max_)
{
copy_from(other);
}
template<class Allocator>
auto
basic_flat_buffer<Allocator>::
operator=(basic_flat_buffer&& other) ->
basic_flat_buffer&
{
if(this != &other)
move_assign(other,
typename alloc_traits::propagate_on_container_move_assignment{});
return *this;
}
template<class Allocator>
auto
basic_flat_buffer<Allocator>::
operator=(basic_flat_buffer const& other) ->
basic_flat_buffer&
{
if(this != &other)
copy_assign(other,
typename alloc_traits::propagate_on_container_copy_assignment{});
return *this;
}
//------------------------------------------------------------------------------
template<class Allocator> template<class Allocator>
auto auto
basic_flat_buffer<Allocator>:: basic_flat_buffer<Allocator>::
@@ -311,6 +362,143 @@ shrink_to_fit()
end_ = out_; end_ = out_;
} }
//------------------------------------------------------------------------------
template<class Allocator>
inline
void
basic_flat_buffer<Allocator>::
reset()
{
consume(size());
shrink_to_fit();
}
template<class Allocator>
template<class DynamicBuffer>
inline
void
basic_flat_buffer<Allocator>::
copy_from(DynamicBuffer const& buffer)
{
if(buffer.size() == 0)
return;
using boost::asio::buffer_copy;
commit(buffer_copy(
prepare(buffer.size()), buffer.data()));
}
template<class Allocator>
inline
void
basic_flat_buffer<Allocator>::
move_assign(basic_flat_buffer& other, std::true_type)
{
reset();
this->member() = std::move(other.member());
begin_ = other.begin_;
in_ = other.in_;
out_ = other.out_;
last_ = out_;
end_ = other.end_;
max_ = other.max_;
other.begin_ = nullptr;
other.in_ = nullptr;
other.out_ = nullptr;
other.last_ = nullptr;
other.end_ = nullptr;
}
template<class Allocator>
inline
void
basic_flat_buffer<Allocator>::
move_assign(basic_flat_buffer& other, std::false_type)
{
reset();
if(this->member() != other.member())
{
copy_from(other);
other.reset();
}
else
{
move_assign(other, std::true_type{});
}
}
template<class Allocator>
inline
void
basic_flat_buffer<Allocator>::
copy_assign(basic_flat_buffer const& other, std::true_type)
{
reset();
this->member() = other.member();
copy_from(other);
}
template<class Allocator>
inline
void
basic_flat_buffer<Allocator>::
copy_assign(basic_flat_buffer const& other, std::false_type)
{
reset();
copy_from(other);
}
template<class Allocator>
inline
void
basic_flat_buffer<Allocator>::
swap(basic_flat_buffer& other)
{
swap(other,
typename alloc_traits::propagate_on_container_swap{});
}
template<class Allocator>
inline
void
basic_flat_buffer<Allocator>::
swap(basic_flat_buffer& other, std::true_type)
{
using std::swap;
swap(this->member(), other.member());
swap(this->begin_, other.begin_);
swap(this->in_, other.in_);
swap(this->out_, other.out_);
this->last_ = this->out_;
other->last_ = other->out_;
swap(this->end_, other.end_);
}
template<class Allocator>
inline
void
basic_flat_buffer<Allocator>::
swap(basic_flat_buffer& other, std::false_type)
{
BOOST_ASSERT(this->member() == other.member());
using std::swap;
swap(this->begin_, other.begin_);
swap(this->in_, other.in_);
swap(this->out_, other.out_);
this->last_ = this->out_;
other->last_ = other->out_;
swap(this->end_, other.end_);
}
template<class Allocator>
void
swap(
basic_flat_buffer<Allocator>& lhs,
basic_flat_buffer<Allocator>& rhs)
{
lhs.swap(rhs);
}
} // beast } // beast
#endif #endif

View File

@@ -87,7 +87,7 @@ public:
basic_flat_buffer<allocator> b1{10}; basic_flat_buffer<allocator> b1{10};
} }
{ {
basic_flat_buffer<allocator> b1{allocator{}, 10}; basic_flat_buffer<allocator> b1{10, allocator{}};
} }
} }
@@ -193,11 +193,11 @@ public:
basic_flat_buffer<alloc_type>; basic_flat_buffer<alloc_type>;
alloc_type alloc; alloc_type alloc;
{ {
type fba{alloc, 1}; type fba{1, alloc};
BEAST_EXPECT(fba.max_size() == 1); BEAST_EXPECT(fba.max_size() == 1);
} }
{ {
type fba{alloc, 1024}; type fba{1024, alloc};
BEAST_EXPECT(fba.max_size() == 1024); BEAST_EXPECT(fba.max_size() == 1024);
} }
{ {