Stream traits are in stream_traits.hpp (API Change):

These metafunctions are moved from type_traits.hpp
to stream_traits.hpp:

- has_get_executor
- is_sync_stream
- is_sync_read_stream
- is_sync_write_stream
- is_async_stream
- is_async_read_stream
- is_async_write_stream

Actions Required:

* Include the file stream_traits.hpp as needed
This commit is contained in:
Vinnie Falco
2019-02-05 07:40:30 -08:00
parent 9cee4e053f
commit 477cd75153
12 changed files with 553 additions and 476 deletions

View File

@ -6,6 +6,14 @@ Version 210:
* Add stream_traits.hpp * Add stream_traits.hpp
* Add executor_type trait * Add executor_type trait
API Changes:
* Stream traits are now in stream_traits.hpp
Actions Required:
* Include the file stream_traits.hpp as needed
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
Version 209: Version 209:

View File

@ -32,21 +32,31 @@ New websocket-chat-multi example
[/* `BASIC_TIMEOUT_STREAM` TODO] [/* `BASIC_TIMEOUT_STREAM` TODO]
* ([issue 1305]) Better `flat_buffer`, `flat_static_buffer`, `multi_buffer`, and `static_buffer`: * ([issue 1305]) Better
`flat_buffer`,
`flat_static_buffer`,
`multi_buffer`, and
`static_buffer`:
* Revise all reference documentation * Revise all reference documentation
* Move construction does not always invalidate buffers * Move construction does not always invalidate buffers
* non-const `data()` returns a mutable buffer sequence * non-const `data()` returns a mutable buffer sequence
* Add `cdata()` to also return constant readable bytes * Add `cdata()` to also return constant readable bytes
* Eligible member functions are declared `noexcept` * Eligible member functions are declared `noexcept`
* ([issue 1345]) Better `flat_buffer`, `multi_buffer` * ([issue 1345]) Better
`flat_buffer`,
`multi_buffer`
* Add `clear`, `reserve()`, `max_size()`, `shrink_to_fit()` * Add `clear`, `reserve()`, `max_size()`, `shrink_to_fit()`
* Respect Allocator `max_size()` * Respect Allocator `max_size()`
* Specify exception safety * Specify exception safety
* ([issue 1384]) New functions `bind_back_handler`, `bind_front_handler` * ([issue 1384]) New functions
`bind_back_handler`,
`bind_front_handler`
* Better `static_buffer`, `flat_static_buffer` * Better
`static_buffer`,
`flat_static_buffer`
* Add `clear()` * Add `clear()`
* More members are `noexcept` * More members are `noexcept`
* Specify exception safety * Specify exception safety
@ -56,23 +66,32 @@ New websocket-chat-multi example
* New file <boost/beast/core/buffer_traits.hpp> * New file <boost/beast/core/buffer_traits.hpp>
* New variadic `is_const_buffer_sequence` * New variadic `is_const_buffer_sequence`
* New variadic `is_mutable_buffer_sequence` * New variadic `is_mutable_buffer_sequence`
* New `buffers_iterator_type` trait * New trait `buffers_iterator_type`
* New `buffers_type` trait * New trait `buffers_type`
* New classes `async_op_base` and `stable_async_op_base` * New classes
`async_op_base`,
`stable_async_op_base`
* Handle boilerplate for writing composed operations * Handle boilerplate for writing composed operations
* New `allocate_stable` is preferred over `handler_ptr` * New
`allocate_stable`
is preferred over `handler_ptr`
* New `buffer_size` replacement for `net::buffer_size` * New
`buffer_size`
replacement for `net::buffer_size`
* New: * New:
* `saved_handler` * `saved_handler`
* `buffers_range_ref` * `buffers_range_ref`
* `dynamic_buffer_ref` * `dynamic_buffer_ref`
* `executor_type` * `executor_type`
* `get_lowest_layer` and `lowest_layer_type` * `get_lowest_layer`,
* `close_socket` and `beast_close_socket` `lowest_layer_type`
* `error` and `condition` * `close_socket`,
`beast_close_socket`
* `error`,
`condition`
[*API Changes] [*API Changes]
@ -80,38 +99,64 @@ New websocket-chat-multi example
from the stream. Previously, they returned the number of bytes from the stream. Previously, they returned the number of bytes
consumed by the parser. consumed by the parser.
['Actions Required]: ['Actions Required]:
* Callers depending on the return value of `http::read` or * Callers depending on the return value of
`http::async_read` overloads should adjust the usage of `http::read` or
`http::async_read`
overloads should adjust the usage of
the returned value as needed. the returned value as needed.
* `flat_static_buffer::reset()` is deprecated. * Metafunctions
['Actions Required]: `has_get_executor`,
* call `clear()` instead. `is_sync_stream`,
`is_sync_read_stream`,
`is_sync_write_stream`,
`is_async_stream`,
`is_async_read_stream`, and
`is_async_write_stream`
are now located in stream_traits.hpp.
['Actions Required]: Include stream_traits.hpp as needed.
* `buffers_adapter` is now called `buffers_adaptor`. * `flat_static_buffer::reset()`
is deprecated.
['Actions Required]: ['Actions Required]:
* Replace `buffers_adapter` with `buffers_adaptor`, or define * call
`BOOST_BEAST_ALLOW_DEPRECATED`. `clear()` instead.
* `buffers` is now called `make_printable`. * `buffers_adapter` is now spelled
`buffers_adaptor`.
['Actions Required]: ['Actions Required]:
* Replace `buffers` with `make_printable`, and include * Replace `buffers_adapter` with
"make_printable.hpp" instead of "ostream.hpp". `buffers_adaptor`,
or define `BOOST_BEAST_ALLOW_DEPRECATED`.
* `buffers` is now spelled
`make_printable`.
['Actions Required]:
* Replace `buffers` with
`make_printable`,
and include "make_printable.hpp" instead of "ostream.hpp".
* `file_mode::append_new` is removed, as it makes no sense. * `file_mode::append_new` is removed, as it makes no sense.
['Actions Required]: ['Actions Required]:
- Replace `file_mode::append_new` with either `file_mode::append` - Replace `file_mode::append_new` with either
or `file_mode::append_existing` as needed. `file_mode::append` or
`file_mode::append_existing`
as needed.
* `buffers_range_ref` is preferred to `std::reference_wrapper`. * `buffers_range_ref`
is preferred to `std::reference_wrapper`.
['Actions Required]: ['Actions Required]:
- Call `buffers_range_ref` with the buffer, instead of calling - Call
`buffers_range` with a reference wrapper constructed from `buffers_range_ref`
the buffer. with the buffer, instead of calling
`buffers_range`
with a reference wrapper constructed from the buffer.
* Nested `lowest_layer` and `lowest_layer_type` are removed. * Nested `lowest_layer` and `lowest_layer_type` are removed.
['Actions Required]: Use the free function `get_lowest_layer` and the ['Actions Required]: Use the free function
type trait `lowest_layer_type` instead. `get_lowest_layer` and the
type trait
`lowest_layer_type` instead.
[*Examples] [*Examples]
@ -119,9 +164,10 @@ New websocket-chat-multi example
* ([issue 1347]) Improve echo-op * ([issue 1347]) Improve echo-op
* ([issue 1401]) Examples use `flat_buffer` * ([issue 1401]) Examples use
`flat_buffer`
* New websocket-chat-multi example * New example [[source_file example/websocket/server/chat-multi]]
* `async_echo` works with move-only handlers * `async_echo` works with move-only handlers
@ -129,33 +175,42 @@ New websocket-chat-multi example
* ([issue 1223]) HTTP read counts bytes correctly when an error occurs * ([issue 1223]) HTTP read counts bytes correctly when an error occurs
* ([issue 1247]) Update `ssl_stream` for Asio changes * ([issue 1247]) Update `ssl_stream`
for Asio changes
* ([issue 1279]) Enable explicit instantiations of `websocket::stream` * ([issue 1279]) Enable explicit instantiations of
`websocket::stream`
* ([issue 1290]) Don't use deprecated Asio interfaces * ([issue 1290]) Don't use deprecated Asio interfaces
* ([issue 1306]) `http::message` is not-a `boost::empty_value` * ([issue 1306]) `http::message`
is not-a `boost::empty_value`
* ([issue 1306]) `test::stream` has fewer dependencies * ([issue 1306]) `test::stream`
has fewer dependencies
* ([issue 1365]) Handler wrappers decay parameters sooner * ([issue 1365]) Handler wrappers decay parameters sooner
* ([issue 1408]) `session_alloc` is thread-safe * ([issue 1408]) `session_alloc`
is thread-safe
* ([issue 1414]) Boost.System is header-only * ([issue 1414]) Boost.System is header-only
* ([issue 1418]) `test::stream` maintains a handler work guard * ([issue 1418]) `test::stream`
maintains a handler work guard
* `buffers_cat` correctly skips empty buffers when iterated * `buffers_cat`
correctly skips empty buffers when iterated
* `ostream` does not overflow or exceed the dynamic buffer's maximum size * `ostream`
does not overflow or exceed the dynamic buffer's maximum size
* A handler work guard is maintained on paused websocket operations * A handler work guard is maintained on paused websocket operations
* All behavior of default-constructed iterators is conforming * All behavior of default-constructed iterators is conforming
* `file_mode::append_existing` works correctly * `file_mode::append_existing`
works correctly
[/-----------------------------------------------------------------------------] [/-----------------------------------------------------------------------------]

View File

@ -14,7 +14,7 @@
#include <boost/beast/core/detail/static_const.hpp> #include <boost/beast/core/detail/static_const.hpp>
#include <boost/beast/core/detail/type_traits.hpp> #include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/type_traits.hpp> #include <boost/type_traits/make_void.hpp>
#include <type_traits> #include <type_traits>
namespace boost { namespace boost {

View File

@ -13,7 +13,6 @@
#include <boost/beast/core/bind_handler.hpp> #include <boost/beast/core/bind_handler.hpp>
#include <boost/beast/core/async_op_base.hpp> #include <boost/beast/core/async_op_base.hpp>
#include <boost/beast/core/flat_static_buffer.hpp> #include <boost/beast/core/flat_static_buffer.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/asio/basic_stream_socket.hpp> #include <boost/asio/basic_stream_socket.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>

View File

@ -12,7 +12,7 @@
#include <boost/beast/core/detail/config.hpp> #include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/error.hpp> #include <boost/beast/core/error.hpp>
#include <boost/beast/core/type_traits.hpp> #include <boost/beast/core/stream_traits.hpp>
#include <boost/asio/async_result.hpp> #include <boost/asio/async_result.hpp>
#include <cstdlib> #include <cstdlib>

View File

@ -10,6 +10,8 @@
#ifndef BOOST_BEAST_DETAIL_STREAM_TRAITS_HPP #ifndef BOOST_BEAST_DETAIL_STREAM_TRAITS_HPP
#define BOOST_BEAST_DETAIL_STREAM_TRAITS_HPP #define BOOST_BEAST_DETAIL_STREAM_TRAITS_HPP
#include <boost/beast/core/error.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/type_traits/make_void.hpp> #include <boost/type_traits/make_void.hpp>
#include <type_traits> #include <type_traits>
@ -25,13 +27,11 @@ namespace detail {
// //
template <class T> template <class T>
std::false_type has_next_layer_impl(void*) {} std::false_type has_next_layer_impl(void*);
template <class T> template <class T>
auto has_next_layer_impl(decltype(nullptr)) -> auto has_next_layer_impl(decltype(nullptr)) ->
decltype(std::declval<T&>().next_layer(), std::true_type{}) decltype(std::declval<T&>().next_layer(), std::true_type{});
{
}
template <class T> template <class T>
using has_next_layer = decltype(has_next_layer_impl<T>(nullptr)); using has_next_layer = decltype(has_next_layer_impl<T>(nullptr));
@ -73,6 +73,37 @@ get_lowest_layer_impl(
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Types that meet the requirements,
// for use with std::declval only.
template<class BufferType>
struct BufferSequence
{
using value_type = BufferType;
using const_iterator = BufferType const*;
~BufferSequence();
BufferSequence(BufferSequence const&) = default;
const_iterator begin() const noexcept;
const_iterator end() const noexcept;
};
using ConstBufferSequence =
BufferSequence<net::const_buffer>;
using MutableBufferSequence =
BufferSequence<net::mutable_buffer>;
//
// Types that meet the requirements,
// for use with std::declval only.
struct StreamHandler
{
StreamHandler(StreamHandler const&) = default;
void operator()(error_code ec, std::size_t);
};
using ReadHandler = StreamHandler;
using WriteHandler = StreamHandler;
//------------------------------------------------------------------------------
} // detail } // detail
} // beast } // beast
} // boost } // boost

View File

@ -13,7 +13,7 @@
#include <boost/beast/core/error.hpp> #include <boost/beast/core/error.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/mp11/function.hpp> #include <boost/mp11/function.hpp>
#include <boost/type_traits.hpp> #include <boost/type_traits/make_void.hpp>
#include <iterator> #include <iterator>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
@ -161,39 +161,6 @@ struct is_contiguous_container<T, E, void_t<
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
//
// buffer concepts
//
// Types that meet the requirements,
// for use with std::declval only.
template<class BufferType>
struct BufferSequence
{
using value_type = BufferType;
using const_iterator = BufferType const*;
~BufferSequence();
BufferSequence(BufferSequence const&) = default;
const_iterator begin() const noexcept;
const_iterator end() const noexcept;
};
using ConstBufferSequence =
BufferSequence<net::const_buffer>;
using MutableBufferSequence =
BufferSequence<net::mutable_buffer>;
//
// Types that meet the requirements,
// for use with std::declval only.
struct StreamHandler
{
StreamHandler(StreamHandler const&) = default;
void operator()(error_code ec, std::size_t);
};
using ReadHandler = StreamHandler;
using WriteHandler = StreamHandler;
/* If this static assert goes off, it means that the completion /* If this static assert goes off, it means that the completion
handler you provided to an asynchronous initiating function did handler you provided to an asynchronous initiating function did
not have the right signature. Check the parameter types for your not have the right signature. Check the parameter types for your

View File

@ -1,5 +1,5 @@
// //
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com) // Copyright (c) 2019 Vinnie Falco (vinnie dot falco at gmail dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@ -87,6 +87,8 @@ get_lowest_layer(T& t) noexcept
t, detail::has_next_layer<T>{}); t, detail::has_next_layer<T>{});
} }
//------------------------------------------------------------------------------
/** A trait to determine the return type of get_executor. /** A trait to determine the return type of get_executor.
This type alias will be the type of values returned by This type alias will be the type of values returned by
@ -110,6 +112,318 @@ using executor_type =
decltype(std::declval<T&>().get_executor()); decltype(std::declval<T&>().get_executor());
#endif #endif
/** Determine if `T` has the `get_executor` member function.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` has the member
function with the correct signature, else type will be `std::false_type`.
@par Example
Use with tag dispatching:
@code
template<class T>
void maybe_hello(T const& t, std::true_type)
{
net::post(
t.get_executor(),
[]
{
std::cout << "Hello, world!" << std::endl;
});
}
template<class T>
void maybe_hello(T const&, std::false_type)
{
// T does not have get_executor
}
template<class T>
void maybe_hello(T const& t)
{
maybe_hello(t, has_get_executor<T>{});
}
@endcode
Use with `static_assert`:
@code
struct stream
{
using executor_type = net::io_context::executor_type;
executor_type get_executor() noexcept;
};
static_assert(has_get_executor<stream>::value, "Missing get_executor member");
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct has_get_executor : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct has_get_executor : std::false_type {};
template<class T>
struct has_get_executor<T, boost::void_t<decltype(
std::declval<T&>().get_executor())>> : std::true_type {};
#endif
//------------------------------------------------------------------------------
/** Determine if `T` meets the requirements of @b SyncReadStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class SyncReadStream>
void f(SyncReadStream& stream)
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class SyncReadStream>
typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
f(SyncReadStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_sync_read_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_sync_read_stream : std::false_type {};
template<class T>
struct is_sync_read_stream<T, boost::void_t<decltype(
std::declval<std::size_t&>() = std::declval<T>().read_some(
std::declval<detail::MutableBufferSequence>()),
std::declval<std::size_t&>() = std::declval<T>().read_some(
std::declval<detail::MutableBufferSequence>(),
std::declval<boost::system::error_code&>())
)>> : std::true_type {};
#endif
/** Determine if `T` meets the requirements of @b SyncWriteStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class SyncReadStream>
void f(SyncReadStream& stream)
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class SyncReadStream>
typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
f(SyncReadStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_sync_write_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_sync_write_stream : std::false_type {};
template<class T>
struct is_sync_write_stream<T, boost::void_t<decltype(
(
std::declval<std::size_t&>() = std::declval<T&>().write_some(
std::declval<detail::ConstBufferSequence>()))
,std::declval<std::size_t&>() = std::declval<T&>().write_some(
std::declval<detail::ConstBufferSequence>(),
std::declval<boost::system::error_code&>())
)>> : std::true_type {};
#endif
/** Determine if `T` meets the requirements of @b SyncStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class SyncStream>
void f(SyncStream& stream)
{
static_assert(is_sync_stream<SyncStream>::value,
"SyncStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class SyncStream>
typename std::enable_if<is_sync_stream<SyncStream>::value>::type
f(SyncStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_sync_stream : std::integral_constant<bool, ...>{};
#else
template<class T>
using is_sync_stream = std::integral_constant<bool,
is_sync_read_stream<T>::value && is_sync_write_stream<T>::value>;
#endif
//------------------------------------------------------------------------------
/** Determine if `T` meets the requirements of @b AsyncReadStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class AsyncReadStream>
void f(AsyncReadStream& stream)
{
static_assert(is_async_read_stream<AsyncReadStream>::value,
"AsyncReadStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class AsyncReadStream>
typename std::enable_if<is_async_read_stream<AsyncReadStream>::value>::type
f(AsyncReadStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_async_read_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_async_read_stream : std::false_type {};
template<class T>
struct is_async_read_stream<T, boost::void_t<decltype(
std::declval<T>().async_read_some(
std::declval<detail::MutableBufferSequence>(),
std::declval<detail::ReadHandler>())
)>> : std::integral_constant<bool,
has_get_executor<T>::value
> {};
#endif
/** Determine if `T` meets the requirements of @b AsyncWriteStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class AsyncWriteStream>
void f(AsyncWriteStream& stream)
{
static_assert(is_async_write_stream<AsyncWriteStream>::value,
"AsyncWriteStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class AsyncWriteStream>
typename std::enable_if<is_async_write_stream<AsyncWriteStream>::value>::type
f(AsyncWriteStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_async_write_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_async_write_stream : std::false_type {};
template<class T>
struct is_async_write_stream<T, boost::void_t<decltype(
std::declval<T>().async_write_some(
std::declval<detail::ConstBufferSequence>(),
std::declval<detail::WriteHandler>())
)>> : std::integral_constant<bool,
has_get_executor<T>::value
> {};
#endif
/** Determine if `T` meets the requirements of @b AsyncStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class AsyncStream>
void f(AsyncStream& stream)
{
static_assert(is_async_stream<AsyncStream>::value,
"AsyncStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class AsyncStream>
typename std::enable_if<is_async_stream<AsyncStream>::value>::type
f(AsyncStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_async_stream : std::integral_constant<bool, ...>{};
#else
template<class T>
using is_async_stream = std::integral_constant<bool,
is_async_read_stream<T>::value && is_async_write_stream<T>::value>;
#endif
} // beast } // beast
} // boost } // boost

View File

@ -56,320 +56,6 @@ using is_completion_handler = std::integral_constant<bool,
detail::is_invocable<T, Signature>::value>; detail::is_invocable<T, Signature>::value>;
#endif #endif
//------------------------------------------------------------------------------
//
// Stream concepts
//
//------------------------------------------------------------------------------
/** Determine if `T` has the `get_executor` member function.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` has the member
function with the correct signature, else type will be `std::false_type`.
@par Example
Use with tag dispatching:
@code
template<class T>
void maybe_hello(T& t, std::true_type)
{
net::post(
t.get_executor(),
[]
{
std::cout << "Hello, world!" << std::endl;
});
}
template<class T>
void maybe_hello(T&, std::false_type)
{
// T does not have get_executor
}
template<class T>
void maybe_hello(T& t)
{
maybe_hello(t, has_get_executor<T>{});
}
@endcode
Use with `static_assert`:
@code
struct stream
{
using executor_type = net::io_context::executor_type;
executor_type get_executor() noexcept;
};
static_assert(has_get_executor<stream>::value, "Missing get_executor member");
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct has_get_executor : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct has_get_executor : std::false_type {};
template<class T>
struct has_get_executor<T, beast::detail::void_t<decltype(
std::declval<T&>().get_executor())>> : std::true_type {};
#endif
/** Determine if `T` meets the requirements of @b AsyncReadStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class AsyncReadStream>
void f(AsyncReadStream& stream)
{
static_assert(is_async_read_stream<AsyncReadStream>::value,
"AsyncReadStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class AsyncReadStream>
typename std::enable_if<is_async_read_stream<AsyncReadStream>::value>::type
f(AsyncReadStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_async_read_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_async_read_stream : std::false_type {};
template<class T>
struct is_async_read_stream<T, detail::void_t<decltype(
std::declval<T>().async_read_some(
std::declval<detail::MutableBufferSequence>(),
std::declval<detail::ReadHandler>())
)>> : std::integral_constant<bool,
has_get_executor<T>::value
> {};
#endif
/** Determine if `T` meets the requirements of @b AsyncWriteStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class AsyncWriteStream>
void f(AsyncWriteStream& stream)
{
static_assert(is_async_write_stream<AsyncWriteStream>::value,
"AsyncWriteStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class AsyncWriteStream>
typename std::enable_if<is_async_write_stream<AsyncWriteStream>::value>::type
f(AsyncWriteStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_async_write_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_async_write_stream : std::false_type {};
template<class T>
struct is_async_write_stream<T, detail::void_t<decltype(
std::declval<T>().async_write_some(
std::declval<detail::ConstBufferSequence>(),
std::declval<detail::WriteHandler>())
)>> : std::integral_constant<bool,
has_get_executor<T>::value
> {};
#endif
/** Determine if `T` meets the requirements of @b SyncReadStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class SyncReadStream>
void f(SyncReadStream& stream)
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class SyncReadStream>
typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
f(SyncReadStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_sync_read_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_sync_read_stream : std::false_type {};
template<class T>
struct is_sync_read_stream<T, detail::void_t<decltype(
std::declval<std::size_t&>() = std::declval<T>().read_some(
std::declval<detail::MutableBufferSequence>()),
std::declval<std::size_t&>() = std::declval<T>().read_some(
std::declval<detail::MutableBufferSequence>(),
std::declval<boost::system::error_code&>())
)>> : std::true_type {};
#endif
/** Determine if `T` meets the requirements of @b SyncWriteStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class SyncReadStream>
void f(SyncReadStream& stream)
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class SyncReadStream>
typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
f(SyncReadStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_sync_write_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_sync_write_stream : std::false_type {};
template<class T>
struct is_sync_write_stream<T, detail::void_t<decltype(
(
std::declval<std::size_t&>() = std::declval<T&>().write_some(
std::declval<detail::ConstBufferSequence>()))
,std::declval<std::size_t&>() = std::declval<T&>().write_some(
std::declval<detail::ConstBufferSequence>(),
std::declval<boost::system::error_code&>())
)>> : std::true_type {};
#endif
/** Determine if `T` meets the requirements of @b AsyncStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class AsyncStream>
void f(AsyncStream& stream)
{
static_assert(is_async_stream<AsyncStream>::value,
"AsyncStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class AsyncStream>
typename std::enable_if<is_async_stream<AsyncStream>::value>::type
f(AsyncStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_async_stream : std::integral_constant<bool, ...>{};
#else
template<class T>
using is_async_stream = std::integral_constant<bool,
is_async_read_stream<T>::value && is_async_write_stream<T>::value>;
#endif
/** Determine if `T` meets the requirements of @b SyncStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class SyncStream>
void f(SyncStream& stream)
{
static_assert(is_sync_stream<SyncStream>::value,
"SyncStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class SyncStream>
typename std::enable_if<is_sync_stream<SyncStream>::value>::type
f(SyncStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_sync_stream : std::integral_constant<bool, ...>{};
#else
template<class T>
using is_sync_stream = std::integral_constant<bool,
is_sync_read_stream<T>::value && is_sync_write_stream<T>::value>;
#endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// //
// File concepts // File concepts

View File

@ -12,7 +12,7 @@
#include <boost/beast/_experimental/unit_test/suite.hpp> #include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/beast/core/error.hpp> #include <boost/beast/core/error.hpp>
#include <boost/beast/core/type_traits.hpp> #include <boost/beast/core/stream_traits.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/asio/spawn.hpp> #include <boost/asio/spawn.hpp>
#include <boost/asio/use_future.hpp> #include <boost/asio/use_future.hpp>

View File

@ -13,6 +13,7 @@
#include <boost/beast/_experimental/unit_test/suite.hpp> #include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/beast/core/error.hpp> #include <boost/beast/core/error.hpp>
#include <boost/beast/core/type_traits.hpp> #include <boost/beast/core/type_traits.hpp>
#include <boost/asio/io_context.hpp>
namespace boost { namespace boost {
namespace beast { namespace beast {
@ -161,7 +162,7 @@ public:
}; };
void void
testJavadoc() testGetLowestLayerJavadoc()
{ {
write_stream<without> s; write_stream<without> s;
BOOST_STATIC_ASSERT( BOOST_STATIC_ASSERT(
@ -178,11 +179,102 @@ public:
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
void
testExecutorType()
{
}
void
testExecutorTypeJavadoc()
{
}
//--------------------------------------------------------------------------
struct sync_read_stream
{
template<class MutableBufferSequence>
std::size_t
read_some(MutableBufferSequence const&);
template<class MutableBufferSequence>
std::size_t
read_some(MutableBufferSequence const&,
error_code& ec);
};
struct sync_write_stream
{
template<class ConstBufferSequence>
std::size_t
write_some(ConstBufferSequence const&);
template<class ConstBufferSequence>
std::size_t
write_some(
ConstBufferSequence const&, error_code&);
};
struct async_read_stream
{
net::io_context::executor_type
get_executor();
template<class MutableBufferSequence, class ReadHandler>
void
async_read_some(
MutableBufferSequence const&, ReadHandler&&);
};
struct async_write_stream
{
net::io_context::executor_type
get_executor();
template<class ConstBufferSequence, class WriteHandler>
void
async_write_some(
ConstBufferSequence const&, WriteHandler&&);
};
struct sync_stream : sync_read_stream, sync_write_stream
{
};
struct async_stream : async_read_stream, async_write_stream
{
using async_read_stream::get_executor;
};
BOOST_STATIC_ASSERT(is_sync_read_stream<sync_read_stream>::value);
BOOST_STATIC_ASSERT(is_sync_write_stream<sync_write_stream>::value);
BOOST_STATIC_ASSERT(is_sync_read_stream<sync_stream>::value);
BOOST_STATIC_ASSERT(is_sync_write_stream<sync_stream>::value);
BOOST_STATIC_ASSERT(is_sync_stream<sync_stream>::value);
BOOST_STATIC_ASSERT(is_async_read_stream<async_read_stream>::value);
BOOST_STATIC_ASSERT(is_async_write_stream<async_write_stream>::value);
BOOST_STATIC_ASSERT(is_async_read_stream<async_stream>::value);
BOOST_STATIC_ASSERT(is_async_write_stream<async_stream>::value);
BOOST_STATIC_ASSERT(is_async_stream<async_stream>::value);
BOOST_STATIC_ASSERT(! is_sync_read_stream<sync_write_stream>::value);
BOOST_STATIC_ASSERT(! is_sync_write_stream<sync_read_stream>::value);
BOOST_STATIC_ASSERT(! is_async_read_stream<async_write_stream>::value);
BOOST_STATIC_ASSERT(! is_async_write_stream<async_read_stream>::value);
BOOST_STATIC_ASSERT(! is_sync_stream<async_stream>::value);
BOOST_STATIC_ASSERT(! is_async_stream<sync_stream>::value);
//--------------------------------------------------------------------------
void void
run() override run() override
{ {
testGetLowestLayer(); testGetLowestLayer();
testJavadoc(); testGetLowestLayerJavadoc();
testExecutorType();
testExecutorTypeJavadoc();
} }
}; };

View File

@ -79,80 +79,5 @@ struct H
BOOST_STATIC_ASSERT(is_completion_handler<H, void(int)>::value); BOOST_STATIC_ASSERT(is_completion_handler<H, void(int)>::value);
BOOST_STATIC_ASSERT(! is_completion_handler<H, void(void)>::value); BOOST_STATIC_ASSERT(! is_completion_handler<H, void(void)>::value);
//
// stream concepts
//
struct sync_write_stream
{
net::io_context&
get_io_service();
template<class ConstBufferSequence>
std::size_t
write_some(ConstBufferSequence const& buffers);
template<class ConstBufferSequence>
std::size_t
write_some(
ConstBufferSequence const& buffers, error_code& ec);
};
struct sync_read_stream
{
template<class MutableBufferSequence>
std::size_t
read_some(MutableBufferSequence const& buffers);
template<class MutableBufferSequence>
std::size_t
read_some(MutableBufferSequence const& buffers,
error_code& ec);
};
struct sync_stream : sync_read_stream, sync_write_stream
{
};
BOOST_STATIC_ASSERT(! is_sync_read_stream<sync_write_stream>::value);
BOOST_STATIC_ASSERT(! is_sync_write_stream<sync_read_stream>::value);
BOOST_STATIC_ASSERT(is_sync_read_stream<sync_read_stream>::value);
BOOST_STATIC_ASSERT(is_sync_write_stream<sync_write_stream>::value);
BOOST_STATIC_ASSERT(is_sync_read_stream<sync_stream>::value);
BOOST_STATIC_ASSERT(is_sync_write_stream<sync_stream>::value);
namespace {
using stream_type = net::ip::tcp::socket;
struct not_a_stream
{
void
get_io_service();
};
BOOST_STATIC_ASSERT(has_get_executor<stream_type>::value);
BOOST_STATIC_ASSERT(is_async_read_stream<stream_type>::value);
BOOST_STATIC_ASSERT(is_async_write_stream<stream_type>::value);
BOOST_STATIC_ASSERT(is_async_stream<stream_type>::value);
BOOST_STATIC_ASSERT(is_sync_read_stream<stream_type>::value);
BOOST_STATIC_ASSERT(is_sync_write_stream<stream_type>::value);
BOOST_STATIC_ASSERT(is_sync_stream<stream_type>::value);
BOOST_STATIC_ASSERT(! has_get_executor<not_a_stream>::value);
BOOST_STATIC_ASSERT(! is_async_read_stream<not_a_stream>::value);
BOOST_STATIC_ASSERT(! is_async_write_stream<not_a_stream>::value);
BOOST_STATIC_ASSERT(! is_sync_read_stream<not_a_stream>::value);
BOOST_STATIC_ASSERT(! is_sync_write_stream<not_a_stream>::value);
BOOST_STATIC_ASSERT(is_sync_read_stream<test::stream>::value);
BOOST_STATIC_ASSERT(is_sync_write_stream<test::stream>::value);
BOOST_STATIC_ASSERT(is_async_read_stream<test::stream>::value);
BOOST_STATIC_ASSERT(is_async_write_stream<test::stream>::value);
} // (anonymous)
} // beast } // beast
} // boost } // boost