Make buffers_view a public interface

This commit is contained in:
Vinnie Falco
2017-05-16 07:34:09 -07:00
parent 7c19f72b07
commit 9e16e24ec4
8 changed files with 189 additions and 146 deletions

View File

@@ -2,6 +2,7 @@ Version 42
* Fix javadoc typo * Fix javadoc typo
* Add formal review notes * Add formal review notes
* Make buffers_view a public interface
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -120,13 +120,12 @@ dynamic buffer concept using various strategies:
[table Dynamic buffer implementations [table Dynamic buffer implementations
[[Name][Description]] [[Name][Description]]
[[ [[
[link beast.ref.multi_buffer `multi_buffer`] [link beast.ref.buffers_adapter `buffers_adapter`]
[link beast.ref.basic_multi_buffer `basic_multi_buffer`]
][ ][
Uses a sequence of one or more character arrays of varying sizes. This wrapper adapts any __MutableBufferSequence__ into a
Additional character array objects are appended to the sequence to __DynamicBuffer__ with an upper limit on the total size of the input and
accommodate changes in the size of the character sequence. The basic output areas equal to the size of the underlying mutable buffer sequence.
container supports the standard allocator model. The implementation does not perform heap allocations.
]] ]]
[[ [[
[link beast.ref.flat_buffer `flat_buffer`] [link beast.ref.flat_buffer `flat_buffer`]
@@ -137,6 +136,15 @@ dynamic buffer concept using various strategies:
size of the input and output areas may be set. The basic container size of the input and output areas may be set. The basic container
supports the standard allocator model. supports the standard allocator model.
]] ]]
[[
[link beast.ref.multi_buffer `multi_buffer`]
[link beast.ref.basic_multi_buffer `basic_multi_buffer`]
][
Uses a sequence of one or more character arrays of varying sizes.
Additional character array objects are appended to the sequence to
accommodate changes in the size of the character sequence. The basic
container supports the standard allocator model.
]]
[[ [[
[link beast.ref.static_buffer `static_buffer`] [link beast.ref.static_buffer `static_buffer`]
[link beast.ref.static_buffer `static_buffer_n`] [link beast.ref.static_buffer `static_buffer_n`]
@@ -146,14 +154,6 @@ dynamic buffer concept using various strategies:
by a constexpr template parameter. The storage for the sequences are by a constexpr template parameter. The storage for the sequences are
kept in the class; the implementation does not perform heap allocations. kept in the class; the implementation does not perform heap allocations.
]] ]]
[[
[link beast.ref.buffers_adapter `buffers_adapter`]
][
This wrapper adapts any __MutableBufferSequence__ into a
__DynamicBuffer__ with an upper limit on the total size of the input and
output areas equal to the size of the underlying mutable buffer sequence.
The implementation does not perform heap allocations.
]]
] ]
[endsect] [endsect]
@@ -180,6 +180,20 @@ underlying memory, whose lifetime is retained by the caller.
to a stream's `write_some` function to be combined into one, eliminating to a stream's `write_some` function to be combined into one, eliminating
expensive system calls. expensive system calls.
]] ]]
[[
[link beast.ref.buffer_prefix `buffer_prefix`]
][
This function returns a new buffer or buffer sequence which wraps the
underlying memory of an existing buffer sequence, but with a smaller size.
This lets callers work with a prefix of a buffer sequence.
]]
[[
[link beast.ref.buffer_cat `buffers_view`]
][
This class represents a buffer sequence which represents the concatenation
of two or more buffer sequences. This is type of object returned by
[link beast.ref.buffer_cat `buffer_cat`].
]]
[[ [[
[link beast.ref.consuming_buffers `consuming_buffers`] [link beast.ref.consuming_buffers `consuming_buffers`]
][ ][
@@ -188,13 +202,6 @@ underlying memory, whose lifetime is retained by the caller.
may be progressively shortened. This lets callers work with sequential may be progressively shortened. This lets callers work with sequential
increments of a buffer sequence. increments of a buffer sequence.
]] ]]
[[
[link beast.ref.buffer_prefix `buffer_prefix`]
][
This function returns a new buffer or buffer sequence which wraps the
underlying memory of an existing buffer sequence, but with a smaller size.
This lets callers work with a prefix of a buffer sequence.
]]
] ]
[endsect] [endsect]
@@ -236,12 +243,13 @@ the associated asynchronous initiation functions used to launch them.
[table Asynchronous Helpers [table Asynchronous Helpers
[[Name][Description]] [[Name][Description]]
[[ [[
[link beast.ref.handler_type `handler_type`] [link beast.ref.async_completion `async_completion`]
][ ][
This template alias converts a completion token and signature to the This class aggregates the completion handler customization point and
correct completion handler type. It is used in the implementation of the asynchronous initiation function return value customization point
asynchronous initiation functions to meet the requirements of the into a single object which exposes the appropriate output types for the
Extensible Asynchronous Model. given input types, and also contains boilerplate that is necessary to
implement an initiation function using the Extensible Model.
]] ]]
[[ [[
[link beast.ref.async_return_type `async_return_type`] [link beast.ref.async_return_type `async_return_type`]
@@ -252,13 +260,15 @@ the associated asynchronous initiation functions used to launch them.
Extensible Asynchronous Model. Extensible Asynchronous Model.
]] ]]
[[ [[
[link beast.ref.async_completion `async_completion`] [link beast.ref.bind_handler `bind_handler`]
][ ][
This class aggregates the completion handler customization point and This function returns a new, nullary completion handler which when
the asynchronous initiation function return value customization point invoked with no arguments invokes the original completion handler with a
into a single object which exposes the appropriate output types for the list of bound arguments. The invocation is made from the same implicit
given input types, and also contains boilerplate that is necessary to or explicit strand as that which would be used to invoke the original
implement an initiation function using the Extensible Model. handler. This is accomplished by using the correct overload of
`asio_handler_invoke` associated with the original completion handler.
]] ]]
[[ [[
[link beast.ref.handler_alloc `handler_alloc`] [link beast.ref.handler_alloc `handler_alloc`]
@@ -282,15 +292,12 @@ the associated asynchronous initiation functions used to launch them.
optimizations transparently. optimizations transparently.
]] ]]
[[ [[
[link beast.ref.bind_handler `bind_handler`] [link beast.ref.handler_type `handler_type`]
][ ][
This function returns a new, nullary completion handler which when This template alias converts a completion token and signature to the
invoked with no arguments invokes the original completion handler with a correct completion handler type. It is used in the implementation of
list of bound arguments. The invocation is made from the same implicit asynchronous initiation functions to meet the requirements of the
or explicit strand as that which would be used to invoke the original Extensible Asynchronous Model.
handler. This is accomplished by using the correct overload of
`asio_handler_invoke` associated with the original completion handler.
]] ]]
] ]

