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 09:56:34 -08:00
parent 9cee4e053f
commit 477cd75153
12 changed files with 553 additions and 476 deletions
+8
View File
@@ -6,6 +6,14 @@ Version 210:
* Add stream_traits.hpp
* 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:
+97 -42
View File
@@ -32,21 +32,31 @@ New websocket-chat-multi example
[/* `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
* Move construction does not always invalidate buffers
* non-const `data()` returns a mutable buffer sequence
* Add `cdata()` to also return constant readable bytes
* 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()`
* Respect Allocator `max_size()`
* 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()`
* More members are `noexcept`
* Specify exception safety
@@ -56,23 +66,32 @@ New websocket-chat-multi example
* New file <boost/beast/core/buffer_traits.hpp>
* New variadic `is_const_buffer_sequence`
* New variadic `is_mutable_buffer_sequence`
* New `buffers_iterator_type` trait
* New `buffers_type` trait
* New trait `buffers_iterator_type`
* 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
* 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:
* `saved_handler`
* `buffers_range_ref`
* `dynamic_buffer_ref`
* `executor_type`
* `get_lowest_layer` and `lowest_layer_type`
* `close_socket` and `beast_close_socket`
* `error` and `condition`
* `get_lowest_layer`,
`lowest_layer_type`
* `close_socket`,
`beast_close_socket`
* `error`,
`condition`
[*API Changes]
@@ -80,38 +99,64 @@ New websocket-chat-multi example
from the stream. Previously, they returned the number of bytes
consumed by the parser.
['Actions Required]:
* Callers depending on the return value of `http::read` or
`http::async_read` overloads should adjust the usage of
* Callers depending on the return value of
`http::read` or
`http::async_read`
overloads should adjust the usage of
the returned value as needed.
* `flat_static_buffer::reset()` is deprecated.
['Actions Required]:
* call `clear()` instead.
* Metafunctions
`has_get_executor`,
`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]:
* Replace `buffers_adapter` with `buffers_adaptor`, or define
`BOOST_BEAST_ALLOW_DEPRECATED`.
* call
`clear()` instead.
* `buffers` is now called `make_printable`.
* `buffers_adapter` is now spelled
`buffers_adaptor`.
['Actions Required]:
* Replace `buffers` with `make_printable`, and include
"make_printable.hpp" instead of "ostream.hpp".
* Replace `buffers_adapter` with
`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.
['Actions Required]:
- Replace `file_mode::append_new` with either `file_mode::append`
or `file_mode::append_existing` as needed.
- Replace `file_mode::append_new` with either
`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]:
- Call `buffers_range_ref` with the buffer, instead of calling
`buffers_range` with a reference wrapper constructed from
the buffer.
- Call
`buffers_range_ref`
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.
['Actions Required]: Use the free function `get_lowest_layer` and the
type trait `lowest_layer_type` instead.
['Actions Required]: Use the free function
`get_lowest_layer` and the
type trait
`lowest_layer_type` instead.
[*Examples]
@@ -119,9 +164,10 @@ New websocket-chat-multi example
* ([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
@@ -129,33 +175,42 @@ New websocket-chat-multi example
* ([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 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 1408]) `session_alloc` is thread-safe
* ([issue 1408]) `session_alloc`
is thread-safe
* ([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
* All behavior of default-constructed iterators is conforming
* `file_mode::append_existing` works correctly
* `file_mode::append_existing`
works correctly
[/-----------------------------------------------------------------------------]
+1 -1
View File
@@ -14,7 +14,7 @@
#include <boost/beast/core/detail/static_const.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/type_traits.hpp>
#include <boost/type_traits/make_void.hpp>
#include <type_traits>
namespace boost {
@@ -13,7 +13,6 @@
#include <boost/beast/core/bind_handler.hpp>
#include <boost/beast/core/async_op_base.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/coroutine.hpp>
#include <boost/throw_exception.hpp>
+1 -1
View File
@@ -12,7 +12,7 @@
#include <boost/beast/core/detail/config.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 <cstdlib>
@@ -10,6 +10,8 @@
#ifndef 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 <type_traits>
@@ -25,13 +27,11 @@ namespace detail {
//
template <class T>
std::false_type has_next_layer_impl(void*) {}
std::false_type has_next_layer_impl(void*);
template <class T>
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>
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
} // beast
} // boost
@@ -13,7 +13,7 @@
#include <boost/beast/core/error.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/mp11/function.hpp>
#include <boost/type_traits.hpp>
#include <boost/type_traits/make_void.hpp>
#include <iterator>
#include <tuple>
#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
handler you provided to an asynchronous initiating function did
not have the right signature. Check the parameter types for your
+315 -1
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
// 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>{});
}
//------------------------------------------------------------------------------
/** A trait to determine the return type of get_executor.
This type alias will be the type of values returned by
@@ -110,6 +112,318 @@ using executor_type =
decltype(std::declval<T&>().get_executor());
#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
} // boost
-314
View File
@@ -56,320 +56,6 @@ using is_completion_handler = std::integral_constant<bool,
detail::is_invocable<T, Signature>::value>;
#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
+1 -1
View File
@@ -12,7 +12,7 @@
#include <boost/beast/_experimental/unit_test/suite.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/spawn.hpp>
#include <boost/asio/use_future.hpp>
+94 -2
View File
@@ -13,6 +13,7 @@
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/type_traits.hpp>
#include <boost/asio/io_context.hpp>
namespace boost {
namespace beast {
@@ -161,7 +162,7 @@ public:
};
void
testJavadoc()
testGetLowestLayerJavadoc()
{
write_stream<without> s;
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
run() override
{
testGetLowestLayer();
testJavadoc();
testGetLowestLayerJavadoc();
testExecutorType();
testExecutorTypeJavadoc();
}
};
-75
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(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
} // boost