View File

@@ -157,6 +157,7 @@
<member><link linkend="beast.ref.basic_flat_buffer">basic_flat_buffer</link></member> <member><link linkend="beast.ref.basic_flat_buffer">basic_flat_buffer</link></member>
<member><link linkend="beast.ref.basic_multi_buffer">basic_multi_buffer</link></member> <member><link linkend="beast.ref.basic_multi_buffer">basic_multi_buffer</link></member>
<member><link linkend="beast.ref.buffers_adapter">buffers_adapter</link></member> <member><link linkend="beast.ref.buffers_adapter">buffers_adapter</link></member>
<member><link linkend="beast.ref.buffers_view">buffers_view</link></member>
<member><link linkend="beast.ref.consuming_buffers">consuming_buffers</link></member> <member><link linkend="beast.ref.consuming_buffers">consuming_buffers</link></member>
<member><link linkend="beast.ref.buffered_read_stream">buffered_read_stream</link></member> <member><link linkend="beast.ref.buffered_read_stream">buffered_read_stream</link></member>
<member><link linkend="beast.ref.error_category">error_category</link></member> <member><link linkend="beast.ref.error_category">error_category</link></member>

View File

@@ -9,17 +9,67 @@
#define BEAST_BUFFER_CAT_HPP #define BEAST_BUFFER_CAT_HPP
#include <beast/config.hpp> #include <beast/config.hpp>
#include <beast/core/detail/buffer_cat.hpp> #include <beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <cstdint>
#include <iterator>
#include <new>
#include <stdexcept>
#include <tuple> #include <tuple>
#include <utility>
namespace beast { namespace beast {
/** A buffer sequence representing a concatenation of buffer sequences.
@see @ref buffer_cat
*/
template<class... Buffers>
class buffers_view
{
std::tuple<Buffers...> bn_;
public:
/** The type of buffer returned when dereferencing an iterator.
If every buffer sequence in the view is a @b MutableBufferSequence,
then `value_type` will be `boost::asio::mutable_buffer`.
Otherwise, `value_type` will be `boost::asio::const_buffer`.
*/
using value_type =
#if BEAST_DOXYGEN
implementation_defined;
#else
typename detail::common_buffers_type<Buffers...>::type;
#endif
/// The type of iterator used by the concatenated sequence
class const_iterator;
/// Move constructor
buffers_view(buffers_view&&) = default;
/// Copy constructor
buffers_view(buffers_view const&) = default;
/// Move assignment
buffers_view& operator=(buffers_view&&) = default;
// Copy assignment
buffers_view& operator=(buffers_view const&) = default;
/** Constructor
@param buffers The list of buffer sequences to concatenate.
Copies of the arguments will be made; however, the ownership
of memory is not transferred.
*/
explicit
buffers_view(Buffers const&... buffers);
/// Return an iterator to the beginning of the concatenated sequence.
const_iterator
begin() const;
/// Return an iterator to the end of the concatenated sequence.
const_iterator
end() const;
};
/** Concatenate 2 or more buffer sequences. /** Concatenate 2 or more buffer sequences.
This function returns a constant or mutable buffer sequence which, This function returns a constant or mutable buffer sequence which,
@@ -36,24 +86,28 @@ namespace beast {
@b MutableBufferSequence if each of the passed buffer sequences is @b MutableBufferSequence if each of the passed buffer sequences is
also a @b MutableBufferSequence; otherwise the returned buffer also a @b MutableBufferSequence; otherwise the returned buffer
sequence will be a @b ConstBufferSequence. sequence will be a @b ConstBufferSequence.
@see @ref buffers_view
*/ */
#if BEAST_DOXYGEN #if BEAST_DOXYGEN
template<class... BufferSequence> template<class... BufferSequence>
implementation_defined buffers_view<BufferSequence...>
buffer_cat(BufferSequence const&... buffers) buffer_cat(BufferSequence const&... buffers)
#else #else
template<class B1, class B2, class... Bn> template<class B1, class B2, class... Bn>
detail::buffer_cat_helper<B1, B2, Bn...> inline
buffers_view<B1, B2, Bn...>
buffer_cat(B1 const& b1, B2 const& b2, Bn const&... bn) buffer_cat(B1 const& b1, B2 const& b2, Bn const&... bn)
#endif #endif
{ {
static_assert( static_assert(
detail::is_all_ConstBufferSequence<B1, B2, Bn...>::value, detail::is_all_const_buffer_sequence<B1, B2, Bn...>::value,
"BufferSequence requirements not met"); "BufferSequence requirements not met");
return detail::buffer_cat_helper< return buffers_view<B1, B2, Bn...>{b1, b2, bn...};
B1, B2, Bn...>{b1, b2, bn...};
} }
} // beast } // beast
#include <beast/core/impl/buffer_cat.ipp>
#endif #endif

View File

@@ -244,20 +244,6 @@ public:
type3::value && type4::value>; type3::value && type4::value>;
}; };
template<class B1, class... Bn>
struct is_all_ConstBufferSequence
: std::integral_constant<bool,
is_buffer_sequence<B1, boost::asio::const_buffer>::type::value &&
is_all_ConstBufferSequence<Bn...>::value>
{
};
template<class B1>
struct is_all_ConstBufferSequence<B1>
: is_buffer_sequence<B1, boost::asio::const_buffer>::type
{
};
template<class T> template<class T>
class is_dynamic_buffer class is_dynamic_buffer
{ {
@@ -335,6 +321,33 @@ public:
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template<class B1, class... Bn>
struct is_all_const_buffer_sequence
: std::integral_constant<bool,
is_buffer_sequence<B1, boost::asio::const_buffer>::type::value &&
is_all_const_buffer_sequence<Bn...>::value>
{
};
template<class B1>
struct is_all_const_buffer_sequence<B1>
: is_buffer_sequence<B1, boost::asio::const_buffer>::type
{
};
template<class... Bn>
struct common_buffers_type
{
using type = typename std::conditional<
std::is_convertible<std::tuple<Bn...>,
typename repeat_tuple<sizeof...(Bn),
boost::asio::mutable_buffer>::type>::value,
boost::asio::mutable_buffer,
boost::asio::const_buffer>::type;
};
//------------------------------------------------------------------------------
// //
// stream concepts // stream concepts
// //

View File

@@ -5,10 +5,10 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#ifndef BEAST_DETAIL_BUFFER_CAT_HPP #ifndef BEAST_IMPL_BUFFER_CAT_IPP
#define BEAST_DETAIL_BUFFER_CAT_HPP #define BEAST_IMPL_BUFFER_CAT_IPP
#include <beast/core/type_traits.hpp> #include <beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <cstdint> #include <cstdint>
#include <iterator> #include <iterator>
@@ -18,57 +18,16 @@
#include <utility> #include <utility>
namespace beast { namespace beast {
namespace detail {
template<class... Bn> template<class... Bn>
struct common_buffers_type class buffers_view<Bn...>::const_iterator
{
using type = typename std::conditional<
std::is_convertible<std::tuple<Bn...>,
typename repeat_tuple<sizeof...(Bn),
boost::asio::mutable_buffer>::type>::value,
boost::asio::mutable_buffer,
boost::asio::const_buffer>::type;
};
template<class... Bn>
class buffer_cat_helper
{
std::tuple<Bn...> bn_;
public:
using value_type = typename
common_buffers_type<Bn...>::type;
class const_iterator;
buffer_cat_helper(buffer_cat_helper&&) = default;
buffer_cat_helper(buffer_cat_helper const&) = default;
buffer_cat_helper& operator=(buffer_cat_helper&&) = delete;
buffer_cat_helper& operator=(buffer_cat_helper const&) = delete;
explicit
buffer_cat_helper(Bn const&... bn)
: bn_(bn...)
{
}
const_iterator
begin() const;
const_iterator
end() const;
};
template<class... Bn>
class buffer_cat_helper<Bn...>::const_iterator
{ {
std::size_t n_; std::size_t n_;
std::tuple<Bn...> const* bn_; std::tuple<Bn...> const* bn_;
std::array<std::uint8_t, char buf_[detail::max_sizeof<
max_sizeof<typename Bn::const_iterator...>()> buf_; typename Bn::const_iterator...>()];
friend class buffer_cat_helper<Bn...>; friend class buffers_view<Bn...>;
template<std::size_t I> template<std::size_t I>
using C = std::integral_constant<std::size_t, I>; using C = std::integral_constant<std::size_t, I>;
@@ -83,8 +42,7 @@ class buffer_cat_helper<Bn...>::const_iterator
{ {
// type-pun // type-pun
return *reinterpret_cast< return *reinterpret_cast<
iter_t<I>*>(static_cast<void*>( iter_t<I>*>(static_cast<void*>(buf_));
buf_.data()));
} }
template<std::size_t I> template<std::size_t I>
@@ -94,12 +52,12 @@ class buffer_cat_helper<Bn...>::const_iterator
// type-pun // type-pun
return *reinterpret_cast< return *reinterpret_cast<
iter_t<I> const*>(static_cast< iter_t<I> const*>(static_cast<
void const*>(buf_.data())); void const*>(buf_));
} }
public: public:
using value_type = typename using value_type = typename
common_buffers_type<Bn...>::type; detail::common_buffers_type<Bn...>::type;
using pointer = value_type const*; using pointer = value_type const*;
using reference = value_type; using reference = value_type;
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
@@ -119,7 +77,7 @@ public:
bool bool
operator!=(const_iterator const& other) const operator!=(const_iterator const& other) const
{ {
return !(*this == other); return ! (*this == other);
} }
reference reference
@@ -169,7 +127,7 @@ private:
std::get<I>(*bn_).end()) std::get<I>(*bn_).end())
{ {
n_ = I; n_ = I;
new(buf_.data()) iter_t<I>{ new(buf_) iter_t<I>{
std::get<I>(*bn_).begin()}; std::get<I>(*bn_).begin()};
return; return;
} }
@@ -208,7 +166,7 @@ private:
{ {
if(n_ == I) if(n_ == I)
{ {
new(buf_.data()) iter_t<I>{ new(buf_) iter_t<I>{
std::move(other.iter<I>())}; std::move(other.iter<I>())};
return; return;
} }
@@ -228,7 +186,7 @@ private:
{ {
if(n_ == I) if(n_ == I)
{ {
new(buf_.data()) iter_t<I>{ new(buf_) iter_t<I>{
other.iter<I>()}; other.iter<I>()};
return; return;
} }
@@ -300,7 +258,7 @@ private:
if(n_ == I) if(n_ == I)
{ {
--n_; --n_;
new(buf_.data()) iter_t<I-1>{ new(buf_) iter_t<I-1>{
std::get<I-1>(*bn_).end()}; std::get<I-1>(*bn_).end()};
} }
decrement(C<I-1>{}); decrement(C<I-1>{});
@@ -333,7 +291,7 @@ private:
--n_; --n_;
using Iter = iter_t<I>; using Iter = iter_t<I>;
iter<I>().~Iter(); iter<I>().~Iter();
new(buf_.data()) iter_t<I-1>{ new(buf_) iter_t<I-1>{
std::get<I-1>(*bn_).end()}; std::get<I-1>(*bn_).end()};
} }
decrement(C<I-1>{}); decrement(C<I-1>{});
@@ -343,14 +301,14 @@ private:
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template<class... Bn> template<class... Bn>
buffer_cat_helper<Bn...>:: buffers_view<Bn...>::
const_iterator::~const_iterator() const_iterator::~const_iterator()
{ {
destroy(C<0>{}); destroy(C<0>{});
} }
template<class... Bn> template<class... Bn>
buffer_cat_helper<Bn...>:: buffers_view<Bn...>::
const_iterator::const_iterator() const_iterator::const_iterator()
: n_(sizeof...(Bn)) : n_(sizeof...(Bn))
, bn_(nullptr) , bn_(nullptr)
@@ -358,7 +316,7 @@ const_iterator::const_iterator()
} }
template<class... Bn> template<class... Bn>
buffer_cat_helper<Bn...>:: buffers_view<Bn...>::
const_iterator::const_iterator( const_iterator::const_iterator(
std::tuple<Bn...> const& bn, bool at_end) std::tuple<Bn...> const& bn, bool at_end)
: bn_(&bn) : bn_(&bn)
@@ -370,7 +328,7 @@ const_iterator::const_iterator(
} }
template<class... Bn> template<class... Bn>
buffer_cat_helper<Bn...>:: buffers_view<Bn...>::
const_iterator::const_iterator(const_iterator&& other) const_iterator::const_iterator(const_iterator&& other)
: n_(other.n_) : n_(other.n_)
, bn_(other.bn_) , bn_(other.bn_)
@@ -379,7 +337,7 @@ const_iterator::const_iterator(const_iterator&& other)
} }
template<class... Bn> template<class... Bn>
buffer_cat_helper<Bn...>:: buffers_view<Bn...>::
const_iterator::const_iterator(const_iterator const& other) const_iterator::const_iterator(const_iterator const& other)
: n_(other.n_) : n_(other.n_)
, bn_(other.bn_) , bn_(other.bn_)
@@ -389,7 +347,7 @@ const_iterator::const_iterator(const_iterator const& other)
template<class... Bn> template<class... Bn>
auto auto
buffer_cat_helper<Bn...>:: buffers_view<Bn...>::
const_iterator::operator=(const_iterator&& other) -> const_iterator::operator=(const_iterator&& other) ->
const_iterator& const_iterator&
{ {
@@ -404,7 +362,7 @@ const_iterator::operator=(const_iterator&& other) ->
template<class... Bn> template<class... Bn>
auto auto
buffer_cat_helper<Bn...>:: buffers_view<Bn...>::
const_iterator::operator=(const_iterator const& other) -> const_iterator::operator=(const_iterator const& other) ->
const_iterator& const_iterator&
{ {
@@ -419,7 +377,7 @@ const_iterator&
template<class... Bn> template<class... Bn>
bool bool
buffer_cat_helper<Bn...>:: buffers_view<Bn...>::
const_iterator::operator==(const_iterator const& other) const const_iterator::operator==(const_iterator const& other) const
{ {
if(bn_ != other.bn_) if(bn_ != other.bn_)
@@ -431,7 +389,7 @@ const_iterator::operator==(const_iterator const& other) const
template<class... Bn> template<class... Bn>
auto auto
buffer_cat_helper<Bn...>:: buffers_view<Bn...>::
const_iterator::operator*() const -> const_iterator::operator*() const ->
reference reference
{ {
@@ -440,7 +398,7 @@ const_iterator::operator*() const ->
template<class... Bn> template<class... Bn>
auto auto
buffer_cat_helper<Bn...>:: buffers_view<Bn...>::
const_iterator::operator++() -> const_iterator::operator++() ->
const_iterator& const_iterator&
{ {
@@ -450,7 +408,7 @@ const_iterator::operator++() ->
template<class... Bn> template<class... Bn>
auto auto
buffer_cat_helper<Bn...>:: buffers_view<Bn...>::
const_iterator::operator--() -> const_iterator::operator--() ->
const_iterator& const_iterator&
{ {
@@ -458,10 +416,20 @@ const_iterator::operator--() ->
return *this; return *this;
} }
//------------------------------------------------------------------------------
template<class... Bn>
buffers_view<Bn...>::
buffers_view(Bn const&... bn)
: bn_(bn...)
{
}
template<class... Bn> template<class... Bn>
inline inline
auto auto
buffer_cat_helper<Bn...>::begin() const -> buffers_view<Bn...>::begin() const ->
const_iterator const_iterator
{ {
return const_iterator{bn_, false}; return const_iterator{bn_, false};
@@ -470,13 +438,12 @@ buffer_cat_helper<Bn...>::begin() const ->
template<class... Bn> template<class... Bn>
inline inline
auto auto
buffer_cat_helper<Bn...>::end() const -> buffers_view<Bn...>::end() const ->
const_iterator const_iterator
{ {
return const_iterator{bn_, true}; return const_iterator{bn_, true};
} }
} // detail
} // beast } // beast
#endif #endif

View File

@@ -39,7 +39,7 @@ template<class ConstBufferSequence>
#if BEAST_DOXYGEN #if BEAST_DOXYGEN
implementation_defined implementation_defined
#else #else
beast::detail::buffer_cat_helper< beast::buffers_view<
detail::chunk_encode_delim, detail::chunk_encode_delim,
ConstBufferSequence, ConstBufferSequence,
boost::asio::const_buffers_1> boost::asio::const_buffers_1>

View File

@@ -215,29 +215,29 @@ public:
{ {
}; };
// Check is_all_ConstBufferSequence // Check is_all_const_buffer_sequence
static_assert( static_assert(
detail::is_all_ConstBufferSequence< detail::is_all_const_buffer_sequence<
const_buffers_1 const_buffers_1
>::value, ""); >::value, "");
static_assert( static_assert(
detail::is_all_ConstBufferSequence< detail::is_all_const_buffer_sequence<
const_buffers_1, const_buffers_1 const_buffers_1, const_buffers_1
>::value, ""); >::value, "");
static_assert( static_assert(
detail::is_all_ConstBufferSequence< detail::is_all_const_buffer_sequence<
mutable_buffers_1 mutable_buffers_1
>::value, ""); >::value, "");
static_assert( static_assert(
detail::is_all_ConstBufferSequence< detail::is_all_const_buffer_sequence<
mutable_buffers_1, mutable_buffers_1 mutable_buffers_1, mutable_buffers_1
>::value, ""); >::value, "");
static_assert( static_assert(
detail::is_all_ConstBufferSequence< detail::is_all_const_buffer_sequence<
const_buffers_1, mutable_buffers_1 const_buffers_1, mutable_buffers_1
>::value, ""); >::value, "");
static_assert( static_assert(
! detail::is_all_ConstBufferSequence< ! detail::is_all_const_buffer_sequence<
const_buffers_1, mutable_buffers_1, int const_buffers_1, mutable_buffers_1, int
>::value, ""); >::value, "");