From e5da42f6cd323b6c334f0190fb309c78067ede49 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Wed, 28 Jun 2023 21:51:22 +0800 Subject: [PATCH 01/43] ported boost.buffers --- CMakeLists.txt | 19 +- doc/reference/io/buffers/overview.adoc | 29 + include/boost/async/config.hpp | 10 +- include/boost/async/detail/exception.hpp | 6 + include/boost/async/detail/type_traits.hpp | 91 +++ include/boost/async/io/buffers.hpp | 32 ++ include/boost/async/io/buffers/algorithm.hpp | 234 ++++++++ .../async/io/buffers/any_dynamic_buffer.hpp | 174 ++++++ include/boost/async/io/buffers/buffer.hpp | 99 ++++ .../boost/async/io/buffers/buffer_copy.hpp | 126 ++++ .../boost/async/io/buffers/buffer_size.hpp | 78 +++ .../async/io/buffers/circular_buffer.hpp | 125 ++++ .../boost/async/io/buffers/const_buffer.hpp | 158 +++++ .../async/io/buffers/const_buffer_pair.hpp | 134 +++++ .../async/io/buffers/const_buffer_span.hpp | 142 +++++ .../async/io/buffers/const_buffer_subspan.hpp | 121 ++++ .../boost/async/io/buffers/flat_buffer.hpp | 148 +++++ .../io/buffers/impl/const_buffer_span.hpp | 56 ++ .../io/buffers/impl/const_buffer_subspan.hpp | 144 +++++ .../io/buffers/impl/mutable_buffer_span.hpp | 55 ++ .../buffers/impl/mutable_buffer_subspan.hpp | 144 +++++ .../boost/async/io/buffers/mutable_buffer.hpp | 165 ++++++ .../async/io/buffers/mutable_buffer_pair.hpp | 115 ++++ .../async/io/buffers/mutable_buffer_span.hpp | 140 +++++ .../io/buffers/mutable_buffer_subspan.hpp | 121 ++++ include/boost/async/io/buffers/range.hpp | 237 ++++++++ .../boost/async/io/buffers/string_buffer.hpp | 162 ++++++ include/boost/async/io/buffers/tag_invoke.hpp | 31 + .../boost/async/io/buffers/type_traits.hpp | 249 ++++++++ src/detail/exception.cpp | 17 + src/io/buffers/circular_buffer.cpp | 94 +++ src/io/buffers/const_buffer_pair.cpp | 53 ++ src/io/buffers/const_buffer_subspan.cpp | 154 +++++ src/io/buffers/mutable_buffer_pair.cpp | 53 ++ src/io/buffers/mutable_buffer_subspan.cpp | 155 +++++ test/CMakeLists.txt | 4 +- test/io/CMakeLists.txt | 1 + test/io/buffers/CMakeLists.txt | 45 ++ test/io/buffers/Jamfile | 48 ++ test/io/buffers/algorithm.cpp | 204 +++++++ test/io/buffers/any_dynamic_buffer.cpp | 86 +++ test/io/buffers/buffer.cpp | 82 +++ test/io/buffers/buffer_copy.cpp | 85 +++ test/io/buffers/buffer_size.cpp | 50 ++ test/io/buffers/buffers.cpp | 11 + test/io/buffers/circular_buffer.cpp | 185 ++++++ test/io/buffers/const_buffer.cpp | 114 ++++ test/io/buffers/const_buffer_pair.cpp | 150 +++++ test/io/buffers/const_buffer_span.cpp | 81 +++ test/io/buffers/const_buffer_subspan.cpp | 190 ++++++ test/io/buffers/flat_buffer.cpp | 169 ++++++ test/io/buffers/mutable_buffer.cpp | 114 ++++ test/io/buffers/mutable_buffer_pair.cpp | 130 +++++ test/io/buffers/mutable_buffer_span.cpp | 81 +++ test/io/buffers/mutable_buffer_subspan.cpp | 190 ++++++ test/io/buffers/range.cpp | 29 + test/io/buffers/string_buffer.cpp | 173 ++++++ test/io/buffers/tag_invoke.cpp | 11 + test/io/buffers/test_helpers.hpp | 216 +++++++ test/io/buffers/test_main.cpp | 544 ++++++++++++++++++ test/io/buffers/test_suite.hpp | 502 ++++++++++++++++ test/io/buffers/type_traits.cpp | 11 + 62 files changed, 7368 insertions(+), 9 deletions(-) create mode 100644 doc/reference/io/buffers/overview.adoc create mode 100644 include/boost/async/detail/type_traits.hpp create mode 100644 include/boost/async/io/buffers.hpp create mode 100644 include/boost/async/io/buffers/algorithm.hpp create mode 100644 include/boost/async/io/buffers/any_dynamic_buffer.hpp create mode 100644 include/boost/async/io/buffers/buffer.hpp create mode 100644 include/boost/async/io/buffers/buffer_copy.hpp create mode 100644 include/boost/async/io/buffers/buffer_size.hpp create mode 100644 include/boost/async/io/buffers/circular_buffer.hpp create mode 100644 include/boost/async/io/buffers/const_buffer.hpp create mode 100644 include/boost/async/io/buffers/const_buffer_pair.hpp create mode 100644 include/boost/async/io/buffers/const_buffer_span.hpp create mode 100644 include/boost/async/io/buffers/const_buffer_subspan.hpp create mode 100644 include/boost/async/io/buffers/flat_buffer.hpp create mode 100644 include/boost/async/io/buffers/impl/const_buffer_span.hpp create mode 100644 include/boost/async/io/buffers/impl/const_buffer_subspan.hpp create mode 100644 include/boost/async/io/buffers/impl/mutable_buffer_span.hpp create mode 100644 include/boost/async/io/buffers/impl/mutable_buffer_subspan.hpp create mode 100644 include/boost/async/io/buffers/mutable_buffer.hpp create mode 100644 include/boost/async/io/buffers/mutable_buffer_pair.hpp create mode 100644 include/boost/async/io/buffers/mutable_buffer_span.hpp create mode 100644 include/boost/async/io/buffers/mutable_buffer_subspan.hpp create mode 100644 include/boost/async/io/buffers/range.hpp create mode 100644 include/boost/async/io/buffers/string_buffer.hpp create mode 100644 include/boost/async/io/buffers/tag_invoke.hpp create mode 100644 include/boost/async/io/buffers/type_traits.hpp create mode 100644 src/io/buffers/circular_buffer.cpp create mode 100644 src/io/buffers/const_buffer_pair.cpp create mode 100644 src/io/buffers/const_buffer_subspan.cpp create mode 100644 src/io/buffers/mutable_buffer_pair.cpp create mode 100644 src/io/buffers/mutable_buffer_subspan.cpp create mode 100644 test/io/CMakeLists.txt create mode 100644 test/io/buffers/CMakeLists.txt create mode 100644 test/io/buffers/Jamfile create mode 100644 test/io/buffers/algorithm.cpp create mode 100644 test/io/buffers/any_dynamic_buffer.cpp create mode 100644 test/io/buffers/buffer.cpp create mode 100644 test/io/buffers/buffer_copy.cpp create mode 100644 test/io/buffers/buffer_size.cpp create mode 100644 test/io/buffers/buffers.cpp create mode 100644 test/io/buffers/circular_buffer.cpp create mode 100644 test/io/buffers/const_buffer.cpp create mode 100644 test/io/buffers/const_buffer_pair.cpp create mode 100644 test/io/buffers/const_buffer_span.cpp create mode 100644 test/io/buffers/const_buffer_subspan.cpp create mode 100644 test/io/buffers/flat_buffer.cpp create mode 100644 test/io/buffers/mutable_buffer.cpp create mode 100644 test/io/buffers/mutable_buffer_pair.cpp create mode 100644 test/io/buffers/mutable_buffer_span.cpp create mode 100644 test/io/buffers/mutable_buffer_subspan.cpp create mode 100644 test/io/buffers/range.cpp create mode 100644 test/io/buffers/string_buffer.cpp create mode 100644 test/io/buffers/tag_invoke.cpp create mode 100644 test/io/buffers/test_helpers.hpp create mode 100644 test/io/buffers/test_main.cpp create mode 100644 test/io/buffers/test_suite.hpp create mode 100644 test/io/buffers/type_traits.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e40dc4e..a0806ad6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,13 +79,18 @@ if (NOT MSVC) endif() add_library(boost_async - src/detail/exception.cpp - src/detail/util.cpp - src/error.cpp - src/channel.cpp - src/main.cpp - src/this_thread.cpp - src/thread.cpp) + src/detail/exception.cpp + src/detail/util.cpp + src/error.cpp + src/channel.cpp + src/main.cpp + src/this_thread.cpp + src/io/buffers/circular_buffer.cpp + src/io/buffers/const_buffer_pair.cpp + src/io/buffers/const_buffer_subspan.cpp + src/io/buffers/mutable_buffer_pair.cpp + src/io/buffers/mutable_buffer_subspan.cpp + src/thread.cpp) target_include_directories(boost_async PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(boost_async PUBLIC Boost::system diff --git a/doc/reference/io/buffers/overview.adoc b/doc/reference/io/buffers/overview.adoc new file mode 100644 index 00000000..fc28344e --- /dev/null +++ b/doc/reference/io/buffers/overview.adoc @@ -0,0 +1,29 @@ +//// +Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Official repository: https://github.com/CPPAlliance/buffers +//// + +== Overview + +Boost.Buffers is a portable, low-level C++ library which provides +containers and algorithms for describing contiguous buffers of +arbitrary bytes. + +Boost.Buffers offers these features: + +* Require only C++11 +* Works without exceptions +* Fast compilation, few templates +* Does not require Asio + +=== Requirements + +* Requires Boost and a compiler supporting at least C++20 +* Aliases for standard types use their Boost equivalents +* Link to a built static or dynamic Boost library, or use header-only (see below) +* Supports `-fno-exceptions`, detected automatically + diff --git a/include/boost/async/config.hpp b/include/boost/async/config.hpp index 50fa94a9..5403991c 100644 --- a/include/boost/async/config.hpp +++ b/include/boost/async/config.hpp @@ -66,7 +66,15 @@ namespace pmr = boost::container::pmr; #if defined(BOOST_ASYNC_USE_STD_PMR) namespace pmr = std::pmr; #endif - } +# define BOOST_ASYNC_ERR(ev) ( \ + ::boost::system::error_code( (ev), [] { \ + static constexpr auto loc((BOOST_CURRENT_LOCATION)); \ + return &loc; }())) +# define BOOST_ASYNC_RETURN_EC(ev) \ + static constexpr auto loc ## __LINE__((BOOST_CURRENT_LOCATION)); \ + return ::boost::system::error_code((ev), &loc ## __LINE__) + + #endif //BOOST_ASYNC_CONFIG_HPP diff --git a/include/boost/async/detail/exception.hpp b/include/boost/async/detail/exception.hpp index 575f88db..ff4eedd2 100644 --- a/include/boost/async/detail/exception.hpp +++ b/include/boost/async/detail/exception.hpp @@ -23,6 +23,12 @@ BOOST_ASYNC_DECL std::exception_ptr wait_not_ready(); BOOST_ASYNC_DECL std::exception_ptr already_awaited(); BOOST_ASYNC_DECL std::exception_ptr allocation_failed(); +BOOST_ASYNC_DECL void BOOST_NORETURN throw_invalid_argument( + source_location const& loc = BOOST_CURRENT_LOCATION); + +BOOST_ASYNC_DECL void BOOST_NORETURN throw_length_error( + source_location const& loc = BOOST_CURRENT_LOCATION); + template std::exception_ptr wait_not_ready() { return boost::async::detail::wait_not_ready();} diff --git a/include/boost/async/detail/type_traits.hpp b/include/boost/async/detail/type_traits.hpp new file mode 100644 index 00000000..c9883401 --- /dev/null +++ b/include/boost/async/detail/type_traits.hpp @@ -0,0 +1,91 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/http_proto +// + +#ifndef BOOST_ASYNC_DETAIL_TYPE_TRAITS_HPP +#define BOOST_ASYNC_DETAIL_TYPE_TRAITS_HPP + +#include +#include +#include + +namespace boost::async::detail { + +// is bidirectional iterator +template +struct is_bidirectional_iterator : std::false_type +{ +}; + +template +struct is_bidirectional_iterator() + ), + // LegacyIterator + typename std::iterator_traits::value_type, + typename std::iterator_traits::difference_type, + typename std::iterator_traits::reference, + typename std::iterator_traits::pointer, + typename std::iterator_traits::iterator_category, + typename std::enable_if< + // LegacyIterator + std::is_copy_constructible::value && + std::is_copy_assignable::value && + std::is_destructible::value && + std::is_same())>::value && + // Swappable + // VFALCO TODO + // EqualityComparable + std::is_convertible() == + std::declval()), + bool>::value && + // LegacyInputIterator + std::is_convertible::reference, typename + std::iterator_traits::value_type>::value && + std::is_same::reference, + decltype(*std::declval())>::value && + std::is_convertible() != + std::declval()), + bool>::value && + std::is_same())>::value && + // VFALCO (void)r++ (void)++r + std::is_convertible()++), typename + std::iterator_traits::value_type>::value && + // LegacyForwardIterator + std::is_default_constructible::value && + std::is_same()++)>::value && + std::is_same::reference, + decltype(*std::declval()++) + >::value && + // LegacyBidirectionalIterator + std::is_same())>::value && + std::is_convertible()--), + T const&>::value && + std::is_same::reference, + decltype(*std::declval()--)>::value + >::type >> + : std::true_type +{ +}; + +} // boost::buffers::detail + +#endif diff --git a/include/boost/async/io/buffers.hpp b/include/boost/async/io/buffers.hpp new file mode 100644 index 00000000..6f215946 --- /dev/null +++ b/include/boost/async/io/buffers.hpp @@ -0,0 +1,32 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_ASYNC_BUFFERS_HPP +#define BOOST_ASYNC_BUFFERS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/include/boost/async/io/buffers/algorithm.hpp b/include/boost/async/io/buffers/algorithm.hpp new file mode 100644 index 00000000..9e45320c --- /dev/null +++ b/include/boost/async/io/buffers/algorithm.hpp @@ -0,0 +1,234 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_ALGORITHM_HPP +#define BOOST_BUFFERS_ALGORITHM_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost::async::io::buffers { + +#ifdef BOOST_BUFFERS_DOCS + +/** Returns the type of a prefix of a buffer sequence. +*/ +template +using prefix_type = __see_below__; + +/** Returns the type of a suffix of a buffer sequence. +*/ +template +using suffix_type = __see_below__; + +/** Return a prefix of the buffer sequence. +*/ +template +prefix_type +prefix( + BufferSequence const& b, + std::size_t n); + +/** Return a prefix of the buffer sequence. +*/ +template +prefix_type +sans_suffix( + BufferSequence const& b, + std::size_t n); + +/** Return a suffix of the buffer sequence. +*/ +template +suffix_type +suffix( + BufferSequence const& b, + std::size_t n); + +/** Return a suffix of the buffer sequence. +*/ +template +suffix_type +sans_prefix( + BufferSequence const& b, + std::size_t n); + +/** Return the first buffer in a sequence. +*/ +template +__see_below__ +front( + BufferSequence const& b); + +#else + +template +void +tag_invoke( + prefix_tag const&, + BufferSequence const&, + std::size_t) = delete; + +template +void +tag_invoke( + suffix_tag const&, + BufferSequence const&, + std::size_t) = delete; + +template +using prefix_type = decltype( + tag_invoke( + prefix_tag{}, + std::declval(), + std::size_t{})); + +template +using suffix_type = decltype( + tag_invoke( + suffix_tag{}, + std::declval(), + std::size_t{})); + +namespace detail { + +struct prefix_impl +{ + template + prefix_type + operator()( + BufferSequence const& b, + std::size_t n) const + { + static_assert( + is_const_buffer_sequence< + BufferSequence>::value, + "Type requirements not met"); + + return tag_invoke( + prefix_tag{}, b, n); + } +}; + +struct sans_suffix_impl +{ + template + prefix_type + operator()( + BufferSequence const& b, + std::size_t n) const + { + auto const n0 = buffer_size(b); + if(n < n0) + return tag_invoke( + prefix_tag{}, b, n0 - n); + return tag_invoke( + prefix_tag{}, b, 0); + } +}; + +struct suffix_impl +{ + template + suffix_type + operator()( + BufferSequence const& b, + std::size_t n) const + { + static_assert( + is_const_buffer_sequence< + BufferSequence>::value, + "Type requirements not met"); + + return tag_invoke( + suffix_tag{}, b, n); + } +}; + +struct sans_prefix_impl +{ + template + suffix_type + operator()( + BufferSequence const& b, + std::size_t n) const + { + static_assert( + is_const_buffer_sequence< + BufferSequence>::value, + "Type requirements not met"); + + auto const n0 = buffer_size(b); + if(n < n0) + return tag_invoke( + suffix_tag{}, b, n0 - n); + return tag_invoke( + suffix_tag{}, b, 0); + } +}; + +struct front_impl +{ + template< + class MutableBufferSequence + , class = typename std::enable_if< + is_mutable_buffer_sequence< + MutableBufferSequence>::value + >::type> + mutable_buffer + operator()( + MutableBufferSequence const& bs) const noexcept + { + auto const it = begin(bs); + if(it != end(bs)) + return *it; + return {}; + } + + template< + class ConstBufferSequence + , class = typename std::enable_if< + ! is_mutable_buffer_sequence< + ConstBufferSequence>::value + >::type> + const_buffer + operator()( + ConstBufferSequence const& bs) const noexcept + { + static_assert( + is_const_buffer_sequence< + ConstBufferSequence>::value, + "Type requirements not met"); + + auto const it = bs.begin(); + if(it != bs.end()) + return *it; + return {}; + } +}; + +} // detail + +constexpr detail::prefix_impl prefix{}; +constexpr detail::suffix_impl suffix{}; +constexpr detail::sans_prefix_impl sans_prefix{}; +constexpr detail::sans_suffix_impl sans_suffix{}; +constexpr detail::front_impl front{}; + +#endif + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/any_dynamic_buffer.hpp b/include/boost/async/io/buffers/any_dynamic_buffer.hpp new file mode 100644 index 00000000..d36171af --- /dev/null +++ b/include/boost/async/io/buffers/any_dynamic_buffer.hpp @@ -0,0 +1,174 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_ANY_DYNAMIC_BUFFER_HPP +#define BOOST_BUFFERS_ANY_DYNAMIC_BUFFER_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost::async::io::buffers { + +/** An abstract, type-erased dynamic buffer. +*/ +struct any_dynamic_buffer +{ + using const_buffers_type = + buffers::const_buffer_span; + + using mutable_buffers_type = + buffers::mutable_buffer_span; + + virtual ~any_dynamic_buffer() = default; + virtual std::size_t size() const = 0; + virtual std::size_t max_size() const = 0; + virtual std::size_t capacity() const = 0; + virtual const_buffers_type data() const = 0; + virtual mutable_buffers_type prepare(std::size_t) = 0; + virtual void commit(std::size_t) = 0; + virtual void consume(std::size_t) = 0; +}; + +//----------------------------------------------- + +/** A type-erased dynamic buffer. +*/ +template< + class DynamicBuffer, + std::size_t N = 8> +class any_dynamic_buffer_impl + : public any_dynamic_buffer +{ + DynamicBuffer b_; + buffers::const_buffer data_[N]; + buffers::mutable_buffer out_[N]; + std::size_t data_len_ = 0; + std::size_t out_len_ = 0; + + template + static + std::size_t + unroll( + Buffers const& bs, + value_type* dest, + std::size_t len) + { + std::size_t i = 0; + for(auto b : buffers::range(bs)) + { + dest[i++] = b; + if(i == len) + break; + } + return i; + } + +public: + template + explicit + any_dynamic_buffer_impl( + DynamicBuffer_&& b) + : b_(std::forward< + DynamicBuffer_>(b)) + { + } + + DynamicBuffer& + buffer() noexcept + { + return b_; + } + + DynamicBuffer const& + buffer() const noexcept + { + return b_; + } + + std::size_t + size() const override + { + return b_.size(); + } + + std::size_t + max_size() const override + { + return b_.max_size(); + } + + std::size_t + capacity() const override + { + return b_.capacity(); + } + + const_buffers_type + data() const override + { + return const_buffers_type( + data_, data_len_); + } + + auto + prepare( + std::size_t n) -> + mutable_buffers_type override + { + out_len_ = unroll( + b_.prepare(n), out_, N); + return mutable_buffers_type( + out_, out_len_); + } + + void + commit( + std::size_t n) override + { + b_.commit(n); + data_len_ = unroll( + b_.data(), data_, N); + } + + void + consume( + std::size_t n) override + { + b_.consume(n); + data_len_ = unroll( + b_.data(), data_, N); + } +}; + +template< + class DynamicBuffer +#ifndef BOOST_BUFFERS_DOCS + , class = typename std::enable_if< + is_dynamic_buffer< + typename std::decay::type + >::value>::type +#endif +> +auto +make_any(DynamicBuffer&& b) -> + any_dynamic_buffer_impl::type> +{ + return any_dynamic_buffer_impl::type>( + std::forward(b)); +} + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/buffer.hpp b/include/boost/async/io/buffers/buffer.hpp new file mode 100644 index 00000000..103a0f07 --- /dev/null +++ b/include/boost/async/io/buffers/buffer.hpp @@ -0,0 +1,99 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_BUFFER_HPP +#define BOOST_BUFFERS_BUFFER_HPP + +#include +#include +#include +#include +#include + +namespace boost::async::io::buffers { + +/** Return a buffer. +*/ +inline +mutable_buffer +buffer( + mutable_buffer const& b) noexcept +{ + return b; +} + +/** Return a buffer. +*/ +inline +mutable_buffer +buffer( + void* data, + std::size_t size) noexcept +{ + return mutable_buffer(data, size); +} + +/** Return a buffer. +*/ +inline +const_buffer +buffer( + const_buffer const& b) noexcept +{ + return b; +} + +/** Return a buffer. +*/ +inline +const_buffer +buffer( + void const* data, + std::size_t size) noexcept +{ + return const_buffer(data, size); +} + +/** Return a buffer. +*/ +template< + class T, std::size_t N +#ifndef BOOST_BUFFERS_DOCS + , class = typename std::enable_if< + std::is_trivially_copyable::value>::type +#endif +> +mutable_buffer +buffer( + T (&data)[N]) noexcept +{ + return mutable_buffer( + data, N * sizeof(T)); +} + +/** Return a buffer. +*/ +template< + class T, std::size_t N +#ifndef BOOST_BUFFERS_DOCS + , class = typename std::enable_if< + std::is_trivially_copyable::value>::type +#endif +> +const_buffer +buffer( + T const (&data)[N]) noexcept +{ + return const_buffer( + data, N * sizeof(T)); +} + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/buffer_copy.hpp b/include/boost/async/io/buffers/buffer_copy.hpp new file mode 100644 index 00000000..d9a6ab9e --- /dev/null +++ b/include/boost/async/io/buffers/buffer_copy.hpp @@ -0,0 +1,126 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_BUFFER_COPY_HPP +#define BOOST_BUFFERS_BUFFER_COPY_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost::async::io::buffers { + +#ifdef BOOST_BUFFERS_DOCS + +/** Copy buffer contents +*/ +template< + class MutableBufferSequence, + class ConstBufferSequence> +std::size_t +buffer_copy( + MutableBufferSequence const& to, + ConstBufferSequence const& from, + std::size_t at_most = + std::size_t(-1)) noexcept; + +#else + +namespace detail { + +struct buffer_copy_impl +{ + template< + class MutableBuffers, + class ConstBuffers> + std::size_t + operator()( + MutableBuffers const& to, + ConstBuffers const& from, + std::size_t at_most = + std::size_t(-1)) const noexcept + { + // If you get a compile error here it + // means that one or both of your types + // do not meet the requirements. + static_assert( + is_mutable_buffer_sequence< + MutableBuffers>::value, + "Type requirements not met"); + static_assert( + is_const_buffer_sequence< + ConstBuffers>::value, + "Type requirements not met"); + + std::size_t total = 0; + std::size_t pos0 = 0; + std::size_t pos1 = 0; + auto const end0 = end(from); + auto const end1 = end(to); + auto it0 = begin(from); + auto it1 = begin(to); + while( + total < at_most && + it0 != end0 && + it1 != end1) + { + const_buffer b0 = + const_buffer(*it0) + pos0; + mutable_buffer b1 = + mutable_buffer(*it1) + pos1; + std::size_t const amount = + [&] + { + std::size_t n = b0.size(); + if( n > b1.size()) + n = b1.size(); + if( n > at_most - total) + n = at_most - total; + std::memcpy( + b1.data(), + b0.data(), + n); + return n; + }(); + total += amount; + if(amount == b1.size()) + { + ++it1; + pos1 = 0; + } + else + { + pos1 += amount; + } + if(amount == b0.size()) + { + ++it0; + pos0 = 0; + } + else + { + pos0 += amount; + } + } + return total; + } +}; + +} // detail + +constexpr detail::buffer_copy_impl buffer_copy{}; + +#endif + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/buffer_size.hpp b/include/boost/async/io/buffers/buffer_size.hpp new file mode 100644 index 00000000..caba6b10 --- /dev/null +++ b/include/boost/async/io/buffers/buffer_size.hpp @@ -0,0 +1,78 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_BUFFER_SIZE_HPP +#define BOOST_BUFFERS_BUFFER_SIZE_HPP + +#include +#include +#include +#include +#include + +namespace boost::async::io::buffers { + +#ifdef BOOST_BUFFERS_DOCS + +/** Return the total octets in a buffer sequence + + @par Constraints + @code + is_const_buffer_sequence< ConstBufferSequence >::value == true + @endcode +*/ +template< + class ConstBufferSequence> +std::size_t +buffer_size( + ConstBufferSequence const& b) noexcept; + +#else + +template +std::size_t +tag_invoke( + size_tag const&, + Buffers const& bs) noexcept +{ + std::size_t n = 0; + for(const_buffer b : range(bs)) + n += b.size(); + return n; +} + +namespace detail { + +struct buffer_size_impl +{ + template + std::size_t + operator()( + Buffers const& bs) const noexcept + { + // If you get a compile error here it + // means that your type does not meet + // the requirements. + static_assert( + is_const_buffer_sequence::value, + "Type requirements not met."); + + return tag_invoke(size_tag{}, bs); + } +}; + +} // detail + +constexpr detail::buffer_size_impl buffer_size{}; + +#endif + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/circular_buffer.hpp b/include/boost/async/io/buffers/circular_buffer.hpp new file mode 100644 index 00000000..88f65df4 --- /dev/null +++ b/include/boost/async/io/buffers/circular_buffer.hpp @@ -0,0 +1,125 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_CIRCULAR_BUFFER_HPP +#define BOOST_BUFFERS_CIRCULAR_BUFFER_HPP + +#include +#include +#include +#include + +namespace boost::async::io::buffers { + +class circular_buffer +{ + unsigned char* base_ = nullptr; + std::size_t cap_ = 0; + std::size_t in_pos_ = 0; + std::size_t in_len_ = 0; + std::size_t out_size_ = 0; + +public: + using const_buffers_type = + const_buffer_pair; + + using mutable_buffers_type = + mutable_buffer_pair; + + /** Constructor. + */ + circular_buffer() = default; + + /** Constructor. + */ + circular_buffer( + circular_buffer const&) = default; + +#if 0 + /** Constructor. + */ + explicit + circular_buffer( + mutable_buffer b) noexcept + : base_(static_cast< + unsigned char*>(b.data())) + , cap_(b.size()) + { + } +#endif + + /** Constructor. + */ + circular_buffer( + void* base, + std::size_t capacity) noexcept + : base_(static_cast< + unsigned char*>(base)) + , cap_(capacity) + { + } + + /** Constructor. + */ + circular_buffer( + void* base, + std::size_t capacity, + std::size_t initial_size) + : base_(static_cast< + unsigned char*>(base)) + , cap_(capacity) + , in_len_(initial_size) + { + if(in_len_ > capacity) + async::detail::throw_invalid_argument(); + } + + /** Assignment. + */ + circular_buffer& operator=( + circular_buffer const&) = default; + + std::size_t + size() const noexcept + { + return in_len_; + } + + std::size_t + max_size() const noexcept + { + return cap_; + } + + std::size_t + capacity() const noexcept + { + return cap_ - in_len_; + } + + BOOST_ASYNC_DECL + const_buffers_type + data() const noexcept; + + BOOST_ASYNC_DECL + mutable_buffers_type + prepare(std::size_t n); + + BOOST_ASYNC_DECL + void + commit(std::size_t n) noexcept; + + BOOST_ASYNC_DECL + void + consume(std::size_t n) noexcept; +}; + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/const_buffer.hpp b/include/boost/async/io/buffers/const_buffer.hpp new file mode 100644 index 00000000..4e61000c --- /dev/null +++ b/include/boost/async/io/buffers/const_buffer.hpp @@ -0,0 +1,158 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_CONST_BUFFER_HPP +#define BOOST_BUFFERS_CONST_BUFFER_HPP + +#include +#include + +namespace boost::async::io::buffers { + +/** Holds a buffer that cannot be modified. +*/ +class const_buffer +{ + unsigned char const* p_ = nullptr; + std::size_t n_ = 0; + +public: + /** Constructor. + */ + const_buffer() = default; + + /** Constructor. + */ + const_buffer( + void const* data, + std::size_t size) noexcept + : p_(static_cast< + unsigned char const*>(data)) + , n_(size) + { + } + + /** Constructor. + */ + const_buffer( + const_buffer const&) = default; + + /** Constructor. + */ + const_buffer( + mutable_buffer const& b) noexcept + : p_(static_cast< + unsigned char const*>(b.data())) + , n_(b.size()) + { + } + + /** Assignment. + */ + const_buffer& operator=( + const_buffer const&) = default; + +#ifndef BOOST_BUFFERS_DOCS + // conversion to boost::asio::const_buffer + template< + class T + , class = typename std::enable_if< + std::is_constructible::value && + ! std::is_same::value && + ! std::is_same::value + >::type + > + operator T() const noexcept + { + return T{ data(), size() }; + } +#endif + + void const* + data() const noexcept + { + return p_; + } + + std::size_t + size() const noexcept + { + return n_; + } + + /** Remove a prefix from the buffer. + */ + const_buffer& + operator+=(std::size_t n) noexcept + { + if(n >= n_) + { + p_ = p_ + n_; + n_ = 0; + return *this; + } + p_ = p_ + n; + n_ -= n; + return *this; + } + + /** Return the buffer with a prefix removed. + */ + friend + const_buffer + operator+( + const_buffer b, + std::size_t n) noexcept + { + return b += n; + } + + /** Return the buffer with a prefix removed. + */ + friend + const_buffer + operator+( + std::size_t n, + const_buffer b) noexcept + { + return b += n; + } + +#ifndef BOOST_BUFFERS_DOCS + friend + const_buffer + tag_invoke( + prefix_tag const&, + const_buffer const& b, + std::size_t n) noexcept + { + if(n < b.size()) + return { b.data(), n }; + return b; + } + + friend + const_buffer + tag_invoke( + suffix_tag const&, + const_buffer const& b, + std::size_t n) noexcept + { + auto const n0 = b.size(); + if(n < n0) + return { b.p_ + (n0 - n), n }; + return b; + } +#endif +}; + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/const_buffer_pair.hpp b/include/boost/async/io/buffers/const_buffer_pair.hpp new file mode 100644 index 00000000..65b7cc8c --- /dev/null +++ b/include/boost/async/io/buffers/const_buffer_pair.hpp @@ -0,0 +1,134 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_CONST_BUFFER_PAIR_HPP +#define BOOST_BUFFERS_CONST_BUFFER_PAIR_HPP + +#include +#include +#include +#include + +namespace boost::async::io::buffers { + +/** A constant buffer pair +*/ +class const_buffer_pair +{ +public: + using value_type = const_buffer; + + using const_iterator = value_type const*; + + /** Constructor. + */ + const_buffer_pair() = default; + + /** Constructor. + */ + const_buffer_pair( + const_buffer_pair const&) = default; + + /** Constructor. + */ + const_buffer_pair( + const_buffer const& b0, + const_buffer const& b1) noexcept + : b_{ b0, b1 } + { + } + + /** Constructor. + */ + const_buffer_pair( + mutable_buffer_pair const& bs) noexcept + : b_{ bs.begin()[0], bs.begin()[1] } + { + } + + /** Assignment. + */ + const_buffer_pair& operator=( + const_buffer_pair const&) = default; + + /** Assignment. + */ + const_buffer_pair& operator=( + mutable_buffer_pair const& other) noexcept + { + b_[0] = other.begin()[0]; + b_[1] = other.begin()[1]; + return *this; + } + + const_buffer const& + operator[](unsigned i) const noexcept + { + BOOST_ASSERT(i < 2); + return b_[i]; + } + + const_buffer& + operator[](unsigned i) noexcept + { + BOOST_ASSERT(i < 2); + return b_[i]; + } + + const_iterator + begin() const noexcept + { + return b_; + } + + const_iterator + end() const noexcept + { + return b_ + 2; + } + +#ifndef BOOST_BUFFERS_DOCS + friend + const_buffer_pair + tag_invoke( + prefix_tag const&, + const_buffer_pair const& b, + std::size_t n) noexcept + { + return b.prefix_impl(n); + } + + friend + const_buffer_pair + tag_invoke( + suffix_tag const&, + const_buffer_pair const& b, + std::size_t n) noexcept + { + return b.suffix_impl(n); + } +#endif + +private: + BOOST_ASYNC_DECL + const_buffer_pair + prefix_impl( + std::size_t n) const noexcept; + + BOOST_ASYNC_DECL + const_buffer_pair + suffix_impl( + std::size_t n) const noexcept; + + const_buffer b_[2]; +}; + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/const_buffer_span.hpp b/include/boost/async/io/buffers/const_buffer_span.hpp new file mode 100644 index 00000000..c25fc26c --- /dev/null +++ b/include/boost/async/io/buffers/const_buffer_span.hpp @@ -0,0 +1,142 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_CONST_BUFFER_SPAN_HPP +#define BOOST_BUFFERS_CONST_BUFFER_SPAN_HPP + +#include +#include +#include +#include + +namespace boost::async::io::buffers { + +/** Holds a span of buffers that cannot be modified. + + Objects of this type meet the requirements + of ConstBufferSequence. +*/ +class const_buffer_span +{ + const_buffer const* p_ = nullptr; + std::size_t n_ = 0; + + friend class const_buffer_subspan; + +public: + /** The type of buffer. + */ + using value_type = const_buffer; + + /** The type of iterators returned. + */ + using const_iterator = value_type const*; + + /** Constructor. + */ + const_buffer_span() = default; + + /** Constructor. + */ + const_buffer_span( + const_buffer const* p, + std::size_t n) noexcept + : p_(p) + , n_(n) + { + } + + /** Constructor. + */ + template< + class ConstBufferSequence +#ifndef BOOST_BUFFERS_DOCS + , class = typename std::enable_if< + ! std::is_same< + ConstBufferSequence, + const_buffer_span>::value && + is_const_buffer_sequence< + ConstBufferSequence>::value && + std::is_same().begin()), + const_buffer const*>::value + >::type +#endif + > + explicit + const_buffer_span( + ConstBufferSequence const& bs) noexcept + : p_(bs.begin()) + , n_(bs.end() - bs.begin()) + { + } + + /** Constructor. + */ + const_buffer_span( + const_buffer_span const&) = default; + + /** Assignment. + */ + const_buffer_span& operator=( + const_buffer_span const&) = default; + + /** Return an iterator to the beginning. + */ + const_iterator + begin() const noexcept + { + return p_; + } + + /** Return an iterator to the end. + */ + const_iterator + end() const noexcept + { + return p_ + n_; + } + +#ifndef BOOST_BUFFERS_DOCS + friend + const_buffer_subspan + tag_invoke( + prefix_tag const&, + const_buffer_span const& s, + std::size_t n) noexcept + { + return s.prefix_impl(n); + } + + friend + const_buffer_subspan + tag_invoke( + suffix_tag const&, + const_buffer_span const& s, + std::size_t n) noexcept + { + return s.suffix_impl(n); + } +#endif + +private: + const_buffer_subspan prefix_impl( + std::size_t n) const noexcept; + const_buffer_subspan suffix_impl( + std::size_t n) const noexcept; +}; + +//----------------------------------------------- + +} // boost::buffers + +#include + +#endif diff --git a/include/boost/async/io/buffers/const_buffer_subspan.hpp b/include/boost/async/io/buffers/const_buffer_subspan.hpp new file mode 100644 index 00000000..303be352 --- /dev/null +++ b/include/boost/async/io/buffers/const_buffer_subspan.hpp @@ -0,0 +1,121 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_CONST_BUFFER_SUBSPAN_HPP +#define BOOST_BUFFERS_CONST_BUFFER_SUBSPAN_HPP + +#include +#include + +namespace boost::async::io::buffers { + +#ifndef BOOST_BUFFERS_DOCS +class const_buffer_span; +#endif + +/** Holds a span of buffers that cannot be modified. + + Objects of this type meet the requirements + of ConstBufferSequence. +*/ +class const_buffer_subspan +{ + const_buffer const* p_ = nullptr; + std::size_t n_ = 0; + std::size_t p0_ = 0; + std::size_t p1_ = 0; + + friend class const_buffer_span; + + const_buffer_subspan( + const_buffer const* p, + std::size_t n, + std::size_t p0, + std::size_t p1) noexcept; + +public: + /** The type of buffer. + */ + using value_type = const_buffer; + + /** The type of iterators returned. + */ + class const_iterator; + + /** Constructor. + */ + const_buffer_subspan() = default; + + /** Constructor. + */ + BOOST_ASYNC_DECL + const_buffer_subspan( + const_buffer const* p, + std::size_t n) noexcept; + + /** Constructor. + */ + explicit + const_buffer_subspan( + const_buffer_span const& s) noexcept; + + /** Constructor. + */ + const_buffer_subspan( + const_buffer_subspan const&) = default; + + /** Assignment. + */ + const_buffer_subspan& operator=( + const_buffer_subspan const&) = default; + + /** Return an iterator to the beginning. + */ + const_iterator + begin() const noexcept; + + /** Return an iterator to the end. + */ + const_iterator + end() const noexcept; + +#ifndef BOOST_BUFFERS_DOCS + friend + const_buffer_subspan + tag_invoke( + prefix_tag const&, + const_buffer_subspan const& s, + std::size_t n) noexcept + { + return s.prefix_impl(n); + } + + friend + const_buffer_subspan + tag_invoke( + suffix_tag const&, + const_buffer_subspan const& s, + std::size_t n) noexcept + { + return s.suffix_impl(n); + } +#endif + +private: + BOOST_ASYNC_DECL const_buffer_subspan + prefix_impl(std::size_t n) const noexcept; + BOOST_ASYNC_DECL const_buffer_subspan + suffix_impl(std::size_t n) const noexcept; +}; + +} // boost::buffers + +#include + +#endif diff --git a/include/boost/async/io/buffers/flat_buffer.hpp b/include/boost/async/io/buffers/flat_buffer.hpp new file mode 100644 index 00000000..8eaefcb3 --- /dev/null +++ b/include/boost/async/io/buffers/flat_buffer.hpp @@ -0,0 +1,148 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_FLAT_BUFFER_HPP +#define BOOST_BUFFERS_FLAT_BUFFER_HPP + +#include +#include +#include +#include + +namespace boost::async::io::buffers { + +/** A DynamicBuffer with a fixed capacity +*/ +class flat_buffer +{ + unsigned char* data_ = nullptr; + std::size_t cap_ = 0; + std::size_t in_pos_ = 0; + std::size_t in_size_ = 0; + std::size_t out_size_ = 0; + +public: + using const_buffers_type = + const_buffer; + + using mutable_buffers_type = + mutable_buffer; + + /** Constructor. + */ + flat_buffer() = default; + + /** Constructor. + */ + flat_buffer( + void* data, + std::size_t capacity, + std::size_t initial_size = 0) + : data_(static_cast< + unsigned char*>(data)) + , cap_(capacity) + , in_size_(initial_size) + { + // initial size too large + if(in_size_ > cap_) + async::detail::throw_invalid_argument(); + } + + /** Constructor. + */ + explicit + flat_buffer( + mutable_buffer const& b, + std::size_t initial_size = 0) + : flat_buffer( + b.data(), + b.size(), + initial_size) + { + } + + /** Constructor. + */ + flat_buffer( + flat_buffer const&) = default; + + /** Constructor. + */ + flat_buffer& operator=( + flat_buffer const&) = default; + + std::size_t + size() const noexcept + { + return in_size_; + } + + std::size_t + max_size() const noexcept + { + return cap_; + } + + std::size_t + capacity() const noexcept + { + return cap_ - in_pos_; + } + + const_buffers_type + data() const noexcept + { + return { + data_ + in_pos_, + in_size_ }; + } + + mutable_buffers_type + prepare(std::size_t n) + { + // n exceeds available space + if(n > cap_ - in_size_) + async::detail::throw_invalid_argument(); + + out_size_ = n; + return { data_ + + in_pos_ + in_size_, n }; + } + + void + commit( + std::size_t n) noexcept + { + if(n < out_size_) + in_size_ += n; + else + in_size_ += out_size_; + out_size_ = 0; + } + + void + consume( + std::size_t n) noexcept + { + if(n < in_size_) + { + in_pos_ += n; + in_size_ -= n; + } + else + { + in_pos_ = 0; + in_size_ = 0; + } + } +}; + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/impl/const_buffer_span.hpp b/include/boost/async/io/buffers/impl/const_buffer_span.hpp new file mode 100644 index 00000000..61016a90 --- /dev/null +++ b/include/boost/async/io/buffers/impl/const_buffer_span.hpp @@ -0,0 +1,56 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_IMPL_CONST_BUFFER_SPAN_HPP +#define BOOST_BUFFERS_IMPL_CONST_BUFFER_SPAN_HPP + +namespace boost::async::io::buffers { + +inline +const_buffer_subspan +const_buffer_span:: +prefix_impl( + std::size_t n) const noexcept +{ + return const_buffer_subspan( + *this).prefix_impl(n); +} + +inline +const_buffer_subspan +const_buffer_span:: +suffix_impl( + std::size_t n) const noexcept +{ + return const_buffer_subspan( + *this).suffix_impl(n); +} + +//----------------------------------------------- + +// here because circular dependency +inline +const_buffer_subspan:: +const_buffer_subspan( + const_buffer_span const& s) noexcept + : p_(s.p_) + , n_(s.n_) + , p1_([&]() -> std::size_t + { + if(n_ > 0) + return p_[n_-1].size(); + return 0; + }()) +{ +} + + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/impl/const_buffer_subspan.hpp b/include/boost/async/io/buffers/impl/const_buffer_subspan.hpp new file mode 100644 index 00000000..e48d0bb0 --- /dev/null +++ b/include/boost/async/io/buffers/impl/const_buffer_subspan.hpp @@ -0,0 +1,144 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_IMPL_CONST_BUFFER_SUBSPAN_HPP +#define BOOST_BUFFERS_IMPL_CONST_BUFFER_SUBSPAN_HPP + +#include +#include + +namespace boost::async::io::buffers { + +class const_buffer_subspan:: + const_iterator +{ + const_buffer_subspan const* s_ = nullptr; + std::size_t i_ = 0; + + friend class const_buffer_subspan; + + const_iterator( + const_buffer_subspan const& s, + std::size_t i) noexcept + : s_(&s) + , i_(i) + { + } + +public: + using value_type = const_buffer; + using reference = const_buffer; + using pointer = void; + using difference_type = std::ptrdiff_t; + using iterator_category = + std::bidirectional_iterator_tag; + + const_iterator() = default; + const_iterator( + const_iterator const&) = default; + const_iterator& operator=( + const_iterator const&) = default; + + bool + operator==( + const_iterator const& other) const noexcept + { + return + s_ == other.s_ && + i_ == other.i_; + } + + bool + operator!=( + const_iterator const& other) const noexcept + { + return !(*this == other); + } + + BOOST_ASYNC_DECL + reference + operator*() const noexcept; + + const_iterator& + operator++() noexcept + { + BOOST_ASSERT(i_ < s_->n_); + ++i_; + return *this; + } + + const_iterator + operator++(int) noexcept + { + auto temp = *this; + ++(*this); + return temp; + } + + const_iterator& + operator--() noexcept + { + BOOST_ASSERT(i_ > 0); + --i_; + return *this; + } + + const_iterator + operator--(int) noexcept + { + auto temp = *this; + --(*this); + return temp; + } +}; + +inline +auto +const_buffer_subspan:: +begin() const noexcept -> + const_iterator +{ + return { *this, 0 }; +} + +inline +auto +const_buffer_subspan:: +end() const noexcept -> + const_iterator +{ + return { *this, n_ }; +} + +inline +const_buffer_subspan:: +const_buffer_subspan( + const_buffer const* p, + std::size_t n, + std::size_t p0, + std::size_t p1) noexcept + : p_(p) + , n_(n) + , p0_(p0) + , p1_(p1) +{ + BOOST_ASSERT( + n_ > 1 || + p1_ >= p0_); + BOOST_ASSERT( + n_ == 0 || + p0 < p[0].size()); + BOOST_ASSERT( + n_ == 0 || + p1 <= p[n_ - 1].size()); +} + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/impl/mutable_buffer_span.hpp b/include/boost/async/io/buffers/impl/mutable_buffer_span.hpp new file mode 100644 index 00000000..75df2660 --- /dev/null +++ b/include/boost/async/io/buffers/impl/mutable_buffer_span.hpp @@ -0,0 +1,55 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_IMPL_MUTABLE_BUFFER_SPAN_HPP +#define BOOST_BUFFERS_IMPL_MUTABLE_BUFFER_SPAN_HPP + +namespace boost::async::io::buffers { + +inline +mutable_buffer_subspan +mutable_buffer_span:: +prefix_impl( + std::size_t n) const noexcept +{ + return mutable_buffer_subspan( + *this).prefix_impl(n); +} + +inline +mutable_buffer_subspan +mutable_buffer_span:: +suffix_impl( + std::size_t n) const noexcept +{ + return mutable_buffer_subspan( + *this).suffix_impl(n); +} + +//----------------------------------------------- + +// here because circular dependency +inline +mutable_buffer_subspan:: +mutable_buffer_subspan( + mutable_buffer_span const& s) noexcept + : p_(s.p_) + , n_(s.n_) + , p1_([&]() -> std::size_t + { + if(n_ > 0) + return p_[n_-1].size(); + return 0; + }()) +{ +} + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/impl/mutable_buffer_subspan.hpp b/include/boost/async/io/buffers/impl/mutable_buffer_subspan.hpp new file mode 100644 index 00000000..9ddf17bc --- /dev/null +++ b/include/boost/async/io/buffers/impl/mutable_buffer_subspan.hpp @@ -0,0 +1,144 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_IMPL_MUTABLE_BUFFER_SUBSPAN_HPP +#define BOOST_BUFFERS_IMPL_MUTABLE_BUFFER_SUBSPAN_HPP + +#include +#include + +namespace boost::async::io::buffers { + +class mutable_buffer_subspan:: + const_iterator +{ + mutable_buffer_subspan const* s_ = nullptr; + std::size_t i_ = 0; + + friend class mutable_buffer_subspan; + + const_iterator( + mutable_buffer_subspan const& s, + std::size_t i) noexcept + : s_(&s) + , i_(i) + { + } + +public: + using value_type = mutable_buffer; + using reference = mutable_buffer; + using pointer = void; + using difference_type = std::ptrdiff_t; + using iterator_category = + std::bidirectional_iterator_tag; + + const_iterator() = default; + const_iterator( + const_iterator const&) = default; + const_iterator& operator=( + const_iterator const&) = default; + + bool + operator==( + const_iterator const& other) const noexcept + { + return + s_ == other.s_ && + i_ == other.i_; + } + + bool + operator!=( + const_iterator const& other) const noexcept + { + return !(*this == other); + } + + BOOST_ASYNC_DECL + reference + operator*() const noexcept; + + const_iterator& + operator++() noexcept + { + BOOST_ASSERT(i_ < s_->n_); + ++i_; + return *this; + } + + const_iterator + operator++(int) noexcept + { + auto temp = *this; + ++(*this); + return temp; + } + + const_iterator& + operator--() noexcept + { + BOOST_ASSERT(i_ > 0); + --i_; + return *this; + } + + const_iterator + operator--(int) noexcept + { + auto temp = *this; + --(*this); + return temp; + } +}; + +inline +auto +mutable_buffer_subspan:: +begin() const noexcept -> + const_iterator +{ + return { *this, 0 }; +} + +inline +auto +mutable_buffer_subspan:: +end() const noexcept -> + const_iterator +{ + return { *this, n_ }; +} + +inline +mutable_buffer_subspan:: +mutable_buffer_subspan( + mutable_buffer const* p, + std::size_t n, + std::size_t p0, + std::size_t p1) noexcept + : p_(p) + , n_(n) + , p0_(p0) + , p1_(p1) +{ + BOOST_ASSERT( + n_ > 1 || + p1_ >= p0_); + BOOST_ASSERT( + n_ == 0 || + p0 < p[0].size()); + BOOST_ASSERT( + n_ == 0 || + p1 <= p[n_ - 1].size()); +} + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/mutable_buffer.hpp b/include/boost/async/io/buffers/mutable_buffer.hpp new file mode 100644 index 00000000..372e7f07 --- /dev/null +++ b/include/boost/async/io/buffers/mutable_buffer.hpp @@ -0,0 +1,165 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_MUTABLE_BUFFER_HPP +#define BOOST_BUFFERS_MUTABLE_BUFFER_HPP + +#include +#include +#include +#include + +namespace boost::async::io::buffers { + +/** Holds a buffer that can be modified. +*/ +class mutable_buffer +{ + unsigned char* p_ = nullptr; + std::size_t n_ = 0; + +public: + using value_type = mutable_buffer; + using const_iterator = + value_type const*; + + /** Constructor. + */ + mutable_buffer() = default; + + /** Constructor. + */ + mutable_buffer( + mutable_buffer const&) = default; + + /** Constructor. + */ + mutable_buffer( + void* data, + std::size_t size) noexcept + : p_(static_cast< + unsigned char*>(data)) + , n_(size) + { + } + + /** Assignment. + */ + mutable_buffer& operator=( + mutable_buffer const&) = default; + +#ifndef BOOST_BUFFERS_DOCS + // conversion to boost::asio::mutable_buffer + template< + class T + , class = typename std::enable_if< + std::is_constructible::value + && ! std::is_same::value + //&& ! std::is_same::value + >::type + > + operator T() const noexcept + { + return T{ data(), size() }; + } +#endif + + void* + data() const noexcept + { + return p_; + } + + std::size_t + size() const noexcept + { + return n_; + } + + const_iterator + begin() const noexcept + { + return this; + } + + const_iterator + end() const noexcept + { + return this + 1; + } + + /** Remove a prefix from the buffer. + */ + mutable_buffer& + operator+=(std::size_t n) noexcept + { + if(n >= n_) + { + p_ = p_ + n_; + n_ = 0; + return *this; + } + p_ = p_ + n; + n_ -= n; + return *this; + } + + /** Return the buffer with a prefix removed. + */ + friend + mutable_buffer + operator+( + mutable_buffer b, + std::size_t n) noexcept + { + return b += n; + } + + /** Return the buffer with a prefix removed. + */ + friend + mutable_buffer + operator+( + std::size_t n, + mutable_buffer b) noexcept + { + return b += n; + } + +#ifndef BOOST_BUFFER_DOCS + friend + mutable_buffer + tag_invoke( + prefix_tag const&, + mutable_buffer const& b, + std::size_t n) noexcept + { + if(n < b.size()) + return { b.p_, n }; + return b; + } + + friend + mutable_buffer + tag_invoke( + suffix_tag const&, + mutable_buffer const& b, + std::size_t n) noexcept + { + if(n < b.size()) + return { b.p_ + b.n_ - n, n }; + return b; + } +#endif +}; + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/mutable_buffer_pair.hpp b/include/boost/async/io/buffers/mutable_buffer_pair.hpp new file mode 100644 index 00000000..326c7c24 --- /dev/null +++ b/include/boost/async/io/buffers/mutable_buffer_pair.hpp @@ -0,0 +1,115 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_MUTABLE_BUFFER_PAIR_HPP +#define BOOST_BUFFERS_MUTABLE_BUFFER_PAIR_HPP + +#include +#include +#include + +namespace boost::async::io::buffers { + +/** A mutable buffer pair +*/ +class mutable_buffer_pair +{ +public: + using value_type = mutable_buffer; + + using const_iterator = value_type const*; + + /** Constructor. + */ + mutable_buffer_pair() = default; + + /** Constructor. + */ + mutable_buffer_pair( + mutable_buffer_pair const&) = default; + + /** Constructor. + */ + mutable_buffer_pair( + mutable_buffer const& b0, + mutable_buffer const& b1) noexcept + : b_{ b0, b1 } + { + } + + /** Assignment. + */ + mutable_buffer_pair& operator=( + mutable_buffer_pair const&) = default; + + mutable_buffer const& + operator[](unsigned i) const noexcept + { + BOOST_ASSERT(i < 2); + return b_[i]; + } + + mutable_buffer& + operator[](unsigned i) noexcept + { + BOOST_ASSERT(i < 2); + return b_[i]; + } + + const_iterator + begin() const noexcept + { + return b_; + } + + const_iterator + end() const noexcept + { + return b_ + 2; + } + +#ifndef BOOST_BUFFERS_DOCS + friend + mutable_buffer_pair + tag_invoke( + prefix_tag const&, + mutable_buffer_pair const& b, + std::size_t n) noexcept + { + return b.prefix_impl(n); + } + + friend + mutable_buffer_pair + tag_invoke( + suffix_tag const&, + mutable_buffer_pair const& b, + std::size_t n) noexcept + { + return b.suffix_impl(n); + } +#endif + +private: + BOOST_ASYNC_DECL + mutable_buffer_pair + prefix_impl( + std::size_t n) const noexcept; + + BOOST_ASYNC_DECL + mutable_buffer_pair + suffix_impl( + std::size_t n) const noexcept; + + mutable_buffer b_[2]; +}; + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/mutable_buffer_span.hpp b/include/boost/async/io/buffers/mutable_buffer_span.hpp new file mode 100644 index 00000000..e3abec84 --- /dev/null +++ b/include/boost/async/io/buffers/mutable_buffer_span.hpp @@ -0,0 +1,140 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_MUTABLE_BUFFER_SPAN_HPP +#define BOOST_BUFFERS_MUTABLE_BUFFER_SPAN_HPP + +#include +#include +#include +#include + +namespace boost::async::io::buffers { + +/** Holds a span of buffers that are modifiable. + + Objects of this type meet the requirements + of MutableBufferSequence. +*/ +class mutable_buffer_span +{ + mutable_buffer const* p_ = nullptr; + std::size_t n_ = 0; + + friend class mutable_buffer_subspan; + +public: + /** The type of buffer. + */ + using value_type = mutable_buffer; + + /** The type of iterators returned. + */ + using const_iterator = value_type const*; + + /** Constructor. + */ + mutable_buffer_span() = default; + + /** Constructor. + */ + mutable_buffer_span( + mutable_buffer const* p, + std::size_t n) noexcept + : p_(p) + , n_(n) + { + } + + /** Constructor. + */ + template< + class MutableBufferSequence +#ifndef BOOST_BUFFERS_DOCS + , class = typename std::enable_if< + ! std::is_same< + MutableBufferSequence, + mutable_buffer_span>::value && + is_mutable_buffer_sequence< + MutableBufferSequence>::value && + std::is_same().begin()), + mutable_buffer const*>::value + >::type +#endif + > + explicit + mutable_buffer_span( + MutableBufferSequence const& bs) noexcept + : p_(bs.begin()) + , n_(bs.end() - bs.begin()) + { + } + + /** Constructor. + */ + mutable_buffer_span( + mutable_buffer_span const&) = default; + + /** Assignment. + */ + mutable_buffer_span& operator=( + mutable_buffer_span const&) = default; + + /** Return an iterator to the beginning. + */ + const_iterator + begin() const noexcept + { + return p_; + } + + /** Return an iterator to the end. + */ + const_iterator + end() const noexcept + { + return p_ + n_; + } + +#ifndef BOOST_BUFFERS_DOCS + friend + mutable_buffer_subspan + tag_invoke( + prefix_tag const&, + mutable_buffer_span const& s, + std::size_t n) noexcept + { + return s.prefix_impl(n); + } + + friend + mutable_buffer_subspan + tag_invoke( + suffix_tag const&, + mutable_buffer_span const& s, + std::size_t n) noexcept + { + return s.suffix_impl(n); + } +#endif + +private: + mutable_buffer_subspan prefix_impl( + std::size_t n) const noexcept; + mutable_buffer_subspan suffix_impl( + std::size_t n) const noexcept; +}; + +} // boost::buffers + +#include + +#endif diff --git a/include/boost/async/io/buffers/mutable_buffer_subspan.hpp b/include/boost/async/io/buffers/mutable_buffer_subspan.hpp new file mode 100644 index 00000000..e3c53399 --- /dev/null +++ b/include/boost/async/io/buffers/mutable_buffer_subspan.hpp @@ -0,0 +1,121 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_MUTABLE_BUFFER_SUBSPAN_HPP +#define BOOST_BUFFERS_MUTABLE_BUFFER_SUBSPAN_HPP + +#include +#include + +namespace boost::async::io::buffers { + +#ifndef BOOST_BUFFERS_DOCS +class mutable_buffer_span; +#endif + +/** Holds a span of buffers whose contents are modifiable. + + Objects of this type meet the requirements + of MutableBufferSequence. +*/ +class mutable_buffer_subspan +{ + mutable_buffer const* p_ = nullptr; + std::size_t n_ = 0; + std::size_t p0_ = 0; + std::size_t p1_ = 0; + + friend class mutable_buffer_span; + + mutable_buffer_subspan( + mutable_buffer const* p, + std::size_t n, + std::size_t p0, + std::size_t p1) noexcept; + +public: + /** The type of buffer. + */ + using value_type = mutable_buffer; + + /** The type of iterators returned. + */ + class const_iterator; + + /** Constructor. + */ + mutable_buffer_subspan() = default; + + /** Constructor. + */ + BOOST_ASYNC_DECL + mutable_buffer_subspan( + mutable_buffer const* p, + std::size_t n) noexcept; + + /** Constructor. + */ + explicit + mutable_buffer_subspan( + mutable_buffer_span const& s) noexcept; + + /** Constructor. + */ + mutable_buffer_subspan( + mutable_buffer_subspan const&) = default; + + /** Assignment. + */ + mutable_buffer_subspan& operator=( + mutable_buffer_subspan const&) = default; + + /** Return an iterator to the beginning. + */ + const_iterator + begin() const noexcept; + + /** Return an iterator to the end. + */ + const_iterator + end() const noexcept; + +#ifndef BOOST_BUFFERS_DOCS + friend + mutable_buffer_subspan + tag_invoke( + prefix_tag const&, + mutable_buffer_subspan const& s, + std::size_t n) noexcept + { + return s.prefix_impl(n); + } + + friend + mutable_buffer_subspan + tag_invoke( + suffix_tag const&, + mutable_buffer_subspan const& s, + std::size_t n) noexcept + { + return s.suffix_impl(n); + } +#endif + +private: + BOOST_ASYNC_DECL mutable_buffer_subspan + prefix_impl(std::size_t n) const noexcept; + BOOST_ASYNC_DECL mutable_buffer_subspan + suffix_impl(std::size_t n) const noexcept; +}; + +} // boost::buffers + +#include + +#endif diff --git a/include/boost/async/io/buffers/range.hpp b/include/boost/async/io/buffers/range.hpp new file mode 100644 index 00000000..b446144c --- /dev/null +++ b/include/boost/async/io/buffers/range.hpp @@ -0,0 +1,237 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_RANGE_HPP +#define BOOST_BUFFERS_RANGE_HPP + +#include +#include +#include +#include +#include + +namespace boost::async::io::buffers { + +#ifdef BOOST_BUFFERS_DOCS + +/** Return an iterator to the beginning of the buffer sequence. +*/ +template +__see_below__ +begin(BufferSequence&& b) noexcept; + +/** Return an iterator to the end of the buffer sequence. +*/ +template +__see_below__ +end(BufferSequence&& b) noexcept; + +/** Return a range representing the buffer sequence. +*/ +template +__see_below__ +range(BufferSequence&& bs) noexcept; + +#else + +namespace detail { + +struct begin_impl +{ + template + auto + operator()( + MutableBuffer const& b) const noexcept -> + typename std::enable_if< + std::is_convertible< + MutableBuffer const*, + mutable_buffer const*>::value, + mutable_buffer const*>::type + { + return static_cast< + mutable_buffer const*>( + std::addressof(b)); + } + + template + auto + operator()( + ConstBuffer const& b) const noexcept -> + typename std::enable_if< + std::is_convertible< + ConstBuffer const*, + const_buffer const*>::value, + const_buffer const*>::type + { + return static_cast< + const_buffer const*>( + std::addressof(b)); + } + + template + auto + operator()( + BufferSequence& bs) const noexcept -> + typename std::enable_if< + ! std::is_convertible< + BufferSequence const*, + const_buffer const*>::value && + ! std::is_convertible< + BufferSequence const*, + mutable_buffer const*>::value, + decltype(bs.begin())>::type + { + return bs.begin(); + } + + template + auto + operator()( + BufferSequence const& bs) const noexcept -> + typename std::enable_if< + ! std::is_convertible< + BufferSequence const*, + const_buffer const*>::value && + ! std::is_convertible< + BufferSequence const*, + mutable_buffer const*>::value, + decltype(bs.begin())>::type + { + return bs.begin(); + } +}; + +struct end_impl +{ + template + auto + operator()( + MutableBuffer const& b) const noexcept -> + typename std::enable_if< + std::is_convertible< + MutableBuffer const*, + mutable_buffer const*>::value, + mutable_buffer const*>::type + { + return static_cast< + mutable_buffer const*>( + std::addressof(b)) + 1; + } + + template + auto + operator()( + ConstBuffer const& b) const noexcept -> + typename std::enable_if< + std::is_convertible< + ConstBuffer const*, + const_buffer const*>::value, + const_buffer const*>::type + { + return static_cast< + const_buffer const*>( + std::addressof(b)) + 1; + } + + template + auto + operator()( + BufferSequence& bs) const noexcept -> + typename std::enable_if< + ! std::is_convertible< + BufferSequence const*, + const_buffer const*>::value && + ! std::is_convertible< + BufferSequence const*, + mutable_buffer const*>::value, + decltype(bs.end())>::type + { + return bs.end(); + } + + template + auto + operator()( + BufferSequence const& bs) const noexcept -> + typename std::enable_if< + ! std::is_convertible< + BufferSequence const*, + const_buffer const*>::value && + ! std::is_convertible< + BufferSequence const*, + mutable_buffer const*>::value, + decltype(bs.end())>::type + { + return bs.end(); + } +}; + +} // detail + +constexpr detail::begin_impl begin{}; +constexpr detail::end_impl end{}; + +//------------------------------------------------ + +namespace detail { + +template +class iter_range +{ + using begin_type = decltype( + buffers::begin(std::declval())); + using end_type = decltype( + buffers::end(std::declval())); + + begin_type begin_; + end_type end_; + +public: + iter_range(T& t) noexcept + : begin_(buffers::begin(t)) + , end_(buffers::end(t)) + { + } + + begin_type + begin() const noexcept + { + return begin_; + } + + end_type + end() const noexcept + { + return end_; + } +}; + +struct range_impl +{ + template + auto + operator()( + BufferSequence&& bs) const noexcept -> + iter_range::type> + { + return { bs }; + } +}; + +} // detail + +constexpr detail::range_impl range{}; + +#endif + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/string_buffer.hpp b/include/boost/async/io/buffers/string_buffer.hpp new file mode 100644 index 00000000..e41a49b2 --- /dev/null +++ b/include/boost/async/io/buffers/string_buffer.hpp @@ -0,0 +1,162 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_STRING_BUFFER_HPP +#define BOOST_BUFFERS_STRING_BUFFER_HPP + +#include +#include +#include +#include +#include + +namespace boost::async::io::buffers { + +/** A dynamic buffer using an underlying string +*/ +template< + class CharT, + class Traits = std::char_traits, + class Allocator = std::allocator> +class basic_string_buffer +{ + std::basic_string< + CharT, Traits, Allocator>* s_; + std::size_t max_size_; + +public: + using string_type = std::basic_string< + CharT, Traits, Allocator>; + + unsigned char* data_ = nullptr; + std::size_t in_size_ = 0; + std::size_t out_size_ = 0; + +public: + using const_buffers_type = + const_buffer; + + using mutable_buffers_type = + mutable_buffer; + + ~basic_string_buffer() + { + if(s_) + s_->resize(in_size_); + } + + /** Constructor. + */ + basic_string_buffer( + basic_string_buffer&& other) noexcept + : s_(other.s_) + , max_size_(other.max_size_) + { + other.s_ = nullptr; + } + + /** Constructor. + */ + explicit + basic_string_buffer( + string_type* s, + std::size_t max_size = + std::size_t(-1)) noexcept + : s_(s) + , max_size_( + max_size > s_->max_size() + ? s_->max_size() + : max_size) + { + if(s_->size() > max_size_) + s_->resize(max_size_); + in_size_ = s_->size(); + } + + /** Assignment. + */ + basic_string_buffer& operator=( + basic_string_buffer const&) = delete; + + std::size_t + size() const noexcept + { + return in_size_; + } + + std::size_t + max_size() const noexcept + { + return max_size_; + } + + std::size_t + capacity() const noexcept + { + if(s_->capacity() <= max_size_) + return s_->capacity() - in_size_; + return max_size_ - in_size_; + } + + const_buffers_type + data() const noexcept + { + return { + s_->data(), + in_size_ }; + } + + mutable_buffers_type + prepare(std::size_t n) + { + // n exceeds available space + if(n > max_size_ - in_size_) + async::detail::throw_invalid_argument(); + + if( s_->size() < in_size_ + n) + s_->resize(in_size_ + n); + out_size_ = n; + return { + &(*s_)[in_size_], + out_size_ }; + } + + void + commit( + std::size_t n) noexcept + { + if(n < out_size_) + in_size_ += n; + else + in_size_ += out_size_; + out_size_ = 0; + } + + void + consume( + std::size_t n) noexcept + { + if(n < in_size_) + { + s_->erase(0, n); + in_size_ -= n; + } + else + { + in_size_ = 0; + } + out_size_ = 0; + } +}; + +using string_buffer = basic_string_buffer; + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/tag_invoke.hpp b/include/boost/async/io/buffers/tag_invoke.hpp new file mode 100644 index 00000000..1d1742a1 --- /dev/null +++ b/include/boost/async/io/buffers/tag_invoke.hpp @@ -0,0 +1,31 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_TAG_INVOKE_HPP +#define BOOST_BUFFERS_TAG_INVOKE_HPP + +#include + +namespace boost::async::io::buffers { + +/** size tag for tag_invoke. +*/ +struct size_tag {}; + +/** prefix tag for tag_invoke. +*/ +struct prefix_tag {}; + +/** suffix tag for tag-invoke. +*/ +struct suffix_tag {}; + +} // boost::buffers + +#endif diff --git a/include/boost/async/io/buffers/type_traits.hpp b/include/boost/async/io/buffers/type_traits.hpp new file mode 100644 index 00000000..0d837169 --- /dev/null +++ b/include/boost/async/io/buffers/type_traits.hpp @@ -0,0 +1,249 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_TYPE_TRAITS_HPP +#define BOOST_BUFFERS_TYPE_TRAITS_HPP + +#include +#include +#include + +namespace boost::async::io::buffers { + +#ifndef BOOST_BUFFERS_DOCS +class const_buffer; +class mutable_buffer; +#endif + +// https://www.boost.org/doc/libs/1_65_0/doc/html/boost_asio/reference/ConstBufferSequence.html + +/** Determine if T is a ConstBuffers. +*/ +#if BOOST_BUFFERS_DOCS +template +struct is_const_buffer_sequence + : std::integral_constant{}; +#else + +template +struct is_const_buffer_sequence + : std::false_type +{ +}; + +template +struct is_const_buffer_sequence + : is_const_buffer_sequence::type> +{ +}; + +template +struct is_const_buffer_sequence + : is_const_buffer_sequence::type> +{ +}; + +template +struct is_const_buffer_sequence + : is_const_buffer_sequence::type> +{ +}; + +template<> +struct is_const_buffer_sequence< + const_buffer> + : std::true_type +{ +}; + +template<> +struct is_const_buffer_sequence< + mutable_buffer> + : std::true_type +{ +}; + +template +struct is_const_buffer_sequence::value + || std::is_same::value + ) && + detail::is_bidirectional_iterator::value && + std::is_same().begin()) + >::value && + std::is_same().end()) + >::value && ( + std::is_same::value_type>::type + >::value || + std::is_same::value_type>::type + >::value) + // VFALCO This causes problems when the + // trait is used to constrain ctors + // && std::is_move_constructible::value + >::type + > > : std::true_type +{ +}; + +#endif + +/** Determine if T is a MutableBuffers. +*/ +#if BOOST_BUFFERS_DOCS +template +struct is_mutable_buffer_sequence + : std::integral_constant{}; +#else + +template +struct is_mutable_buffer_sequence : std::false_type +{ +}; + +template +struct is_mutable_buffer_sequence + : is_mutable_buffer_sequence::type> +{ +}; + +template +struct is_mutable_buffer_sequence + : is_mutable_buffer_sequence::type> +{ +}; + +template +struct is_mutable_buffer_sequence + : is_mutable_buffer_sequence::type> +{ +}; + +template<> +struct is_mutable_buffer_sequence< + mutable_buffer> + : std::true_type +{ +}; + +template +struct is_mutable_buffer_sequence::value && + detail::is_bidirectional_iterator::value && + std::is_same().begin()) + >::value && + std::is_same().end()) + >::value && + std::is_same::value_type>::type + >::value + // VFALCO This causes problems when the + // trait is used to constrain ctors + // && std::is_move_constructible::value + >::type + >> : std::true_type +{ +}; + +#endif + +//------------------------------------------------ + +/** Determine if T is a DynamicBuffer +*/ +#if BOOST_BUFFERS_DOCS +template +struct is_dynamic_buffer + : std::integral_constant{}; +#else + +template< + class T, + class = void> +struct is_dynamic_buffer : std::false_type {}; + +template +struct is_dynamic_buffer< + T, std::void_t() = + std::declval().size() + ,std::declval() = + std::declval().max_size() + ,std::declval() = + std::declval().capacity() + ,std::declval().commit( + std::declval()) + ,std::declval().consume( + std::declval()) + ) + ,typename std::enable_if< + is_const_buffer_sequence::value + && is_mutable_buffer_sequence::value + >::type + ,typename std::enable_if< + std::is_same().data()), + typename T::const_buffers_type>::value + && std::is_same().prepare( + std::declval())), + typename T::mutable_buffers_type>::value + >::type + > > : std::true_type +{ +}; + +/** Return the underlying buffer type of a sequence. +*/ +template +using value_type = typename + std::conditional< + is_mutable_buffer_sequence::value, + mutable_buffer, + const_buffer + >::type; + +#endif + +} // boost::buffers + +#endif diff --git a/src/detail/exception.cpp b/src/detail/exception.cpp index 1269aad9..3eeda915 100644 --- a/src/detail/exception.cpp +++ b/src/detail/exception.cpp @@ -62,5 +62,22 @@ std::exception_ptr allocation_failed() return ep; } +void +throw_invalid_argument( + source_location const& loc) +{ + throw_exception( + std::invalid_argument( + "invalid argument"), loc); +} + +void +throw_length_error( + source_location const& loc) +{ + throw_exception( + std::length_error( + "length error"), loc); +} } diff --git a/src/io/buffers/circular_buffer.cpp b/src/io/buffers/circular_buffer.cpp new file mode 100644 index 00000000..9f59efb8 --- /dev/null +++ b/src/io/buffers/circular_buffer.cpp @@ -0,0 +1,94 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#include +#include +#include +#include +#include + +namespace boost::async::io::buffers { + +BOOST_STATIC_ASSERT( + is_dynamic_buffer< + circular_buffer>::value); + +auto +circular_buffer:: +data() const noexcept -> + const_buffers_type +{ + if(in_pos_ + in_len_ <= cap_) + return { + const_buffer{ + base_ + in_pos_, in_len_ }, + const_buffer{ base_, 0} }; + return { + const_buffer{ + base_ + in_pos_, cap_ - in_pos_}, + const_buffer{ + base_, in_len_- (cap_ - in_pos_)}}; +} + +auto +circular_buffer:: +prepare(std::size_t n) -> + mutable_buffers_type +{ + // Buffer is too small for n + if(n > cap_ - in_len_) + detail::throw_length_error(); + + out_size_ = n; + auto const pos = ( + in_pos_ + in_len_) % cap_; + if(pos + n <= cap_) + return { + mutable_buffer{ + base_ + pos, n}, + mutable_buffer{base_, 0}}; + return { + mutable_buffer{ + base_ + pos, cap_ - pos}, + mutable_buffer{ + base_, n - (cap_ - pos)}}; +} + +void +circular_buffer:: +commit( + std::size_t n) noexcept +{ + if(n < out_size_) + in_len_ += n; + else + in_len_ += out_size_; + out_size_ = 0; +} + +void +circular_buffer:: +consume( + std::size_t n) noexcept +{ + if(n < in_len_) + { + in_pos_ = (in_pos_ + n) % cap_; + in_len_ -= n; + } + else + { + // make prepare return a + // bigger single buffer + in_pos_ = 0; + in_len_ = 0; + } +} + +} // boost::buffers diff --git a/src/io/buffers/const_buffer_pair.cpp b/src/io/buffers/const_buffer_pair.cpp new file mode 100644 index 00000000..fb1b47b1 --- /dev/null +++ b/src/io/buffers/const_buffer_pair.cpp @@ -0,0 +1,53 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#include + +namespace boost::async::io::buffers { + +const_buffer_pair +const_buffer_pair:: +prefix_impl( + std::size_t n) const noexcept +{ + auto const it0 = begin(); + if(n <= it0->size()) + return { { + it0->data(), n }, + const_buffer{} }; + n -= it0->size(); + auto it1 = it0; + ++it1; + if(n < it1->size()) + return { *it0, { + it1->data(), n } }; + return *this; +} + +const_buffer_pair +const_buffer_pair:: +suffix_impl( + std::size_t n) const noexcept +{ + auto it0 = end(); + --it0; + if(n <= it0->size()) + return { *it0 + ( + it0->size() - n), + const_buffer{} }; + n -= it0->size(); + auto it1 = it0; + --it1; + if(n < it1->size()) + return { *it1 + ( + it1->size() - n), *it0 }; + return *this; +} + +} // boost::buffers diff --git a/src/io/buffers/const_buffer_subspan.cpp b/src/io/buffers/const_buffer_subspan.cpp new file mode 100644 index 00000000..daf2f729 --- /dev/null +++ b/src/io/buffers/const_buffer_subspan.cpp @@ -0,0 +1,154 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#include +#include +#include + +namespace boost::async::io::buffers { + +auto +const_buffer_subspan:: +const_iterator:: +operator*() const noexcept -> + reference +{ + BOOST_ASSERT(s_->n_ > 0); + auto b = s_->p_[i_]; + if(s_->n_ > 1) + { + if(i_ > 0) + { + if(i_ < s_->n_ - 1) + return b; + return prefix(b, s_->p1_); + } + return sans_prefix(b, s_->p0_); + } + return { static_cast< + unsigned char const*>( + b.data()) + s_->p0_, + s_->p1_ - s_->p0_ }; +} + +const_buffer_subspan:: +const_buffer_subspan( + const_buffer const* p, + std::size_t n) noexcept + : p_(p) + , n_(n) + , p1_([&]() -> std::size_t + { + if(n > 0) + return p[n-1].size(); + return 0; + }()) +{ +} + +const_buffer_subspan +const_buffer_subspan:: +prefix_impl( + std::size_t n) const noexcept +{ + switch(n_) + { + case 0: + { + return *this; + } + case 1: + { + if(n == 0) + return { p_, 0, p0_, p0_ }; + if(n == std::size_t(-1)) + return *this; + auto const d = p1_ - p0_; + if(n <= d) + return { p_, 1, p0_, p0_ + n }; + return *this; + } + default: + { + if(n == 0) + return { p_, 0, p0_, p0_ }; + if(n == std::size_t(-1)) + return *this; + auto d = p_[0].size() - p0_; + if(n <= d) + return { p_, 1, p0_, p0_ + n }; + n -= d; + std::size_t i = 1; + for(;;) + { + if(i == n_ - 1) + break; + if(n <= p_[i].size()) + return { p_, i + 1, p0_, n }; + n -= p_[i].size(); + ++i; + } + if(n <= p1_) + return { p_, n_, p0_, n }; + return { p_, n_, p0_, p1_ }; + } + } +} + +const_buffer_subspan +const_buffer_subspan:: +suffix_impl( + std::size_t n) const noexcept +{ + switch(n_) + { + case 0: + { + return *this; + } + case 1: + { + if(n == 0) + return { p_, 0, p1_, p1_ }; + if(n == std::size_t(-1)) + return *this; + auto const d = p1_ - p0_; + if(n < d) + return { p_, 1, p1_ - n, p1_ }; + return *this; + } + default: + { + if(n == 0) + return { p_, 0, p1_, p1_ }; + if(n == std::size_t(-1)) + return *this; + std::size_t i = n_ - 1; + if(n <= p1_) + return { p_ + i, 1, p1_ - n, p1_ }; + n -= p1_; + for(;;) + { + if(--i == 0) + break; + if(n <= p_[i].size()) + return { p_ + i, n_ - i, + p_[i].size() - n, p1_ }; + n -= p_[i].size(); + } + auto d = p_[0].size() - p0_; + if(n <= d) + return { p_, n_, + p_[0].size() - n, p1_ }; + return { p_, n_, p0_, p1_ }; + } + } +} + +} // boost::buffers diff --git a/src/io/buffers/mutable_buffer_pair.cpp b/src/io/buffers/mutable_buffer_pair.cpp new file mode 100644 index 00000000..3b0f3404 --- /dev/null +++ b/src/io/buffers/mutable_buffer_pair.cpp @@ -0,0 +1,53 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#include + +namespace boost::async::io::buffers { + +mutable_buffer_pair +mutable_buffer_pair:: +prefix_impl( + std::size_t n) const noexcept +{ + auto const it0 = begin(); + if(n <= it0->size()) + return { { + it0->data(), n }, + mutable_buffer{} }; + n -= it0->size(); + auto it1 = it0; + ++it1; + if(n < it1->size()) + return { *it0, { + it1->data(), n } }; + return *this; +} + +mutable_buffer_pair +mutable_buffer_pair:: +suffix_impl( + std::size_t n) const noexcept +{ + auto it0 = end(); + --it0; + if(n <= it0->size()) + return { *it0 + ( + it0->size() - n), + mutable_buffer{} }; + n -= it0->size(); + auto it1 = it0; + --it1; + if(n < it1->size()) + return { *it1 + ( + it1->size() - n), *it0 }; + return *this; +} + +} // boost::buffers diff --git a/src/io/buffers/mutable_buffer_subspan.cpp b/src/io/buffers/mutable_buffer_subspan.cpp new file mode 100644 index 00000000..ee5e9539 --- /dev/null +++ b/src/io/buffers/mutable_buffer_subspan.cpp @@ -0,0 +1,155 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#include +#include +#include + +namespace boost::async::io::buffers { + +auto +mutable_buffer_subspan:: +const_iterator:: +operator*() const noexcept -> + reference +{ + BOOST_ASSERT(s_->n_ > 0); + auto b = s_->p_[i_]; + if(s_->n_ > 1) + { + if(i_ > 0) + { + if(i_ < s_->n_ - 1) + return b; + return prefix(b, s_->p1_); + } + return sans_prefix(b, s_->p0_); + } + return { static_cast< + unsigned char*>( + b.data()) + s_->p0_, + s_->p1_ - s_->p0_ }; +} + +mutable_buffer_subspan:: +mutable_buffer_subspan( + mutable_buffer const* p, + std::size_t n) noexcept + : p_(p) + , n_(n) + , p1_([&]() -> std::size_t + { + if(n > 0) + return p[n-1].size(); + return 0; + }()) +{ +} + +mutable_buffer_subspan +mutable_buffer_subspan:: +prefix_impl( + std::size_t n) const noexcept +{ + switch(n_) + { + case 0: + { + return *this; + } + case 1: + { + if(n == 0) + return { p_, 0, p0_, p0_ }; + if(n == std::size_t(-1)) + return *this; + auto const d = p1_ - p0_; + if(n <= d) + return { p_, 1, p0_, p0_ + n }; + return *this; + } + default: + { + if(n == 0) + return { p_, 0, p0_, p0_ }; + if(n == std::size_t(-1)) + return *this; + auto d = p_[0].size() - p0_; + if(n <= d) + return { p_, 1, p0_, p0_ + n }; + n -= d; + std::size_t i = 1; + for(;;) + { + if(i == n_ - 1) + break; + if(n <= p_[i].size()) + return { p_, i + 1, p0_, n }; + n -= p_[i].size(); + ++i; + } + if(n <= p1_) + return { p_, n_, p0_, n }; + return { p_, n_, p0_, p1_ }; + } + } +} + +mutable_buffer_subspan +mutable_buffer_subspan:: +suffix_impl( + std::size_t n) const noexcept +{ + switch(n_) + { + case 0: + { + return *this; + } + case 1: + { + if(n == 0) + return { p_, 0, p1_, p1_ }; + if(n == std::size_t(-1)) + return *this; + auto const d = p1_ - p0_; + if(n < d) + return { p_, 1, p1_ - n, p1_ }; + return *this; + } + default: + { + if(n == 0) + return { p_, 0, p1_, p1_ }; + if(n == std::size_t(-1)) + return *this; + std::size_t i = n_ - 1; + if(n <= p1_) + return { p_ + i, 1, p1_ - n, p1_ }; + n -= p1_; + for(;;) + { + if(--i == 0) + break; + if(n <= p_[i].size()) + return { p_ + i, n_ - i, + p_[i].size() - n, p1_ }; + n -= p_[i].size(); + } + auto d = p_[0].size() - p0_; + if(n <= d) + return { p_, n_, + p_[0].size() - n, p1_ }; + return { p_, n_, p0_, p1_ }; + } + } +} + +} // boost::buffers + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0ee48eb7..8a3f48a2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -28,4 +28,6 @@ foreach(HEADER ${ALL_PUBLIC_HEADERS}) endforeach() add_library(boost_async_test_all_public_headers_test OBJECT ${ALL_PUBLIC_HEADER_TESTS}) -target_link_libraries(boost_async_test_all_public_headers_test PUBLIC Boost::headers) \ No newline at end of file +target_link_libraries(boost_async_test_all_public_headers_test PUBLIC Boost::headers) + +add_subdirectory(io) diff --git a/test/io/CMakeLists.txt b/test/io/CMakeLists.txt new file mode 100644 index 00000000..b4b3fce4 --- /dev/null +++ b/test/io/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(buffers) diff --git a/test/io/buffers/CMakeLists.txt b/test/io/buffers/CMakeLists.txt new file mode 100644 index 00000000..b5574172 --- /dev/null +++ b/test/io/buffers/CMakeLists.txt @@ -0,0 +1,45 @@ +# +# Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# +# Official repository: https://github.com/CPPAlliance/buffers +# + +set(PFILES + CMakeLists.txt + Jamfile + test_helpers.hpp + algorithm.cpp + any_dynamic_buffer.cpp + buffer.cpp + buffer_copy.cpp + buffer_size.cpp + buffers.cpp + circular_buffer.cpp + const_buffer.cpp + const_buffer_pair.cpp + const_buffer_span.cpp + const_buffer_subspan.cpp + flat_buffer.cpp + mutable_buffer.cpp + mutable_buffer_pair.cpp + mutable_buffer_span.cpp + mutable_buffer_subspan.cpp + range.cpp + string_buffer.cpp + tag_invoke.cpp + test_main.cpp + type_traits.cpp + ) + +add_executable(boost_async_io_buffers_tests ${PFILES} ${EXTRAFILES}) + +add_test(NAME boost_async_io-buffers_tests COMMAND boost_async_io_buffers_tests) + +target_include_directories(boost_async_io_buffers_tests PRIVATE . ) +target_link_libraries( + boost_async_io_buffers_tests PRIVATE + boost_async + ) diff --git a/test/io/buffers/Jamfile b/test/io/buffers/Jamfile new file mode 100644 index 00000000..b5279826 --- /dev/null +++ b/test/io/buffers/Jamfile @@ -0,0 +1,48 @@ +# +# Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# +# Official repository: https://github.com/CPPAlliance/buffers +# + +import testing ; + +project + : requirements + $(c11-requires) + /boost/async//boost_async + ../../url/extra/test_main.cpp + . + ../../url/extra + ; + +local SOURCES = + algorithm.cpp + any_dynamic_buffer.cpp + buffers.cpp + buffer_copy.cpp + buffer_size.cpp + buffers.cpp + circular_buffer.cpp + const_buffer.cpp + const_buffer_pair.cpp + const_buffer_span.cpp + const_buffer_subspan.cpp + flat_buffer.cpp + mutable_buffer.cpp + mutable_buffer_pair.cpp + mutable_buffer_span.cpp + mutable_buffer_subspan.cpp + range.cpp + string_buffer.cpp + tag_invoke.cpp + type_traits.cpp + ; + +for local f in $(SOURCES) +{ + run $(f) : : : ; + #run $(f) : target-name $(f:B)_ ; +} diff --git a/test/io/buffers/algorithm.cpp b/test/io/buffers/algorithm.cpp new file mode 100644 index 00000000..54bcaa6a --- /dev/null +++ b/test/io/buffers/algorithm.cpp @@ -0,0 +1,204 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include +#include +#include +#include +#include +#include +#include "test_suite.hpp" + +namespace boost::async::io::buffers { + +struct asio_mutable_buffer +{ + std::size_t size() const noexcept { return 0; } + void* data() const noexcept { return nullptr; } +}; + +struct asio_const_buffer +{ + std::size_t size() const noexcept { return 0; } + void const* data() const noexcept { return nullptr; } +}; + +struct not_a_buffer +{ + std::size_t size() const noexcept; + char* data() const noexcept; +}; + +struct asio_mutable_buffers +{ + asio_mutable_buffer const* begin() const noexcept; + asio_mutable_buffer const* end() const noexcept; +}; + +struct asio_const_buffers +{ + asio_const_buffer const* begin() const noexcept; + asio_const_buffer const* end() const noexcept; +}; + +BOOST_STATIC_ASSERT( is_const_buffer_sequence ::value); +BOOST_STATIC_ASSERT( is_const_buffer_sequence ::value); +BOOST_STATIC_ASSERT(! is_mutable_buffer_sequence ::value); +BOOST_STATIC_ASSERT( is_mutable_buffer_sequence ::value); + +//BOOST_STATIC_ASSERT( is_const_buffer_sequence ::value); +//BOOST_STATIC_ASSERT( is_const_buffer_sequence ::value); +//BOOST_STATIC_ASSERT( is_mutable_buffer_sequence ::value); +//BOOST_STATIC_ASSERT(! is_mutable_buffer_sequence ::value); + +BOOST_STATIC_ASSERT( is_const_buffer_sequence ::value); +BOOST_STATIC_ASSERT( is_const_buffer_sequence ::value); +BOOST_STATIC_ASSERT(! is_mutable_buffer_sequence ::value); +BOOST_STATIC_ASSERT( is_mutable_buffer_sequence ::value); + +struct algorithm_test +{ + void + testBufferSize() + { + { + char a[7]{}; + char b[11]{}; + const_buffer_pair p( + const_buffer(a, sizeof(a)), + const_buffer(b, sizeof(b))); + BOOST_TEST_EQ( + buffer_size(p), + sizeof(a) + sizeof(b)); + } + } + + void + testBufferCopy() + { + std::string const s = + "Howdy partner"; + auto const N = s.size(); + for(std::size_t i = 0; + i < N; ++i) + { + for(std::size_t j = 0; + j < N; ++j) + { + for(std::size_t k = 0; + k < N + 2; ++k) + { + const_buffer_pair p0( + const_buffer( + s.data(), i), + const_buffer( + s.data() + i, N - i)); + char tmp[13]; + std::memset(tmp, 0, sizeof(tmp)); + mutable_buffer_pair p1( + mutable_buffer( + tmp, j), + mutable_buffer( + tmp + j, N - j)); + auto const n = buffer_copy( + p1, p0, k); + BOOST_TEST_LE(n, N); + BOOST_TEST_EQ( + s.substr(0, n), + std::string(tmp, n)); + } + } + } + } + + void + testAlgorithms() + { + // prefix + + { + char buf[16]{}; + const_buffer b(buf, sizeof(buf)); + const_buffer bp = prefix(b, 5); + BOOST_TEST_EQ(bp.size(), 5); + } + + { + char buf[16]{}; + mutable_buffer b(buf, sizeof(buf)); + mutable_buffer bp = prefix(b, 5); + BOOST_TEST_EQ(bp.size(), 5); + } + + // sans_prefix + + { + char buf[16]{}; + const_buffer b(buf, sizeof(buf)); + const_buffer bp = sans_prefix(b, 5); + BOOST_TEST_EQ(bp.size(), 11); + } + + { + char buf[16]{}; + mutable_buffer b(buf, sizeof(buf)); + mutable_buffer bp = sans_prefix(b, 5); + BOOST_TEST_EQ(bp.size(), 11); + } + + // suffix + + { + char buf[16]{}; + const_buffer b(buf, sizeof(buf)); + const_buffer bp = suffix(b, 5); + BOOST_TEST_EQ(bp.size(), 5); + } + + { + char buf[16]{}; + mutable_buffer b(buf, sizeof(buf)); + mutable_buffer bp = suffix(b, 5); + BOOST_TEST_EQ(bp.size(), 5); + } + + // sans_suffix + + { + char buf[16]{}; + const_buffer b(buf, sizeof(buf)); + const_buffer bp = sans_suffix(b, 5); + BOOST_TEST_EQ(bp.size(), 11); + } + + { + char buf[16]{}; + mutable_buffer b(buf, sizeof(buf)); + mutable_buffer bp = sans_suffix(b, 5); + BOOST_TEST_EQ(bp.size(), 11); + } + } + + void + run() + { + testBufferSize(); + testBufferCopy(); + testAlgorithms(); + } +}; + +TEST_SUITE( + algorithm_test, + "boost.buffers.algorithm"); + +} // boost::buffers diff --git a/test/io/buffers/any_dynamic_buffer.cpp b/test/io/buffers/any_dynamic_buffer.cpp new file mode 100644 index 00000000..9108d93f --- /dev/null +++ b/test/io/buffers/any_dynamic_buffer.cpp @@ -0,0 +1,86 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include +#include +#include "test_helpers.hpp" + +namespace boost::async::io::buffers { + +struct any_dynamic_buffer_test +{ + BOOST_STATIC_ASSERT( + is_dynamic_buffer< + any_dynamic_buffer>::value); + + void + testAny() + { + auto const& pat = test_pattern(); + + for(std::size_t i = 0; + i <= pat.size(); ++i) + for(std::size_t j = 0; + j <= pat.size(); ++j) + for(std::size_t k = 0; + k <= pat.size(); ++k) + { + std::string s(pat.size(), 0); + auto db = make_any(circular_buffer( + &s[0], s.size())); + if( j < pat.size() && + i > 0) + { + db.prepare(i); + db.commit(i); + db.consume(i - 1); + db.commit(buffer_copy( + db.prepare(j), + buffer( + pat.data(), + pat.size()))); + db.consume(1); + } + else + { + db.commit(buffer_copy( + db.prepare(j), + buffer( + pat.data(), + pat.size()))); + } + db.commit(buffer_copy( + db.prepare(pat.size() - j), + buffer( + pat.data() + j, + pat.size() - j))); + BOOST_TEST_EQ(test_to_string( + db.data()), pat); + test_buffer_sequence(db.data()); + db.consume(k); + BOOST_TEST_EQ(test_to_string( + db.data()), pat.substr(k)); + } + } + + void + run() + { + testAny(); + } +}; + +TEST_SUITE( + any_dynamic_buffer_test, + "boost.buffers.any_dynamic_buffer"); + +} // boost::buffers diff --git a/test/io/buffers/buffer.cpp b/test/io/buffers/buffer.cpp new file mode 100644 index 00000000..f2007b70 --- /dev/null +++ b/test/io/buffers/buffer.cpp @@ -0,0 +1,82 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include "test_suite.hpp" + +namespace boost::async::io::buffers { + +struct buffer_test +{ + void + testBuffer() + { + char buf[3]{}; + char const* cbuf = buf; + + // buffer(mutable_buffer) + { + mutable_buffer b(buf, 3); + auto b1 = buffer(b); + BOOST_TEST_EQ(b1.data(), b.data()); + BOOST_TEST_EQ(b1.size(), b.size()); + } + + // buffer(void*, std::size_t) + { + auto b = buffer(buf, 3); + BOOST_TEST_EQ(b.data(), buf); + BOOST_TEST_EQ(b.size(), 3); + } + + // buffer(const_buffer) + { + const_buffer b(cbuf, 3); + auto b1 = buffer(b); + BOOST_TEST_EQ(b1.data(), b.data()); + BOOST_TEST_EQ(b1.size(), b.size()); + } + + // buffer(void const*, std::size_t) + { + auto b = buffer(cbuf, 3); + BOOST_TEST_EQ(b.data(), cbuf); + BOOST_TEST_EQ(b.size(), 3); + } + + // buffer(T(&)[N]) + { + mutable_buffer b = buffer(buf); + BOOST_TEST_EQ(b.data(), buf); + BOOST_TEST_EQ(b.size(), 3); + } + + // buffer(T const(&)[N]) + { + char const cbuf3[3]{}; + const_buffer b = buffer(cbuf3); + BOOST_TEST_EQ(b.data(), cbuf3); + BOOST_TEST_EQ(b.size(), 3); + } + } + + void + run() + { + testBuffer(); + } +}; + +TEST_SUITE( + buffer_test, + "boost.buffers.buffer"); + +} // boost::buffers diff --git a/test/io/buffers/buffer_copy.cpp b/test/io/buffers/buffer_copy.cpp new file mode 100644 index 00000000..c4ffa875 --- /dev/null +++ b/test/io/buffers/buffer_copy.cpp @@ -0,0 +1,85 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include +#include +#include "test_helpers.hpp" + +namespace boost::async::io::buffers { + +struct buffer_copy_test +{ + void + testBufferCopy() + { + auto const& pat = test_pattern(); + + for(std::size_t i = 0; + i <= pat.size(); ++i) + { + for(std::size_t j = 0; + j <= pat.size(); ++j) + { + std::string s; + s.resize(pat.size()); + const_buffer cb[2] = { + { &pat[0], i }, + { &pat[i], + pat.size() - i } }; + mutable_buffer mb[2] = { + { &s[0], j }, + { &s[j], + pat.size() - j } }; + auto n = buffer_copy( + mutable_buffer_span(mb, 2), + const_buffer_span(cb, 2)); + BOOST_TEST_EQ(n, pat.size()); + BOOST_TEST_EQ(s, pat); + } + for(std::size_t j = 0; + j <= pat.size(); ++j) + { + for(std::size_t k = 0; + k <= pat.size(); ++k) + { + std::string s; + s.resize(pat.size()); + const_buffer cb[2] = { + { &pat[0], i }, + { &pat[i], + pat.size() - i } }; + mutable_buffer mb[2] = { + { &s[0], j }, + { &s[j], + pat.size() - j } }; + auto n = buffer_copy( + mutable_buffer_span(mb, 2), + const_buffer_span(cb, 2), k); + s.resize(n); + BOOST_TEST_EQ(s, + pat.substr(0, k)); + } + } + } + } + void + run() + { + testBufferCopy(); + } +}; + +TEST_SUITE( + buffer_copy_test, + "boost.buffers.buffer_copy"); + +} // boost::buffers diff --git a/test/io/buffers/buffer_size.cpp b/test/io/buffers/buffer_size.cpp new file mode 100644 index 00000000..24be1f0c --- /dev/null +++ b/test/io/buffers/buffer_size.cpp @@ -0,0 +1,50 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include +#include + +#include "test_suite.hpp" + +namespace boost::async::io::buffers { + +struct buffer_size_test +{ + void + testBufferSize() + { + char data[9]; + for(std::size_t i = 0; i < 3; ++i) + for(std::size_t j = 0; j < 3; ++j) + for(std::size_t k = 0; k < 3; ++k) + { + const_buffer cb[3] = { + { data, i }, + { data + i, j }, + { data + i + j, k } + }; + const_buffer_span s(cb, 3); + BOOST_TEST_EQ( + buffer_size(s), i + j + k); + } + } + + void + run() + { + testBufferSize(); + } +}; + +TEST_SUITE( + buffer_size_test, + "boost.buffers.buffer_size"); + +} // boost::buffers diff --git a/test/io/buffers/buffers.cpp b/test/io/buffers/buffers.cpp new file mode 100644 index 00000000..f6cf257c --- /dev/null +++ b/test/io/buffers/buffers.cpp @@ -0,0 +1,11 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include diff --git a/test/io/buffers/circular_buffer.cpp b/test/io/buffers/circular_buffer.cpp new file mode 100644 index 00000000..da348101 --- /dev/null +++ b/test/io/buffers/circular_buffer.cpp @@ -0,0 +1,185 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include "test_helpers.hpp" + +namespace boost::async::io::buffers { + +struct circular_buffer_test +{ + void + testMembers() + { + std::string pat = test_pattern(); + + // circular_buffer() + { + circular_buffer cb; + BOOST_TEST_EQ(cb.size(), 0); + } + +#if 0 + // circular_buffer(mutable_buffer) + { + circular_buffer cb( + buffer(&pat[0], pat.size())); + BOOST_TEST_EQ(cb.size(), 0); + BOOST_TEST_EQ(cb.capacity(), pat.size()); + BOOST_TEST_EQ(cb.max_size(), pat.size()); + } +#endif + + // circular_buffer(void*, std::size_t) + { + circular_buffer cb( + &pat[0], pat.size()); + BOOST_TEST_EQ(cb.size(), 0); + BOOST_TEST_EQ(cb.capacity(), pat.size()); + BOOST_TEST_EQ(cb.max_size(), pat.size()); + } + + // circular_buffer( + // void*, std::size_t, std:size_t) + { + circular_buffer cb( + &pat[0], pat.size(), 6); + BOOST_TEST_EQ(cb.size(), 6); + BOOST_TEST_EQ( + cb.capacity(), pat.size() - 6); + BOOST_TEST_EQ(cb.max_size(), pat.size()); + BOOST_TEST_EQ( + test_to_string(cb.data()), + pat.substr(0, 6)); + } + { + BOOST_TEST_THROWS( + circular_buffer( + &pat[0], pat.size(), 600), + std::exception); + } + + // circular_buffer( + // circular_buffer const&) + { + circular_buffer cb0( + buffer(&pat[0], pat.size())); + circular_buffer cb1(cb0); + BOOST_TEST_EQ(cb1.size(), cb0.size()); + BOOST_TEST_EQ(cb1.capacity(), cb0.capacity()); + BOOST_TEST_EQ(cb1.max_size(), cb0.max_size()); + } + + // operator=( + // circular_buffer const&) + { + circular_buffer cb0( + buffer(&pat[0], pat.size())); + circular_buffer cb1; + cb1 = cb0; + BOOST_TEST_EQ(cb1.size(), cb0.size()); + BOOST_TEST_EQ(cb1.capacity(), cb0.capacity()); + BOOST_TEST_EQ(cb1.max_size(), cb0.max_size()); + } + + // prepare(std::size_t) + { + circular_buffer cb(buffer( + &pat[0], pat.size())); + BOOST_TEST_THROWS( + cb.prepare(cb.capacity() + 1), + std::length_error); + } + + // commit(std::size_t) + { + circular_buffer cb(buffer( + &pat[0], pat.size())); + auto n = pat.size() / 2; + cb.prepare(pat.size()); + cb.commit(n); + BOOST_TEST_EQ( + test_to_string(cb.data()), + pat.substr(0, n)); + } + } + + void + testBuffer() + { + auto const& pat = test_pattern(); + + for(std::size_t i = 0; + i <= pat.size(); ++i) + for(std::size_t j = 0; + j <= pat.size(); ++j) + for(std::size_t k = 0; + k <= pat.size(); ++k) + { + std::string s(pat.size(), 0); + circular_buffer bs( + &s[0], s.size()); + BOOST_TEST_EQ( + bs.capacity(), s.size()); + if( j < pat.size() && + i > 0) + { + bs.prepare(i); + bs.commit(i); + BOOST_TEST_EQ( + bs.capacity(), + bs.max_size() - bs.size()); + bs.consume(i - 1); + bs.commit(buffer_copy( + bs.prepare(j), + buffer( + pat.data(), + pat.size()))); + bs.consume(1); + } + else + { + bs.commit(buffer_copy( + bs.prepare(j), + buffer( + pat.data(), + pat.size()))); + BOOST_TEST_EQ( + bs.capacity(), + bs.max_size() - bs.size()); + } + bs.commit(buffer_copy( + bs.prepare(pat.size() - j), + buffer( + pat.data() + j, + pat.size() - j))); + BOOST_TEST_EQ(test_to_string( + bs.data()), pat); + test_buffer_sequence(bs.data()); + bs.consume(k); + BOOST_TEST_EQ(test_to_string( + bs.data()), pat.substr(k)); + } + } + + void + run() + { + testMembers(); + testBuffer(); + } +}; + +TEST_SUITE( + circular_buffer_test, + "boost.buffers.circular_buffer"); + +} // boost::buffers diff --git a/test/io/buffers/const_buffer.cpp b/test/io/buffers/const_buffer.cpp new file mode 100644 index 00000000..33584e18 --- /dev/null +++ b/test/io/buffers/const_buffer.cpp @@ -0,0 +1,114 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include "test_helpers.hpp" + +namespace boost::async::io::buffers { + +struct const_buffer_test +{ + void + testMembers() + { + // const_buffer() + BOOST_TEST_EQ(const_buffer().size(), 0); + + // const_buffer(void const*, size_t) + { + auto p = "12345"; + const_buffer b( p, 5 ); + BOOST_TEST_EQ(b.data(), p); + BOOST_TEST_EQ(b.size(), 5); + } + + // const_buffer(const_buffer) + { + auto p = "12345"; + const_buffer b0( p, 5 ); + const_buffer b(b0); + BOOST_TEST_EQ(b.data(), p); + BOOST_TEST_EQ(b.size(), 5); + } + + // const_buffer(mutable_buffer) + { + char buf[6] = "12345"; + mutable_buffer b0( buf, 5 ); + const_buffer b(b0); + BOOST_TEST_EQ(b.data(), buf); + BOOST_TEST_EQ(b.size(), 5); + } + + // operator=(const_buffer) + { + auto p = "12345"; + const_buffer b; + b = const_buffer(p, 5); + BOOST_TEST_EQ(b.data(), p); + BOOST_TEST_EQ(b.size(), 5); + } + + // operator+=(std::size_t) + { + { + auto p = "12345"; + const_buffer b; + b = const_buffer(p, 5); + b += 2; + BOOST_TEST_EQ(b.data(), p + 2); + BOOST_TEST_EQ(b.size(), 3); + } + { + auto p = "12345"; + const_buffer b; + b = const_buffer(p, 5); + b += 6; + BOOST_TEST_EQ(b.size(), 0); + } + } + + // operator+(const_buffer, size_t) + // operator+(size_t, const_buffer) + { + auto p = "12345"; + const_buffer b0(p, 5); + const_buffer b1(p, 5); + b0 = b0 + 2; + b1 = 2 + b1; + BOOST_TEST_EQ(b0.data(), p + 2); + BOOST_TEST_EQ(b0.size(), 3); + BOOST_TEST_EQ(b0.data(), b1.data()); + BOOST_TEST_EQ(b0.size(), b1.size()); + } + } + + void + testBuffer() + { + auto const& pat = test_pattern(); + const_buffer cb(&pat[0], pat.size()); + test_buffer_sequence(cb); + } + + void + run() + { + testMembers(); + testBuffer(); + } +}; + +TEST_SUITE( + const_buffer_test, + "boost.buffers.const_buffer"); + +} // boost::buffers diff --git a/test/io/buffers/const_buffer_pair.cpp b/test/io/buffers/const_buffer_pair.cpp new file mode 100644 index 00000000..6ece786a --- /dev/null +++ b/test/io/buffers/const_buffer_pair.cpp @@ -0,0 +1,150 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include "test_helpers.hpp" + +namespace boost::async::io::buffers { + +struct const_buffer_pair_test +{ + void + testMembers() + { + auto const& pat = test_pattern(); + + // const_buffer_pair() + { + const_buffer_pair cb; + BOOST_TEST_EQ( + buffer_size(cb), 0); + } + + // const_buffer_pair( + // const_buffer_pair const&), + // const_buffer_pair( + // const_buffer const&) + // const_buffer const&) + { + for(std::size_t i = 0; + i <= pat.size(); ++i) + { + const_buffer_pair cb0( + { &pat[0], i }, + { &pat[i], + pat.size() - i }); + const_buffer_pair cb1(cb0); + BOOST_TEST_EQ( + test_to_string(cb0), pat); + BOOST_TEST_EQ( + test_to_string(cb0), + test_to_string(cb1)); + BOOST_TEST_EQ( + cb0[0].data(), cb1[0].data()); + BOOST_TEST_EQ( + cb0[1].size(), cb1[1].size()); + auto const& ccb0 = cb0; + auto const& ccb1 = cb1; + BOOST_TEST_EQ( + ccb0[0].data(), ccb1[0].data()); + BOOST_TEST_EQ( + ccb0[1].size(), ccb1[1].size()); + } + } + + // const_buffer_pair( + // mutable_buffer_pair) + { + for(std::size_t i = 0; + i <= pat.size(); ++i) + { + auto s = pat; + mutable_buffer_pair b( + { &s[0], i }, + { &s[i], + s.size() - i }); + const_buffer_pair cb(b); + BOOST_TEST_EQ( + test_to_string(cb), pat); + BOOST_TEST_EQ( + test_to_string(cb), + test_to_string(b)); + } + } + + // operator=(const_buffer_pair const&) + { + for(std::size_t i = 0; + i <= pat.size(); ++i) + { + const_buffer_pair cb0( + { &pat[0], i }, + { &pat[i], + pat.size() - i }); + const_buffer_pair cb1; + cb1 = cb0; + BOOST_TEST_EQ( + test_to_string(cb0), pat); + BOOST_TEST_EQ( + test_to_string(cb0), + test_to_string(cb1)); + } + } + + // operator=(mutable_buffer_pair const&) + { + for(std::size_t i = 0; + i <= pat.size(); ++i) + { + auto s = pat; + mutable_buffer_pair b( + { &s[0], i }, + { &s[i], + s.size() - i }); + const_buffer_pair cb; + cb = b; + BOOST_TEST_EQ( + test_to_string(cb), pat); + BOOST_TEST_EQ( + test_to_string(cb), + test_to_string(b)); + } + } + } + + void + testBuffer() + { + auto const& pat = test_pattern(); + for(std::size_t i = 0; + i <= pat.size(); ++i) + { + const_buffer_pair cb( + { &pat[0], i }, + { &pat[i], + pat.size() - i }); + test_buffer_sequence(cb); + } + } + + void + run() + { + testMembers(); + testBuffer(); + } +}; + +TEST_SUITE( + const_buffer_pair_test, + "boost.buffers.const_buffer_pair"); + +} // boost::buffers diff --git a/test/io/buffers/const_buffer_span.cpp b/test/io/buffers/const_buffer_span.cpp new file mode 100644 index 00000000..c588091f --- /dev/null +++ b/test/io/buffers/const_buffer_span.cpp @@ -0,0 +1,81 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include +#include "test_helpers.hpp" + +namespace boost::async::io::buffers { + +struct const_buffer_span_test +{ + void + testMembers() + { + auto const& pat = test_pattern(); + const_buffer cb[3] = { + { &pat[0], 3 }, + { &pat[3], 5 }, + { &pat[8], 7 } }; + + // const_buffer_span() + { + const_buffer_span bs; + BOOST_TEST_EQ(buffer_size(bs), 0); + } + + // const_buffer_span( + // const_buffer const*, + // std::size_t n) + { + const_buffer_span cbs(cb, 3); + test_buffer_sequence(cbs); + } + + // const_buffer_span( + // ConstBufferSequence + { + const_buffer_pair bp; + const_buffer_span sp(bp); + BOOST_TEST( + sp.end() - sp.begin() == 2); + } + + // const_buffer_span( + // const_buffer_span const&) + { + const_buffer_span cbs0(cb, 3); + const_buffer_span cbs1(cbs0); + test_buffer_sequence(cbs1); + } + + // operator=( + // const_buffer_span const&) + { + const_buffer_span cbs0(cb, 3); + const_buffer_span cbs1; + cbs1 = cbs0; + test_buffer_sequence(cbs1); + } + } + + void + run() + { + testMembers(); + } +}; + +TEST_SUITE( + const_buffer_span_test, + "boost.buffers.const_buffer_span"); + +} // boost::buffers diff --git a/test/io/buffers/const_buffer_subspan.cpp b/test/io/buffers/const_buffer_subspan.cpp new file mode 100644 index 00000000..05844f50 --- /dev/null +++ b/test/io/buffers/const_buffer_subspan.cpp @@ -0,0 +1,190 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include +#include "test_helpers.hpp" + +namespace boost::async::io::buffers { + +struct const_buffer_subspan_test +{ + void + testMembers() + { + auto const& pat = test_pattern(); + const_buffer const cb[3] = { + { pat.data(), 3 }, + { pat.data() + 3, 5 }, + { pat.data() + 8, 7 } }; + + // const_buffer_subspan() + { + const_buffer_subspan bs; + BOOST_TEST_EQ(buffer_size(bs), 0); + } + + // const_buffer_subspan( + // const_buffer const*, std::size_t) + { + const_buffer_subspan s(cb, 3); + BOOST_TEST_EQ(buffer_size(s), 15); + } + { + const_buffer_subspan s(cb, 0); + BOOST_TEST_EQ(buffer_size(s), 0); + } + + // const_buffer_subspan( + // const_buffer_span const&) + { + const_buffer_span cs0(cb, 3); + const_buffer_subspan cs1(cs0); + BOOST_TEST_EQ( + buffer_size(cs0), + buffer_size(cs1)); + } + { + const_buffer_span cs0(cb, 0); + const_buffer_subspan cs1(cs0); + BOOST_TEST_EQ( + buffer_size(cs0), + buffer_size(cs1)); + } + + // const_buffer_subspan( + // const_buffer_subspan const&) + { + const_buffer_subspan s0(cb, 3); + const_buffer_subspan s1(s0); + BOOST_TEST_EQ( + buffer_size(s1), + buffer_size(s0)); + } + + // operator=( + // const_buffer_subspan const&) + { + const_buffer_subspan s; + BOOST_TEST_EQ(buffer_size(s), 0); + s = const_buffer_subspan(cb, 3); + BOOST_TEST_EQ(buffer_size(s), 15); + } + } + + void + testSequence() + { + auto const pat = test_pattern(); + + // length 1 + { + const_buffer cb = { + &pat[0], pat.size() }; + const_buffer_subspan s(&cb, 1); + test_buffer_sequence(s); + } + + // length 2 + { + const_buffer const cb[2] = { + { &pat[0], 7 }, + { &pat[7], 8 } }; + const_buffer_subspan s(cb, 2); + test_buffer_sequence(s); + } + + // length 3 + { + const_buffer const cb[3] = { + { &pat[0], 3 }, + { &pat[3], 5 }, + { &pat[8], 7 } }; + const_buffer_subspan s(cb, 3); + test_buffer_sequence(s); + } + } + + void + testSubspan() + { + std::string tmp; + auto const& pat = test_pattern(); + const_buffer const cb[3] = { + { &pat[0], 3 }, + { &pat[3], 5 }, + { &pat[8], 7 } }; + const_buffer_span const cs0(cb, 3); + + for(std::size_t i = 0; i <= pat.size(); ++i ) + { + { + auto b0 = prefix(cs0, i); + auto b1 = sans_prefix(cs0, i); + tmp = std::string(pat.size(), ' '); + mutable_buffer dest(&tmp[0], tmp.size()); + auto n = buffer_copy(dest, b0); + dest += n; + n += buffer_copy(dest, b1); + BOOST_TEST_EQ(n, pat.size()); + BOOST_TEST_EQ(tmp, pat); + } + for(std::size_t j = 0; j <= pat.size(); ++j) + { + auto b = prefix(sans_prefix(cs0, i), j); + tmp.resize(pat.size()); + tmp.resize(buffer_copy( + mutable_buffer( + &tmp[0], tmp.size()), b)); + if(i <= pat.size()) + BOOST_TEST_EQ(tmp, pat.substr(i, j)); + else + BOOST_TEST(tmp.empty()); + } + for(std::size_t j = 0; j <= pat.size(); ++j) + { + auto b = suffix(sans_suffix(cs0, i), j); + tmp.resize(pat.size()); + tmp.resize(buffer_copy( + mutable_buffer( + &tmp[0], tmp.size()), b)); + if(i <= pat.size()) + { + auto n = pat.size() - i; // inner length + if(n >= j) + BOOST_TEST_EQ(tmp, + pat.substr(n - j, j)); + else + BOOST_TEST_EQ(tmp, + pat.substr(0, n)); + } + else + { + BOOST_TEST(tmp.empty()); + } + } + } + } + + void + run() + { + testMembers(); + testSequence(); + testSubspan(); + } +}; + +TEST_SUITE( + const_buffer_subspan_test, + "boost.buffers.const_buffer_subspan"); + +} // boost::buffers diff --git a/test/io/buffers/flat_buffer.cpp b/test/io/buffers/flat_buffer.cpp new file mode 100644 index 00000000..ad3c182e --- /dev/null +++ b/test/io/buffers/flat_buffer.cpp @@ -0,0 +1,169 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include +#include +#include "test_helpers.hpp" + +namespace boost::async::io::buffers { + +struct flat_buffer_test +{ + BOOST_STATIC_ASSERT( + is_dynamic_buffer< + flat_buffer>::value); + + void + testMembers() + { + std::string pat = test_pattern(); + + // flat_buffer() + { + flat_buffer fb; + BOOST_TEST_EQ(fb.size(), 0); + BOOST_TEST_EQ(fb.max_size(), 0); + BOOST_TEST_EQ(fb.capacity(), 0); + } + + // flat_buffer(void*, size_t) + { + std::string s = pat; + flat_buffer fb(&s[0], s.size()); + BOOST_TEST_EQ(fb.size(), 0); + BOOST_TEST_EQ(fb.max_size(), s.size()); + BOOST_TEST_EQ(fb.capacity(), s.size()); + } + + // flat_buffer(void*, size_t, size_t) + { + std::string s = pat; + flat_buffer fb(&s[0], s.size(), 6); + BOOST_TEST_EQ(fb.size(), 6); + BOOST_TEST_EQ(fb.max_size(), s.size()); + BOOST_TEST_EQ(fb.capacity(), s.size()); + } + { + std::string s = pat; + BOOST_TEST_THROWS( + flat_buffer(&s[0], s.size(), + s.size() + 1), + std::invalid_argument); + } + + // flat_buffer(mutable_buffer) + { + std::string s = pat; + flat_buffer fb(mutable_buffer( + &s[0], s.size())); + BOOST_TEST_EQ(fb.size(), 0); + BOOST_TEST_EQ(fb.max_size(), s.size()); + BOOST_TEST_EQ(fb.capacity(), s.size()); + } + + // flat_buffer(mutable_buffer, size_t) + { + std::string s = pat; + flat_buffer fb(mutable_buffer( + &s[0], s.size()), 6); + BOOST_TEST_EQ(fb.size(), 6); + BOOST_TEST_EQ(fb.max_size(), s.size()); + BOOST_TEST_EQ(fb.capacity(), s.size()); + } + + // flat_buffer(flat_buffer const&) + { + std::string s = pat; + flat_buffer fb0(&s[0], s.size()); + flat_buffer fb1(fb0); + BOOST_TEST_EQ(fb1.size(), fb0.size()); + BOOST_TEST_EQ(fb1.max_size(), fb0.max_size()); + BOOST_TEST_EQ(fb1.capacity(), fb0.capacity()); + } + + // operator=(flat_buffer const&) + { + std::string s = pat; + flat_buffer fb0(&s[0], s.size()); + flat_buffer fb1; + fb1 = fb0; + BOOST_TEST_EQ(fb1.size(), fb0.size()); + BOOST_TEST_EQ(fb1.max_size(), fb0.max_size()); + BOOST_TEST_EQ(fb1.capacity(), fb0.capacity()); + } + + // prepare(std::size_t) + { + std::string s = pat; + flat_buffer fb(&s[0], s.size()); + BOOST_TEST_THROWS( + fb.prepare(s.size() + 1), + std::invalid_argument); + } + + // commit(std::size_t) + { + std::string s = pat; + for(std::size_t i = 0; + i <= pat.size(); ++i) + { + flat_buffer fb( + &s[0], s.size()); + fb.prepare(s.size()); + fb.commit(i); + BOOST_TEST_EQ( + test_to_string(fb.data()), + pat.substr(0, i)); + } + } + + // consume(std::size_t) + { + } + } + + void + testBuffer() + { + auto const& pat = test_pattern(); + for(std::size_t i = 0; + i <= pat.size(); ++i) + { + std::string s(pat.size(), 0); + flat_buffer fb(&s[0], s.size()); + fb.commit(buffer_copy( + fb.prepare(i), + buffer(&pat[0], i))); + fb.commit(buffer_copy( + fb.prepare(pat.size() - i), + buffer(&pat[i], pat.size() - i))); + BOOST_TEST_EQ(test_to_string( + fb.data()), pat); + fb.consume(i); + BOOST_TEST_EQ(test_to_string( + fb.data()), pat.substr(i)); + } + } + + void + run() + { + testMembers(); + testBuffer(); + } +}; + +TEST_SUITE( + flat_buffer_test, + "boost.buffers.flat_buffer"); + +} // boost::buffers diff --git a/test/io/buffers/mutable_buffer.cpp b/test/io/buffers/mutable_buffer.cpp new file mode 100644 index 00000000..dcc712de --- /dev/null +++ b/test/io/buffers/mutable_buffer.cpp @@ -0,0 +1,114 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include "test_helpers.hpp" + +namespace boost::async::io::buffers { + +struct mutable_buffer_test +{ + void + testMembers() + { + // mutable_buffer() + BOOST_TEST_EQ(mutable_buffer().size(), 0); + + // mutable_buffer(void const*, size_t) + { + char p[6] = "12345"; + mutable_buffer b( p, 5 ); + BOOST_TEST_EQ(b.data(), p); + BOOST_TEST_EQ(b.size(), 5); + } + + // mutable_buffer(mutable_buffer) + { + char p[6] = "12345"; + mutable_buffer b0( p, 5 ); + mutable_buffer b(b0); + BOOST_TEST_EQ(b.data(), p); + BOOST_TEST_EQ(b.size(), 5); + } + + // mutable_buffer(mutable_buffer) + { + char buf[6] = "12345"; + mutable_buffer b0( buf, 5 ); + mutable_buffer b(b0); + BOOST_TEST_EQ(b.data(), buf); + BOOST_TEST_EQ(b.size(), 5); + } + + // operator=(mutable_buffer) + { + char p[6] = "12345"; + mutable_buffer b; + b = mutable_buffer(p, 5); + BOOST_TEST_EQ(b.data(), p); + BOOST_TEST_EQ(b.size(), 5); + } + + // operator+=(std::size_t) + { + { + char p[6] = "12345"; + mutable_buffer b; + b = mutable_buffer(p, 5); + b += 2; + BOOST_TEST_EQ(b.data(), p + 2); + BOOST_TEST_EQ(b.size(), 3); + } + { + char p[6] = "12345"; + mutable_buffer b; + b = mutable_buffer(p, 5); + b += 6; + BOOST_TEST_EQ(b.size(), 0); + } + } + + // operator+(mutable_buffer, size_t) + // operator+(size_t, mutable_buffer) + { + char p[6] = "12345"; + mutable_buffer b0(p, 5); + mutable_buffer b1(p, 5); + b0 = b0 + 2; + b1 = 2 + b1; + BOOST_TEST_EQ(b0.data(), p + 2); + BOOST_TEST_EQ(b0.size(), 3); + BOOST_TEST_EQ(b0.data(), b1.data()); + BOOST_TEST_EQ(b0.size(), b1.size()); + } + } + + void + testBuffer() + { + std::string s = test_pattern(); + mutable_buffer cb(&s[0], s.size()); + test_buffer_sequence(cb); + } + + void + run() + { + testMembers(); + testBuffer(); + } +}; + +TEST_SUITE( + mutable_buffer_test, + "boost.buffers.mutable_buffer"); + +} // boost::buffers diff --git a/test/io/buffers/mutable_buffer_pair.cpp b/test/io/buffers/mutable_buffer_pair.cpp new file mode 100644 index 00000000..558c69fa --- /dev/null +++ b/test/io/buffers/mutable_buffer_pair.cpp @@ -0,0 +1,130 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include "test_helpers.hpp" + +namespace boost::async::io::buffers { + +struct mutable_buffer_pair_test +{ + void + testMembers() + { + std::string pat = test_pattern(); + + // mutable_buffer_pair() + { + mutable_buffer_pair mb; + BOOST_TEST_EQ( + buffer_size(mb), 0); + } + + // mutable_buffer_pair( + // mutable_buffer_pair const&), + // mutable_buffer_pair( + // mutable_buffer const&) + // mutable_buffer const&) + { + for(std::size_t i = 0; + i <= pat.size(); ++i) + { + mutable_buffer_pair mb0( + { &pat[0], i }, + { &pat[i], + pat.size() - i }); + mutable_buffer_pair mb1(mb0); + BOOST_TEST_EQ( + test_to_string(mb0), pat); + BOOST_TEST_EQ( + test_to_string(mb0), + test_to_string(mb1)); + BOOST_TEST_EQ( + mb0[0].data(), mb1[0].data()); + BOOST_TEST_EQ( + mb0[1].size(), mb1[1].size()); + auto const& cmb0 = mb0; + auto const& cmb1 = mb1; + BOOST_TEST_EQ( + cmb0[0].data(), cmb1[0].data()); + BOOST_TEST_EQ( + cmb0[1].size(), cmb1[1].size()); + } + } + + // operator=(mutable_buffer_pair const&) + { + for(std::size_t i = 0; + i <= pat.size(); ++i) + { + mutable_buffer_pair mb0( + { &pat[0], i }, + { &pat[i], + pat.size() - i }); + mutable_buffer_pair mb1; + mb1 = mb0; + BOOST_TEST_EQ( + test_to_string(mb0), pat); + BOOST_TEST_EQ( + test_to_string(mb0), + test_to_string(mb1)); + } + } + + // operator=(mutable_buffer_pair const&) + { + for(std::size_t i = 0; + i <= pat.size(); ++i) + { + auto s = pat; + mutable_buffer_pair b( + { &s[0], i }, + { &s[i], + s.size() - i }); + mutable_buffer_pair mb; + mb = b; + BOOST_TEST_EQ( + test_to_string(mb), pat); + BOOST_TEST_EQ( + test_to_string(mb), + test_to_string(b)); + } + } + } + + void + testBuffer() + { + std::string pat = test_pattern(); + for(std::size_t i = 0; + i <= pat.size(); ++i) + { + mutable_buffer_pair cb( + { &pat[0], i }, + { &pat[i], + pat.size() - i }); + test_buffer_sequence(cb); + } + } + + void + run() + { + testMembers(); + testBuffer(); + } +}; + +TEST_SUITE( + mutable_buffer_pair_test, + "boost.buffers.mutable_buffer_pair"); + +} // boost::buffers diff --git a/test/io/buffers/mutable_buffer_span.cpp b/test/io/buffers/mutable_buffer_span.cpp new file mode 100644 index 00000000..04b27c84 --- /dev/null +++ b/test/io/buffers/mutable_buffer_span.cpp @@ -0,0 +1,81 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include +#include "test_helpers.hpp" + +namespace boost::async::io::buffers { + +struct mutable_buffer_span_test +{ + void + testMembers() + { + std::string pat = test_pattern(); + mutable_buffer mb[3] = { + { &pat[0], 3 }, + { &pat[3], 5 }, + { &pat[8], 7 } }; + + // mutable_buffer_span() + { + mutable_buffer_span bs; + BOOST_TEST_EQ(buffer_size(bs), 0); + } + + // mutable_buffer_span( + // mutable_buffer const*, + // std::size_t n) + { + mutable_buffer_span mbs(mb, 3); + test_buffer_sequence(mbs); + } + + // mutable_buffer_span( + // MutableBufferSequence) + { + mutable_buffer_pair bp; + mutable_buffer_span sp(bp); + BOOST_TEST( + sp.end() - sp.begin() == 2); + } + + // mutable_buffer_span( + // mutable_buffer_span const&) + { + mutable_buffer_span mbs0(mb, 3); + mutable_buffer_span mbs1(mbs0); + test_buffer_sequence(mbs1); + } + + // operator=( + // mutable_buffer_span const&) + { + mutable_buffer_span mbs0(mb, 3); + mutable_buffer_span mbs1; + mbs1 = mbs0; + test_buffer_sequence(mbs1); + } + } + + void + run() + { + testMembers(); + } +}; + +TEST_SUITE( + mutable_buffer_span_test, + "boost.buffers.mutable_buffer_span"); + +} // boost::buffers diff --git a/test/io/buffers/mutable_buffer_subspan.cpp b/test/io/buffers/mutable_buffer_subspan.cpp new file mode 100644 index 00000000..47e824c4 --- /dev/null +++ b/test/io/buffers/mutable_buffer_subspan.cpp @@ -0,0 +1,190 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include +#include "test_helpers.hpp" + +namespace boost::async::io::buffers { + +struct mutable_buffer_subspan_test +{ + void + testMembers() + { + std::string pat = test_pattern(); + mutable_buffer const mb[3] = { + { &pat[0], 3 }, + { &pat[0] + 3, 5 }, + { &pat[0] + 8, 7 } }; + + // mutable_buffer_subspan() + { + mutable_buffer_subspan bs; + BOOST_TEST_EQ(buffer_size(bs), 0); + } + + // mutable_buffer_subspan( + // mutable_buffer const*, std::size_t) + { + mutable_buffer_subspan s(mb, 3); + BOOST_TEST_EQ(buffer_size(s), 15); + } + { + mutable_buffer_subspan s(mb, 0); + BOOST_TEST_EQ(buffer_size(s), 0); + } + + // mutable_buffer_subspan( + // mutable_buffer_span const&) + { + mutable_buffer_span ms0(mb, 3); + mutable_buffer_subspan ms1(ms0); + BOOST_TEST_EQ( + buffer_size(ms0), + buffer_size(ms1)); + } + { + mutable_buffer_span ms0(mb, 0); + mutable_buffer_subspan ms1(ms0); + BOOST_TEST_EQ( + buffer_size(ms0), + buffer_size(ms1)); + } + + // mutable_buffer_subspan( + // mutable_buffer_subspan const&) + { + mutable_buffer_subspan s0(mb, 3); + mutable_buffer_subspan s1(s0); + BOOST_TEST_EQ( + buffer_size(s1), + buffer_size(s0)); + } + + // operator=( + // mutable_buffer_subspan const&) + { + mutable_buffer_subspan s; + BOOST_TEST_EQ(buffer_size(s), 0); + s = mutable_buffer_subspan(mb, 3); + BOOST_TEST_EQ(buffer_size(s), 15); + } + } + + void + testSequence() + { + std::string pat = test_pattern(); + + // length 1 + { + mutable_buffer mb = { + &pat[0], pat.size() }; + mutable_buffer_subspan s(&mb, 1); + test_buffer_sequence(s); + } + + // length 2 + { + mutable_buffer const mb[2] = { + { &pat[0], 7 }, + { &pat[7], 8 } }; + mutable_buffer_subspan s(mb, 2); + test_buffer_sequence(s); + } + + // length 3 + { + mutable_buffer const mb[3] = { + { &pat[0], 3 }, + { &pat[3], 5 }, + { &pat[8], 7 } }; + mutable_buffer_subspan s(mb, 3); + test_buffer_sequence(s); + } + } + + void + testSubspan() + { + std::string tmp; + std::string pat = test_pattern(); + mutable_buffer const mb[3] = { + { &pat[0], 3 }, + { &pat[3], 5 }, + { &pat[8], 7 } }; + mutable_buffer_span const cs0(mb, 3); + + for(std::size_t i = 0; i <= pat.size(); ++i ) + { + { + auto b0 = prefix(cs0, i); + auto b1 = sans_prefix(cs0, i); + tmp = std::string(pat.size(), ' '); + mutable_buffer dest(&tmp[0], tmp.size()); + auto n = buffer_copy(dest, b0); + dest += n; + n += buffer_copy(dest, b1); + BOOST_TEST_EQ(n, pat.size()); + BOOST_TEST_EQ(tmp, pat); + } + for(std::size_t j = 0; j <= pat.size(); ++j) + { + auto b = prefix(sans_prefix(cs0, i), j); + tmp.resize(pat.size()); + tmp.resize(buffer_copy( + mutable_buffer( + &tmp[0], tmp.size()), b)); + if(i <= pat.size()) + BOOST_TEST_EQ(tmp, pat.substr(i, j)); + else + BOOST_TEST(tmp.empty()); + } + for(std::size_t j = 0; j <= pat.size(); ++j) + { + auto b = suffix(sans_suffix(cs0, i), j); + tmp.resize(pat.size()); + tmp.resize(buffer_copy( + mutable_buffer( + &tmp[0], tmp.size()), b)); + if(i <= pat.size()) + { + auto n = pat.size() - i; // inner length + if(n >= j) + BOOST_TEST_EQ(tmp, + pat.substr(n - j, j)); + else + BOOST_TEST_EQ(tmp, + pat.substr(0, n)); + } + else + { + BOOST_TEST(tmp.empty()); + } + } + } + } + + void + run() + { + testMembers(); + testSequence(); + testSubspan(); + } +}; + +TEST_SUITE( + mutable_buffer_subspan_test, + "boost.buffers.mutable_buffer_subspan"); + +} // boost::buffers diff --git a/test/io/buffers/range.cpp b/test/io/buffers/range.cpp new file mode 100644 index 00000000..4592d137 --- /dev/null +++ b/test/io/buffers/range.cpp @@ -0,0 +1,29 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include "test_suite.hpp" + +namespace boost::async::io::buffers { + +struct range_test +{ + void + run() + { + } +}; + +TEST_SUITE( + range_test, + "boost.buffers.range"); + +} // boost::buffers diff --git a/test/io/buffers/string_buffer.cpp b/test/io/buffers/string_buffer.cpp new file mode 100644 index 00000000..728b7034 --- /dev/null +++ b/test/io/buffers/string_buffer.cpp @@ -0,0 +1,173 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include +#include "test_helpers.hpp" + +namespace boost::async::io::buffers { + +struct string_buffer_test +{ + BOOST_STATIC_ASSERT( + is_dynamic_buffer::value); + + void + testMembers() + { + std::string s; + + // ~string_buffer + { + s = ""; + string_buffer b(&s); + BOOST_TEST(s.empty()); + } + + // string_buffer + { + std::string s0; + { + string_buffer b0(&s0); + string_buffer b1(std::move(b0)); + auto n = buffer_copy( + b1.prepare(5), + buffer("12345", 5)); + BOOST_TEST_EQ(n, 5); + b1.commit(5); + } + BOOST_TEST_EQ(s0, "12345"); + } + + // string_buffer(std::string) + { + s = ""; + string_buffer b(&s); + BOOST_TEST_EQ( + b.max_size(), s.max_size()); + } + + // string_buffer(std::string, std::size_t) + // max_size() + { + s = ""; + string_buffer b(&s, 20); + BOOST_TEST_EQ(b.max_size(), 20); + } + + // size() + { + s = "1234"; + string_buffer b(&s); + BOOST_TEST_EQ(b.size(), 4); + } + + // capacity() + { + { + s = ""; + s.reserve(30); + string_buffer b(&s); + BOOST_TEST_GE(b.capacity(), 30); + } + { + s = ""; + s.reserve(30); + string_buffer b(&s, 10); + BOOST_TEST_GE(b.capacity(), 10); + } + } + + // data() + { + s = "1234"; + string_buffer b(&s); + BOOST_TEST_EQ( + test_to_string(b.data()), + "1234"); + } + + // prepare() + { + { + string_buffer b(&s, 3); + BOOST_TEST_THROWS( + b.prepare(5), + std::invalid_argument); + } + { + s = std::string(); + string_buffer b(&s); + auto dest = b.prepare(10); + BOOST_TEST_GE(s.capacity(), + buffer_size(dest)); + } + { + s = std::string(); + string_buffer b(&s); + b.prepare(10); + auto dest = b.prepare(10); + BOOST_TEST_EQ( + buffer_size(dest), + 10); + } + } + + // commit() + { + s = ""; + { + string_buffer b(&s); + auto n = buffer_copy( + b.prepare(5), + buffer("12345", 5)); + BOOST_TEST_EQ(n, 5); + b.commit(3); + BOOST_TEST_EQ(b.size(), 3); + } + BOOST_TEST_EQ(s, "123"); + } + + // consume() + { + { + s = "12345"; + { + string_buffer b(&s); + b.consume(2); + } + BOOST_TEST_EQ(s, "345"); + } + { + s = "12345"; + { + string_buffer b(&s); + b.consume(5); + BOOST_TEST_EQ( + buffer_size(b.data()), 0); + } + BOOST_TEST(s.empty()); + } + } + } + + void + run() + { + testMembers(); + } +}; + +TEST_SUITE( + string_buffer_test, + "boost.buffers.string_buffer"); + +} // boost::buffers diff --git a/test/io/buffers/tag_invoke.cpp b/test/io/buffers/tag_invoke.cpp new file mode 100644 index 00000000..66ce9766 --- /dev/null +++ b/test/io/buffers/tag_invoke.cpp @@ -0,0 +1,11 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include diff --git a/test/io/buffers/test_helpers.hpp b/test/io/buffers/test_helpers.hpp new file mode 100644 index 00000000..3de9f8b5 --- /dev/null +++ b/test/io/buffers/test_helpers.hpp @@ -0,0 +1,216 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_TEST_HELPERS_HPP +#define BOOST_BUFFERS_TEST_HELPERS_HPP + +#include +#include +#include +#include +#include +#include +#include "test_suite.hpp" + +namespace boost::async::io::buffers { + +inline +std::string const& +test_pattern() +{ + static std::string const pat = + "012" "34567" "89abcde"; + return pat; +} + +template +std::string +test_to_string(Buffers const& bs) +{ + std::string s( + buffer_size(bs), 0); + s.resize(buffer_copy( + buffer(&s[0], s.size()), + bs)); + return s; +} + +template +void +test_buffer_sequence(T&& t) +{ + static_assert( + is_const_buffer_sequence::value, + ""); + + auto const& pat = test_pattern(); + auto const& ct = t; + + // operator++() + { + std::string s; + auto it = begin(t); + auto const end_ = end(t); + while(it != end_) + { + auto b = *it; + s.append(static_cast< + char const*>(b.data()), + b.size()); + ++it; + } + BOOST_TEST_EQ(s, pat); + } + // operator++(int) + { + std::string s; + auto it = begin(t); + auto const end_ = end(t); + while(it != end_) + { + auto b = *it; + s.append(static_cast< + char const*>(b.data()), + b.size()); + it++; + } + BOOST_TEST_EQ(s, pat); + } + // operator++() const + { + std::string s; + auto it = begin(ct); + auto const end_ = end(ct); + while(it != end_) + { + auto b = *it; + s.append(static_cast< + char const*>(b.data()), + b.size()); + ++it; + } + BOOST_TEST_EQ(s, pat); + } + // operator++(int) const + { + std::string s; + auto it = begin(ct); + auto const end_ = end(ct); + while(it != end_) + { + auto b = *it; + s.append(static_cast< + char const*>(b.data()), + b.size()); + it++; + } + BOOST_TEST_EQ(s, pat); + } + + // operator--() + { + std::string s; + auto it = end(t); + auto const begin_ = begin(t); + while(it != begin_) + { + --it; + auto b = *it; + s.insert(0, static_cast< + char const*>(b.data()), + b.size()); + } + BOOST_TEST_EQ(s, pat); + } + // operator--(int) + { + std::string s; + auto it = end(t); + auto const begin_ = begin(t); + while(it != begin_) + { + it--; + auto b = *it; + s.insert(0, static_cast< + char const*>(b.data()), + b.size()); + } + BOOST_TEST_EQ(s, pat); + } + // operator--() const + { + std::string s; + auto it = end(ct); + auto const begin_ = begin(ct); + while(it != begin_) + { + --it; + auto b = *it; + s.insert(0, static_cast< + char const*>(b.data()), + b.size()); + } + BOOST_TEST_EQ(s, pat); + } + // operator--(int) const + { + std::string s; + auto it = end(ct); + auto const begin_ = begin(ct); + while(it != begin_) + { + it--; + auto b = *it; + s.insert(0, static_cast< + char const*>(b.data()), + b.size()); + } + BOOST_TEST_EQ(s, pat); + } + + // prefix + for(std::size_t i = 0; + i <= pat.size(); ++i) + BOOST_TEST_EQ( + test_to_string(prefix(t, i)), + pat.substr(0, i)); + BOOST_TEST_EQ(test_to_string(prefix( + t, std::size_t(-1))), pat); + + // prefix + for(std::size_t i = 0; + i <= pat.size(); ++i) + BOOST_TEST_EQ( + test_to_string(prefix(ct, i)), + pat.substr(0, i)); + BOOST_TEST_EQ(test_to_string(prefix( + ct, std::size_t(-1))), pat); + + // suffix + for(std::size_t i = 0; + i <= pat.size(); ++i) + BOOST_TEST_EQ( + test_to_string(suffix(t, i)), + pat.substr(pat.size() - i, i)); + BOOST_TEST_EQ(test_to_string(suffix( + t, std::size_t(-1))), pat); + + // suffix + for(std::size_t i = 0; + i <= pat.size(); ++i) + BOOST_TEST_EQ( + test_to_string(suffix(ct, i)), + pat.substr(pat.size() - i, i)); + BOOST_TEST_EQ(test_to_string(suffix( + ct, std::size_t(-1))), pat); +} + +} // boost::buffers + +#endif diff --git a/test/io/buffers/test_main.cpp b/test/io/buffers/test_main.cpp new file mode 100644 index 00000000..c10ff426 --- /dev/null +++ b/test/io/buffers/test_main.cpp @@ -0,0 +1,544 @@ +// +// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/url +// + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#endif + +namespace test_suite { + +//------------------------------------------------ +// +// debug_stream +// +//------------------------------------------------ + +#ifdef _MSC_VER + +namespace detail { + +class debug_streambuf + : public std::stringbuf +{ + std::ostream& os_; + bool dbg_; + + void + write(char const* s) + { + if(dbg_) + ::OutputDebugStringA(s); + os_ << s; + } + +public: + explicit + debug_streambuf( + std::ostream& os) + : os_(os) + , dbg_(::IsDebuggerPresent() != 0) + { + } + + ~debug_streambuf() + { + sync(); + } + + int sync() override + { + write(this->str().c_str()); + this->str(""); + return 0; + } +}; + +} // detail + +//------------------------------------------------ + +/** std::ostream with Visual Studio IDE redirection. + + Instances of this stream wrap a specified + `ostream` (such as `cout` or `cerr`). If a + debugger is attached when the stream is + created, output will additionally copied + to the debugger's output window. +*/ +class debug_stream : public std::ostream +{ + detail::debug_streambuf buf_; + +public: + /** Construct a stream. + + @param os The output stream to wrap. + */ + explicit + debug_stream( + std::ostream& os) + : std::ostream(&buf_) + , buf_(os) + { + if(os.flags() & std::ios::unitbuf) + std::unitbuf(*this); + } + +}; + +#else + +using debug_stream = std::ostream&; + +#endif + +//------------------------------------------------ +// +// suite +// +//------------------------------------------------ + +any_suite:: +~any_suite() = default; + +//------------------------------------------------ + +suites& +suites:: +instance() noexcept +{ + class suites_impl : public suites + { + std::vector v_; + + public: + virtual ~suites_impl() = default; + + void + insert(any_suite const& t) override + { + v_.push_back(&t); + } + + iterator + begin() const noexcept override + { + if(! v_.empty()) + return &v_[0]; + return nullptr; + } + + iterator + end() const noexcept override + { + if(! v_.empty()) + return &v_[0] + v_.size(); + return nullptr; + } + + void + sort() override + { + std::sort( + v_.begin(), + v_.end(), + []( any_suite const* p0, + any_suite const* p1) + { + auto s0 = p0->name(); + auto n0 = std::strlen(s0); + auto s1 = p1->name(); + auto n1 = std::strlen(s1); + return std::lexicographical_compare( + s0, s0 + n0, s1, s1 + n1); + }); + } + }; + static suites_impl impl; + return impl; +} + +//------------------------------------------------ +// +// runner +// +//------------------------------------------------ + +any_runner*& +any_runner:: +instance_impl() noexcept +{ + static any_runner* p = nullptr; + return p; +} + +any_runner& +any_runner:: +instance() noexcept +{ + return *instance_impl(); +} + +any_runner:: +any_runner() noexcept + : prev_(instance_impl()) +{ + instance_impl() = this; +} + +any_runner:: +~any_runner() +{ + instance_impl() = prev_; +} + +//------------------------------------------------ +// +// implementation +// +//------------------------------------------------ + +namespace detail { + +bool +test_impl( + bool cond, + char const* expr, + char const* func, + char const* file, + int line) +{ + return any_runner::instance().test( + cond, expr, func, file, line); +} + +void +throw_failed_impl( + const char* expr, + char const* excep, + char const* func, + char const* file, + int line) +{ + std::stringstream ss; + ss << + "expression '" << expr << + "' didn't throw '" << excep << + "' in function '" << func << + "'"; + any_runner::instance().test(false, ss.str().c_str(), + func, file, line); +} + +void +no_throw_failed_impl( + const char* expr, + char const* excep, + char const* func, + char const* file, + int line) +{ + std::stringstream ss; + ss << + "expression '" << expr << + "' threw '" << excep << + "' in function '" << func << + "'"; + any_runner::instance().test(false, ss.str().c_str(), + func, file, line); +} + +void +no_throw_failed_impl( + const char* expr, + char const* func, + char const* file, + int line) +{ + std::stringstream ss; + ss << + "expression '" << expr << + "' threw in function '" << func << "'"; + any_runner::instance().test(false, ss.str().c_str(), + func, file, line); +} + +//------------------------------------------------ +// +// simple_runner +// +//------------------------------------------------ + +using clock_type = + std::chrono::steady_clock; + +struct elapsed +{ + clock_type::duration d; +}; + +std::ostream& +operator<<( + std::ostream& os, + elapsed const& e) +{ + using namespace std::chrono; + auto const ms = duration_cast< + milliseconds>(e.d); + if(ms < seconds{1}) + { + os << ms.count() << "ms"; + } + else + { + std::streamsize width{ + os.width()}; + std::streamsize precision{ + os.precision()}; + os << std::fixed << + std::setprecision(1) << + (ms.count() / 1000.0) << "s"; + os.precision(precision); + os.width(width); + } + return os; +} + +} // detail +} // test_suite + +//------------------------------------------------ + +namespace test_suite { +namespace detail { + +class simple_runner : public any_runner +{ + struct summary + { + char const* name; + clock_type::time_point start; + clock_type::duration elapsed; + std::atomic failed; + std::atomic total; + + summary(summary const& other) noexcept + : name(other.name) + , start(other.start) + , elapsed(other.elapsed) + , failed(other.failed.load()) + , total(other.total.load()) + { + } + + explicit + summary(char const* name_) noexcept + : name(name_) + , start(clock_type::now()) + , failed(0) + , total(0) + { + } + }; + + summary all_; + std::ostream& log_; + std::vector v_; + +public: + explicit + simple_runner( + std::ostream& os) + : all_("(all)") + , log_(os) + { + std::unitbuf(log_); + v_.reserve(256); + } + + virtual ~simple_runner() + { + log_ << + elapsed{clock_type::now() - + all_.start } << ", " << + v_.size() << " suites, " << + all_.failed.load() << " failures, " << + all_.total.load() << " total." << + std::endl; + } + + // true if no failures + bool + success() const noexcept + { + return all_.failed.load() == 0; + } + + void + run(any_suite const& test) override + { + v_.emplace_back(test.name()); + log_ << test.name() << "\n"; + test.run(); + v_.back().elapsed = + clock_type::now() - + v_.back().start; + } + + void + note(char const* msg) override + { + log_ << msg << "\n"; + } + + std::ostream& + log() noexcept override + { + return log_; + } + + char const* + filename( + char const* file) + { + auto const p0 = file; + auto p = p0 + std::strlen(file); + while(p-- != p0) + { + #ifdef _MSC_VER + if(*p == '\\') + #else + if(*p == '/') + #endif + break; + } + return p + 1; + } + + bool test(bool, char const*, char const*, char const*, int) override; +}; + +//------------------------------------------------ + +bool +simple_runner:: +test( + bool cond, + char const* expr, + char const* func, + char const* file, + int line) +{ + auto const id = ++all_.total; + ++v_.back().total; + if(cond) + return true; + ++all_.failed; + ++v_.back().failed; + (void)func; + log_ << + "#" << id << " " << + filename(file) << "(" << line << ") " + "failed: " << expr << + //" in " << func << + "\n"; + log_.flush(); + return false; +} + +//------------------------------------------------ + +int +run(std::ostream& out, + int argc, char const* const* argv) +{ + if(argc == 2) + { + std::string arg(argv[1]); + if(arg == "-h" || arg == "--help") + { + log << + "Usage:\n" + " " << argv[0] << ": { ... }" << + std::endl; + return EXIT_SUCCESS; + } + } + + simple_runner any_runner(out); + suites::instance().sort(); + if(argc == 1) + { + for(any_suite const* sp : + suites::instance()) + any_runner.run(*sp); + } + else + { + std::vector args; + args.reserve(argc - 1); + for(int i = 0; i < argc - 1; ++i) + args.push_back(argv[i + 1]); + for(auto const& e : suites::instance()) + { + std::string s(e->name()); + if(std::find_if( + args.begin(), args.end(), + [&](std::string const& arg) + { + if(arg.size() > s.size()) + return false; + return s.compare( + s.size() - arg.size(), + arg.size(), + arg.data(), + arg.size()) == 0; + }) != args.end()) + { + any_runner.run(*e); + } + } + } + return any_runner.success() ? + EXIT_SUCCESS : EXIT_FAILURE; +} + +} // detail +} // test_suite + +//------------------------------------------------ + +// Simple main used to produce stand +// alone executables that run unit tests. +int main(int argc, char const* const* argv) +{ +#if defined(_MSC_VER) && !defined(__clang__) + int flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + flags |= _CRTDBG_LEAK_CHECK_DF; + _CrtSetDbgFlag(flags); +#endif + + ::test_suite::debug_stream log(std::cerr); + return ::test_suite::detail::run(log, argc, argv); +} diff --git a/test/io/buffers/test_suite.hpp b/test/io/buffers/test_suite.hpp new file mode 100644 index 00000000..9eb33428 --- /dev/null +++ b/test/io/buffers/test_suite.hpp @@ -0,0 +1,502 @@ +// +// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/url +// + +#ifndef BOOST_URL_EXTRA_TEST_SUITE_HPP +#define BOOST_URL_EXTRA_TEST_SUITE_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +#include +#include +#include +#include + +// This is a derivative work +// Copyright 2002-2018 Peter Dimov +// Copyright (c) 2002, 2009, 2014 Peter Dimov +// Copyright (2) Beman Dawes 2010, 2011 +// Copyright (3) Ion Gaztanaga 2013 +// +// Copyright 2018 Glen Joseph Fernandes +// (glenjofe@gmail.com) + +namespace test_suite { + +//------------------------------------------------ + +struct any_suite +{ + virtual ~any_suite() = 0; + virtual char const* name() const noexcept = 0; + virtual void run() const = 0; +}; + +//------------------------------------------------ + +struct suites +{ + virtual ~suites() = default; + + using iterator = any_suite const* const*; + virtual void insert(any_suite const&) = 0; + virtual iterator begin() const noexcept = 0; + virtual iterator end() const noexcept = 0; + + // DEPRECATED + virtual void sort() = 0; + + static suites& instance() noexcept; +}; + +//------------------------------------------------ + +template +class suite : public any_suite +{ + char const* name_; + +public: + explicit + suite(char const* name) noexcept + : name_(name) + { + suites::instance().insert(*this); + } + + char const* + name() const noexcept override + { + return name_; + } + + void + run() const override + { + T().run(); + } +}; + +//------------------------------------------------ + +class any_runner +{ + any_runner* prev_; + + static any_runner*& + instance_impl() noexcept; + +public: + static any_runner& instance() noexcept; + + any_runner() noexcept; + virtual ~any_runner(); + + virtual void run(any_suite const& test) = 0; + virtual void note(char const* msg) = 0; + virtual bool test(bool cond, + char const* expr, char const* func, + char const* file, int line) = 0; + virtual std::ostream& log() noexcept = 0; +}; + +//------------------------------------------------ + +namespace detail { + +// In the comparisons below, it is possible that +// T and U are signed and unsigned integer types, +// which generates warnings in some compilers. +// A cleaner fix would require common_type trait +// or some meta-programming, which would introduce +// a dependency on Boost.TypeTraits. To avoid +// the dependency we just disable the warnings. +#if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wsign-compare") +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wsign-compare" +# endif +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4389) +# pragma warning(disable: 4018) +#elif defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wsign-compare" +#endif + +template +struct make_void +{ + using type = void; +}; + +template +struct is_streamable : std::false_type +{}; + +template +struct is_streamable< + T, std::void_t() << std::declval()) + > > : std::true_type +{}; + +template +auto +test_output_impl(T const& v) -> + typename std::enable_if< + is_streamable::value, + T const&>::type +{ + return v; +} + +template +auto +test_output_impl(T const&) -> + typename std::enable_if< + ! is_streamable::value, + std::string>::type +{ + return "?"; +} + +// specialize test output for char pointers to avoid printing as cstring +template + const void* test_output_impl(T volatile* v) { return const_cast(v); } +inline const void* test_output_impl(const char* v) { return v; } +inline const void* test_output_impl(const unsigned char* v) { return v; } +inline const void* test_output_impl(const signed char* v) { return v; } +inline const void* test_output_impl(char* v) { return v; } +inline const void* test_output_impl(unsigned char* v) { return v; } +inline const void* test_output_impl(signed char* v) { return v; } +inline const void* test_output_impl(std::nullptr_t) { return nullptr; } + +// print chars as numeric +inline int test_output_impl( signed char const& v ) { return v; } +inline unsigned test_output_impl( unsigned char const& v ) { return v; } + +// Whether wchar_t is signed is implementation-defined +template struct lwt_long_type {}; +template<> struct lwt_long_type { typedef long type; }; +template<> struct lwt_long_type { typedef unsigned long type; }; +inline lwt_long_type< + (static_cast(-1) < static_cast(0)) + >::type test_output_impl( wchar_t const& v ) { return v; } + +#if !defined( BOOST_NO_CXX11_CHAR16_T ) +inline unsigned long test_output_impl( char16_t const& v ) { return v; } +#endif + +#if !defined( BOOST_NO_CXX11_CHAR32_T ) +inline unsigned long test_output_impl( char32_t const& v ) { return v; } +#endif + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4996) +#endif + +inline std::string test_output_impl( char const& v ) +{ + if( std::isprint( static_cast( v ) ) ) + { + return { 1, v }; + } + else + { + char buffer[ 8 ]; + std::sprintf( buffer, "\\x%02X", static_cast( v ) ); + + return buffer; + } +} + +bool +test_impl( + bool cond, + char const* expr, + char const* func, + char const* file, + int line); + +void +throw_failed_impl( + const char* expr, + char const* excep, + char const* func, + char const* file, + int line); + +void +no_throw_failed_impl( + const char* expr, + char const* excep, + char const* func, + char const* file, + int line); + +void +no_throw_failed_impl( + const char* expr, + char const* func, + char const* file, + int line); + +struct lw_test_eq +{ + template + bool operator()(const T& t, const U& u) const + { + return t == u; + } +}; + +struct lw_test_ne +{ + + template + bool operator()(const T& t, const U& u) const + { + return t != u; + } +}; + +struct lw_test_lt +{ + template + bool operator()(const T& t, const U& u) const + { + return t < u; + } +}; + +struct lw_test_gt +{ + template + bool operator()(const T& t, const U& u) const + { + return t > u; + } +}; + +struct lw_test_le +{ + template + bool operator()(const T& t, const U& u) const + { + return t <= u; + } +}; + +struct lw_test_ge +{ + template + bool operator()(const T& t, const U& u) const + { + return t >= u; + } +}; + +// lwt_predicate_name + +template char const * lwt_predicate_name( T const& ) +{ + return "~="; +} + +inline char const * lwt_predicate_name( lw_test_eq const& ) +{ + return "=="; +} + +inline char const * lwt_predicate_name( lw_test_ne const& ) +{ + return "!="; +} + +inline char const * lwt_predicate_name( lw_test_lt const& ) +{ + return "<"; +} + +inline char const * lwt_predicate_name( lw_test_le const& ) +{ + return "<="; +} + +inline char const * lwt_predicate_name( lw_test_gt const& ) +{ + return ">"; +} + +inline char const * lwt_predicate_name( lw_test_ge const& ) +{ + return ">="; +} + +//------------------------------------------------ + +template +bool +test_with_impl( + Pred pred, + char const* expr1, + char const* expr2, + char const* func, + char const* file, + int line, + T const& t, U const& u) +{ + if(pred(t, u)) + { + any_runner::instance().test( + true, "", func, file, line); + return true; + } + std::stringstream ss; + ss << + "\"" << test_output_impl(t) << "\" " << + lwt_predicate_name(pred) << + " \"" << test_output_impl(u) << "\" (" << + expr1 << " " << + lwt_predicate_name(pred) << + " " << expr2 << ")"; + any_runner::instance().test( + false, ss.str().c_str(), func, file, line); + return false; +} + +#if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wsign-compare") +# pragma clang diagnostic pop +# endif +#elif defined(_MSC_VER) +# pragma warning(pop) +#elif defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 +# pragma GCC diagnostic pop +#endif + +//------------------------------------------------ + +struct log_type +{ + template + friend + std::ostream& + operator<<( + log_type const&, T&& t) + { + return any_runner::instance().log() << t; + } +}; + +//------------------------------------------------ + +} // detail + +/** Log output to the current suite +*/ +constexpr detail::log_type log{}; + +#define BOOST_TEST(expr) ( \ + ::test_suite::detail::test_impl( \ + (expr) ? true : false, #expr, \ + BOOST_CURRENT_FUNCTION, __FILE__, __LINE__ ) ) + +#define BOOST_ERROR(msg) \ + ::test_suite::detail::test_impl( \ + false, msg, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__ ) + +#define BOOST_TEST_WITH(expr1,expr2,predicate) ( \ + ::test_suite::detail::test_with_impl( \ + predicate, #expr1, #expr2, BOOST_CURRENT_FUNCTION, \ + __FILE__, __LINE__, expr1, expr2) ) + +#define BOOST_TEST_EQ(expr1,expr2) \ + BOOST_TEST_WITH( expr1, expr2, \ + ::test_suite::detail::lw_test_eq() ) + +#define BOOST_TEST_CSTR_EQ(expr1,expr2) \ + BOOST_TEST_EQ( string_view(expr1), string_view(expr2) ) + +#define BOOST_TEST_NE(expr1,expr2) \ + BOOST_TEST_WITH( expr1, expr2, \ + ::test_suite::detail::lw_test_ne() ) + +#define BOOST_TEST_LT(expr1,expr2) \ + BOOST_TEST_WITH( expr1, expr2, \ + ::test_suite::detail::lw_test_lt() ) + +#define BOOST_TEST_LE(expr1,expr2) \ + BOOST_TEST_WITH( expr1, expr2, \ + ::test_suite::detail::lw_test_le() ) + +#define BOOST_TEST_GT(expr1,expr2) \ + BOOST_TEST_WITH( expr1, expr2, \ + ::test_suite::detail::lw_test_gt() ) + +#define BOOST_TEST_GE(expr1,expr2) \ + BOOST_TEST_WITH( expr1, expr2, \ + ::test_suite::detail::lw_test_ge() ) + +#define BOOST_TEST_PASS() BOOST_TEST(true) + +#define BOOST_TEST_FAIL() BOOST_TEST(false) + +#define BOOST_TEST_NOT(expr) BOOST_TEST(!(expr)) + +#ifndef BOOST_NO_EXCEPTIONS +# define BOOST_TEST_THROWS( expr, ex ) \ + try { \ + (void)(expr); \ + ::test_suite::detail::throw_failed_impl( \ + #expr, #ex, BOOST_CURRENT_FUNCTION, \ + __FILE__, __LINE__); \ + } \ + catch(ex const&) { \ + BOOST_TEST_PASS(); \ + } \ + catch(...) { \ + ::test_suite::detail::throw_failed_impl( \ + #expr, #ex, BOOST_CURRENT_FUNCTION, \ + __FILE__, __LINE__); \ + } + // +#else + #define BOOST_TEST_THROWS( expr, ex ) +#endif + +#ifndef BOOST_NO_EXCEPTIONS +# define BOOST_TEST_NO_THROW( expr ) \ + try { \ + (void)(expr); \ + BOOST_TEST_PASS(); \ + } catch (const std::exception& e) { \ + ::test_suite::detail::no_throw_failed_impl( \ + #expr, e.what(), BOOST_CURRENT_FUNCTION, \ + __FILE__, __LINE__); \ + } catch (...) { \ + ::test_suite::detail::no_throw_failed_impl( \ + #expr, BOOST_CURRENT_FUNCTION, \ + __FILE__, __LINE__); \ + } + // +#else +# define BOOST_TEST_NO_THROW( expr ) ( [&]{ expr; return true; }() ) +#endif + +#define TEST_SUITE(type, name) \ + static ::test_suite::suite type##_(name) + +} // test_suite + +#endif diff --git a/test/io/buffers/type_traits.cpp b/test/io/buffers/type_traits.cpp new file mode 100644 index 00000000..7a9d9e6d --- /dev/null +++ b/test/io/buffers/type_traits.cpp @@ -0,0 +1,11 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include From dfd28e49672bf45b5765a8a22fe9b84dcfb616e0 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Thu, 29 Jun 2023 15:12:45 +0800 Subject: [PATCH 02/43] added endpoint type --- CMakeLists.txt | 4 +- doc/reference/io.adoc | 4 + doc/reference/io/endpoint.adoc | 132 ++++++++++++ include/boost/async/io/endpoint.hpp | 321 ++++++++++++++++++++++++++++ src/io/endpoint.cpp | 226 ++++++++++++++++++++ test/CMakeLists.txt | 2 +- test/io/CMakeLists.txt | 4 + test/io/endpoint.cpp | 183 ++++++++++++++++ 8 files changed, 874 insertions(+), 2 deletions(-) create mode 100644 doc/reference/io.adoc create mode 100644 doc/reference/io/endpoint.adoc create mode 100644 include/boost/async/io/endpoint.hpp create mode 100644 src/io/endpoint.cpp create mode 100644 test/io/endpoint.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a0806ad6..8df8a9e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,12 +85,14 @@ add_library(boost_async src/channel.cpp src/main.cpp src/this_thread.cpp + src/thread.cpp src/io/buffers/circular_buffer.cpp src/io/buffers/const_buffer_pair.cpp src/io/buffers/const_buffer_subspan.cpp src/io/buffers/mutable_buffer_pair.cpp src/io/buffers/mutable_buffer_subspan.cpp - src/thread.cpp) + src/io/endpoint.cpp) + target_include_directories(boost_async PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(boost_async PUBLIC Boost::system diff --git a/doc/reference/io.adoc b/doc/reference/io.adoc new file mode 100644 index 00000000..a9cb727b --- /dev/null +++ b/doc/reference/io.adoc @@ -0,0 +1,4 @@ +[#io] +== async/io.hpp + +include::io/endpoint.adoc[] diff --git a/doc/reference/io/endpoint.adoc b/doc/reference/io/endpoint.adoc new file mode 100644 index 00000000..ded2b1b6 --- /dev/null +++ b/doc/reference/io/endpoint.adoc @@ -0,0 +1,132 @@ +[#io::endpoint] +=== async/io/endpoint.hpp + +The endpoint header provides a simple wrapper around endpoints. + +The usage is simple: + +[source,cpp] +---- +async::io::endpoint domain_socket{async::io::local_stream, "/var/sys/socket"}; +async::io::local_endpoint le = get(domain_socket); + + +async::io::endpoint ip_socket{async::io::tcp, "192.168.0.1", 8080}; +async::io::local_endpoint le = get(domain_socket); +---- + +NOTE: `AF_UNSPEC` is treated as an IP that's either ipv6 or ip_v4. + +==== Reference + + +[source,cpp] +---- +// a simple type holding the triplet to describe any endpoint +struct protocol_type +{ + using family_t = *implementation-defined*; + using type_t = *implementation-defined*; + using protocol_t = *implementation-defined*; + + constexpr family_t family() const noexcept {return family_;}; + constexpr type_t type() const noexcept {return type_;}; + constexpr protocol_t protocol() const noexcept {return protocol_;}; + + constexpr explicit + protocol_type(family_t family = static_cast(0), + type_t type = static_cast(0), + protocol_t protocol = static_cast(0)) noexcept + + constexpr protocol_type(const OtherProtocol & op) noexcept; + {} + // asio compatibility + using endpoint = endpoint; +}; + +// the class holding the endpiont +struct endpoint +{ + using storage_type = boost::asio::detail::sockaddr_storage_type; + using addr_type = boost::asio::detail::socket_addr_type; + void resize(std::size_t size); + + void * data(); + const void * data() const; + std::size_t size(); + + protocol_type protocol() const; + + endpoint() = default; + endpoint(const endpoint & ep); + + template + endpoint(static_protocol proto, Args && ... args); + +}; + +// get the type of the endpoint family, see below. +cosnt auto * get_if(const endpoint * ep); +// get the type of the endpoint family, see below. throws `bad_endpoint_access` if a mismatched. +const auto & get(const endpoint & ep); +---- + +To make it type-safe, the library provides a `static_protocol` template: + +[source,cpp] +---- +template(0), + protocol_type::type_t Type = static_cast(0), + protocol_type::protocol_t Protocol = static_cast(0)> +struct static_protocol +{ + using family_t = protocol_type::family_t ; + using type_t = protocol_type::type_t ; + using protocol_t = protocol_type::protocol_t; + + constexpr family_t family() const noexcept {return Family;}; + constexpr type_t type() const noexcept {return Type;}; + constexpr protocol_t protocol() const noexcept {return Protocol;}; + + using endpoint = endpoint; +}; +---- + +These can be used to define a constexpr constant for an endpoint type. The following are provided: + +[source,cpp] +---- +constexpr static_protocol ip {}; +constexpr static_protocol ip_v4 {}; +constexpr static_protocol ip_v6 {}; +constexpr static_protocol tcp {}; +constexpr static_protocol tcp_v4{}; +constexpr static_protocol tcp_v6{}; +constexpr static_protocol udp {}; +constexpr static_protocol udp_v4{}; +constexpr static_protocol udp_v6{}; +constexpr static_protocol icmp {}; +constexpr static_protocol local_stream {}; +constexpr static_protocol local_datagram {}; +constexpr static_protocol local_seqpacket{}; +constexpr static_protocol local_protocol {}; +---- + +To add your own family type you need to implement those two `tag_invoke` functions: + +[source,cpp] +---- +/// returns the size of the emplaced type. +std::size_t tag_invoke(make_endpoint_tag, + boost::asio::detail::socket_addr_type* base, // memory to in-place new + ... /* the arguments you need */); + +/// get a pointer to the endpoint type. +const your_endpoint* tag_invoke(get_endpoint_tag, + protocol_type actual, + const endpoint::addr_type * addr); +---- + diff --git a/include/boost/async/io/endpoint.hpp b/include/boost/async/io/endpoint.hpp new file mode 100644 index 00000000..362722a8 --- /dev/null +++ b/include/boost/async/io/endpoint.hpp @@ -0,0 +1,321 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_ENDPOINT_HPP +#define BOOST_ASYNC_IO_ENDPOINT_HPP + +#include +#include + +#include +#include +#include +#include + +namespace boost::async::detail +{ + +BOOST_ASYNC_DECL BOOST_NORETURN void +throw_bad_endpoint_access( + source_location const& loc); + +} + +namespace boost::async::io +{ + +struct endpoint; + + +struct protocol_type +{ + using family_t = decltype(BOOST_ASIO_OS_DEF(AF_INET)); + using type_t = decltype(BOOST_ASIO_OS_DEF(SOCK_STREAM)); + using protocol_t = decltype(BOOST_ASIO_OS_DEF(IPPROTO_TCP)); + + constexpr family_t family() const noexcept {return family_;}; + constexpr type_t type() const noexcept {return type_;}; + constexpr protocol_t protocol() const noexcept {return protocol_;}; + + constexpr explicit + protocol_type(family_t family = static_cast(0), + type_t type = static_cast(0), + protocol_t protocol = static_cast(0)) noexcept + : family_(family), type_(type), protocol_(protocol) + {} + + template + requires requires (const OtherProtocol & op) + { + {op.family()} -> std::convertible_to; + {op.type()} -> std::convertible_to; + {op.protocol()} -> std::convertible_to; + } + constexpr protocol_type(const OtherProtocol & op) noexcept + : family_(op.family()), type_(op.type()), protocol_(op.protocol()) + {} + + friend + constexpr auto operator<=>(const protocol_type & , const protocol_type &) noexcept = default; + + using endpoint = endpoint; + + private: + family_t family_; + type_t type_; + protocol_t protocol_; +}; + +template(0), + protocol_type::type_t Type = static_cast(0), + protocol_type::protocol_t Protocol = static_cast(0)> +struct static_protocol +{ + using family_t = protocol_type::family_t ; + using type_t = protocol_type::type_t ; + using protocol_t = protocol_type::protocol_t; + + constexpr family_t family() const noexcept {return Family;}; + constexpr type_t type() const noexcept {return Type;}; + constexpr protocol_t protocol() const noexcept {return Protocol;}; + + using endpoint = endpoint; +}; + + +constexpr static_protocol ip {}; +constexpr static_protocol ip_v4 {}; +constexpr static_protocol ip_v6 {}; +constexpr static_protocol tcp {}; +constexpr static_protocol tcp_v4{}; +constexpr static_protocol tcp_v6{}; +constexpr static_protocol udp {}; +constexpr static_protocol udp_v4{}; +constexpr static_protocol udp_v6{}; +constexpr static_protocol icmp {}; +constexpr static_protocol local_stream {}; +constexpr static_protocol local_datagram {}; +constexpr static_protocol local_seqpacket{}; +constexpr static_protocol local_protocol {}; + +template +struct make_endpoint_tag {}; + +template +struct get_endpoint_tag {}; + +struct endpoint +{ + using storage_type = boost::asio::detail::sockaddr_storage_type; + using addr_type = boost::asio::detail::socket_addr_type; + void resize(std::size_t size) + { + BOOST_ASSERT(size < sizeof(storage_)); + size_ = size; + } + + void * data() {return &storage_; } + const void * data() const {return &storage_; } + std::size_t size() {return size_;} + + protocol_type protocol() const + { + return protocol_type{static_cast(base_.sa_family), type_, protocol_}; + } + + endpoint() = default; + endpoint(const endpoint & ep) : storage_(ep.storage_), size_(ep.size_), protocol_(ep.protocol_), type_(ep.type_) + { + } + + template + requires requires (make_endpoint_tag proto, + addr_type* addr, Args && ... args) + { + {tag_invoke(proto, addr, std::forward(args)...)} -> std::convertible_to; + } + endpoint(static_protocol proto, Args && ... args) + : base_{}, + protocol_(Protocol), type_(Type) + { + size_ = tag_invoke(make_endpoint_tag{}, &base_, std::forward(args)...); + } + + template + requires requires (get_endpoint_tag tag, + protocol_type actual, + const addr_type * addr) {{tag_invoke(tag, actual, addr)};} + friend auto get_if(const endpoint * ep) + -> decltype(tag_invoke(get_endpoint_tag{}, protocol_type{}, + static_cast(nullptr))) + { + const auto actual = ep->protocol(); + if (Protocol.type() != 0 && actual.type() != 0 && actual.type() != Protocol.type()) + return nullptr; + if (Protocol.protocol() != 0 && actual.protocol() != 0 && actual.protocol() != Protocol.protocol()) + return nullptr; + return tag_invoke(get_endpoint_tag{}, ep->protocol(), &ep->base_); + } + + + private: + union { + boost::asio::detail::socket_addr_type base_{}; + storage_type storage_; + }; + std::size_t size_{sizeof(base_)}; + protocol_type::protocol_t protocol_; + protocol_type::type_t type_; +}; + +class bad_endpoint_access : public std::exception +{ + public: + + bad_endpoint_access() noexcept = default; + + char const * what() const noexcept + { + return "bad_endpoint_access"; + } +}; + +template + requires requires (get_endpoint_tag tag, + protocol_type actual, + endpoint::addr_type * addr) {{tag_invoke(tag, actual, addr)};} +auto get(const endpoint & ep, const boost::source_location & loc = BOOST_CURRENT_LOCATION) +{ + auto e = get_if(&ep); + if (!e) + detail::throw_bad_endpoint_access(loc); + return *e; +} + +struct local_endpoint +{ + core::string_view path() { return unix_.sun_path;} + private: + union { + boost::asio::detail::sockaddr_storage_type addr_; + boost::asio::detail::sockaddr_un_type unix_; + }; +}; + +BOOST_ASYNC_DECL +std::size_t tag_invoke(make_endpoint_tag, + boost::asio::detail::socket_addr_type* base, + core::string_view sv); + +BOOST_ASYNC_DECL +const local_endpoint* tag_invoke(get_endpoint_tag, + protocol_type actual, + const endpoint::addr_type * addr); + +struct ip_address_v4 +{ + std::uint16_t port() const {return in_.sin_port;} + std::uint32_t addr() const {return in_.sin_addr.s_addr;} + BOOST_ASYNC_DECL static_string<15> addr_str() const; + + private: + union { + boost::asio::detail::sockaddr_storage_type addr_{}; + boost::asio::detail::sockaddr_in4_type in_; + }; +}; + +BOOST_ASYNC_DECL +std::size_t tag_invoke(make_endpoint_tag, + boost::asio::detail::socket_addr_type* base, + std::uint32_t address, + std::uint16_t port); + +BOOST_ASYNC_DECL +std::size_t tag_invoke(make_endpoint_tag, + boost::asio::detail::socket_addr_type* base, + std::string_view address, + std::uint16_t port); + +BOOST_ASYNC_DECL +const ip_address_v4* tag_invoke(get_endpoint_tag, + protocol_type actual, + const endpoint::addr_type * addr); + + +struct ip_address_v6 +{ + std::uint16_t port() const {return in_.sin6_port;} + std::array addr() const + { + std::array res; + const auto & in = in_.sin6_addr.s6_addr; + std::copy(std::begin(in), std::end(in), res.begin()); + return res; + } + BOOST_ASYNC_DECL static_string<45> addr_str() const; + private: + union { + boost::asio::detail::sockaddr_storage_type addr_{}; + boost::asio::detail::sockaddr_in6_type in_; + }; +}; + +BOOST_ASYNC_DECL +std::size_t tag_invoke(make_endpoint_tag, + boost::asio::detail::socket_addr_type* base, + std::span address, + std::uint16_t port); + +BOOST_ASYNC_DECL +std::size_t tag_invoke(make_endpoint_tag, + boost::asio::detail::socket_addr_type* base, + std::string_view address, + std::uint16_t port); + +BOOST_ASYNC_DECL +const ip_address_v6* tag_invoke(get_endpoint_tag, + protocol_type actual, + const endpoint::addr_type * addr); + + +struct ip_address +{ + + bool is_ipv6() const { return addr_.ss_family == BOOST_ASIO_OS_DEF(AF_INET6); } + bool is_ipv4() const { return addr_.ss_family == BOOST_ASIO_OS_DEF(AF_INET); } + + std::uint16_t port() const {return addr_.ss_family == AF_INET ? in_.sin_port : in6_.sin6_port;} + + BOOST_ASYNC_DECL std::array addr() const; + BOOST_ASYNC_DECL static_string<45> addr_str() const; + private: + union { + boost::asio::detail::sockaddr_storage_type addr_{}; + boost::asio::detail::sockaddr_in4_type in_; + boost::asio::detail::sockaddr_in6_type in6_; + }; +}; + +BOOST_ASYNC_DECL +std::size_t tag_invoke(make_endpoint_tag, + boost::asio::detail::socket_addr_type* base, + std::string_view address, + std::uint16_t port); + +BOOST_ASYNC_DECL +const ip_address* tag_invoke(get_endpoint_tag, + protocol_type actual, + const endpoint::addr_type * addr); + + +} + +#endif //BOOST_ASYNC_IO_ENDPOINT_HPP diff --git a/src/io/endpoint.cpp b/src/io/endpoint.cpp new file mode 100644 index 00000000..4936d3ba --- /dev/null +++ b/src/io/endpoint.cpp @@ -0,0 +1,226 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include + +#include +#include + +namespace boost::async::detail +{ + +void +throw_bad_endpoint_access( + source_location const &loc) +{ + throw_exception( + async::io::bad_endpoint_access(), loc); +} + +} + +namespace boost::async::io +{ +static_assert(std::is_standard_layout_v); +static_assert(std::is_standard_layout_v); +static_assert(std::is_standard_layout_v); +static_assert(std::is_standard_layout_v); +static_assert(std::is_standard_layout_v); + +std::size_t tag_invoke(make_endpoint_tag, + boost::asio::detail::socket_addr_type* base, + core::string_view sv) +{ + auto un = new (base) boost::asio::detail::sockaddr_un_type{ + .sun_family=AF_UNIX + }; + + if (sv.size() >= sizeof(un->sun_path)) + detail::throw_length_error(); + + *std::copy(sv.begin(), sv.end(), un->sun_path) = '\0'; + return sizeof(un->sun_family + sv.size() + 1u); +} + +const local_endpoint* tag_invoke(get_endpoint_tag, + protocol_type actual, + const endpoint::addr_type * addr) +{ + if (actual.family() != AF_UNIX) + return nullptr; + return reinterpret_cast(addr); +} + +static_string<15> ip_address_v4::addr_str() const +{ + char buf[16]; + inet_ntop(AF_INET, &in_.sin_addr.s_addr, buf, sizeof(buf)); + return buf; +} + + +std::size_t tag_invoke(make_endpoint_tag, + boost::asio::detail::socket_addr_type* base, + std::uint32_t address, + std::uint16_t port) +{ + new (base) boost::asio::detail::sockaddr_in4_type{ + .sin_family=AF_INET, + .sin_port=port, + .sin_addr={address} + }; + return sizeof(boost::asio::detail::sockaddr_in4_type); +} + +std::size_t tag_invoke(make_endpoint_tag, + boost::asio::detail::socket_addr_type* base, + std::string_view address, + std::uint16_t port) +{ + if (address.size() > 15) + detail::throw_length_error(); + static_string<16> addr{address.begin(), address.end()}; + + + auto a = boost::asio::ip::address_v4::from_string(addr.c_str()).to_uint(); + auto in4 = new (base) boost::asio::detail::sockaddr_in4_type{ + .sin_family=AF_INET, + .sin_port=port, + .sin_addr={boost::asio::detail::socket_ops::host_to_network_long(a)} + }; + return sizeof(boost::asio::detail::sockaddr_in4_type); +} + +const ip_address_v4* tag_invoke(get_endpoint_tag, + protocol_type actual, + const endpoint::addr_type * addr) +{ + if (actual.family() != AF_INET) + return nullptr; + return reinterpret_cast(addr); +} + + +static_string<45> ip_address_v6::addr_str() const +{ + char buf[46]; + inet_ntop(AF_INET6, &in_.sin6_addr.s6_addr, buf, sizeof(buf)); + return buf; +} + + +std::size_t tag_invoke(make_endpoint_tag, + boost::asio::detail::socket_addr_type* base, + std::span address, + std::uint16_t port) +{ + auto in6 = new (base) boost::asio::detail::sockaddr_in6_type{ + .sin6_family=AF_INET6, + .sin6_port=port + }; + std::copy(address.begin(), address.end(), in6->sin6_addr.s6_addr); + return sizeof(boost::asio::detail::sockaddr_in6_type); +} + +std::size_t tag_invoke(make_endpoint_tag, + boost::asio::detail::socket_addr_type* base, + std::string_view address, + std::uint16_t port) +{ + if (address.size() > 45) + detail::throw_length_error(); + static_string<46> addr{address.begin(), address.end()}; + + auto a = boost::asio::ip::address_v6::from_string(addr.c_str()).to_bytes(); + auto in6 = new (base) boost::asio::detail::sockaddr_in6_type{ + .sin6_family=AF_INET6, + .sin6_port=port + }; + std::copy(a.begin(), a.end(), in6->sin6_addr.s6_addr); + return sizeof(boost::asio::detail::sockaddr_in6_type); +} + +const ip_address_v6* tag_invoke(get_endpoint_tag, + protocol_type actual, + const endpoint::addr_type * addr) +{ + if (actual.family() != AF_INET6) + return nullptr; + return reinterpret_cast(addr); +} + + +std::array ip_address::addr() const +{ + std::array res; + if (addr_.ss_family == AF_INET) + { + const auto & in = in_.sin_addr.s_addr; + const auto c = reinterpret_cast(&in); + auto itr = std::fill_n(res.begin(), 12u, 0u); + std::copy(c, c + 4, itr); + } + else + { + const auto & in = in6_.sin6_addr.s6_addr; + std::copy(std::begin(in), std::end(in), res.begin()); + } + return res; +} + +static_string<45> ip_address::addr_str() const +{ + char buf[46]; + inet_ntop(addr_.ss_family, + (addr_.ss_family == AF_INET6) ? + static_cast(&in6_.sin6_addr.s6_addr) : &in_.sin_addr.s_addr, + buf, sizeof(buf)); + return buf; +} + +std::size_t tag_invoke(make_endpoint_tag, + boost::asio::detail::socket_addr_type* base, + std::string_view address, + std::uint16_t port) +{ + if (address.size() > 45) + detail::throw_length_error(); + static_string<46> addr{address.begin(), address.end()}; + + auto ad = boost::asio::ip::address::from_string(addr.c_str()); + if (ad.is_v4()) + { + new (base) boost::asio::detail::sockaddr_in4_type{ + .sin_family=AF_INET, + .sin_port=port, + .sin_addr={boost::asio::detail::socket_ops::network_to_host_long(ad.to_v4().to_uint())} + }; + return sizeof(boost::asio::detail::sockaddr_in4_type); + } + else + { + auto in6 = new (base) boost::asio::detail::sockaddr_in6_type{ + .sin6_family=AF_INET6, + .sin6_port=port + }; + auto a = ad.to_v6().to_bytes(); + std::copy(a.begin(), a.end(), in6->sin6_addr.s6_addr); + return sizeof(boost::asio::detail::sockaddr_in4_type); + } +} + +const ip_address* tag_invoke(get_endpoint_tag, + protocol_type actual, + const endpoint::addr_type * addr) +{ + if ((actual.family() != AF_INET) && (actual.family() != AF_INET6)) + return nullptr; + return reinterpret_cast(addr); +} + +} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8a3f48a2..0f235110 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -15,7 +15,7 @@ target_link_libraries(boost_async_main_compile Boost::async OpenSSL::SSL) target_link_libraries(boost_async_basic_tests Boost::async OpenSSL::SSL) add_test(NAME boost_async-main COMMAND boost_async_main) -add_test(NAME boost_async-basic_tests COMMAND boost_async_basic_tests) +add_test(NAME boost_async-basic COMMAND boost_async_basic_tests) file(GLOB ALL_PUBLIC_HEADERS RELATIVE ${CMAKE_SOURCE_DIR}/include/async ${CMAKE_SOURCE_DIR}/include/boost/async/*.hpp) set(ALL_PUBLIC_HEADER_TESTS "") diff --git a/test/io/CMakeLists.txt b/test/io/CMakeLists.txt index b4b3fce4..15b9f3f3 100644 --- a/test/io/CMakeLists.txt +++ b/test/io/CMakeLists.txt @@ -1 +1,5 @@ add_subdirectory(buffers) + +add_executable(boost_async_io_tests endpoint.cpp ../doctest.cpp) +target_link_libraries(boost_async_io_tests Boost::container Boost::async OpenSSL::SSL Boost::url) +add_test(NAME boost_async-io COMMAND boost_async_io_tests) diff --git a/test/io/endpoint.cpp b/test/io/endpoint.cpp new file mode 100644 index 00000000..be470c03 --- /dev/null +++ b/test/io/endpoint.cpp @@ -0,0 +1,183 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include "../doctest.h" + + +TEST_SUITE_BEGIN("endpoint"); + +using namespace boost::async::io; + +/* + use-case analyzer + + vector eps = resolve("http://www.google.com"); + auto tcc = get(eps.front()); + assert(ipa.port() == 80); + + endpoint loc{"tcp://127.0.0.1"}; + endpoint unx{"unix:/home/klemens/.local_thingy"}; + unx.set_type(SOCK_DGRAM); + endpoint uns{local_stream, "/home/klemens/.local_thingy"}; + + endpoint ep{tcp_v4, "127.0.0.1", 5000}; + + auto ip = get(ep); +*/ + +TEST_CASE("any") +{ + endpoint ep{}; + CHECK(ep.protocol() == any_protocol); + //CHECK(!holds_endpoint(ep)); +} + +TEST_CASE("unix") +{ + endpoint ep{local_protocol, "~/thingy"}; + CHECK(ep.protocol() == local_protocol); + //CHECK(ep.protocol() == any_local); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get(ep).path() == "~/thingy"); + + ep = endpoint{local_stream, "/home/klemens/thingy"}; + CHECK(ep.protocol() == local_stream); + CHECK(get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get(ep).path() == "/home/klemens/thingy"); +} + +TEST_CASE("ip_v4") +{ + endpoint ep{ip_v4, "129.168.0.1", 8080}; + CHECK(ep.protocol() == ip_v4); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(get(ep).port() == 8080); + CHECK(get(ep).addr_str() == "129.168.0.1"); + + ep = endpoint{tcp_v4, "192.168.1.4", 8181}; + CHECK(ep.protocol() == tcp_v4); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(get(ep).port() == 8181); + CHECK(get(ep).addr_str() == "192.168.1.4"); +} + + +TEST_CASE("ip_v6") +{ + endpoint ep{ip_v6, "2001:db8::", 8080}; + CHECK(ep.protocol() == ip_v6); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(get(ep).port() == 8080); + CHECK(get(ep).addr_str() == "2001:db8::"); + + ep = endpoint{tcp_v6, "2001:db8:1::ab9:c0a8:102", 8181}; + CHECK(ep.protocol() == tcp_v6); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(get(ep).port() == 8181); + CHECK(get(ep).addr_str() == "2001:db8:1::ab9:c0a8:102"); +} + + +TEST_CASE("ip") +{ + endpoint ep{ip, "129.168.0.1", 8080}; + CHECK(ep.protocol() == ip_v4); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(get(ep).port() == 8080); + CHECK(get(ep).addr_str() == "129.168.0.1"); + + ep = endpoint{tcp, "192.168.1.4", 8181}; + CHECK(ep.protocol() == tcp_v4); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(get(ep).port() == 8181); + CHECK(get(ep).addr_str() == "192.168.1.4"); + + ep = endpoint{ip, "2001:db8::", 8080}; + CHECK(ep.protocol() == ip_v6); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(get(ep).port() == 8080); + CHECK(get(ep).addr_str() == "2001:db8::"); + + ep = endpoint{tcp, "2001:db8:1::ab9:c0a8:102", 8181}; + CHECK(ep.protocol() == tcp_v6); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(!get_if(&ep)); + CHECK(get(ep).port() == 8181); + CHECK(get(ep).addr_str() == "2001:db8:1::ab9:c0a8:102"); +} + +TEST_SUITE_END(); \ No newline at end of file From 15185bde96ac49a7b6f113b392c8bdd776110146 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Thu, 29 Jun 2023 21:47:17 +0800 Subject: [PATCH 03/43] added timers. --- CMakeLists.txt | 4 +- doc/reference/io.adoc | 1 + doc/reference/io/timer.adoc | 52 ++++++++++++++ include/boost/async/io/sleep.hpp | 74 ++++++++++++++++++++ include/boost/async/io/steady_timer.hpp | 93 +++++++++++++++++++++++++ include/boost/async/io/system_timer.hpp | 92 ++++++++++++++++++++++++ src/io/steady_timer.cpp | 42 +++++++++++ src/io/system_timer.cpp | 42 +++++++++++ test/io/CMakeLists.txt | 7 +- test/io/endpoint.cpp | 6 -- test/io/sleep.cpp | 37 ++++++++++ test/test.hpp | 17 ++++- 12 files changed, 457 insertions(+), 10 deletions(-) create mode 100644 doc/reference/io/timer.adoc create mode 100644 include/boost/async/io/sleep.hpp create mode 100644 include/boost/async/io/steady_timer.hpp create mode 100644 include/boost/async/io/system_timer.hpp create mode 100644 src/io/steady_timer.cpp create mode 100644 src/io/system_timer.cpp create mode 100644 test/io/sleep.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8df8a9e7..b40f93d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,9 @@ add_library(boost_async src/io/buffers/const_buffer_subspan.cpp src/io/buffers/mutable_buffer_pair.cpp src/io/buffers/mutable_buffer_subspan.cpp - src/io/endpoint.cpp) + src/io/endpoint.cpp + src/io/steady_timer.cpp + src/io/system_timer.cpp) target_include_directories(boost_async PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(boost_async PUBLIC diff --git a/doc/reference/io.adoc b/doc/reference/io.adoc index a9cb727b..13d03670 100644 --- a/doc/reference/io.adoc +++ b/doc/reference/io.adoc @@ -1,4 +1,5 @@ [#io] == async/io.hpp +include::io/timer.adoc[] include::io/endpoint.adoc[] diff --git a/doc/reference/io/timer.adoc b/doc/reference/io/timer.adoc new file mode 100644 index 00000000..2fe88e23 --- /dev/null +++ b/doc/reference/io/timer.adoc @@ -0,0 +1,52 @@ +[#io::timer] +=== async/io/steady_timer.hpp, async/io/system_timer.hpp & async/io/sleep.hpp + +async.io provides simple timers based on a `std::chrono::steady_clock` and `std::chrono::system_clock`. + +The interface between `boost::async::io::steady_timer` and `boost::async::io::system_timer` are equivalent. + +[source,cpp] +---- +struct steady_timer +{ + + using wait_result = system::result; + + /// The clock type. + typedef std::chrono::steady_clock clock_type; + + /// The duration type of the clock. + typedef typename clock_type::duration duration; + + /// The time point type of the clock. + typedef typename clock_type::time_point time_point; + + steady_timer(); + steady_timer(const time_point& expiry_time); + steady_timer(const duration& expiry_duration); + + void cancel(); + + time_point expiry() const; + void reset(const time_point& expiry_time); + void reset(const duration& expiry_time); + bool expired() const; + + [[nodiscard]] awaitable> wait() { return wait_op_{this}; } + // allow the timer to be directly be awaited + awaitable> operator co_await () { return wait(); } +}; + +awaitable> sleep(const steady_timer::time_point& expiry_time); +awaitable> sleep(const steady_timer::duration& expiry_duration); +---- + +==== Example + +[source,cpp] +---- +async::promise do_delay() +{ + co_await sleep(std::chrono::milliseconds(100)); +} +---- \ No newline at end of file diff --git a/include/boost/async/io/sleep.hpp b/include/boost/async/io/sleep.hpp new file mode 100644 index 00000000..5274dc64 --- /dev/null +++ b/include/boost/async/io/sleep.hpp @@ -0,0 +1,74 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_SLEEP_HPP +#define BOOST_ASYNC_IO_SLEEP_HPP + +#include +#include + +#include + +namespace boost::async::detail::io +{ + +struct steady_sleep +{ + steady_sleep(const std::chrono::steady_clock::time_point & tp) : tim{tp} {} + steady_sleep(const std::chrono::steady_clock::duration & du) : tim{du} {} + + auto operator co_await() { return tim.wait(); } + private: + async::io::steady_timer tim; +}; + + +struct system_sleep +{ + system_sleep(const std::chrono::system_clock::time_point & tp) : tim{tp} {} + system_sleep(const std::chrono::system_clock::duration & du) : tim{du} {} + + auto operator co_await() { return tim.wait(); } + private: + async::io::system_timer tim; +}; + +} + +namespace boost::async::io +{ + + + +// NOTE: these don't need to be coros, we can optimize that out. Not sure that's worth it though +detail::io::steady_sleep sleep(const std::chrono::steady_clock::duration & d) { return d;} +detail::io::steady_sleep sleep(const std::chrono::steady_clock::time_point & tp) { return tp;} +detail::io::system_sleep sleep(const std::chrono::system_clock::time_point & tp) { return tp;} + +template +detail::io::steady_sleep sleep(const std::chrono::time_point & tp) +{ + return sleep(std::chrono::time_point_cast(tp)); +} + + +template +detail::io::system_sleep sleep(const std::chrono::time_point & tp) +{ + return sleep(std::chrono::time_point_cast(tp)); +} + + +template +detail::io::steady_sleep sleep(const std::chrono::duration & dur) +{ + return sleep(std::chrono::duration_cast(dur)); +} + +} + +#endif //BOOST_ASYNC_IO_SLEEP_HPP diff --git a/include/boost/async/io/steady_timer.hpp b/include/boost/async/io/steady_timer.hpp new file mode 100644 index 00000000..cab36fab --- /dev/null +++ b/include/boost/async/io/steady_timer.hpp @@ -0,0 +1,93 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_STEADY_TIMER_HPP +#define BOOST_ASYNC_IO_STEADY_TIMER_HPP + +#include +#include + +#include + +namespace boost::async::io +{ + +struct steady_timer +{ + using wait_result = system::result; + + /// The clock type. + typedef std::chrono::steady_clock clock_type; + + /// The duration type of the clock. + typedef typename clock_type::duration duration; + + /// The time point type of the clock. + typedef typename clock_type::time_point time_point; + + steady_timer(); + steady_timer(const time_point& expiry_time); + steady_timer(const duration& expiry_time); + + void cancel(); + + time_point expiry() const; + void reset(const time_point& expiry_time); + void reset(const duration& expiry_time); + bool expired() const; + + private: + struct wait_op_ + { + bool await_ready() const { return timer_->expired(); } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + auto & res = resource.emplace( + buffer, sizeof(buffer), + asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); + timer_->timer_.async_wait(completion_handler{h, result_, &res}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] wait_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + auto ec = std::get<0>(result_.value_or(std::make_tuple(system::error_code{}))); + return ec ? wait_result(ec) : system::in_place_value; + } + wait_op_(steady_timer * timer) : timer_(timer) {} + private: + steady_timer * timer_; + std::exception_ptr error; + std::optional> result_; + char buffer[256]; + std::optional resource; + }; + + public: + [[nodiscard]] wait_op_ wait() { return wait_op_{this}; } + wait_op_ operator co_await () { return wait(); } + private: + boost::asio::basic_waitable_timer, + asio::io_context::executor_type> timer_; +}; + +} + +#endif //BOOST_ASYNC_IO_STEADY_TIMER_HPP diff --git a/include/boost/async/io/system_timer.hpp b/include/boost/async/io/system_timer.hpp new file mode 100644 index 00000000..a8c3712e --- /dev/null +++ b/include/boost/async/io/system_timer.hpp @@ -0,0 +1,92 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_SYSTEM_TIMER_HPP +#define BOOST_ASYNC_IO_SYSTEM_TIMER_HPP + +#include +#include + +#include + +namespace boost::async::io +{ + +struct system_timer final +{ + using wait_result = system::result; + + /// The clock type. + typedef std::chrono::system_clock clock_type; + + /// The duration type of the clock. + typedef typename clock_type::duration duration; + + /// The time point type of the clock. + typedef typename clock_type::time_point time_point; + + system_timer(); + system_timer(const time_point& expiry_time); + system_timer(const duration& expiry_time); + + void cancel(); + + time_point expiry() const; + void reset(const time_point& expiry_time); + void reset(const duration& expiry_time); + bool expired() const; + + struct wait_op_ + { + bool await_ready() const { return timer_->expired(); } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + auto & res = resource.emplace( + buffer, sizeof(buffer), + asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); + timer_->timer_.async_wait(completion_handler{h, result_, &res}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] wait_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + auto ec = std::get<0>(result_.value_or(std::make_tuple(system::error_code{}))); + return ec ? wait_result(ec) : system::in_place_value; + } + + wait_op_(system_timer * timer) : timer_(timer) {} + private: + system_timer * timer_; + std::exception_ptr error; + std::optional> result_; + char buffer[256]; + std::optional resource; + }; + + public: + [[nodiscard]] wait_op_ wait() { return wait_op_{this}; } + wait_op_ operator co_await () { return wait(); } + private: + boost::asio::basic_waitable_timer, + asio::io_context::executor_type> timer_; +}; + +} + +#endif //BOOST_ASYNC_IO_SYSTEM_TIMER_HPP diff --git a/src/io/steady_timer.cpp b/src/io/steady_timer.cpp new file mode 100644 index 00000000..289ce8c2 --- /dev/null +++ b/src/io/steady_timer.cpp @@ -0,0 +1,42 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include + +#include + +namespace boost::async::io +{ + +steady_timer::steady_timer() : timer_(this_thread::get_executor()) {} +steady_timer::steady_timer(const time_point &expiry_time) : timer_(this_thread::get_executor(), expiry_time) {} +steady_timer::steady_timer(const duration &expiry_time) : timer_(this_thread::get_executor(), expiry_time) {} + +void steady_timer::cancel() +{ + timer_.cancel(); +} + + +auto steady_timer::expiry() const -> time_point +{ + return timer_.expiry(); +} + +void steady_timer::reset(const time_point &expiry_time) +{ + timer_.expires_at(expiry_time); +} + +void steady_timer::reset(const duration &expiry_time) +{ + timer_.expires_after(expiry_time); +} + +bool steady_timer::expired() const { return timer_.expiry() < clock_type::now(); } + +} \ No newline at end of file diff --git a/src/io/system_timer.cpp b/src/io/system_timer.cpp new file mode 100644 index 00000000..c64f8f64 --- /dev/null +++ b/src/io/system_timer.cpp @@ -0,0 +1,42 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include + +#include + +namespace boost::async::io +{ + +system_timer::system_timer() : timer_(this_thread::get_executor()) {} +system_timer::system_timer(const time_point &expiry_time) : timer_(this_thread::get_executor(), expiry_time) {} +system_timer::system_timer(const duration &expiry_time) : timer_(this_thread::get_executor(), expiry_time) {} + +void system_timer::cancel() +{ + timer_.cancel(); +} + +auto system_timer::expiry() const -> time_point +{ + return timer_.expiry(); +} + +void system_timer::reset(const time_point &expiry_time) +{ + timer_.expires_at(expiry_time); +} + +void system_timer::reset(const duration &expiry_time) +{ + timer_.expires_after(expiry_time); +} + +bool system_timer::expired() const { return timer_.expiry() < clock_type::now(); } + + +} \ No newline at end of file diff --git a/test/io/CMakeLists.txt b/test/io/CMakeLists.txt index 15b9f3f3..beb8bec6 100644 --- a/test/io/CMakeLists.txt +++ b/test/io/CMakeLists.txt @@ -1,5 +1,8 @@ add_subdirectory(buffers) -add_executable(boost_async_io_tests endpoint.cpp ../doctest.cpp) -target_link_libraries(boost_async_io_tests Boost::container Boost::async OpenSSL::SSL Boost::url) +add_executable(boost_async_io_tests + endpoint.cpp + sleep.cpp + ../doctest.cpp) +target_link_libraries(boost_async_io_tests Boost::container Boost::async OpenSSL::SSL) add_test(NAME boost_async-io COMMAND boost_async_io_tests) diff --git a/test/io/endpoint.cpp b/test/io/endpoint.cpp index be470c03..f7fe8f28 100644 --- a/test/io/endpoint.cpp +++ b/test/io/endpoint.cpp @@ -30,12 +30,6 @@ using namespace boost::async::io; auto ip = get(ep); */ -TEST_CASE("any") -{ - endpoint ep{}; - CHECK(ep.protocol() == any_protocol); - //CHECK(!holds_endpoint(ep)); -} TEST_CASE("unix") { diff --git a/test/io/sleep.cpp b/test/io/sleep.cpp new file mode 100644 index 00000000..a199a4dc --- /dev/null +++ b/test/io/sleep.cpp @@ -0,0 +1,37 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include "../test.hpp" + +#include + +TEST_SUITE_BEGIN("sleep"); + +CO_TEST_CASE_TEMPLATE("sleep-timepoint", Clock, std::chrono::steady_clock, std::chrono::system_clock) +{ + auto pre = Clock::now(); + (co_await boost::async::io::sleep(pre)).value(); + auto post = Clock::now(); + CHECK((post - pre) < std::chrono::milliseconds(50)); + (co_await boost::async::io::sleep(pre + std::chrono::milliseconds(50))).value(); + post = Clock::now(); + CHECK((post - pre) >= std::chrono::milliseconds(50)); +} + +CO_TEST_CASE("sleep-duration") +{ + auto pre = std::chrono::steady_clock::now(); + (co_await boost::async::io::sleep(std::chrono::milliseconds(0))).value(); + auto post = std::chrono::steady_clock::now(); + CHECK((post - pre) < std::chrono::milliseconds(50)); + (co_await boost::async::io::sleep(std::chrono::milliseconds(50))).value(); + post = std::chrono::steady_clock::now(); + CHECK((post - pre) >= std::chrono::milliseconds(50)); +} + + +TEST_SUITE_END(); \ No newline at end of file diff --git a/test/test.hpp b/test/test.hpp index 2f2bda5d..30d8457a 100644 --- a/test/test.hpp +++ b/test/test.hpp @@ -40,7 +40,8 @@ inline void test_run(boost::async::task (*func) ()) spawn(ctx, func(), +[](std::exception_ptr e) { - CHECK(e == nullptr); + if (e) + CHECK_NOTHROW(std::rethrow_exception(e)); }); std::size_t n; n = ctx.run(); @@ -71,6 +72,20 @@ DOCTEST_TEST_CASE(__VA_ARGS__) static ::boost::async::task Function() #define CO_TEST_CASE(...) CO_TEST_CASE_IMPL(DOCTEST_ANONYMOUS(CO_DOCTEST_ANON_FUNC_), __VA_ARGS__) +// end::test_case_macro[] + + // tag::test_case_macro[] +#define CO_TEST_CASE_TEMPLATE_IMPL(Function, Name, T, ...) \ +template \ +static ::boost::async::task Function(); \ +DOCTEST_TEST_CASE_TEMPLATE(Name, T, __VA_ARGS__) \ +{ \ + test_run(&Function); \ +} \ +template \ +static ::boost::async::task Function() + +#define CO_TEST_CASE_TEMPLATE(...) CO_TEST_CASE_TEMPLATE_IMPL(DOCTEST_ANONYMOUS(CO_DOCTEST_ANON_FUNC_), __VA_ARGS__) // end::test_case_macro[] struct stop From b95d51b03900463a4f0ba4613002564b774692b2 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Thu, 29 Jun 2023 23:11:23 +0800 Subject: [PATCH 04/43] added resolver. --- CMakeLists.txt | 1 + doc/reference/io.adoc | 1 + doc/reference/io/resolver.adoc | 76 +++++++++++++++++++++ include/boost/async/io/endpoint.hpp | 16 ++--- include/boost/async/io/resolver.hpp | 101 ++++++++++++++++++++++++++++ src/io/resolver.cpp | 39 +++++++++++ test/io/CMakeLists.txt | 1 + test/io/resolver.cpp | 27 ++++++++ 8 files changed, 254 insertions(+), 8 deletions(-) create mode 100644 doc/reference/io/resolver.adoc create mode 100644 include/boost/async/io/resolver.hpp create mode 100644 src/io/resolver.cpp create mode 100644 test/io/resolver.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b40f93d1..0d3dba7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,6 +92,7 @@ add_library(boost_async src/io/buffers/mutable_buffer_pair.cpp src/io/buffers/mutable_buffer_subspan.cpp src/io/endpoint.cpp + src/io/resolver.cpp src/io/steady_timer.cpp src/io/system_timer.cpp) diff --git a/doc/reference/io.adoc b/doc/reference/io.adoc index 13d03670..c973ed95 100644 --- a/doc/reference/io.adoc +++ b/doc/reference/io.adoc @@ -3,3 +3,4 @@ include::io/timer.adoc[] include::io/endpoint.adoc[] +include::io/resolver.adoc[] diff --git a/doc/reference/io/resolver.adoc b/doc/reference/io/resolver.adoc new file mode 100644 index 00000000..38f63de2 --- /dev/null +++ b/doc/reference/io/resolver.adoc @@ -0,0 +1,76 @@ +[#io::resolve] +=== async/io/resolver.hpp + +[source,cpp] +---- +// a simple type holding the triplet to describe any endpoint +struct protocol_type +{ + using family_t = *implementation-defined*; + using type_t = *implementation-defined*; + using protocol_t = *implementation-defined*; + + constexpr family_t family() const noexcept {return family_;}; + constexpr type_t type() const noexcept {return type_;}; + constexpr protocol_t protocol() const noexcept {return protocol_;}; + + constexpr explicit + protocol_type(family_t family = static_cast(0), + type_t type = static_cast(0), + protocol_t protocol = static_cast(0)) noexcept + + constexpr protocol_type(const OtherProtocol & op) noexcept; + {} + // asio compatibility + using endpoint = endpoint; +}; + +// the class holding the endpiont +struct endpoint +{ + using storage_type = boost::asio::detail::sockaddr_storage_type; + using addr_type = boost::asio::detail::socket_addr_type; + void resize(std::size_t size); + + void * data(); + const void * data() const; + std::size_t size(); + + protocol_type protocol() const; + + endpoint() = default; + endpoint(const endpoint & ep); + + template + endpoint(static_protocol proto, Args && ... args); + +}; + +// get the type of the endpoint family, see below. +cosnt auto * get_if(const endpoint * ep); +// get the type of the endpoint family, see below. throws `bad_endpoint_access` if a mismatched. +const auto & get(const endpoint & ep); +---- + +To make it type-safe, the library provides a `static_protocol` template: + +[source,cpp] +---- + +struct resolver +{ + using resolve_result = system::result>; + resolver(); + resolver(resolver && ) = delete; + + void cancel(); + + awaitable resolve_op_ resolve(core::string_view host, core::string_view service); +}; + +awaitable lookup(core::string_view host, core::string_view service); +---- + diff --git a/include/boost/async/io/endpoint.hpp b/include/boost/async/io/endpoint.hpp index 362722a8..67372d49 100644 --- a/include/boost/async/io/endpoint.hpp +++ b/include/boost/async/io/endpoint.hpp @@ -65,9 +65,9 @@ struct protocol_type using endpoint = endpoint; private: - family_t family_; - type_t type_; - protocol_t protocol_; + family_t family_ = static_cast(0); + type_t type_ = static_cast(0); + protocol_t protocol_ = static_cast(0); }; template(0), @@ -87,9 +87,9 @@ struct static_protocol }; -constexpr static_protocol ip {}; -constexpr static_protocol ip_v4 {}; -constexpr static_protocol ip_v6 {}; +constexpr static_protocol(0), BOOST_ASIO_OS_DEF(IPPROTO_IP)> ip {}; +constexpr static_protocol(0), BOOST_ASIO_OS_DEF(IPPROTO_IP)> ip_v4 {}; +constexpr static_protocol(0), BOOST_ASIO_OS_DEF(IPPROTO_IP)> ip_v6 {}; constexpr static_protocol tcp {}; constexpr static_protocol tcp_v4{}; constexpr static_protocol tcp_v6{}; @@ -171,8 +171,8 @@ struct endpoint storage_type storage_; }; std::size_t size_{sizeof(base_)}; - protocol_type::protocol_t protocol_; - protocol_type::type_t type_; + protocol_type::protocol_t protocol_ = static_cast(0); + protocol_type::type_t type_ = static_cast(0); }; class bad_endpoint_access : public std::exception diff --git a/include/boost/async/io/resolver.hpp b/include/boost/async/io/resolver.hpp new file mode 100644 index 00000000..5cc03d8a --- /dev/null +++ b/include/boost/async/io/resolver.hpp @@ -0,0 +1,101 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_RESOLVER_HPP +#define BOOST_ASYNC_IO_RESOLVER_HPP + +#include + +#include +#include +#include +#include +#include + +namespace boost::async::io +{ + + +struct resolver +{ + using resolve_result = system::result>; + resolver(); + resolver(resolver && ) = delete; + + void cancel(); + + private: + + struct resolve_op_ + { + using result_type = asio::ip::basic_resolver::results_type; + + constexpr static bool await_ready() { return false; } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + auto & res = resource.emplace( + buffer, sizeof(buffer), + asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); + initiate_(completion_handler{h, result_, &res}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] resolve_result await_resume(); + resolve_op_(asio::ip::basic_resolver & resolver, + core::string_view host, core::string_view service) + : resolver_(resolver), host_(host), service_(service) {} + private: + asio::ip::basic_resolver & resolver_; + core::string_view host_; + core::string_view service_; + std::exception_ptr error; + std::optional> result_; + char buffer[256]; + std::optional resource; + + void initiate_(completion_handler); + + }; + + public: + + [[nodiscard]] resolve_op_ resolve(core::string_view host, core::string_view service) + { + return resolve_op_{resolver_, host, service}; + } + + + private: + asio::ip::basic_resolver resolver_; +}; + +// NOTE: Doesn't need to be a promise, can be optimized. +struct lookup +{ + lookup(core::string_view host, core::string_view service) + : host_(host), service_(service) {} + auto operator co_await() {return resolver_.resolve(host_, service_);} + private: + core::string_view host_; + core::string_view service_; + resolver resolver_; + +}; + +} + +#endif //BOOST_ASYNC_IO_RESOLVER_HPP diff --git a/src/io/resolver.cpp b/src/io/resolver.cpp new file mode 100644 index 00000000..aedc03b2 --- /dev/null +++ b/src/io/resolver.cpp @@ -0,0 +1,39 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include + +namespace boost::async::io +{ + + +resolver::resolver() : resolver_(this_thread::get_executor()) {} +void resolver::cancel() { resolver_.cancel(); } + + +[[nodiscard]] resolver::resolve_result resolver::resolve_op_::await_resume() +{ + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + + auto [ec, rr] = result_.value(); + if (ec) + return ec; + else + { + container::pmr::vector r{this_thread::get_allocator()}; + r.assign(rr.begin(), rr.end()); + return r; + } +} + +void resolver::resolve_op_::initiate_(completion_handler h) +{ + resolver_.async_resolve(async::io::ip, host_, service_, std::move(h)); +} + +} \ No newline at end of file diff --git a/test/io/CMakeLists.txt b/test/io/CMakeLists.txt index beb8bec6..5b4f5b26 100644 --- a/test/io/CMakeLists.txt +++ b/test/io/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(buffers) add_executable(boost_async_io_tests endpoint.cpp sleep.cpp + resolver.cpp ../doctest.cpp) target_link_libraries(boost_async_io_tests Boost::container Boost::async OpenSSL::SSL) add_test(NAME boost_async-io COMMAND boost_async_io_tests) diff --git a/test/io/resolver.cpp b/test/io/resolver.cpp new file mode 100644 index 00000000..887766e3 --- /dev/null +++ b/test/io/resolver.cpp @@ -0,0 +1,27 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include "../doctest.h" +#include "../test.hpp" +#include +#include + + + +CO_TEST_CASE("resolver") +{ + using namespace boost; + + auto t = co_await async::io::lookup("boost.org", "http"); + + CHECK(t.error() == system::error_code{}); + REQUIRE(t.value().size() > 0u); + for (auto & ep : *t) + CHECK(ep.protocol() == async::io::ip_v4); + + +} \ No newline at end of file From 82d0b01e2d6bc5657cddbeb17d3b1496d29b0225 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Thu, 29 Jun 2023 23:55:26 +0800 Subject: [PATCH 05/43] added duplicate function. --- CMakeLists.txt | 1 + include/boost/async/io/detail/duplicate.hpp | 28 ++++++++ src/io/detail/duplicate.cpp | 75 +++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 include/boost/async/io/detail/duplicate.hpp create mode 100644 src/io/detail/duplicate.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d3dba7a..7d8ece76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,7 @@ add_library(boost_async src/io/buffers/const_buffer_subspan.cpp src/io/buffers/mutable_buffer_pair.cpp src/io/buffers/mutable_buffer_subspan.cpp + src/io/detail/duplicate.cpp src/io/endpoint.cpp src/io/resolver.cpp src/io/steady_timer.cpp diff --git a/include/boost/async/io/detail/duplicate.hpp b/include/boost/async/io/detail/duplicate.hpp new file mode 100644 index 00000000..c3b22d23 --- /dev/null +++ b/include/boost/async/io/detail/duplicate.hpp @@ -0,0 +1,28 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_DUPLICATE_HPP +#define BOOST_ASYNC_IO_DUPLICATE_HPP + +#include +#include +#include + +namespace boost::async::io::detail +{ + +#if defined(BOOST_ASIO_WINDOWS) +BOOST_ASYNC_DECL system::result duplicate_handle(HANDLE h); +BOOST_ASYNC_DECL system::result duplicate_socket(SOCKET fd); +#else +BOOST_ASYNC_DECL system::result duplicate_handle(int fd); +BOOST_ASYNC_DECL system::result duplicate_socket(int fd); +#endif + +} + +#endif //BOOST_ASYNC_IO_DUPLICATE_HPP diff --git a/src/io/detail/duplicate.cpp b/src/io/detail/duplicate.cpp new file mode 100644 index 00000000..0db4a02e --- /dev/null +++ b/src/io/detail/duplicate.cpp @@ -0,0 +1,75 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include + +#if defined(BOOST_ASIO_WINDOWS) +#include +#else +// implement windows shite +#include +#endif + +namespace boost::async::io::detail +{ + +#if defined(BOOST_ASIO_WINDOWS) + +system::result duplicate_handle(HANDLE h) +{ + HANDLE ho; + if (!::DuplicateHandle( + ::GetCurrentProcess(), + h, + ::GetCurrentProcess(), + &ho, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) + return system::error_code(::GetLastError(), system::system_category()); + return ho; +} + +system::result duplicate_handle(SOCKET sock) +{ + WSAPROTOCOL_INFOW info; + if (SOCKET_ERROR == ::WSADuplicateSocketW( + sock, + ::GetCurrentProcessId(), + &info + )) + return system::error_code(::WSAGetLastError(), system::system_category()); + + auto res = WSASocketW( + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + &info, + 0, + 0); + if (res == INVALID_SOCKET) + return system::error_code(::WSAGetLastError(), system::system_category()); + + + return res; +} + +#else + +system::result duplicate_handle(int fd) +{ + auto r = dup(fd); + if (r == -1) + return system::error_code(errno, system::system_category()); + return r; +} + +system::result duplicate_socket(int fd) {return duplicate_handle(fd);} + +#endif +} + From f8adf1520355b49932f091a0d930970992017c60 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 07:35:36 +0800 Subject: [PATCH 06/43] added signal_set. --- CMakeLists.txt | 1 + include/boost/async/io/signal_set.hpp | 85 +++++++++++++++++++++++++++ src/io/signal_set.cpp | 49 +++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 include/boost/async/io/signal_set.hpp create mode 100644 src/io/signal_set.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d8ece76..fc6c92d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ add_library(boost_async src/io/detail/duplicate.cpp src/io/endpoint.cpp src/io/resolver.cpp + src/io/signal_set.cpp src/io/steady_timer.cpp src/io/system_timer.cpp) diff --git a/include/boost/async/io/signal_set.hpp b/include/boost/async/io/signal_set.hpp new file mode 100644 index 00000000..3f910a25 --- /dev/null +++ b/include/boost/async/io/signal_set.hpp @@ -0,0 +1,85 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_SIGNAL_SET_HPP +#define BOOST_ASYNC_IO_SIGNAL_SET_HPP + +#include + +#include +#include + +#include + +namespace boost::async::io +{ + +struct signal_set +{ + using wait_result = system::result; + + signal_set(); + signal_set(std::initializer_list sigs); + + [[nodiscard]] system::result cancel(); + [[nodiscard]] system::result clear(); + [[nodiscard]] system::result add(int signal_number); + [[nodiscard]] system::result remove(int signal_number); + + + private: + struct wait_op_ + { + constexpr static bool await_ready() { return false; } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + auto & res = resource.emplace( + buffer, sizeof(buffer), + asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); + signal_set_.async_wait(completion_handler{h, result_, &res}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] wait_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + auto [ec, sig] = result_.value_or(std::make_tuple(system::error_code{}, 0)); + if (ec) + return ec; + else + return sig; + } + wait_op_(boost::asio::basic_signal_set & signal_set) : signal_set_(signal_set) {} + private: + boost::asio::basic_signal_set & signal_set_; + std::exception_ptr error; + std::optional> result_; + char buffer[256]; + std::optional resource; + }; + public: + [[nodiscard]] wait_op_ wait() { return wait_op_{signal_set_}; } + wait_op_ operator co_await () { return wait(); } + private: + boost::asio::basic_signal_set signal_set_; +}; + + +} + +#endif //BOOST_ASYNC_IO_SIGNAL_SET_HPP diff --git a/src/io/signal_set.cpp b/src/io/signal_set.cpp new file mode 100644 index 00000000..a8cee2eb --- /dev/null +++ b/src/io/signal_set.cpp @@ -0,0 +1,49 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include + +namespace boost::async::io +{ + +signal_set::signal_set() : signal_set_(this_thread::get_executor()) {} +signal_set::signal_set(std::initializer_list sigs) + : signal_set_(this_thread::get_executor()) +{ + for (auto i : sigs) + add(i).value(); +} + +system::result signal_set::cancel() +{ + system::error_code ec; + signal_set_.cancel(ec); + return ec ? ec : system::result{}; +} + +system::result signal_set::clear() +{ + system::error_code ec; + signal_set_.clear(ec); + return ec ? ec : system::result{}; +} +system +::result signal_set::add(int signal_number) +{ + system::error_code ec; + signal_set_.add(signal_number, ec); + return ec ? ec : system::result{}; +} + +system::result signal_set::remove(int signal_number) +{ + system::error_code ec; + signal_set_.remove(signal_number, ec); + return ec ? ec : system::result{}; +} + +} \ No newline at end of file From 516c9b3a4bb4ec03a16ae6c2cfc1f0e829902076 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 07:42:35 +0800 Subject: [PATCH 07/43] added stream IF. --- CMakeLists.txt | 2 + include/boost/async/io/detail/stream.hpp | 187 +++++++++++++++++++++++ include/boost/async/io/stream.hpp | 74 +++++++++ src/io/detail/stream.cpp | 19 +++ 4 files changed, 282 insertions(+) create mode 100644 include/boost/async/io/detail/stream.hpp create mode 100644 include/boost/async/io/stream.hpp create mode 100644 src/io/detail/stream.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fc6c92d7..ae0a37dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,7 +92,9 @@ add_library(boost_async src/io/buffers/mutable_buffer_pair.cpp src/io/buffers/mutable_buffer_subspan.cpp src/io/detail/duplicate.cpp + src/io/detail/stream.cpp src/io/endpoint.cpp + src/io/pipe.cpp src/io/resolver.cpp src/io/signal_set.cpp src/io/steady_timer.cpp diff --git a/include/boost/async/io/detail/stream.hpp b/include/boost/async/io/detail/stream.hpp new file mode 100644 index 00000000..7b3a4876 --- /dev/null +++ b/include/boost/async/io/detail/stream.hpp @@ -0,0 +1,187 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_DETAIL_STREAM_HPP +#define BOOST_ASYNC_IO_DETAIL_STREAM_HPP + +#include + +namespace boost::async::io +{ + +struct stream::read_some_op_ +{ + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + auto & res = resource.emplace( + buffer, sizeof(buffer), + asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); + rstream_.async_read_some_impl_({&buffer_, 1u}, + completion_handler{h, result_, &res}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + + read_some_op_(stream & rs, buffers::mutable_buffer buffer) + : rstream_(rs), buffer_(buffer) {} + + private: + stream & rstream_; + buffers::mutable_buffer buffer_; + std::exception_ptr error; + std::optional> result_; + char buffer[2048]; + std::optional resource; +}; + + +struct stream::read_some_op_seq_ +{ + constexpr bool await_ready() noexcept {return false;}; + + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + auto & res = resource.emplace( + buffer, sizeof(buffer), + asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); + rstream_.async_read_some_impl_(buffer_, completion_handler{h, result_, &res}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + + read_some_op_seq_(stream & rs, buffers::mutable_buffer_span buffer) + : rstream_(rs), buffer_(buffer) {} + + private: + stream & rstream_; + buffers::mutable_buffer_span buffer_; + std::exception_ptr error; + std::optional> result_; + char buffer[2048]; + std::optional resource; +}; +struct stream::write_some_op_ +{ + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + auto & res = resource.emplace( + buffer, sizeof(buffer), + asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); + rstream_.async_write_some_impl_({&buffer_, 1}, + completion_handler{h, result_, &res}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + + write_some_op_(stream & rs, buffers::const_buffer buffer) + : rstream_(rs), buffer_(buffer) {} + + private: + stream & rstream_; + buffers::const_buffer buffer_; + std::exception_ptr error; + std::optional> result_; + char buffer[2048]; + std::optional resource; +}; + + +struct stream::write_some_op_seq_ +{ + constexpr bool await_writey() noexcept {return false;}; + + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + auto & res = resource.emplace( + buffer, sizeof(buffer), + asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); + rstream_.async_write_some_impl_(buffer_, completion_handler{h, result_, &res}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + + write_some_op_seq_(stream & rs, buffers::const_buffer_span buffer) + : rstream_(rs), buffer_(buffer) {} + + private: + stream & rstream_; + buffers::const_buffer_span buffer_; + std::exception_ptr error; + std::optional> result_; + char buffer[2048]; + std::optional resource; +}; + +} + +#endif //BOOST_ASYNC_IO_DETAIL_STREAM_HPP diff --git a/include/boost/async/io/stream.hpp b/include/boost/async/io/stream.hpp new file mode 100644 index 00000000..cbbab342 --- /dev/null +++ b/include/boost/async/io/stream.hpp @@ -0,0 +1,74 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_STREAM_HPP +#define BOOST_ASYNC_IO_STREAM_HPP + +#include + +#include +#include +#include +#include +#include + +namespace boost::async::io +{ + +struct [[nodiscard]] transfer_result +{ + system::error_code error; + std::size_t transferred; + + using value_type = std::size_t; + using error_type = system::error_code; + + // queries + constexpr bool has_value() const noexcept { return transferred != 0; } + constexpr bool has_error() const noexcept { return error.failed(); } + constexpr explicit operator bool() const noexcept { return has_value() || !has_error(); } + constexpr std::size_t value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const noexcept + { + if (!has_value() || !has_error()) + throw_exception_from_error(error, loc); + return transferred; + } + constexpr std::size_t operator*() const noexcept { BOOST_ASSERT(has_value()); return transferred; } + + bool operator==(const system::error_code &ec) const { return error == ec;} + bool operator!=(const system::error_code &ec) const { return error != ec;} + + auto operator<=>(std::size_t n) const { return value() <=> n;} + bool operator==(std::size_t n) const { return value() == n;} +}; + +struct stream +{ + [[nodiscard]] virtual system::result close() = 0; + [[nodiscard]] virtual system::result cancel() = 0; + [[nodiscard]] virtual bool is_open() const = 0; + + virtual ~stream() = default; + protected: + virtual void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) = 0; + virtual void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) = 0; + private: + struct read_some_op_; + struct read_some_op_seq_; + struct write_some_op_; + struct write_some_op_seq_; + public: + [[nodiscard]] read_some_op_seq_ read_some(buffers::mutable_buffer_span buffers); + [[nodiscard]] read_some_op_ read_some(buffers::mutable_buffer buffer); + [[nodiscard]] write_some_op_seq_ write_some(buffers::const_buffer_span buffers); + [[nodiscard]] write_some_op_ write_some(buffers::const_buffer buffer); +}; + +} + +#include +#endif //BOOST_ASYNC_IO_STREAM_HPP diff --git a/src/io/detail/stream.cpp b/src/io/detail/stream.cpp new file mode 100644 index 00000000..bbfb839c --- /dev/null +++ b/src/io/detail/stream.cpp @@ -0,0 +1,19 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include + +namespace boost::async::io +{ + +auto stream:: read_some(buffers::mutable_buffer_span buffers) -> read_some_op_seq_ { return read_some_op_seq_{*this, buffers};} +auto stream:: read_some(buffers::mutable_buffer buffer) -> read_some_op_ { return read_some_op_{*this, buffer};} +auto stream::write_some(buffers::const_buffer_span buffers) -> write_some_op_seq_ { return write_some_op_seq_{*this, buffers};} +auto stream::write_some(buffers::const_buffer buffer) -> write_some_op_ { return write_some_op_{*this, buffer};} + + +} \ No newline at end of file From 096be52efcf961502c314aceab22ef84c47e4f1f Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 09:18:33 +0800 Subject: [PATCH 08/43] added pipe. --- include/boost/async/io/detail/stream.hpp | 40 ++---- include/boost/async/io/pipe.hpp | 79 +++++++++++ include/boost/async/io/signal_set.hpp | 7 +- include/boost/async/io/steady_timer.hpp | 9 +- include/boost/async/io/stream.hpp | 4 +- include/boost/async/io/system_timer.hpp | 9 +- src/io/pipe.cpp | 168 +++++++++++++++++++++++ test/io/CMakeLists.txt | 3 +- test/io/pipe.cpp | 40 ++++++ 9 files changed, 308 insertions(+), 51 deletions(-) create mode 100644 include/boost/async/io/pipe.hpp create mode 100644 src/io/pipe.cpp create mode 100644 test/io/pipe.cpp diff --git a/include/boost/async/io/detail/stream.hpp b/include/boost/async/io/detail/stream.hpp index 7b3a4876..371d1e6e 100644 --- a/include/boost/async/io/detail/stream.hpp +++ b/include/boost/async/io/detail/stream.hpp @@ -13,8 +13,10 @@ namespace boost::async::io { -struct stream::read_some_op_ +struct stream::read_some_op_ : detail::deferred_op_resource_base { + read_some_op_(read_some_op_ && ) noexcept = default; + constexpr bool await_ready() noexcept {return false;}; template @@ -22,11 +24,8 @@ struct stream::read_some_op_ { try { - auto & res = resource.emplace( - buffer, sizeof(buffer), - asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); rstream_.async_read_some_impl_({&buffer_, 1u}, - completion_handler{h, result_, &res}); + completion_handler{h, result_, get_resource(h)}); return true; } catch(...) @@ -51,12 +50,10 @@ struct stream::read_some_op_ buffers::mutable_buffer buffer_; std::exception_ptr error; std::optional> result_; - char buffer[2048]; - std::optional resource; }; -struct stream::read_some_op_seq_ +struct stream::read_some_op_seq_ : detail::deferred_op_resource_base { constexpr bool await_ready() noexcept {return false;}; @@ -66,10 +63,7 @@ struct stream::read_some_op_seq_ { try { - auto & res = resource.emplace( - buffer, sizeof(buffer), - asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); - rstream_.async_read_some_impl_(buffer_, completion_handler{h, result_, &res}); + rstream_.async_read_some_impl_(buffer_, completion_handler{h, result_, get_resource(h)}); return true; } catch(...) @@ -94,11 +88,11 @@ struct stream::read_some_op_seq_ buffers::mutable_buffer_span buffer_; std::exception_ptr error; std::optional> result_; - char buffer[2048]; - std::optional resource; }; -struct stream::write_some_op_ +struct stream::write_some_op_ : detail::deferred_op_resource_base { + write_some_op_(write_some_op_ && ) noexcept = default; + constexpr bool await_ready() noexcept {return false;}; template @@ -106,11 +100,8 @@ struct stream::write_some_op_ { try { - auto & res = resource.emplace( - buffer, sizeof(buffer), - asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); rstream_.async_write_some_impl_({&buffer_, 1}, - completion_handler{h, result_, &res}); + completion_handler{h, result_, get_resource(h)}); return true; } catch(...) @@ -135,12 +126,10 @@ struct stream::write_some_op_ buffers::const_buffer buffer_; std::exception_ptr error; std::optional> result_; - char buffer[2048]; - std::optional resource; }; -struct stream::write_some_op_seq_ +struct stream::write_some_op_seq_ : detail::deferred_op_resource_base { constexpr bool await_writey() noexcept {return false;}; @@ -150,10 +139,7 @@ struct stream::write_some_op_seq_ { try { - auto & res = resource.emplace( - buffer, sizeof(buffer), - asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); - rstream_.async_write_some_impl_(buffer_, completion_handler{h, result_, &res}); + rstream_.async_write_some_impl_(buffer_, completion_handler{h, result_, get_resource(h)}); return true; } catch(...) @@ -178,8 +164,6 @@ struct stream::write_some_op_seq_ buffers::const_buffer_span buffer_; std::exception_ptr error; std::optional> result_; - char buffer[2048]; - std::optional resource; }; } diff --git a/include/boost/async/io/pipe.hpp b/include/boost/async/io/pipe.hpp new file mode 100644 index 00000000..1529c10e --- /dev/null +++ b/include/boost/async/io/pipe.hpp @@ -0,0 +1,79 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_PIPE_HPP +#define BOOST_ASYNC_IO_PIPE_HPP + +#include + +#include +#include + +namespace boost::async::io +{ + +system::result> make_pipe(); + +struct readable_pipe final : stream +{ + system::result close() override; + system::result cancel() override; + bool is_open() const override; + + using native_handle_type = typename asio::basic_readable_pipe::native_handle_type; + native_handle_type native_handle() {return pipe_.native_handle();} + + readable_pipe(); + readable_pipe(native_handle_type native_handle); + + system::result assign(native_handle_type native_handle); + system::result release(); + + system::result duplicate(); + + void write_some(buffers::mutable_buffer_span buffers) = delete; + void write_some(buffers::mutable_buffer buffer) = delete; + + private: + void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; + void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + + friend system::result> make_pipe(); + asio::basic_readable_pipe pipe_; +}; + +struct writable_pipe final : stream +{ + system::result close() override; + system::result cancel() override; + bool is_open() const override; + + using native_handle_type = typename asio::basic_readable_pipe::native_handle_type; + native_handle_type native_handle() {return pipe_.native_handle();} + + writable_pipe(); + writable_pipe(native_handle_type native_handle); + + system::result assign(native_handle_type native_handle); + system::result release(); + system::result duplicate(); + + void read_some(buffers::mutable_buffer_span buffers) = delete; + void read_some(buffers::mutable_buffer buffer) = delete; + private: + void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; + void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + friend system::result> make_pipe(); + asio::basic_writable_pipe pipe_; +}; + +system::result> make_pipe(); + + +} + +#endif //BOOST_ASYNC_IO_PIPE_HPP diff --git a/include/boost/async/io/signal_set.hpp b/include/boost/async/io/signal_set.hpp index 3f910a25..1afe040d 100644 --- a/include/boost/async/io/signal_set.hpp +++ b/include/boost/async/io/signal_set.hpp @@ -32,7 +32,7 @@ struct signal_set private: - struct wait_op_ + struct wait_op_ : detail::deferred_op_resource_base { constexpr static bool await_ready() { return false; } @@ -41,10 +41,7 @@ struct signal_set { try { - auto & res = resource.emplace( - buffer, sizeof(buffer), - asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); - signal_set_.async_wait(completion_handler{h, result_, &res}); + signal_set_.async_wait(completion_handler{h, result_, get_resource(h)}); return true; } catch(...) diff --git a/include/boost/async/io/steady_timer.hpp b/include/boost/async/io/steady_timer.hpp index cab36fab..b9de7957 100644 --- a/include/boost/async/io/steady_timer.hpp +++ b/include/boost/async/io/steady_timer.hpp @@ -41,7 +41,7 @@ struct steady_timer bool expired() const; private: - struct wait_op_ + struct wait_op_ : detail::deferred_op_resource_base { bool await_ready() const { return timer_->expired(); } @@ -50,10 +50,7 @@ struct steady_timer { try { - auto & res = resource.emplace( - buffer, sizeof(buffer), - asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); - timer_->timer_.async_wait(completion_handler{h, result_, &res}); + timer_->timer_.async_wait(completion_handler{h, result_, get_resource(h)}); return true; } catch(...) @@ -75,8 +72,6 @@ struct steady_timer steady_timer * timer_; std::exception_ptr error; std::optional> result_; - char buffer[256]; - std::optional resource; }; public: diff --git a/include/boost/async/io/stream.hpp b/include/boost/async/io/stream.hpp index cbbab342..a0a4c27f 100644 --- a/include/boost/async/io/stream.hpp +++ b/include/boost/async/io/stream.hpp @@ -33,7 +33,7 @@ struct [[nodiscard]] transfer_result constexpr explicit operator bool() const noexcept { return has_value() || !has_error(); } constexpr std::size_t value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const noexcept { - if (!has_value() || !has_error()) + if (!has_value() || has_error()) throw_exception_from_error(error, loc); return transferred; } @@ -42,8 +42,6 @@ struct [[nodiscard]] transfer_result bool operator==(const system::error_code &ec) const { return error == ec;} bool operator!=(const system::error_code &ec) const { return error != ec;} - auto operator<=>(std::size_t n) const { return value() <=> n;} - bool operator==(std::size_t n) const { return value() == n;} }; struct stream diff --git a/include/boost/async/io/system_timer.hpp b/include/boost/async/io/system_timer.hpp index a8c3712e..002a5963 100644 --- a/include/boost/async/io/system_timer.hpp +++ b/include/boost/async/io/system_timer.hpp @@ -40,7 +40,7 @@ struct system_timer final void reset(const duration& expiry_time); bool expired() const; - struct wait_op_ + struct wait_op_ : detail::deferred_op_resource_base { bool await_ready() const { return timer_->expired(); } @@ -49,10 +49,7 @@ struct system_timer final { try { - auto & res = resource.emplace( - buffer, sizeof(buffer), - asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); - timer_->timer_.async_wait(completion_handler{h, result_, &res}); + timer_->timer_.async_wait(completion_handler{h, result_, get_resource(h)}); return true; } catch(...) @@ -74,8 +71,6 @@ struct system_timer final system_timer * timer_; std::exception_ptr error; std::optional> result_; - char buffer[256]; - std::optional resource; }; public: diff --git a/src/io/pipe.cpp b/src/io/pipe.cpp new file mode 100644 index 00000000..3f77bcd2 --- /dev/null +++ b/src/io/pipe.cpp @@ -0,0 +1,168 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include +#include +#include +#include + +namespace boost::async::io +{ + +readable_pipe::readable_pipe() : pipe_(this_thread::get_executor()) {} +readable_pipe::readable_pipe(native_handle_type native_handle) + : pipe_(this_thread::get_executor(), native_handle) {} + +system::result readable_pipe::close() +{ + system::error_code ec; + pipe_.close(ec); + return ec ? ec : system::result(); +} + +system::result readable_pipe::cancel() +{ + system::error_code ec; + pipe_.cancel(ec); + return ec ? ec : system::result(); +} + +bool readable_pipe::is_open() const { return pipe_.is_open(); } + +void readable_pipe::async_read_some_impl_( + buffers::mutable_buffer_span buffer, + async::completion_handler h) +{ + pipe_.async_read_some(buffers::mutable_buffer_span(buffer), std::move(h)); +} + +void readable_pipe::async_write_some_impl_( + buffers::const_buffer_span buffer, + async::completion_handler h) +{ + constexpr static source_location loc{BOOST_CURRENT_LOCATION}; + system::error_code ec{asio::error::operation_not_supported, &loc}; + if (h.completed_immediately) + { + *h.completed_immediately = true; + h(ec, 0ul); + } + else + asio::post(h.executor, asio::append(std::move(h), ec, 0ul)); +} + + +system::result readable_pipe::assign(native_handle_type native_handle) +{ + system::error_code ec; + pipe_.assign(native_handle, ec); + return ec ? ec : system::result(); +} +auto readable_pipe::release() -> system::result +{ + system::error_code ec; + auto h = pipe_.release(ec); + if (ec) + return ec; + else + return h; +} + +system::result readable_pipe::duplicate() +{ + auto res = detail::duplicate_handle(pipe_.native_handle()); + if (!res) + return res.error(); + + return readable_pipe(*res); +} + + +writable_pipe::writable_pipe() : pipe_(this_thread::get_executor()) {} +writable_pipe::writable_pipe(native_handle_type native_handle) + : pipe_(this_thread::get_executor(), native_handle) {} + +system::result writable_pipe::close() +{ + system::error_code ec; + pipe_.close(ec); + return ec ? ec : system::result(); +} + +system::result writable_pipe::cancel() +{ + system::error_code ec; + pipe_.cancel(ec); + return ec ? ec : system::result(); +} + +bool writable_pipe::is_open() const { return pipe_.is_open(); } + +void writable_pipe::async_write_some_impl_( + buffers::const_buffer_span buffer, + async::completion_handler h) +{ + pipe_.async_write_some(buffer, std::move(h)); +} + + +void writable_pipe::async_read_some_impl_( + buffers::mutable_buffer_span buffer, + async::completion_handler h) +{ + constexpr static source_location loc{BOOST_CURRENT_LOCATION}; + system::error_code ec{asio::error::operation_not_supported, &loc}; + if (h.completed_immediately) + { + *h.completed_immediately = true; + h(ec, 0ul); + } + else + asio::post(h.executor, asio::append(std::move(h), ec, 0ul)); +} + +system::result writable_pipe::assign(native_handle_type native_handle) +{ + system::error_code ec; + pipe_.assign(native_handle, ec); + return ec ? ec : system::result(); +} +auto writable_pipe::release() -> system::result +{ + system::error_code ec; + auto h = pipe_.release(ec); + if (ec) + return ec; + else + return h; +} + +system::result writable_pipe::duplicate() +{ + auto res = detail::duplicate_handle(pipe_.native_handle()); + if (!res) + return res.error(); + + return writable_pipe(*res); +} + +system::result> make_pipe() +{ + readable_pipe rp{}; + writable_pipe wp{}; + + system::error_code ec; + asio::connect_pipe(rp.pipe_, wp.pipe_, ec); + if (ec) + return ec; + else + return std::make_pair(std::move(rp), std::move(wp)); +} + + +} \ No newline at end of file diff --git a/test/io/CMakeLists.txt b/test/io/CMakeLists.txt index 5b4f5b26..c8e3a07d 100644 --- a/test/io/CMakeLists.txt +++ b/test/io/CMakeLists.txt @@ -2,8 +2,9 @@ add_subdirectory(buffers) add_executable(boost_async_io_tests endpoint.cpp - sleep.cpp + pipe.cpp resolver.cpp + sleep.cpp ../doctest.cpp) target_link_libraries(boost_async_io_tests Boost::container Boost::async OpenSSL::SSL) add_test(NAME boost_async-io COMMAND boost_async_io_tests) diff --git a/test/io/pipe.cpp b/test/io/pipe.cpp new file mode 100644 index 00000000..509762da --- /dev/null +++ b/test/io/pipe.cpp @@ -0,0 +1,40 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include "../doctest.h" +#include "../test.hpp" +#include +#include +#include +#include + +CO_TEST_CASE("pipe") +{ + using namespace boost::async; + auto [r, w] = io::make_pipe().value(); + + { + io::stream & rs = r; + io::stream & ws = w; + char buf[4096]; + auto ec = co_await ws. read_some(io::buffers::buffer(buf)); + CHECK(co_await ws. read_some(io::buffers::buffer(buf)) == boost::asio::error::operation_not_supported); + CHECK(co_await rs.write_some(io::buffers::buffer(buf)) == boost::asio::error::operation_not_supported); + } + + char data[7] = "nodata"; + + auto [written, read] = + co_await join(w.write_some(io::buffers::buffer("foobar", 6)), + r.read_some(io::buffers::buffer(data))); + + CHECK(written.transferred == 6u); + CHECK(read.transferred == 6u); + CHECK(data == std::string("foobar")); + +} + From 636476ca4aa154e3de09d6a6d7b3f9c1bddcad7b Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 09:23:30 +0800 Subject: [PATCH 09/43] added serial_port. --- CMakeLists.txt | 1 + include/boost/async/io/resolver.hpp | 2 +- include/boost/async/io/serial_port.hpp | 67 +++++++++++ include/boost/async/io/signal_set.hpp | 2 +- include/boost/async/io/steady_timer.hpp | 2 +- include/boost/async/io/system_timer.hpp | 2 +- src/io/serial_port.cpp | 154 ++++++++++++++++++++++++ 7 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 include/boost/async/io/serial_port.hpp create mode 100644 src/io/serial_port.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ae0a37dd..f03137df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,6 +96,7 @@ add_library(boost_async src/io/endpoint.cpp src/io/pipe.cpp src/io/resolver.cpp + src/io/serial_port.cpp src/io/signal_set.cpp src/io/steady_timer.cpp src/io/system_timer.cpp) diff --git a/include/boost/async/io/resolver.hpp b/include/boost/async/io/resolver.hpp index 5cc03d8a..355b8eb1 100644 --- a/include/boost/async/io/resolver.hpp +++ b/include/boost/async/io/resolver.hpp @@ -80,7 +80,7 @@ struct resolver private: - asio::ip::basic_resolver resolver_; + asio::ip::basic_resolver resolver_; }; // NOTE: Doesn't need to be a promise, can be optimized. diff --git a/include/boost/async/io/serial_port.hpp b/include/boost/async/io/serial_port.hpp new file mode 100644 index 00000000..2cabfb15 --- /dev/null +++ b/include/boost/async/io/serial_port.hpp @@ -0,0 +1,67 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_SERIAL_PORT_HPP +#define BOOST_ASYNC_IO_SERIAL_PORT_HPP + +#include + +#include +#include + +namespace boost::async::io +{ + +struct [[nodiscard]] serial_port final : stream +{ + system::result close() override; + system::result cancel() override; + bool is_open() const override; + + [[nodiscard]] system::result send_break(); + + [[nodiscard]] system::result set_baud_rate(unsigned rate); + [[nodiscard]] system::result get_baud_rate(); + + [[nodiscard]] system::result set_character_size(unsigned rate); + [[nodiscard]] system::result get_character_size(); + + using flow_control = asio::serial_port_base::flow_control::type; + + [[nodiscard]] system::result set_flow_control(flow_control rate); + [[nodiscard]] system::result get_flow_control(); + + using parity = asio::serial_port_base::parity::type; + + [[nodiscard]] system::result set_parity(parity rate); + [[nodiscard]] system::result get_parity(); + + using native_handle_type = typename asio::basic_serial_port::native_handle_type; + native_handle_type native_handle() {return serial_port_.native_handle();} + + serial_port(); + serial_port(serial_port && lhs) = default; + serial_port(core::string_view device); + serial_port(native_handle_type native_handle); + + [[nodiscard]] system::result assign(native_handle_type native_handle); + [[nodiscard]] system::result release(); + [[nodiscard]] system::result duplicate(); + + [[nodiscard]] system::result open(core::string_view device); + + private: + void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; + void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + + asio::basic_serial_port serial_port_; +}; + + +} + +#endif //BOOST_ASYNC_IO_SERIAL_PORT_HPP diff --git a/include/boost/async/io/signal_set.hpp b/include/boost/async/io/signal_set.hpp index 1afe040d..95e50871 100644 --- a/include/boost/async/io/signal_set.hpp +++ b/include/boost/async/io/signal_set.hpp @@ -73,7 +73,7 @@ struct signal_set [[nodiscard]] wait_op_ wait() { return wait_op_{signal_set_}; } wait_op_ operator co_await () { return wait(); } private: - boost::asio::basic_signal_set signal_set_; + boost::asio::basic_signal_set signal_set_; }; diff --git a/include/boost/async/io/steady_timer.hpp b/include/boost/async/io/steady_timer.hpp index b9de7957..1395443c 100644 --- a/include/boost/async/io/steady_timer.hpp +++ b/include/boost/async/io/steady_timer.hpp @@ -80,7 +80,7 @@ struct steady_timer private: boost::asio::basic_waitable_timer, - asio::io_context::executor_type> timer_; + executor_type> timer_; }; } diff --git a/include/boost/async/io/system_timer.hpp b/include/boost/async/io/system_timer.hpp index 002a5963..8e31e7e5 100644 --- a/include/boost/async/io/system_timer.hpp +++ b/include/boost/async/io/system_timer.hpp @@ -79,7 +79,7 @@ struct system_timer final private: boost::asio::basic_waitable_timer, - asio::io_context::executor_type> timer_; + executor_type> timer_; }; } diff --git a/src/io/serial_port.cpp b/src/io/serial_port.cpp new file mode 100644 index 00000000..4b73e7d7 --- /dev/null +++ b/src/io/serial_port.cpp @@ -0,0 +1,154 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include + +namespace boost::async::io +{ + +system::result serial_port::close() +{ + system::error_code ec; + serial_port_.close(ec); + return ec ? ec : system::result(); +} + +system::result serial_port::cancel() +{ + system::error_code ec; + serial_port_.cancel(ec); + return ec ? ec : system::result(); +} + +bool serial_port::is_open() const { return serial_port_.is_open(); } + +[[nodiscard]] system::result serial_port::send_break() +{ + system::error_code ec; + serial_port_.send_break(ec); + return ec ? ec : system::result{}; +} + +system::result serial_port::set_baud_rate(unsigned rate) +{ + system::error_code ec; + serial_port_.set_option(asio::serial_port_base::baud_rate(rate), ec); + return ec ? ec : system::result(); +} + +system::result serial_port::get_baud_rate() +{ + system::error_code ec; + asio::serial_port_base::baud_rate br; + serial_port_.get_option(br, ec); + return ec ? ec : system::result(br.value()); +} + +system::result serial_port::set_character_size(unsigned rate) +{ + system::error_code ec; + serial_port_.set_option(asio::serial_port_base::character_size(rate), ec); + return ec ? ec : system::result(); +} + +system::result serial_port::get_character_size() +{ + system::error_code ec; + asio::serial_port_base::character_size br; + serial_port_.get_option(br, ec); + return ec ? ec : system::result(br.value()); +} + + +system::result serial_port::set_flow_control(flow_control rate) +{ + system::error_code ec; + serial_port_.set_option(asio::serial_port_base::flow_control(rate), ec); + return ec ? ec : system::result(); +} + +auto serial_port::get_flow_control() -> system::result +{ + system::error_code ec; + asio::serial_port_base::flow_control br; + serial_port_.get_option(br, ec); + return ec ? ec : system::result(br.value()); +} + + +system::result serial_port::set_parity(parity rate) +{ + system::error_code ec; + serial_port_.set_option(asio::serial_port_base::parity(rate), ec); + return ec ? ec : system::result(); +} + +auto serial_port::get_parity() -> system::result +{ + system::error_code ec; + asio::serial_port_base::parity br; + serial_port_.get_option(br, ec); + return ec ? ec : system::result(br.value()); +} + +serial_port::serial_port() + : serial_port_(this_thread::get_executor()) {} +serial_port::serial_port(core::string_view device) + : serial_port_(this_thread::get_executor(), std::string(device)) {} +serial_port::serial_port(native_handle_type native_handle) + : serial_port_(this_thread::get_executor(), native_handle) {} + +system::result serial_port::assign(native_handle_type native_handle) +{ + system::error_code ec; + serial_port_.assign(native_handle, ec); + return ec ? ec : system::result{}; +} + +[[nodiscard]] system::result serial_port::open(core::string_view device) +{ + std::string dev{device}; + system::error_code ec; + serial_port_.open(dev, ec); + if (ec) + return ec; + else + return system::in_place_value; +} + + +void serial_port::async_read_some_impl_( + buffers::mutable_buffer_span buffer, + async::completion_handler h) +{ + serial_port_.async_read_some(buffers::mutable_buffer_span(buffer), std::move(h)); +} + +void serial_port::async_write_some_impl_( + buffers::const_buffer_span buffer, + async::completion_handler h) +{ + serial_port_.async_write_some(buffer, std::move(h)); +} + +auto serial_port::release() -> system::result +{ + // ain't done in asio, for some reason. + constexpr static source_location loc{BOOST_CURRENT_LOCATION}; + system::error_code ec{asio::error::operation_not_supported, &loc}; + return ec; +} +auto serial_port::duplicate() -> system::result +{ + auto fd = detail::duplicate_handle(serial_port_.native_handle()); + if (fd.has_error()) + return fd.error(); + return serial_port(*fd); +} + +} \ No newline at end of file From 2ba8988ac232242365fee363bffdfa37f0785485 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 11:52:33 +0800 Subject: [PATCH 10/43] move-only result workaround. --- include/boost/async/detail/util.hpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/include/boost/async/detail/util.hpp b/include/boost/async/detail/util.hpp index 32b51615..da46531f 100644 --- a/include/boost/async/detail/util.hpp +++ b/include/boost/async/detail/util.hpp @@ -134,7 +134,8 @@ struct coro_deleter }; template -auto get_resume_result(Awaitable & aw) -> system::result +auto assign_resume_result(system::result().await_resume()), std::exception_ptr> & res, + Awaitable & aw) -> system::result().await_resume()), std::exception_ptr> & { using type = decltype(aw.await_resume()); try @@ -142,14 +143,19 @@ auto get_resume_result(Awaitable & aw) -> system::result) { aw.await_resume(); - return {}; + res.emplace(); } else - return aw.await_resume(); + res.emplace(aw.await_resume()); + return res; } catch(...) { - return std::current_exception(); + // TODO: Talk to @pdimov. + res.~result(); + return *new (&res) system::result().await_resume()), std::exception_ptr>( + system::in_place_error, + std::current_exception()); } } From a3196df20041750f464741a466bef4a3ff0b95d7 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 11:52:49 +0800 Subject: [PATCH 11/43] added networking. --- CMakeLists.txt | 5 + include/boost/async/config.hpp | 8 +- include/boost/async/io/acceptor.hpp | 113 +++++++ include/boost/async/io/datagram_socket.hpp | 68 ++++ .../boost/async/io/detail/datagram_socket.hpp | 319 ++++++++++++++++++ .../async/io/detail/seq_packet_socket.hpp | 169 ++++++++++ include/boost/async/io/detail/socket.hpp | 97 ++++++ include/boost/async/io/endpoint.hpp | 12 +- include/boost/async/io/pipe.hpp | 44 +-- include/boost/async/io/resolver.hpp | 22 +- include/boost/async/io/seq_packet_socket.hpp | 72 ++++ include/boost/async/io/serial_port.hpp | 46 +-- include/boost/async/io/signal_set.hpp | 16 +- include/boost/async/io/sleep.hpp | 6 +- include/boost/async/io/socket.hpp | 102 ++++++ include/boost/async/io/steady_timer.hpp | 16 +- include/boost/async/io/stream.hpp | 8 +- include/boost/async/io/stream_socket.hpp | 51 +++ include/boost/async/io/system_timer.hpp | 16 +- src/io/acceptor.cpp | 37 ++ src/io/datagram_socket.cpp | 119 +++++++ src/io/seq_packet_socket.cpp | 82 +++++ src/io/socket.cpp | 168 +++++++++ src/io/stream_socket.cpp | 63 ++++ test/io/CMakeLists.txt | 4 + test/io/acceptor.cpp | 38 +++ test/io/datagram_socket.cpp | 31 ++ test/io/seq_packet_socket.cpp | 32 ++ test/io/stream_socket.cpp | 30 ++ 29 files changed, 1696 insertions(+), 98 deletions(-) create mode 100644 include/boost/async/io/acceptor.hpp create mode 100644 include/boost/async/io/datagram_socket.hpp create mode 100644 include/boost/async/io/detail/datagram_socket.hpp create mode 100644 include/boost/async/io/detail/seq_packet_socket.hpp create mode 100644 include/boost/async/io/detail/socket.hpp create mode 100644 include/boost/async/io/seq_packet_socket.hpp create mode 100644 include/boost/async/io/socket.hpp create mode 100644 include/boost/async/io/stream_socket.hpp create mode 100644 src/io/acceptor.cpp create mode 100644 src/io/datagram_socket.cpp create mode 100644 src/io/seq_packet_socket.cpp create mode 100644 src/io/socket.cpp create mode 100644 src/io/stream_socket.cpp create mode 100644 test/io/acceptor.cpp create mode 100644 test/io/datagram_socket.cpp create mode 100644 test/io/seq_packet_socket.cpp create mode 100644 test/io/stream_socket.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f03137df..7c64e316 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,12 +93,17 @@ add_library(boost_async src/io/buffers/mutable_buffer_subspan.cpp src/io/detail/duplicate.cpp src/io/detail/stream.cpp + src/io/acceptor.cpp + src/io/datagram_socket.cpp src/io/endpoint.cpp src/io/pipe.cpp src/io/resolver.cpp src/io/serial_port.cpp src/io/signal_set.cpp + src/io/seq_packet_socket.cpp + src/io/socket.cpp src/io/steady_timer.cpp + src/io/stream_socket.cpp src/io/system_timer.cpp) target_include_directories(boost_async PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") diff --git a/include/boost/async/config.hpp b/include/boost/async/config.hpp index 5403991c..65da00d6 100644 --- a/include/boost/async/config.hpp +++ b/include/boost/async/config.hpp @@ -72,9 +72,11 @@ namespace pmr = std::pmr; ::boost::system::error_code( (ev), [] { \ static constexpr auto loc((BOOST_CURRENT_LOCATION)); \ return &loc; }())) -# define BOOST_ASYNC_RETURN_EC(ev) \ - static constexpr auto loc ## __LINE__((BOOST_CURRENT_LOCATION)); \ - return ::boost::system::error_code((ev), &loc ## __LINE__) +# define BOOST_ASYNC_RETURN_EC(ev) \ + do { \ + static constexpr auto loc ## __LINE__((BOOST_CURRENT_LOCATION)); \ + return ::boost::system::error_code((ev), &loc ## __LINE__); \ + } while(false) #endif //BOOST_ASYNC_CONFIG_HPP diff --git a/include/boost/async/io/acceptor.hpp b/include/boost/async/io/acceptor.hpp new file mode 100644 index 00000000..ddb2d88c --- /dev/null +++ b/include/boost/async/io/acceptor.hpp @@ -0,0 +1,113 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_ACCEPTOR_HPP +#define BOOST_ASYNC_IO_ACCEPTOR_HPP + +#include +#include +#include + + +namespace boost::async::io +{ + +struct acceptor +{ + BOOST_ASYNC_DECL acceptor(); + BOOST_ASYNC_DECL acceptor(endpoint ep); + BOOST_ASYNC_DECL system::result bind(endpoint ep); + BOOST_ASYNC_DECL system::result listen(int backlog = asio::socket_base::max_listen_connections); // int backlog = asio::max_backlog() + BOOST_ASYNC_DECL endpoint local_endpoint(); + + private: + + struct accept_op_ : detail::deferred_op_resource_base + { + constexpr static bool await_ready() { return false; } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + acceptor_.template async_accept(socket_.socket_, completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] system::result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + auto [ec] = result_.value_or(std::make_tuple(system::error_code{})); + if (ec) + return ec; + else + return std::move(socket_); + } + accept_op_( asio::basic_socket_acceptor & acceptor) + : acceptor_(acceptor) {} + private: + asio::basic_socket_acceptor & acceptor_; + stream_socket socket_; + std::exception_ptr error; + std::optional> result_; + }; + + struct accept_seq_op_ : detail::deferred_op_resource_base + { + constexpr static bool await_ready() { return false; } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + acceptor_.template async_accept(socket_.socket_, completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] system::result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + auto [ec] = result_.value_or(std::make_tuple(system::error_code{})); + if (ec) + return ec; + else + return std::move(socket_); + } + accept_seq_op_(asio::basic_socket_acceptor & acceptor) + : acceptor_(acceptor) {} + private: + asio::basic_socket_acceptor & acceptor_; + seq_packet_socket socket_; + std::exception_ptr error; + std::optional> result_; + }; + public: + [[nodiscard]] BOOST_ASYNC_DECL accept_op_ accept(); + [[nodiscard]] BOOST_ASYNC_DECL accept_seq_op_ accept_seq_packet(); + private: + asio::basic_socket_acceptor acceptor_; +}; + +} + +#endif //BOOST_ASYNC_IO_ACCEPTOR_HPP diff --git a/include/boost/async/io/datagram_socket.hpp b/include/boost/async/io/datagram_socket.hpp new file mode 100644 index 00000000..192510e1 --- /dev/null +++ b/include/boost/async/io/datagram_socket.hpp @@ -0,0 +1,68 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_DATAGRAM_SOCKET_HPP +#define BOOST_ASYNC_IO_DATAGRAM_SOCKET_HPP + +#include +#include + +#include +#include + +namespace boost::async::io +{ + +struct [[nodiscard]] datagram_socket final : socket +{ + // duplicate onto another thread + system::result duplicate(); + + datagram_socket(); + datagram_socket(datagram_socket && lhs); + datagram_socket(native_handle_type h, protocol_type protocol = protocol_type()); + datagram_socket(endpoint ep); + private: + struct receive_op_; + struct receive_op_seq_; + struct receive_from_op_; + struct receive_from_op_seq_; + struct send_op_; + struct send_op_seq_; + struct send_to_op_; + struct send_to_op_seq_; + + public: + + [[nodiscard]] receive_op_seq_ receive(buffers::mutable_buffer_span buffers); + [[nodiscard]] receive_op_ receive(buffers::mutable_buffer buffer); + [[nodiscard]] receive_from_op_seq_ receive_from(buffers::mutable_buffer_span buffers, endpoint & ep); + [[nodiscard]] receive_from_op_ receive_from(buffers::mutable_buffer buffer, endpoint & ep); + [[nodiscard]] send_op_seq_ send(buffers::const_buffer_span buffers); + [[nodiscard]] send_op_ send(buffers::const_buffer buffer); + [[nodiscard]] send_to_op_seq_ send_to(buffers::const_buffer_span buffers, const endpoint & target); + [[nodiscard]] send_to_op_ send_to(buffers::const_buffer buffer, const endpoint & target); + + asio::basic_datagram_socket datagram_socket_; +}; + +inline system::result> make_pair(decltype(local_datagram) protocol) +{ + std::pair res; + auto c = connect_pair(protocol, res.first, res.second); + if (c) + return res; + else + return c.error(); +} + + +} + +#include + +#endif //BOOST_ASYNC_IO_DATAGRAM_SOCKET_HPP diff --git a/include/boost/async/io/detail/datagram_socket.hpp b/include/boost/async/io/detail/datagram_socket.hpp new file mode 100644 index 00000000..67688c2f --- /dev/null +++ b/include/boost/async/io/detail/datagram_socket.hpp @@ -0,0 +1,319 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_DETAIL_DATAGRAM_SOCKET_HPP +#define BOOST_ASYNC_IO_DETAIL_DATAGRAM_SOCKET_HPP + +#include +#include + +namespace boost::async::io +{ + +struct datagram_socket::receive_op_ : detail::deferred_op_resource_base +{ + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + initiate_(completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + receive_op_(asio::basic_datagram_socket & rs, + buffers::mutable_buffer buffer) + : datagram_socket_(rs), buffer_(buffer) {} + private: + void initiate_(async::completion_handler h); + asio::basic_datagram_socket &datagram_socket_; + buffers::mutable_buffer buffer_; + std::exception_ptr error; + std::optional> result_; +}; + + +struct datagram_socket::receive_op_seq_ : detail::deferred_op_resource_base +{ + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + initiate_(completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + receive_op_seq_(asio::basic_datagram_socket & rs, + buffers::mutable_buffer_span buffer) + : datagram_socket_(rs), buffer_(buffer) {} + private: + void initiate_(async::completion_handler h); + asio::basic_datagram_socket &datagram_socket_; + buffers::mutable_buffer_span buffer_; + std::exception_ptr error; + std::optional> result_; +}; + + +struct datagram_socket::receive_from_op_ : detail::deferred_op_resource_base +{ + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + initiate_(completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + receive_from_op_(asio::basic_datagram_socket & rs, + buffers::mutable_buffer buffer, endpoint & ep) + : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} + private: + void initiate_(async::completion_handler h); + asio::basic_datagram_socket &datagram_socket_; + buffers::mutable_buffer buffer_; + endpoint &ep_; + + std::exception_ptr error; + std::optional> result_; +}; + + +struct datagram_socket::receive_from_op_seq_ : detail::deferred_op_resource_base +{ + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + initiate_(completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + receive_from_op_seq_(asio::basic_datagram_socket & rs, + buffers::mutable_buffer_span buffer, endpoint & ep) + : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} + private: + void initiate_(async::completion_handler h); + asio::basic_datagram_socket &datagram_socket_; + buffers::mutable_buffer_span buffer_; + endpoint & ep_; + std::exception_ptr error; + std::optional> result_; +}; + +struct datagram_socket::send_op_ : detail::deferred_op_resource_base +{ + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + initiate_(completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + send_op_(asio::basic_datagram_socket & rs, + buffers::const_buffer buffer) + : datagram_socket_(rs), buffer_(buffer) {} + private: + void initiate_(async::completion_handler h); + asio::basic_datagram_socket &datagram_socket_; + buffers::const_buffer buffer_; + std::exception_ptr error; + std::optional> result_; +}; + + +struct datagram_socket::send_op_seq_ : detail::deferred_op_resource_base +{ + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + initiate_(completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + send_op_seq_(asio::basic_datagram_socket & rs, + buffers::const_buffer_span buffer) + : datagram_socket_(rs), buffer_(buffer) {} + private: + void initiate_(async::completion_handler h); + asio::basic_datagram_socket &datagram_socket_; + buffers::const_buffer_span buffer_; + std::exception_ptr error; + std::optional> result_; +}; + + +struct datagram_socket::send_to_op_ : detail::deferred_op_resource_base +{ + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + initiate_(completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + send_to_op_(asio::basic_datagram_socket & rs, + buffers::const_buffer buffer, const endpoint & ep) + : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} + private: + void initiate_(async::completion_handler h); + asio::basic_datagram_socket &datagram_socket_; + buffers::const_buffer buffer_; + const endpoint &ep_; + + std::exception_ptr error; + std::optional> result_; +}; + + +struct datagram_socket::send_to_op_seq_ : detail::deferred_op_resource_base +{ + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + initiate_(completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + send_to_op_seq_(asio::basic_datagram_socket & rs, + buffers::const_buffer_span buffer, const endpoint & ep) + : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} + private: + void initiate_(async::completion_handler h); + asio::basic_datagram_socket &datagram_socket_; + buffers::const_buffer_span buffer_; + const endpoint & ep_; + std::exception_ptr error; + std::optional> result_; +}; + +} + +#endif //BOOST_ASYNC_IO_DETAIL_DATAGRAM_SOCKET_HPP diff --git a/include/boost/async/io/detail/seq_packet_socket.hpp b/include/boost/async/io/detail/seq_packet_socket.hpp new file mode 100644 index 00000000..9ced5cd9 --- /dev/null +++ b/include/boost/async/io/detail/seq_packet_socket.hpp @@ -0,0 +1,169 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_DETAIL_SEQ_PACKET_SOCKET_HPP +#define BOOST_ASYNC_IO_DETAIL_SEQ_PACKET_SOCKET_HPP + +#include +#include + +namespace boost::async::io +{ + +struct seq_packet_socket::receive_op_ : detail::deferred_op_resource_base +{ + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + initiate_(completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + receive_op_(asio::basic_seq_packet_socket & rs, + buffers::mutable_buffer buffer, message_flags &out_flags) + : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} + private: + void initiate_(async::completion_handler h); + asio::basic_seq_packet_socket &seq_packet_socket_; + buffers::mutable_buffer buffer_; + message_flags &out_flags_; + std::exception_ptr error; + std::optional> result_; +}; + + +struct seq_packet_socket::receive_op_seq_ : detail::deferred_op_resource_base +{ + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + initiate_(completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + receive_op_seq_(asio::basic_seq_packet_socket & rs, + buffers::mutable_buffer_span buffer, message_flags &out_flags) + : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} + private: + void initiate_(async::completion_handler h); + asio::basic_seq_packet_socket &seq_packet_socket_; + buffers::mutable_buffer_span buffer_; + message_flags &out_flags_; + std::exception_ptr error; + std::optional> result_; +}; + +struct seq_packet_socket::send_op_ : detail::deferred_op_resource_base +{ + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + initiate_(completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + send_op_(asio::basic_seq_packet_socket & rs, + buffers::const_buffer buffer, message_flags out_flags) + : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} + private: + void initiate_(async::completion_handler h); + asio::basic_seq_packet_socket &seq_packet_socket_; + buffers::const_buffer buffer_; + message_flags out_flags_; + std::exception_ptr error; + std::optional> result_; +}; + + +struct seq_packet_socket::send_op_seq_ : detail::deferred_op_resource_base +{ + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + initiate_(completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + send_op_seq_(asio::basic_seq_packet_socket & rs, + buffers::const_buffer_span buffer, message_flags out_flags) + : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} + private: + void initiate_(async::completion_handler h); + asio::basic_seq_packet_socket &seq_packet_socket_; + buffers::const_buffer_span buffer_; + message_flags out_flags_; + std::exception_ptr error; + std::optional> result_; +}; + +} + +#endif //BOOST_ASYNC_IO_DETAIL_SEQ_PACKET_SOCKET_HPP diff --git a/include/boost/async/io/detail/socket.hpp b/include/boost/async/io/detail/socket.hpp new file mode 100644 index 00000000..9a46e990 --- /dev/null +++ b/include/boost/async/io/detail/socket.hpp @@ -0,0 +1,97 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_DETAIL_SOCKET_HPP +#define BOOST_ASYNC_IO_DETAIL_SOCKET_HPP + +#include +#include + +namespace boost::async::io +{ + +struct socket::wait_op_ : detail::deferred_op_resource_base +{ + constexpr static bool await_ready() { return false; } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + socket_.async_wait(wt_, completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] system::result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + auto [ec] = result_.value_or(std::make_tuple(system::error_code{})); + if (ec) + return ec; + else + return {}; + } + wait_op_(asio::basic_socket & socket, + asio::socket_base::wait_type wt) : socket_(socket), wt_(wt) {} + private: + asio::basic_socket & socket_; + asio::socket_base::wait_type wt_; + std::exception_ptr error; + std::optional> result_; +}; + + +struct socket::connect_op_ : detail::deferred_op_resource_base +{ + constexpr static bool await_ready() { return false; } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + socket_.async_connect(ep_, completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] system::result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + auto [ec] = result_.value_or(std::make_tuple(system::error_code{})); + if (ec) + return ec; + else + return {}; + } + connect_op_(asio::basic_socket & socket, + endpoint ep) : socket_(socket), ep_(ep) {} + private: + asio::basic_socket & socket_; + endpoint ep_; + std::exception_ptr error; + std::optional> result_; +}; + + +} + +#endif //BOOST_ASYNC_IO_SOCKET_HPP diff --git a/include/boost/async/io/endpoint.hpp b/include/boost/async/io/endpoint.hpp index 67372d49..d29a6ac5 100644 --- a/include/boost/async/io/endpoint.hpp +++ b/include/boost/async/io/endpoint.hpp @@ -29,7 +29,7 @@ namespace boost::async::io { struct endpoint; - +struct stream_socket; struct protocol_type { @@ -63,7 +63,8 @@ struct protocol_type constexpr auto operator<=>(const protocol_type & , const protocol_type &) noexcept = default; using endpoint = endpoint; - + // for the asio acceptor + using socket = stream_socket; private: family_t family_ = static_cast(0); type_t type_ = static_cast(0); @@ -120,7 +121,8 @@ struct endpoint void * data() {return &storage_; } const void * data() const {return &storage_; } - std::size_t size() {return size_;} + std::size_t size() const {return size_;} + std::size_t capacity() const {return sizeof(storage_);} protocol_type protocol() const { @@ -164,7 +166,6 @@ struct endpoint return tag_invoke(get_endpoint_tag{}, ep->protocol(), &ep->base_); } - private: union { boost::asio::detail::socket_addr_type base_{}; @@ -201,7 +202,7 @@ auto get(const endpoint & ep, const boost::source_location & loc = BOOST_CURRENT struct local_endpoint { - core::string_view path() { return unix_.sun_path;} + core::string_view path() const { return unix_.sun_path;} private: union { boost::asio::detail::sockaddr_storage_type addr_; @@ -224,7 +225,6 @@ struct ip_address_v4 std::uint16_t port() const {return in_.sin_port;} std::uint32_t addr() const {return in_.sin_addr.s_addr;} BOOST_ASYNC_DECL static_string<15> addr_str() const; - private: union { boost::asio::detail::sockaddr_storage_type addr_{}; diff --git a/include/boost/async/io/pipe.hpp b/include/boost/async/io/pipe.hpp index 1529c10e..e78e6b07 100644 --- a/include/boost/async/io/pipe.hpp +++ b/include/boost/async/io/pipe.hpp @@ -20,27 +20,27 @@ system::result> make_pipe( struct readable_pipe final : stream { - system::result close() override; - system::result cancel() override; - bool is_open() const override; + BOOST_ASYNC_DECL system::result close() override; + BOOST_ASYNC_DECL system::result cancel() override; + BOOST_ASYNC_DECL bool is_open() const override; - using native_handle_type = typename asio::basic_readable_pipe::native_handle_type; + using native_handle_type = typename asio::basic_readable_pipe::native_handle_type; native_handle_type native_handle() {return pipe_.native_handle();} - readable_pipe(); - readable_pipe(native_handle_type native_handle); + BOOST_ASYNC_DECL readable_pipe(); + BOOST_ASYNC_DECL readable_pipe(native_handle_type native_handle); - system::result assign(native_handle_type native_handle); - system::result release(); + BOOST_ASYNC_DECL system::result assign(native_handle_type native_handle); + BOOST_ASYNC_DECL system::result release(); - system::result duplicate(); + BOOST_ASYNC_DECL system::result duplicate(); void write_some(buffers::mutable_buffer_span buffers) = delete; void write_some(buffers::mutable_buffer buffer) = delete; private: - void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; - void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; friend system::result> make_pipe(); asio::basic_readable_pipe pipe_; @@ -48,25 +48,25 @@ struct readable_pipe final : stream struct writable_pipe final : stream { - system::result close() override; - system::result cancel() override; - bool is_open() const override; + BOOST_ASYNC_DECL system::result close() override; + BOOST_ASYNC_DECL system::result cancel() override; + BOOST_ASYNC_DECL bool is_open() const override; - using native_handle_type = typename asio::basic_readable_pipe::native_handle_type; + using native_handle_type = typename asio::basic_readable_pipe::native_handle_type; native_handle_type native_handle() {return pipe_.native_handle();} - writable_pipe(); - writable_pipe(native_handle_type native_handle); + BOOST_ASYNC_DECL writable_pipe(); + BOOST_ASYNC_DECL writable_pipe(native_handle_type native_handle); - system::result assign(native_handle_type native_handle); - system::result release(); - system::result duplicate(); + BOOST_ASYNC_DECL system::result assign(native_handle_type native_handle); + BOOST_ASYNC_DECL system::result release(); + BOOST_ASYNC_DECL system::result duplicate(); void read_some(buffers::mutable_buffer_span buffers) = delete; void read_some(buffers::mutable_buffer buffer) = delete; private: - void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; - void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; friend system::result> make_pipe(); asio::basic_writable_pipe pipe_; }; diff --git a/include/boost/async/io/resolver.hpp b/include/boost/async/io/resolver.hpp index 355b8eb1..3d3f32f7 100644 --- a/include/boost/async/io/resolver.hpp +++ b/include/boost/async/io/resolver.hpp @@ -10,6 +10,7 @@ #include +#include #include #include #include @@ -23,16 +24,16 @@ namespace boost::async::io struct resolver { using resolve_result = system::result>; - resolver(); - resolver(resolver && ) = delete; + BOOST_ASYNC_DECL resolver(); + BOOST_ASYNC_DECL resolver(resolver && ) = delete; - void cancel(); + BOOST_ASYNC_DECL void cancel(); private: - struct resolve_op_ + struct resolve_op_ : detail::deferred_op_resource_base { - using result_type = asio::ip::basic_resolver::results_type; + using result_type = asio::ip::basic_resolver::results_type; constexpr static bool await_ready() { return false; } @@ -41,10 +42,7 @@ struct resolver { try { - auto & res = resource.emplace( - buffer, sizeof(buffer), - asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); - initiate_(completion_handler{h, result_, &res}); + initiate_(completion_handler{h, result_, get_resource(h)}); return true; } catch(...) @@ -55,17 +53,15 @@ struct resolver } [[nodiscard]] resolve_result await_resume(); - resolve_op_(asio::ip::basic_resolver & resolver, + resolve_op_(asio::ip::basic_resolver & resolver, core::string_view host, core::string_view service) : resolver_(resolver), host_(host), service_(service) {} private: - asio::ip::basic_resolver & resolver_; + asio::ip::basic_resolver & resolver_; core::string_view host_; core::string_view service_; std::exception_ptr error; std::optional> result_; - char buffer[256]; - std::optional resource; void initiate_(completion_handler); diff --git a/include/boost/async/io/seq_packet_socket.hpp b/include/boost/async/io/seq_packet_socket.hpp new file mode 100644 index 00000000..60ad5531 --- /dev/null +++ b/include/boost/async/io/seq_packet_socket.hpp @@ -0,0 +1,72 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_SEQ_PACKET_SOCKET_HPP +#define BOOST_ASYNC_IO_SEQ_PACKET_SOCKET_HPP + +#include +#include +#include +#include + +namespace boost::async::io +{ + +struct [[nodiscard]] seq_packet_socket final : socket +{ + // duplicate onto another thread + system::result duplicate(); + + using message_flags = boost::asio::socket_base::message_flags; + /// Peek at incoming data without removing it from the input queue. + static constexpr int message_peek = boost::asio::socket_base::message_peek; + + /// Process out-of-band data. + static constexpr int message_out_of_band = boost::asio::socket_base::message_out_of_band; + + /// Specify that the data should not be subject to routing. + static constexpr int message_do_not_route = boost::asio::socket_base::message_do_not_route; + + /// Specifies that the data marks the end of a record. + static constexpr int message_end_of_record = boost::asio::socket_base::message_end_of_record; + + BOOST_ASYNC_DECL seq_packet_socket(); + BOOST_ASYNC_DECL seq_packet_socket(seq_packet_socket && lhs); + BOOST_ASYNC_DECL seq_packet_socket(native_handle_type h, protocol_type protocol = protocol_type()); + BOOST_ASYNC_DECL seq_packet_socket(endpoint ep); + private: + struct receive_op_; + struct receive_op_seq_; + struct send_op_; + struct send_op_seq_; + + public: + + [[nodiscard]] BOOST_ASYNC_DECL receive_op_seq_ receive(buffers::mutable_buffer_span buffers, message_flags & out_flags); + [[nodiscard]] BOOST_ASYNC_DECL receive_op_ receive(buffers::mutable_buffer buffer, message_flags & out_flags); + [[nodiscard]] BOOST_ASYNC_DECL send_op_seq_ send(buffers::const_buffer_span buffers, message_flags out_flags); + [[nodiscard]] BOOST_ASYNC_DECL send_op_ send(buffers::const_buffer buffer, message_flags out_flags); + + asio::basic_seq_packet_socket seq_packet_socket_; +}; + + +inline system::result> make_pair(decltype(local_seqpacket) protocol) +{ + std::pair res; + auto c = connect_pair(protocol, res.first, res.second); + if (c) + return res; + else + return c.error(); +} + +} + +#include + +#endif //BOOST_ASYNC_IO_SEQ_PACKET_SOCKET_HPP diff --git a/include/boost/async/io/serial_port.hpp b/include/boost/async/io/serial_port.hpp index 2cabfb15..512e705e 100644 --- a/include/boost/async/io/serial_port.hpp +++ b/include/boost/async/io/serial_port.hpp @@ -18,45 +18,45 @@ namespace boost::async::io struct [[nodiscard]] serial_port final : stream { - system::result close() override; - system::result cancel() override; - bool is_open() const override; + BOOST_ASYNC_DECL system::result close() override; + BOOST_ASYNC_DECL system::result cancel() override; + BOOST_ASYNC_DECL bool is_open() const override; - [[nodiscard]] system::result send_break(); + [[nodiscard]] BOOST_ASYNC_DECL system::result send_break(); - [[nodiscard]] system::result set_baud_rate(unsigned rate); - [[nodiscard]] system::result get_baud_rate(); + [[nodiscard]] BOOST_ASYNC_DECL system::result set_baud_rate(unsigned rate); + [[nodiscard]] BOOST_ASYNC_DECL system::result get_baud_rate(); - [[nodiscard]] system::result set_character_size(unsigned rate); - [[nodiscard]] system::result get_character_size(); + [[nodiscard]] BOOST_ASYNC_DECL system::result set_character_size(unsigned rate); + [[nodiscard]] BOOST_ASYNC_DECL system::result get_character_size(); using flow_control = asio::serial_port_base::flow_control::type; - [[nodiscard]] system::result set_flow_control(flow_control rate); - [[nodiscard]] system::result get_flow_control(); + [[nodiscard]] BOOST_ASYNC_DECL system::result set_flow_control(flow_control rate); + [[nodiscard]] BOOST_ASYNC_DECL system::result get_flow_control(); using parity = asio::serial_port_base::parity::type; - [[nodiscard]] system::result set_parity(parity rate); - [[nodiscard]] system::result get_parity(); + [[nodiscard]] BOOST_ASYNC_DECL system::result set_parity(parity rate); + [[nodiscard]] BOOST_ASYNC_DECL system::result get_parity(); - using native_handle_type = typename asio::basic_serial_port::native_handle_type; + using native_handle_type = typename asio::basic_serial_port::native_handle_type; native_handle_type native_handle() {return serial_port_.native_handle();} - serial_port(); - serial_port(serial_port && lhs) = default; - serial_port(core::string_view device); - serial_port(native_handle_type native_handle); + BOOST_ASYNC_DECL serial_port(); + BOOST_ASYNC_DECL serial_port(serial_port && lhs) = default; + BOOST_ASYNC_DECL serial_port(core::string_view device); + BOOST_ASYNC_DECL serial_port(native_handle_type native_handle); - [[nodiscard]] system::result assign(native_handle_type native_handle); - [[nodiscard]] system::result release(); - [[nodiscard]] system::result duplicate(); + [[nodiscard]] BOOST_ASYNC_DECL system::result assign(native_handle_type native_handle); + [[nodiscard]] BOOST_ASYNC_DECL system::result release(); + [[nodiscard]] BOOST_ASYNC_DECL system::result duplicate(); - [[nodiscard]] system::result open(core::string_view device); + BOOST_ASYNC_DECL [[nodiscard]] system::result open(core::string_view device); private: - void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; - void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; asio::basic_serial_port serial_port_; }; diff --git a/include/boost/async/io/signal_set.hpp b/include/boost/async/io/signal_set.hpp index 95e50871..faa9af74 100644 --- a/include/boost/async/io/signal_set.hpp +++ b/include/boost/async/io/signal_set.hpp @@ -22,13 +22,13 @@ struct signal_set { using wait_result = system::result; - signal_set(); - signal_set(std::initializer_list sigs); + BOOST_ASYNC_DECL signal_set(); + BOOST_ASYNC_DECL signal_set(std::initializer_list sigs); - [[nodiscard]] system::result cancel(); - [[nodiscard]] system::result clear(); - [[nodiscard]] system::result add(int signal_number); - [[nodiscard]] system::result remove(int signal_number); + [[nodiscard]] BOOST_ASYNC_DECL system::result cancel(); + [[nodiscard]] BOOST_ASYNC_DECL system::result clear(); + [[nodiscard]] BOOST_ASYNC_DECL system::result add(int signal_number); + [[nodiscard]] BOOST_ASYNC_DECL system::result remove(int signal_number); private: @@ -61,9 +61,9 @@ struct signal_set else return sig; } - wait_op_(boost::asio::basic_signal_set & signal_set) : signal_set_(signal_set) {} + wait_op_(boost::asio::basic_signal_set & signal_set) : signal_set_(signal_set) {} private: - boost::asio::basic_signal_set & signal_set_; + boost::asio::basic_signal_set & signal_set_; std::exception_ptr error; std::optional> result_; char buffer[256]; diff --git a/include/boost/async/io/sleep.hpp b/include/boost/async/io/sleep.hpp index 5274dc64..49f07c25 100644 --- a/include/boost/async/io/sleep.hpp +++ b/include/boost/async/io/sleep.hpp @@ -45,9 +45,9 @@ namespace boost::async::io // NOTE: these don't need to be coros, we can optimize that out. Not sure that's worth it though -detail::io::steady_sleep sleep(const std::chrono::steady_clock::duration & d) { return d;} -detail::io::steady_sleep sleep(const std::chrono::steady_clock::time_point & tp) { return tp;} -detail::io::system_sleep sleep(const std::chrono::system_clock::time_point & tp) { return tp;} +BOOST_ASYNC_DECL detail::io::steady_sleep sleep(const std::chrono::steady_clock::duration & d) { return d;} +BOOST_ASYNC_DECL detail::io::steady_sleep sleep(const std::chrono::steady_clock::time_point & tp) { return tp;} +BOOST_ASYNC_DECL detail::io::system_sleep sleep(const std::chrono::system_clock::time_point & tp) { return tp;} template detail::io::steady_sleep sleep(const std::chrono::time_point & tp) diff --git a/include/boost/async/io/socket.hpp b/include/boost/async/io/socket.hpp new file mode 100644 index 00000000..0f06964f --- /dev/null +++ b/include/boost/async/io/socket.hpp @@ -0,0 +1,102 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_SOCKET_HPP +#define BOOST_ASYNC_IO_SOCKET_HPP + +#include +#include +#include + +namespace boost::async::io +{ + +struct socket +{ + [[nodiscard]] system::result open(protocol_type prot = protocol_type {}); + [[nodiscard]] system::result close(); + [[nodiscard]] system::result cancel(); + [[nodiscard]] bool is_open() const; + + // asio acceptor compatibility + template + struct rebind_executor {using other = socket;}; + + using shutdown_type = asio::socket_base::shutdown_type; + using wait_type = asio::socket_base::wait_type; + using message_flags = asio::socket_base::message_flags; + constexpr static int message_peek = asio::socket_base::message_peek; + constexpr static int message_out_of_band = asio::socket_base::message_out_of_band; + constexpr static int message_do_not_route = asio::socket_base::message_do_not_route; + constexpr static int message_end_of_record = asio::socket_base::message_end_of_record; + + using native_handle_type = asio::basic_socket::native_handle_type; + native_handle_type native_handle(); + + [[nodiscard]] BOOST_ASYNC_DECL system::result shutdown(shutdown_type = shutdown_type::shutdown_both); + + [[nodiscard]] BOOST_ASYNC_DECL system::result local_endpoint() const; + [[nodiscard]] BOOST_ASYNC_DECL system::result remote_endpoint() const; + + + BOOST_ASYNC_DECL system::result assign(protocol_type protocol, native_handle_type native_handle); + BOOST_ASYNC_DECL system::result release(); + + /// copied from what asio does + [[nodiscard]] BOOST_ASYNC_DECL system::result bytes_readable(); + + [[nodiscard]] BOOST_ASYNC_DECL system::result set_debug(bool debug); + [[nodiscard]] BOOST_ASYNC_DECL system::result get_debug() const; + + [[nodiscard]] BOOST_ASYNC_DECL system::result set_do_not_route(bool do_not_route); + [[nodiscard]] BOOST_ASYNC_DECL system::result get_do_not_route() const; + + [[nodiscard]] BOOST_ASYNC_DECL system::result set_enable_connection_aborted(bool enable_connection_aborted); + [[nodiscard]] BOOST_ASYNC_DECL system::result get_enable_connection_aborted() const; + + [[nodiscard]] BOOST_ASYNC_DECL system::result set_keep_alive(bool keep_alive); + [[nodiscard]] BOOST_ASYNC_DECL system::result get_keep_alive() const; + + [[nodiscard]] BOOST_ASYNC_DECL system::result set_linger(bool linger, int timeout); + [[nodiscard]] BOOST_ASYNC_DECL system::result> get_linger() const; + + [[nodiscard]] BOOST_ASYNC_DECL system::result set_receive_buffer_size(std::size_t receive_buffer_size); + [[nodiscard]] BOOST_ASYNC_DECL system::result get_receive_buffer_size() const; + + [[nodiscard]] BOOST_ASYNC_DECL system::result set_send_buffer_size(std::size_t send_buffer_size); + [[nodiscard]] BOOST_ASYNC_DECL system::result get_send_buffer_size() const; + + [[nodiscard]] BOOST_ASYNC_DECL system::result set_receive_low_watermark(std::size_t receive_low_watermark); + [[nodiscard]] BOOST_ASYNC_DECL system::result get_receive_low_watermark() const; + + [[nodiscard]] BOOST_ASYNC_DECL system::result set_send_low_watermark(std::size_t send_low_watermark); + [[nodiscard]] BOOST_ASYNC_DECL system::result get_send_low_watermark() const; + + [[nodiscard]] BOOST_ASYNC_DECL system::result set_reuse_address(bool reuse_address); + [[nodiscard]] BOOST_ASYNC_DECL system::result get_reuse_address() const; + + private: + struct connect_op_; + struct wait_op_; + friend struct acceptor; + asio::basic_socket & socket_; + + public: + socket(asio::basic_socket & socket) : socket_(socket) {} + + BOOST_ASYNC_DECL connect_op_ connect(endpoint ep); + BOOST_ASYNC_DECL wait_op_ wait(wait_type = wait_type::wait_read); + BOOST_ASYNC_DECL wait_op_ operator co_await(); // co_await sock; +}; + +BOOST_ASYNC_DECL system::result connect_pair(protocol_type protocol, socket & socket1, socket & socket2); + +} + +#include + +#endif //BOOST_ASYNC_IO_SOCKET_HPP diff --git a/include/boost/async/io/steady_timer.hpp b/include/boost/async/io/steady_timer.hpp index 1395443c..e0562299 100644 --- a/include/boost/async/io/steady_timer.hpp +++ b/include/boost/async/io/steady_timer.hpp @@ -29,16 +29,16 @@ struct steady_timer /// The time point type of the clock. typedef typename clock_type::time_point time_point; - steady_timer(); - steady_timer(const time_point& expiry_time); - steady_timer(const duration& expiry_time); + BOOST_ASYNC_DECL steady_timer(); + BOOST_ASYNC_DECL steady_timer(const time_point& expiry_time); + BOOST_ASYNC_DECL steady_timer(const duration& expiry_time); - void cancel(); + BOOST_ASYNC_DECL void cancel(); - time_point expiry() const; - void reset(const time_point& expiry_time); - void reset(const duration& expiry_time); - bool expired() const; + BOOST_ASYNC_DECL time_point expiry() const; + BOOST_ASYNC_DECL void reset(const time_point& expiry_time); + BOOST_ASYNC_DECL void reset(const duration& expiry_time); + BOOST_ASYNC_DECL bool expired() const; private: struct wait_op_ : detail::deferred_op_resource_base diff --git a/include/boost/async/io/stream.hpp b/include/boost/async/io/stream.hpp index a0a4c27f..3aac76b1 100644 --- a/include/boost/async/io/stream.hpp +++ b/include/boost/async/io/stream.hpp @@ -60,10 +60,10 @@ struct stream struct write_some_op_; struct write_some_op_seq_; public: - [[nodiscard]] read_some_op_seq_ read_some(buffers::mutable_buffer_span buffers); - [[nodiscard]] read_some_op_ read_some(buffers::mutable_buffer buffer); - [[nodiscard]] write_some_op_seq_ write_some(buffers::const_buffer_span buffers); - [[nodiscard]] write_some_op_ write_some(buffers::const_buffer buffer); + BOOST_ASYNC_DECL [[nodiscard]] read_some_op_seq_ read_some(buffers::mutable_buffer_span buffers); + BOOST_ASYNC_DECL [[nodiscard]] read_some_op_ read_some(buffers::mutable_buffer buffer); + BOOST_ASYNC_DECL [[nodiscard]] write_some_op_seq_ write_some(buffers::const_buffer_span buffers); + BOOST_ASYNC_DECL [[nodiscard]] write_some_op_ write_some(buffers::const_buffer buffer); }; } diff --git a/include/boost/async/io/stream_socket.hpp b/include/boost/async/io/stream_socket.hpp new file mode 100644 index 00000000..1a33315b --- /dev/null +++ b/include/boost/async/io/stream_socket.hpp @@ -0,0 +1,51 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_STREAM_SOCKET_HPP +#define BOOST_ASYNC_IO_STREAM_SOCKET_HPP + +#include +#include +#include +#include + +namespace boost::async::io +{ + +struct [[nodiscard]] stream_socket final : stream, socket +{ + // duplicate onto another thread + BOOST_ASYNC_DECL system::result duplicate(); + + [[nodiscard]] BOOST_ASYNC_DECL system::result close() override; + [[nodiscard]] BOOST_ASYNC_DECL system::result cancel() override; + [[nodiscard]] BOOST_ASYNC_DECL bool is_open() const override; + + BOOST_ASYNC_DECL stream_socket(); + BOOST_ASYNC_DECL stream_socket(stream_socket && lhs); + BOOST_ASYNC_DECL stream_socket(native_handle_type h, protocol_type protocol = protocol_type()); + BOOST_ASYNC_DECL stream_socket(endpoint ep); + private: + BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + asio::basic_stream_socket stream_socket_; + friend struct ssl_stream; +}; + +inline system::result> make_pair(decltype(local_stream) protocol) +{ + std::pair res; + auto c = connect_pair(protocol, res.first, res.second); + if (c) + return res; + else + return c.error(); +} + +} + +#endif //BOOST_ASYNC_IO_STREAM_SOCKET_HPP diff --git a/include/boost/async/io/system_timer.hpp b/include/boost/async/io/system_timer.hpp index 8e31e7e5..abb94427 100644 --- a/include/boost/async/io/system_timer.hpp +++ b/include/boost/async/io/system_timer.hpp @@ -29,16 +29,16 @@ struct system_timer final /// The time point type of the clock. typedef typename clock_type::time_point time_point; - system_timer(); - system_timer(const time_point& expiry_time); - system_timer(const duration& expiry_time); + BOOST_ASYNC_DECL system_timer(); + BOOST_ASYNC_DECL system_timer(const time_point& expiry_time); + BOOST_ASYNC_DECL system_timer(const duration& expiry_time); - void cancel(); + BOOST_ASYNC_DECL void cancel(); - time_point expiry() const; - void reset(const time_point& expiry_time); - void reset(const duration& expiry_time); - bool expired() const; + BOOST_ASYNC_DECL time_point expiry() const; + BOOST_ASYNC_DECL void reset(const time_point& expiry_time); + BOOST_ASYNC_DECL void reset(const duration& expiry_time); + BOOST_ASYNC_DECL bool expired() const; struct wait_op_ : detail::deferred_op_resource_base { diff --git a/src/io/acceptor.cpp b/src/io/acceptor.cpp new file mode 100644 index 00000000..b88c6536 --- /dev/null +++ b/src/io/acceptor.cpp @@ -0,0 +1,37 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include + +namespace boost::async::io +{ +acceptor::acceptor() : acceptor_{this_thread::get_executor()} {} +acceptor::acceptor(endpoint ep) : acceptor_{this_thread::get_executor(), ep} {} + + +system::result acceptor::bind(endpoint ep) +{ + system::error_code ec; + acceptor_.bind(ep, ec); + return ec ? ec : system::result{}; +} +system::result acceptor::listen(int backlog) +{ + system::error_code ec; + acceptor_.listen(backlog, ec); + return ec ? ec : system::result{}; +} + +endpoint acceptor::local_endpoint() +{ + return acceptor_.local_endpoint(); +} + +auto acceptor::accept() -> accept_op_ { return accept_op_{acceptor_};} +auto acceptor::accept_seq_packet() -> accept_seq_op_ { return accept_seq_op_{acceptor_};} + +} \ No newline at end of file diff --git a/src/io/datagram_socket.cpp b/src/io/datagram_socket.cpp new file mode 100644 index 00000000..4744a6d1 --- /dev/null +++ b/src/io/datagram_socket.cpp @@ -0,0 +1,119 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include + +namespace boost::async::io +{ + +system::result datagram_socket::duplicate() +{ + auto res = detail::duplicate_socket(datagram_socket_.native_handle()); + if (!res) + return res.error(); + + return {system::in_place_value, datagram_socket(*res)}; +} + + + +datagram_socket::datagram_socket() + : socket(datagram_socket_), datagram_socket_(this_thread::get_executor()) +{ +} + +datagram_socket::datagram_socket(native_handle_type h, protocol_type protocol) + : socket(datagram_socket_), datagram_socket_(this_thread::get_executor(), protocol, h) +{ +} + +datagram_socket::datagram_socket(datagram_socket && lhs) + : socket(datagram_socket_), datagram_socket_(std::move(lhs.datagram_socket_)) +{ +} +datagram_socket::datagram_socket(endpoint ep) + : socket(datagram_socket_), datagram_socket_(this_thread::get_executor(), ep) +{ +} + +auto datagram_socket::receive(buffers::mutable_buffer_span buffers) -> receive_op_seq_ +{ + return receive_op_seq_{datagram_socket_, buffers}; +} +auto datagram_socket::receive(buffers::mutable_buffer buffer) -> receive_op_ +{ + return receive_op_{datagram_socket_, buffer}; +} +auto datagram_socket::receive_from(buffers::mutable_buffer_span buffers, endpoint & ep) -> receive_from_op_seq_ +{ + return receive_from_op_seq_{datagram_socket_, buffers, ep}; +} +auto datagram_socket::receive_from(buffers::mutable_buffer buffer, endpoint & ep) -> receive_from_op_ +{ + return receive_from_op_{datagram_socket_, buffer, ep}; +} +auto datagram_socket::send(buffers::const_buffer_span buffers) -> send_op_seq_ +{ + return send_op_seq_{datagram_socket_, buffers}; +} +auto datagram_socket::send(buffers::const_buffer buffer) -> send_op_ +{ + return send_op_{datagram_socket_, buffer}; +} +auto datagram_socket::send_to(buffers::const_buffer_span buffers, const endpoint & target) -> send_to_op_seq_ +{ + return send_to_op_seq_{datagram_socket_, buffers, target}; +} +auto datagram_socket::send_to(buffers::const_buffer buffer, const endpoint & target) -> send_to_op_ +{ + return send_to_op_{datagram_socket_, buffer, target}; +} + +void datagram_socket::receive_op_::initiate_(async::completion_handler h) +{ + this->datagram_socket_.async_receive(buffers::mutable_buffer_span{&buffer_, 1u}, std::move(h)); +} + +void datagram_socket::receive_op_seq_::initiate_(async::completion_handler h) +{ + this->datagram_socket_.async_receive(buffer_, std::move(h)); +} + +void datagram_socket::receive_from_op_::initiate_(async::completion_handler h) +{ + this->datagram_socket_.async_receive_from(buffers::mutable_buffer_span{&buffer_, 1u}, ep_, std::move(h)); +} + +void datagram_socket::receive_from_op_seq_::initiate_(async::completion_handler h) +{ + this->datagram_socket_.async_receive_from(buffer_, ep_, std::move(h)); +} + +void datagram_socket::send_op_::initiate_(async::completion_handler h) +{ + this->datagram_socket_.async_send(buffers::const_buffer_span{&buffer_, 1u}, std::move(h)); +} + +void datagram_socket::send_op_seq_::initiate_(async::completion_handler h) +{ + this->datagram_socket_.async_send(buffer_, std::move(h)); +} + +void datagram_socket::send_to_op_::initiate_(async::completion_handler h) +{ + this->datagram_socket_.async_send_to(buffers::const_buffer_span{&buffer_, 1u}, ep_, std::move(h)); +} + +void datagram_socket::send_to_op_seq_::initiate_(async::completion_handler h) +{ + this->datagram_socket_.async_send_to(buffer_, ep_, std::move(h)); +} + + + +} \ No newline at end of file diff --git a/src/io/seq_packet_socket.cpp b/src/io/seq_packet_socket.cpp new file mode 100644 index 00000000..5549bab7 --- /dev/null +++ b/src/io/seq_packet_socket.cpp @@ -0,0 +1,82 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include + +namespace boost::async::io +{ + +system::result seq_packet_socket::duplicate() +{ + auto res = detail::duplicate_socket(seq_packet_socket_.native_handle()); + if (!res) + return res.error(); + + return {system::in_place_value, seq_packet_socket(*res)}; +} + + + +seq_packet_socket::seq_packet_socket() + : socket(seq_packet_socket_), seq_packet_socket_(this_thread::get_executor()) +{ +} + +seq_packet_socket::seq_packet_socket(native_handle_type h, protocol_type protocol) + : socket(seq_packet_socket_), seq_packet_socket_(this_thread::get_executor(), protocol, h) +{ +} + +seq_packet_socket::seq_packet_socket(seq_packet_socket && lhs) + : socket(seq_packet_socket_), seq_packet_socket_(std::move(lhs.seq_packet_socket_)) +{ +} +seq_packet_socket::seq_packet_socket(endpoint ep) + : socket(seq_packet_socket_), seq_packet_socket_(this_thread::get_executor(), ep) +{ +} + +auto seq_packet_socket::receive(buffers::mutable_buffer_span buffers, message_flags &out_flags) -> receive_op_seq_ +{ + return receive_op_seq_{seq_packet_socket_, buffers, out_flags}; +} +auto seq_packet_socket::receive(buffers::mutable_buffer buffer, message_flags &out_flags) -> receive_op_ +{ + return receive_op_{seq_packet_socket_, buffer, out_flags}; +} +auto seq_packet_socket::send(buffers::const_buffer_span buffers, message_flags out_flags) -> send_op_seq_ +{ + return send_op_seq_{seq_packet_socket_, buffers, out_flags}; +} +auto seq_packet_socket::send(buffers::const_buffer buffer,message_flags out_flags) -> send_op_ +{ + return send_op_{seq_packet_socket_, buffer, out_flags}; +} + +void seq_packet_socket::receive_op_::initiate_(async::completion_handler h) +{ + this->seq_packet_socket_.async_receive(buffers::mutable_buffer_span{&buffer_, 1u}, out_flags_, std::move(h)); +} + +void seq_packet_socket::receive_op_seq_::initiate_(async::completion_handler h) +{ + this->seq_packet_socket_.async_receive(buffer_, out_flags_, std::move(h)); +} + +void seq_packet_socket::send_op_::initiate_(async::completion_handler h) +{ + this->seq_packet_socket_.async_send(buffers::const_buffer_span{&buffer_, 1u}, out_flags_, std::move(h)); +} + +void seq_packet_socket::send_op_seq_::initiate_(async::completion_handler h) +{ + this->seq_packet_socket_.async_send(buffer_, out_flags_, std::move(h)); +} + + +} \ No newline at end of file diff --git a/src/io/socket.cpp b/src/io/socket.cpp new file mode 100644 index 00000000..7c0ebac4 --- /dev/null +++ b/src/io/socket.cpp @@ -0,0 +1,168 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include +#include + +namespace boost::async::io +{ + +system::result socket::open(protocol_type prot) +{ + system::error_code ec; + socket_.open(prot, ec); + return ec ? ec : system::result{}; +} + +system::result socket::close() +{ + system::error_code ec; + socket_.close(ec); + return ec ? ec : system::result{}; +} + +system::result socket::cancel() +{ + system::error_code ec; + socket_.cancel(ec); + return ec ? ec : system::result{}; +} + +bool socket::is_open() const +{ + return socket_.is_open(); +} + +auto socket::native_handle() -> native_handle_type { return socket_.native_handle(); } + +system::result socket::shutdown(shutdown_type st) +{ + system::error_code ec; + socket_.shutdown(st, ec); + return ec ? ec : system::result{}; +} + +system::result socket::local_endpoint() const +{ + system::error_code ec; + auto res = socket_.local_endpoint(ec); + return ec ? ec : system::result(res); +} + +system::result socket::remote_endpoint() const +{ + system::error_code ec; + auto res = socket_.remote_endpoint(ec); + return ec ? ec : system::result(res); +} + + +system::result socket::assign(protocol_type protocol, native_handle_type native_handle) +{ + system::error_code ec; + socket_.assign(protocol, native_handle, ec); + return ec ? ec : system::result{}; +} + + + +auto socket::release() -> system::result +{ + system::error_code ec; + auto h = socket_.release(ec); + return ec ? ec : system::result(h); +} + +system::result socket::bytes_readable() +{ + system::error_code ec; + asio::socket_base::bytes_readable opt; + socket_.io_control(opt, ec); + return ec ? ec : system::result(opt.get()); +} + +#define DEFINE_OPTION(Name, Type) \ +system::result socket::set_##Name(Type value) \ +{ \ + system::error_code ec; \ + socket_.set_option(asio::socket_base::Name(value), ec); \ + return ec ? ec : system::result{}; \ +} \ + \ +system::result socket::get_##Name() const \ +{ \ + system::error_code ec; \ + asio::socket_base::Name opt; \ + socket_.get_option(opt, ec); \ + return ec ? ec : system::result(opt.value()); \ +} + +DEFINE_OPTION(debug, bool); +DEFINE_OPTION(do_not_route, bool); +DEFINE_OPTION(enable_connection_aborted , bool); +DEFINE_OPTION(keep_alive , bool); +DEFINE_OPTION(receive_buffer_size, std::size_t); +DEFINE_OPTION(send_buffer_size, std::size_t); +DEFINE_OPTION(receive_low_watermark, std::size_t); +DEFINE_OPTION(send_low_watermark, std::size_t); +DEFINE_OPTION(reuse_address, bool); + +system::result socket::set_linger(bool linger, int timeout) +{ + system::error_code ec; + socket_.set_option(asio::socket_base::linger(linger, timeout), ec); + return ec ? ec : system::result{}; +} + +system::result> socket::get_linger() const +{ + system::error_code ec; + asio::socket_base::linger opt; + socket_.get_option(opt, ec); + return ec ? ec : system::result>(opt.enabled(), opt.timeout()); +} + + +auto socket::connect(endpoint ep) -> connect_op_ {return connect_op_{socket_, ep};} +auto socket::wait(wait_type wt) -> wait_op_ {return wait_op_{socket_, wt};} +auto socket::operator co_await() -> wait_op_ {return wait_op_{socket_, wait_type::wait_read};} + +system::result connect_pair(protocol_type protocol, socket & socket1, socket & socket2) +{ + system::error_code ec; + boost::asio::detail::socket_type sv[2]; + if (boost::asio::detail::socket_ops::socketpair(protocol.family(), + protocol.type(), protocol.protocol(), sv, ec) + == boost::asio::detail::socket_error_retval) + BOOST_ASYNC_RETURN_EC(ec); + + auto res = socket1.assign(protocol, sv[0]); + if (!res) + { + boost::system::error_code temp_ec; + boost::asio::detail::socket_ops::state_type state[2] = { 0, 0 }; + boost::asio::detail::socket_ops::close(sv[0], state[0], true, temp_ec); + boost::asio::detail::socket_ops::close(sv[1], state[1], true, temp_ec); + return res; + } + + res = socket2.assign(protocol, sv[1]); + if (!res) + { + boost::system::error_code temp_ec; + (void)socket1.close(); + boost::asio::detail::socket_ops::state_type state = 0; + boost::asio::detail::socket_ops::close(sv[1], state, true, temp_ec); + return res; + } + + return {}; +} + + +} \ No newline at end of file diff --git a/src/io/stream_socket.cpp b/src/io/stream_socket.cpp new file mode 100644 index 00000000..e0b79cc8 --- /dev/null +++ b/src/io/stream_socket.cpp @@ -0,0 +1,63 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include + +namespace boost::async::io +{ + +system::result stream_socket::duplicate() +{ + auto res = detail::duplicate_socket(stream_socket_.native_handle()); + if (!res) + return res.error(); + + return {system::in_place_value, stream_socket(*res)}; +} + + + +stream_socket::stream_socket() + : socket(stream_socket_), stream_socket_(this_thread::get_executor()) +{ +} + +stream_socket::stream_socket(native_handle_type h, protocol_type protocol) + : socket(stream_socket_), stream_socket_(this_thread::get_executor(), protocol, h) +{ +} + +stream_socket::stream_socket(stream_socket && lhs) + : socket(stream_socket_), stream_socket_(std::move(lhs.stream_socket_)) +{ +} +stream_socket::stream_socket(endpoint ep) + : socket(stream_socket_), stream_socket_(this_thread::get_executor(), ep) +{ +} + +void stream_socket::async_read_some_impl_( + buffers::mutable_buffer_span buffer, + async::completion_handler h) +{ + stream_socket_.async_read_some(buffers::mutable_buffer_span(buffer), std::move(h)); +} + +void stream_socket::async_write_some_impl_( + buffers::const_buffer_span buffer, + async::completion_handler h) +{ + stream_socket_.async_write_some(buffer, std::move(h)); +} + +system::result stream_socket::close() { return socket::close(); } +system::result stream_socket::cancel() { return socket::cancel(); } +bool stream_socket::is_open() const {return socket::is_open();} + + +} \ No newline at end of file diff --git a/test/io/CMakeLists.txt b/test/io/CMakeLists.txt index c8e3a07d..5cbbf275 100644 --- a/test/io/CMakeLists.txt +++ b/test/io/CMakeLists.txt @@ -1,6 +1,10 @@ add_subdirectory(buffers) add_executable(boost_async_io_tests + acceptor.cpp + datagram_socket.cpp + stream_socket.cpp + seq_packet_socket.cpp endpoint.cpp pipe.cpp resolver.cpp diff --git a/test/io/acceptor.cpp b/test/io/acceptor.cpp new file mode 100644 index 00000000..f4a57a9d --- /dev/null +++ b/test/io/acceptor.cpp @@ -0,0 +1,38 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + + +#include "../doctest.h" +#include "../test.hpp" +#include +#include +#include + +#include + +CO_TEST_CASE("acceptor") +{ + using namespace boost::async; + io::endpoint ep{io::tcp, "127.0.0.1", 8080}; + io::acceptor acceptor{ep}; + io::stream_socket ss{}; + + auto [accepted, connected] = + co_await join(acceptor.accept(), + ss.connect(ep)); + + CHECK(!accepted.has_error()); + CHECK(!connected.has_error()); + + CHECK(accepted->remote_endpoint()->protocol() == ss.local_endpoint()->protocol()); + CHECK(accepted->local_endpoint()->protocol() == ss.remote_endpoint()->protocol()); + + CHECK(get(*accepted->remote_endpoint()).port() == get(*ss.local_endpoint()) .port()); + CHECK(get(*accepted->local_endpoint()) .port() == get(*ss.remote_endpoint()).port()); + CHECK(get(*accepted->remote_endpoint()).addr() == get(*ss.local_endpoint()) .addr()); + CHECK(get(*accepted->local_endpoint()) .addr() == get(*ss.remote_endpoint()).addr()); +} diff --git a/test/io/datagram_socket.cpp b/test/io/datagram_socket.cpp new file mode 100644 index 00000000..5916daf0 --- /dev/null +++ b/test/io/datagram_socket.cpp @@ -0,0 +1,31 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + + +#include "../doctest.h" +#include "../test.hpp" +#include +#include +#include + +#include + +CO_TEST_CASE("local_datagram") +{ + using namespace boost::async; + auto [r, w] = io::make_pair(io::local_datagram).value(); + + char data[7] = "nodata"; + + auto [written, read] = + co_await join(w.send(io::buffers::buffer("foobar", 6)), + r.receive(io::buffers::buffer(data))); + + CHECK(written.transferred == 6u); + CHECK(read.transferred == 6u); + CHECK(data == std::string("foobar")); +} diff --git a/test/io/seq_packet_socket.cpp b/test/io/seq_packet_socket.cpp new file mode 100644 index 00000000..0c1bb720 --- /dev/null +++ b/test/io/seq_packet_socket.cpp @@ -0,0 +1,32 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include + +#include "../doctest.h" +#include "../test.hpp" +#include +#include +#include + +CO_TEST_CASE("local_seq_packet") +{ + using namespace boost::async; + auto [r, w] = io::make_pair(io::local_seqpacket).value(); + + char data[7] = "nodata"; + + int flags = -1; + auto [written, read] = + co_await join(w.send(io::buffers::buffer("foobar", 6), 0), + r.receive(io::buffers::buffer(data), flags)); + + CHECK(flags == 0); + CHECK(written.transferred == 6u); + CHECK(read.transferred == 6u); + CHECK(data == std::string("foobar")); +} diff --git a/test/io/stream_socket.cpp b/test/io/stream_socket.cpp new file mode 100644 index 00000000..9c29c8d9 --- /dev/null +++ b/test/io/stream_socket.cpp @@ -0,0 +1,30 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include + +#include "../doctest.h" +#include "../test.hpp" +#include +#include +#include + +CO_TEST_CASE("local_stream") +{ + using namespace boost::async; + auto [r, w] = io::make_pair(io::local_stream).value(); + + char data[7] = "nodata"; + + auto [written, read] = + co_await join(w.write_some(io::buffers::buffer("foobar", 6)), + r.read_some(io::buffers::buffer(data))); + + CHECK(written.transferred == 6u); + CHECK(read.transferred == 6u); + CHECK(data == std::string("foobar")); +} From 63a73695fad029f344caf512afbc2cd7e59d09a9 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 14:43:04 +0800 Subject: [PATCH 12/43] added ssl. --- CMakeLists.txt | 1 + include/boost/async/io/datagram_socket.hpp | 1 + include/boost/async/io/detail/socket.hpp | 8 +- include/boost/async/io/detail/ssl.hpp | 167 +++++++++++++++++++ include/boost/async/io/endpoint.hpp | 3 + include/boost/async/io/seq_packet_socket.hpp | 2 +- include/boost/async/io/socket.hpp | 2 + include/boost/async/io/ssl.hpp | 74 ++++++++ include/boost/async/io/stream_socket.hpp | 1 + src/io/datagram_socket.cpp | 16 ++ src/io/seq_packet_socket.cpp | 20 +++ src/io/socket.cpp | 2 +- src/io/ssl.cpp | 105 ++++++++++++ src/io/stream_socket.cpp | 14 ++ test/io/CMakeLists.txt | 1 + test/io/ssl.cpp | 31 ++++ 16 files changed, 443 insertions(+), 5 deletions(-) create mode 100644 include/boost/async/io/detail/ssl.hpp create mode 100644 include/boost/async/io/ssl.hpp create mode 100644 src/io/ssl.cpp create mode 100644 test/io/ssl.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c64e316..47267874 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,6 +102,7 @@ add_library(boost_async src/io/signal_set.cpp src/io/seq_packet_socket.cpp src/io/socket.cpp + src/io/ssl.cpp src/io/steady_timer.cpp src/io/stream_socket.cpp src/io/system_timer.cpp) diff --git a/include/boost/async/io/datagram_socket.hpp b/include/boost/async/io/datagram_socket.hpp index 192510e1..8e7f0231 100644 --- a/include/boost/async/io/datagram_socket.hpp +++ b/include/boost/async/io/datagram_socket.hpp @@ -35,6 +35,7 @@ struct [[nodiscard]] datagram_socket final : socket struct send_op_seq_; struct send_to_op_; struct send_to_op_seq_; + BOOST_ASYNC_DECL void adopt_endpoint_(endpoint & ep) override; public: diff --git a/include/boost/async/io/detail/socket.hpp b/include/boost/async/io/detail/socket.hpp index 9a46e990..86303e41 100644 --- a/include/boost/async/io/detail/socket.hpp +++ b/include/boost/async/io/detail/socket.hpp @@ -10,6 +10,7 @@ #include #include +#include namespace boost::async::io { @@ -62,7 +63,8 @@ struct socket::connect_op_ : detail::deferred_op_resource_base { try { - socket_.async_connect(ep_, completion_handler{h, result_, get_resource(h)}); + socket_->adopt_endpoint_(ep_); + socket_->socket_.async_connect(ep_, completion_handler{h, result_, get_resource(h)}); return true; } catch(...) @@ -82,10 +84,10 @@ struct socket::connect_op_ : detail::deferred_op_resource_base else return {}; } - connect_op_(asio::basic_socket & socket, + connect_op_(socket* socket, endpoint ep) : socket_(socket), ep_(ep) {} private: - asio::basic_socket & socket_; + socket * socket_; endpoint ep_; std::exception_ptr error; std::optional> result_; diff --git a/include/boost/async/io/detail/ssl.hpp b/include/boost/async/io/detail/ssl.hpp new file mode 100644 index 00000000..c415b80c --- /dev/null +++ b/include/boost/async/io/detail/ssl.hpp @@ -0,0 +1,167 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_SSL_HPP +#define BOOST_ASYNC_SSL_HPP + +#include +#include + +namespace boost::async::io +{ +struct ssl_stream::accept_op_ : detail::deferred_op_resource_base +{ + constexpr static bool await_ready() { return false; } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + stream.ssl_stream_.async_handshake(ht, completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] system::result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + auto ec = std::get<0>(result_.value_or(std::make_tuple(system::error_code{}))); + return ec ? system::result(ec) : system::in_place_value; + } + + accept_op_(ssl_stream & stream, handshake_type ht) : stream(stream), ht(ht) {} + private: + + ssl_stream & stream; + handshake_type ht; + std::exception_ptr error; + std::optional> result_; +}; + +struct ssl_stream::accept_op_buf_ : detail::deferred_op_resource_base +{ + constexpr static bool await_ready() { return false; } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + stream.ssl_stream_.async_handshake( + ht, + io::buffers::const_buffer_span{&buf, 1u}, + completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + + accept_op_buf_(ssl_stream & stream, + handshake_type ht, + buffers::const_buffer buf) : stream(stream), ht(ht), buf(buf) {} + private: + ssl_stream & stream; + handshake_type ht; + buffers::const_buffer buf; + std::exception_ptr error; + std::optional> result_; +}; + +struct ssl_stream::accept_op_buf_seq_ : detail::deferred_op_resource_base +{ + constexpr static bool await_ready() { return false; } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + stream.ssl_stream_.async_handshake(ht, buf, completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + + accept_op_buf_seq_(ssl_stream & stream, handshake_type ht, + buffers::const_buffer_span buf) : stream(stream), ht(ht), buf(buf) {} + private: + ssl_stream & stream; + handshake_type ht; + buffers::const_buffer_span buf; + std::exception_ptr error; + std::optional> result_; +}; + +struct ssl_stream::shutdown_op_ : detail::deferred_op_resource_base +{ + constexpr static bool await_ready() { return false; } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + stream.ssl_stream_.template async_shutdown(completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] shutdown_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + auto ec = std::get<0>(result_.value_or(std::make_tuple(system::error_code{}))); + return ec ? shutdown_result(ec) : system::in_place_value; + } + + shutdown_op_(ssl_stream & stream) : stream(stream) {} + private: + + ssl_stream & stream; + std::exception_ptr error; + std::optional> result_; +}; + +} + +#endif //BOOST_ASYNC_SSL_HPP diff --git a/include/boost/async/io/endpoint.hpp b/include/boost/async/io/endpoint.hpp index d29a6ac5..8816a50f 100644 --- a/include/boost/async/io/endpoint.hpp +++ b/include/boost/async/io/endpoint.hpp @@ -124,6 +124,9 @@ struct endpoint std::size_t size() const {return size_;} std::size_t capacity() const {return sizeof(storage_);} + void set_type (protocol_type::type_t type) { type_ = type;} + void set_protocol(protocol_type::protocol_t protocol) { protocol_ = protocol;} + protocol_type protocol() const { return protocol_type{static_cast(base_.sa_family), type_, protocol_}; diff --git a/include/boost/async/io/seq_packet_socket.hpp b/include/boost/async/io/seq_packet_socket.hpp index 60ad5531..110875ca 100644 --- a/include/boost/async/io/seq_packet_socket.hpp +++ b/include/boost/async/io/seq_packet_socket.hpp @@ -43,7 +43,7 @@ struct [[nodiscard]] seq_packet_socket final : socket struct receive_op_seq_; struct send_op_; struct send_op_seq_; - + BOOST_ASYNC_DECL void adopt_endpoint_(endpoint & ep) override; public: [[nodiscard]] BOOST_ASYNC_DECL receive_op_seq_ receive(buffers::mutable_buffer_span buffers, message_flags & out_flags); diff --git a/include/boost/async/io/socket.hpp b/include/boost/async/io/socket.hpp index 0f06964f..516f0f47 100644 --- a/include/boost/async/io/socket.hpp +++ b/include/boost/async/io/socket.hpp @@ -80,6 +80,8 @@ struct socket [[nodiscard]] BOOST_ASYNC_DECL system::result get_reuse_address() const; private: + + virtual void adopt_endpoint_(endpoint & ) {} struct connect_op_; struct wait_op_; friend struct acceptor; diff --git a/include/boost/async/io/ssl.hpp b/include/boost/async/io/ssl.hpp new file mode 100644 index 00000000..710d1a2d --- /dev/null +++ b/include/boost/async/io/ssl.hpp @@ -0,0 +1,74 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_SSL_HPP +#define BOOST_ASYNC_IO_SSL_HPP + +#include +#include +#include +#include + +namespace boost::async::detail +{ + +struct ssl_stream_base +{ + + template + ssl_stream_base(Args && ...args) : ssl_stream_(std::forward(args)...) {} + + asio::ssl::stream> ssl_stream_; +}; + +} + +namespace boost::async::io +{ + +struct ssl_stream : private detail::ssl_stream_base, stream, socket +{ + using shutdown_result = system::result; + + [[nodiscard]] BOOST_ASYNC_DECL system::result close() override; + [[nodiscard]] BOOST_ASYNC_DECL system::result cancel() override; + [[nodiscard]] BOOST_ASYNC_DECL bool is_open() const override; + + BOOST_ASYNC_DECL ssl_stream(); + BOOST_ASYNC_DECL ssl_stream(ssl_stream && steam); + BOOST_ASYNC_DECL ssl_stream(stream_socket && socket); + + BOOST_ASYNC_DECL ssl_stream(asio::ssl::context & ctx); + BOOST_ASYNC_DECL ssl_stream(asio::ssl::context & ctx, stream_socket && socket); + + private: + BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + + struct accept_op_; + struct accept_op_buf_; + struct accept_op_buf_seq_; + struct shutdown_op_; + void adopt_endpoint_(endpoint & ep) override; + public: + using handshake_type = boost::asio::ssl::stream_base::handshake_type; + BOOST_ASYNC_DECL accept_op_ async_handshake(handshake_type ht); + BOOST_ASYNC_DECL accept_op_buf_ async_handshake(handshake_type ht, buffers::const_buffer buf); + BOOST_ASYNC_DECL accept_op_buf_seq_ async_handshake(handshake_type ht, buffers::const_buffer_span buf); + BOOST_ASYNC_DECL shutdown_op_ async_shutdown(); + private: + + // duplicate onto another thread + system::result duplicate() = delete; +}; + +} + +#include + + +#endif //BOOST_ASYNC_IO_SSL_HPP diff --git a/include/boost/async/io/stream_socket.hpp b/include/boost/async/io/stream_socket.hpp index 1a33315b..43e6690d 100644 --- a/include/boost/async/io/stream_socket.hpp +++ b/include/boost/async/io/stream_socket.hpp @@ -34,6 +34,7 @@ struct [[nodiscard]] stream_socket final : stream, socket BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; asio::basic_stream_socket stream_socket_; friend struct ssl_stream; + BOOST_ASYNC_DECL void adopt_endpoint_(endpoint & ep) override; }; inline system::result> make_pair(decltype(local_stream) protocol) diff --git a/src/io/datagram_socket.cpp b/src/io/datagram_socket.cpp index 4744a6d1..f77b95f3 100644 --- a/src/io/datagram_socket.cpp +++ b/src/io/datagram_socket.cpp @@ -114,6 +114,22 @@ void datagram_socket::send_to_op_seq_::initiate_(async::completion_handlerdatagram_socket_.async_send_to(buffer_, ep_, std::move(h)); } +void datagram_socket::adopt_endpoint_(endpoint & ep) +{ + + switch (ep.protocol().family()) + { + case BOOST_ASIO_OS_DEF(AF_INET): BOOST_FALLTHROUGH; + case BOOST_ASIO_OS_DEF(AF_INET6): + if (ep.protocol().protocol() == BOOST_ASIO_OS_DEF(IPPROTO_IP)) + ep.set_protocol(BOOST_ASIO_OS_DEF(IPPROTO_UDP)); + BOOST_FALLTHROUGH; + case AF_UNIX: + if (ep.protocol().type() == 0) + ep.set_type(BOOST_ASIO_OS_DEF(SOCK_DGRAM)); + + } +} } \ No newline at end of file diff --git a/src/io/seq_packet_socket.cpp b/src/io/seq_packet_socket.cpp index 5549bab7..47e48148 100644 --- a/src/io/seq_packet_socket.cpp +++ b/src/io/seq_packet_socket.cpp @@ -78,5 +78,25 @@ void seq_packet_socket::send_op_seq_::initiate_(async::completion_handlerseq_packet_socket_.async_send(buffer_, out_flags_, std::move(h)); } +void seq_packet_socket::adopt_endpoint_(endpoint & ep) +{ + + switch (ep.protocol().family()) + { + +#if defined(IPPROTO_SCTP) + case BOOST_ASIO_OS_DEF(AF_INET): BOOST_FALLTHROUGH; + case BOOST_ASIO_OS_DEF(AF_INET6): + if (ep.protocol().protocol() == BOOST_ASIO_OS_DEF(IPPROTO_IP)) + ep.set_protocol(IPPROTO_SCTP); + BOOST_FALLTHROUGH; +#endif + + case AF_UNIX: + if (ep.protocol().type() == 0) + ep.set_type(BOOST_ASIO_OS_DEF(SOCK_SEQPACKET)); + break; + } +} } \ No newline at end of file diff --git a/src/io/socket.cpp b/src/io/socket.cpp index 7c0ebac4..840e38ae 100644 --- a/src/io/socket.cpp +++ b/src/io/socket.cpp @@ -128,7 +128,7 @@ system::result> socket::get_linger() const } -auto socket::connect(endpoint ep) -> connect_op_ {return connect_op_{socket_, ep};} +auto socket::connect(endpoint ep) -> connect_op_ {return connect_op_{this, ep};} auto socket::wait(wait_type wt) -> wait_op_ {return wait_op_{socket_, wt};} auto socket::operator co_await() -> wait_op_ {return wait_op_{socket_, wait_type::wait_read};} diff --git a/src/io/ssl.cpp b/src/io/ssl.cpp new file mode 100644 index 00000000..8cb1b09d --- /dev/null +++ b/src/io/ssl.cpp @@ -0,0 +1,105 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include +#include + +namespace boost::async::io +{ +/* +system::result ssl_stream::duplicate() +{ + SSL_dup(ssl_stream_.native_handle()); + auto res = detail::duplicate_socket(ssl_stream_.native_handle()); + if (!res) + return res.error(); + + return {system::in_place_value, ssl_stream(*res)}; +}*/ + +static asio::ssl::context & get_ssl_context() +{ + thread_local static asio::ssl::context ctx{asio::ssl::context_base::tls}; + return ctx; +} + + +ssl_stream::ssl_stream() + : ssl_stream_base(this_thread::get_executor(), get_ssl_context()), socket(ssl_stream_.next_layer()) +{ +} + +ssl_stream::ssl_stream(ssl_stream && lhs) + : ssl_stream_base(std::move(lhs.ssl_stream_)), socket(ssl_stream_.next_layer()) +{ +} + +ssl_stream::ssl_stream(stream_socket && socket_) + : ssl_stream_base(std::move(socket_.stream_socket_), get_ssl_context()), socket(ssl_stream_.next_layer()) {} + +ssl_stream::ssl_stream(asio::ssl::context & ctx) + : ssl_stream_base(this_thread::get_executor(), ctx), socket(ssl_stream_.next_layer()) {} + +ssl_stream::ssl_stream(asio::ssl::context & ctx, stream_socket && socket_) + : ssl_stream_base(std::move(socket_.stream_socket_), ctx), socket(ssl_stream_.next_layer()) {} + + + +void ssl_stream::async_read_some_impl_( + buffers::mutable_buffer_span buffer, + async::completion_handler h) +{ + ssl_stream_.async_read_some(buffers::mutable_buffer_span(buffer), std::move(h)); +} + +void ssl_stream::async_write_some_impl_( + buffers::const_buffer_span buffer, + async::completion_handler h) +{ + ssl_stream_.async_write_some(buffer, std::move(h)); +} + +system::result ssl_stream::close() { return socket::close(); } +system::result ssl_stream::cancel() { return socket::cancel(); } +bool ssl_stream::is_open() const {return socket::is_open();} + +ssl_stream::accept_op_ ssl_stream::async_handshake(handshake_type ht) +{ + return accept_op_{*this, ht}; +} +ssl_stream::accept_op_buf_ ssl_stream::async_handshake(handshake_type ht, buffers::const_buffer buf) +{ + return accept_op_buf_{*this, ht, buf}; +} +ssl_stream::accept_op_buf_seq_ ssl_stream::async_handshake(handshake_type ht, buffers::const_buffer_span buf) +{ + return accept_op_buf_seq_{*this, ht, buf}; +} +ssl_stream::shutdown_op_ ssl_stream::async_shutdown() +{ + return shutdown_op_{*this}; +} + +void ssl_stream::adopt_endpoint_(endpoint & ep) +{ + + switch (ep.protocol().family()) + { + case BOOST_ASIO_OS_DEF(AF_INET): BOOST_FALLTHROUGH; + case BOOST_ASIO_OS_DEF(AF_INET6): + if (ep.protocol().protocol() == BOOST_ASIO_OS_DEF(IPPROTO_IP)) + ep.set_protocol(BOOST_ASIO_OS_DEF(IPPROTO_TCP)); + case AF_UNIX: + if (ep.protocol().type() == 0) + ep.set_type(BOOST_ASIO_OS_DEF(SOCK_STREAM)); + } +} + + + +} \ No newline at end of file diff --git a/src/io/stream_socket.cpp b/src/io/stream_socket.cpp index e0b79cc8..908192b0 100644 --- a/src/io/stream_socket.cpp +++ b/src/io/stream_socket.cpp @@ -59,5 +59,19 @@ system::result stream_socket::close() { return socket::close(); } system::result stream_socket::cancel() { return socket::cancel(); } bool stream_socket::is_open() const {return socket::is_open();} +void stream_socket::adopt_endpoint_(endpoint & ep) +{ + + switch (ep.protocol().family()) + { + case BOOST_ASIO_OS_DEF(AF_INET): BOOST_FALLTHROUGH; + case BOOST_ASIO_OS_DEF(AF_INET6): + if (ep.protocol().protocol() == BOOST_ASIO_OS_DEF(IPPROTO_IP)) + ep.set_protocol(BOOST_ASIO_OS_DEF(IPPROTO_TCP)); + case AF_UNIX: + if (ep.protocol().type() == 0) + ep.set_type(BOOST_ASIO_OS_DEF(SOCK_STREAM)); + } +} } \ No newline at end of file diff --git a/test/io/CMakeLists.txt b/test/io/CMakeLists.txt index 5cbbf275..35464121 100644 --- a/test/io/CMakeLists.txt +++ b/test/io/CMakeLists.txt @@ -9,6 +9,7 @@ add_executable(boost_async_io_tests pipe.cpp resolver.cpp sleep.cpp + ssl.cpp ../doctest.cpp) target_link_libraries(boost_async_io_tests Boost::container Boost::async OpenSSL::SSL) add_test(NAME boost_async-io COMMAND boost_async_io_tests) diff --git a/test/io/ssl.cpp b/test/io/ssl.cpp new file mode 100644 index 00000000..6079a630 --- /dev/null +++ b/test/io/ssl.cpp @@ -0,0 +1,31 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include "../doctest.h" +#include "../test.hpp" + +#include +#include + +CO_TEST_CASE("ssl") +{ + using namespace boost; + + auto t = (co_await async::io::lookup("boost.org", "https")).value(); + REQUIRE(!t.empty()); + + async::io::ssl_stream ss{}; + + auto conn = co_await ss.connect(t.front()); + CHECK_MESSAGE(conn, conn.error().message()); + + CHECK(co_await ss.async_handshake(async::io::ssl_stream::handshake_type::client) + == system::in_place_value); + + CHECK(co_await ss.async_shutdown() == system::in_place_value); +} \ No newline at end of file From 9b56a022d19784105d4c550df7576942969ef1d7 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 15:01:57 +0800 Subject: [PATCH 13/43] moved all async_ to source files. --- include/boost/async/io/detail/socket.hpp | 9 ++++--- include/boost/async/io/detail/ssl.hpp | 30 ++++++++++++--------- include/boost/async/io/signal_set.hpp | 4 ++- include/boost/async/io/ssl.hpp | 12 ++++----- include/boost/async/io/steady_timer.hpp | 4 ++- include/boost/async/io/system_timer.hpp | 3 ++- src/io/signal_set.cpp | 5 ++++ src/io/socket.cpp | 11 ++++++++ src/io/ssl.cpp | 34 +++++++++++++++++++----- src/io/steady_timer.cpp | 6 +++++ src/io/system_timer.cpp | 5 ++++ 11 files changed, 92 insertions(+), 31 deletions(-) diff --git a/include/boost/async/io/detail/socket.hpp b/include/boost/async/io/detail/socket.hpp index 86303e41..3f01bb80 100644 --- a/include/boost/async/io/detail/socket.hpp +++ b/include/boost/async/io/detail/socket.hpp @@ -19,12 +19,14 @@ struct socket::wait_op_ : detail::deferred_op_resource_base { constexpr static bool await_ready() { return false; } + BOOST_ASYNC_DECL void init_op(completion_handler handler); + template bool await_suspend(std::coroutine_handle h) { try { - socket_.async_wait(wt_, completion_handler{h, result_, get_resource(h)}); + init_op(completion_handler{h, result_, get_resource(h)}); return true; } catch(...) @@ -58,13 +60,14 @@ struct socket::connect_op_ : detail::deferred_op_resource_base { constexpr static bool await_ready() { return false; } + BOOST_ASYNC_DECL void init_op(completion_handler handler); + template bool await_suspend(std::coroutine_handle h) { try { - socket_->adopt_endpoint_(ep_); - socket_->socket_.async_connect(ep_, completion_handler{h, result_, get_resource(h)}); + init_op(completion_handler{h, result_, get_resource(h)}); return true; } catch(...) diff --git a/include/boost/async/io/detail/ssl.hpp b/include/boost/async/io/detail/ssl.hpp index c415b80c..56029288 100644 --- a/include/boost/async/io/detail/ssl.hpp +++ b/include/boost/async/io/detail/ssl.hpp @@ -13,16 +13,18 @@ namespace boost::async::io { -struct ssl_stream::accept_op_ : detail::deferred_op_resource_base +struct ssl_stream::handshake_op_ : detail::deferred_op_resource_base { constexpr static bool await_ready() { return false; } + BOOST_ASYNC_DECL void init_op(completion_handler handler); + template bool await_suspend(std::coroutine_handle h) { try { - stream.ssl_stream_.async_handshake(ht, completion_handler{h, result_, get_resource(h)}); + init_op(completion_handler{h, result_, get_resource(h)}); return true; } catch(...) @@ -40,7 +42,7 @@ struct ssl_stream::accept_op_ : detail::deferred_op_resource_base return ec ? system::result(ec) : system::in_place_value; } - accept_op_(ssl_stream & stream, handshake_type ht) : stream(stream), ht(ht) {} + handshake_op_(ssl_stream & stream, handshake_type ht) : stream(stream), ht(ht) {} private: ssl_stream & stream; @@ -49,19 +51,18 @@ struct ssl_stream::accept_op_ : detail::deferred_op_resource_base std::optional> result_; }; -struct ssl_stream::accept_op_buf_ : detail::deferred_op_resource_base +struct ssl_stream::handshake_op_buf_ : detail::deferred_op_resource_base { constexpr static bool await_ready() { return false; } + BOOST_ASYNC_DECL void init_op(completion_handler handler); + template bool await_suspend(std::coroutine_handle h) { try { - stream.ssl_stream_.async_handshake( - ht, - io::buffers::const_buffer_span{&buf, 1u}, - completion_handler{h, result_, get_resource(h)}); + init_op(completion_handler{h, result_, get_resource(h)}); return true; } catch(...) @@ -79,7 +80,7 @@ struct ssl_stream::accept_op_buf_ : detail::deferred_op_resource_base return transfer_result{ec, n}; } - accept_op_buf_(ssl_stream & stream, + handshake_op_buf_(ssl_stream & stream, handshake_type ht, buffers::const_buffer buf) : stream(stream), ht(ht), buf(buf) {} private: @@ -90,16 +91,17 @@ struct ssl_stream::accept_op_buf_ : detail::deferred_op_resource_base std::optional> result_; }; -struct ssl_stream::accept_op_buf_seq_ : detail::deferred_op_resource_base +struct ssl_stream::handshake_op_buf_seq_ : detail::deferred_op_resource_base { constexpr static bool await_ready() { return false; } + BOOST_ASYNC_DECL void init_op(completion_handler handler); template bool await_suspend(std::coroutine_handle h) { try { - stream.ssl_stream_.async_handshake(ht, buf, completion_handler{h, result_, get_resource(h)}); + init_op(completion_handler{h, result_, get_resource(h)}); return true; } catch(...) @@ -117,7 +119,7 @@ struct ssl_stream::accept_op_buf_seq_ : detail::deferred_op_resource_base return transfer_result{ec, n}; } - accept_op_buf_seq_(ssl_stream & stream, handshake_type ht, + handshake_op_buf_seq_(ssl_stream & stream, handshake_type ht, buffers::const_buffer_span buf) : stream(stream), ht(ht), buf(buf) {} private: ssl_stream & stream; @@ -131,12 +133,14 @@ struct ssl_stream::shutdown_op_ : detail::deferred_op_resource_base { constexpr static bool await_ready() { return false; } + BOOST_ASYNC_DECL void init_op(completion_handler handler); + template bool await_suspend(std::coroutine_handle h) { try { - stream.ssl_stream_.template async_shutdown(completion_handler{h, result_, get_resource(h)}); + init_op(completion_handler{h, result_, get_resource(h)}); return true; } catch(...) diff --git a/include/boost/async/io/signal_set.hpp b/include/boost/async/io/signal_set.hpp index faa9af74..ad869b7f 100644 --- a/include/boost/async/io/signal_set.hpp +++ b/include/boost/async/io/signal_set.hpp @@ -36,12 +36,14 @@ struct signal_set { constexpr static bool await_ready() { return false; } + BOOST_ASYNC_DECL void init_op(completion_handler handler); + template bool await_suspend(std::coroutine_handle h) { try { - signal_set_.async_wait(completion_handler{h, result_, get_resource(h)}); + init_op(completion_handler{h, result_, get_resource(h)}); return true; } catch(...) diff --git a/include/boost/async/io/ssl.hpp b/include/boost/async/io/ssl.hpp index 710d1a2d..86fbabb8 100644 --- a/include/boost/async/io/ssl.hpp +++ b/include/boost/async/io/ssl.hpp @@ -49,16 +49,16 @@ struct ssl_stream : private detail::ssl_stream_base, stream, socket BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; - struct accept_op_; - struct accept_op_buf_; - struct accept_op_buf_seq_; + struct handshake_op_; + struct handshake_op_buf_; + struct handshake_op_buf_seq_; struct shutdown_op_; void adopt_endpoint_(endpoint & ep) override; public: using handshake_type = boost::asio::ssl::stream_base::handshake_type; - BOOST_ASYNC_DECL accept_op_ async_handshake(handshake_type ht); - BOOST_ASYNC_DECL accept_op_buf_ async_handshake(handshake_type ht, buffers::const_buffer buf); - BOOST_ASYNC_DECL accept_op_buf_seq_ async_handshake(handshake_type ht, buffers::const_buffer_span buf); + BOOST_ASYNC_DECL handshake_op_ async_handshake(handshake_type ht); + BOOST_ASYNC_DECL handshake_op_buf_ async_handshake(handshake_type ht, buffers::const_buffer buf); + BOOST_ASYNC_DECL handshake_op_buf_seq_ async_handshake(handshake_type ht, buffers::const_buffer_span buf); BOOST_ASYNC_DECL shutdown_op_ async_shutdown(); private: diff --git a/include/boost/async/io/steady_timer.hpp b/include/boost/async/io/steady_timer.hpp index e0562299..7942cb5b 100644 --- a/include/boost/async/io/steady_timer.hpp +++ b/include/boost/async/io/steady_timer.hpp @@ -45,12 +45,14 @@ struct steady_timer { bool await_ready() const { return timer_->expired(); } + BOOST_ASYNC_DECL void init_op(completion_handler handler); + template bool await_suspend(std::coroutine_handle h) { try { - timer_->timer_.async_wait(completion_handler{h, result_, get_resource(h)}); + init_op(completion_handler{h, result_, get_resource(h)}); return true; } catch(...) diff --git a/include/boost/async/io/system_timer.hpp b/include/boost/async/io/system_timer.hpp index abb94427..49aff730 100644 --- a/include/boost/async/io/system_timer.hpp +++ b/include/boost/async/io/system_timer.hpp @@ -43,13 +43,14 @@ struct system_timer final struct wait_op_ : detail::deferred_op_resource_base { bool await_ready() const { return timer_->expired(); } + BOOST_ASYNC_DECL void init_op(completion_handler handler); template bool await_suspend(std::coroutine_handle h) { try { - timer_->timer_.async_wait(completion_handler{h, result_, get_resource(h)}); + init_op(completion_handler{h, result_, get_resource(h)}); return true; } catch(...) diff --git a/src/io/signal_set.cpp b/src/io/signal_set.cpp index a8cee2eb..47338bed 100644 --- a/src/io/signal_set.cpp +++ b/src/io/signal_set.cpp @@ -46,4 +46,9 @@ system::result signal_set::remove(int signal_number) return ec ? ec : system::result{}; } +void signal_set::wait_op_::init_op(completion_handler handler) +{ + signal_set_.async_wait(std::move(handler)); +} + } \ No newline at end of file diff --git a/src/io/socket.cpp b/src/io/socket.cpp index 840e38ae..6b3b1304 100644 --- a/src/io/socket.cpp +++ b/src/io/socket.cpp @@ -164,5 +164,16 @@ system::result connect_pair(protocol_type protocol, socket & socket1, sock return {}; } +void socket::wait_op_::init_op(completion_handler handler) +{ + return socket_.async_wait(wt_, std::move(handler)); +} + +void socket::connect_op_::init_op(completion_handler handler) +{ + socket_->adopt_endpoint_(ep_); + socket_->socket_.async_connect(ep_, std::move(handler)); +} + } \ No newline at end of file diff --git a/src/io/ssl.cpp b/src/io/ssl.cpp index 8cb1b09d..46b52f1e 100644 --- a/src/io/ssl.cpp +++ b/src/io/ssl.cpp @@ -68,17 +68,17 @@ system::result ssl_stream::close() { return socket::close(); } system::result ssl_stream::cancel() { return socket::cancel(); } bool ssl_stream::is_open() const {return socket::is_open();} -ssl_stream::accept_op_ ssl_stream::async_handshake(handshake_type ht) +ssl_stream::handshake_op_ ssl_stream::async_handshake(handshake_type ht) { - return accept_op_{*this, ht}; + return handshake_op_{*this, ht}; } -ssl_stream::accept_op_buf_ ssl_stream::async_handshake(handshake_type ht, buffers::const_buffer buf) +ssl_stream::handshake_op_buf_ ssl_stream::async_handshake(handshake_type ht, buffers::const_buffer buf) { - return accept_op_buf_{*this, ht, buf}; + return handshake_op_buf_{*this, ht, buf}; } -ssl_stream::accept_op_buf_seq_ ssl_stream::async_handshake(handshake_type ht, buffers::const_buffer_span buf) +ssl_stream::handshake_op_buf_seq_ ssl_stream::async_handshake(handshake_type ht, buffers::const_buffer_span buf) { - return accept_op_buf_seq_{*this, ht, buf}; + return handshake_op_buf_seq_{*this, ht, buf}; } ssl_stream::shutdown_op_ ssl_stream::async_shutdown() { @@ -100,6 +100,28 @@ void ssl_stream::adopt_endpoint_(endpoint & ep) } } +void ssl_stream::handshake_op_::init_op(completion_handler handler) +{ + stream.ssl_stream_.async_handshake(ht, std::move(handler)); + +} + +void ssl_stream::handshake_op_buf_::init_op(completion_handler handler) +{ + stream.ssl_stream_.async_handshake(ht, io::buffers::const_buffer_span{&buf, 1u}, std::move(handler)); +} + +void ssl_stream::handshake_op_buf_seq_::init_op(completion_handler handler) +{ + stream.ssl_stream_.async_handshake(ht, buf, std::move(handler)); +} + +void ssl_stream::shutdown_op_::init_op(completion_handler handler) +{ + stream.ssl_stream_.async_shutdown(std::move(handler)); +} + + } \ No newline at end of file diff --git a/src/io/steady_timer.cpp b/src/io/steady_timer.cpp index 289ce8c2..5ee775d6 100644 --- a/src/io/steady_timer.cpp +++ b/src/io/steady_timer.cpp @@ -39,4 +39,10 @@ void steady_timer::reset(const duration &expiry_time) bool steady_timer::expired() const { return timer_.expiry() < clock_type::now(); } +void steady_timer::wait_op_::init_op(completion_handler handler) +{ + timer_->timer_.async_wait(std::move(handler)); +} + + } \ No newline at end of file diff --git a/src/io/system_timer.cpp b/src/io/system_timer.cpp index c64f8f64..2ce4d791 100644 --- a/src/io/system_timer.cpp +++ b/src/io/system_timer.cpp @@ -39,4 +39,9 @@ void system_timer::reset(const duration &expiry_time) bool system_timer::expired() const { return timer_.expiry() < clock_type::now(); } +void system_timer::wait_op_::init_op(completion_handler handler) +{ + timer_->timer_.async_wait(std::move(handler)); +} + } \ No newline at end of file From 4841fa922a1b0660874e6e6703cfb737f9d665bd Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 15:49:35 +0800 Subject: [PATCH 14/43] added file. --- CMakeLists.txt | 2 +- .../async/io/detail/random_access_device.hpp | 175 ++++++++++++++++++ include/boost/async/io/file.hpp | 55 ++++++ .../boost/async/io/random_access_device.hpp | 41 ++++ include/boost/async/io/random_access_file.hpp | 40 ++++ include/boost/async/io/stream_file.hpp | 42 +++++ src/io/file.cpp | 86 +++++++++ src/io/pipe.cpp | 2 +- src/io/random_access_file.cpp | 70 +++++++ src/io/serial_port.cpp | 2 +- src/io/ssl.cpp | 2 +- src/io/stream_file.cpp | 68 +++++++ src/io/stream_socket.cpp | 2 +- 13 files changed, 582 insertions(+), 5 deletions(-) create mode 100644 include/boost/async/io/detail/random_access_device.hpp create mode 100644 include/boost/async/io/file.hpp create mode 100644 include/boost/async/io/random_access_device.hpp create mode 100644 include/boost/async/io/random_access_file.hpp create mode 100644 include/boost/async/io/stream_file.hpp create mode 100644 src/io/file.cpp create mode 100644 src/io/random_access_file.cpp create mode 100644 src/io/stream_file.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 47267874..b1b2ac81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,7 +105,7 @@ add_library(boost_async src/io/ssl.cpp src/io/steady_timer.cpp src/io/stream_socket.cpp - src/io/system_timer.cpp) + src/io/system_timer.cpp src/io/stream_file.cpp src/io/random_access_file.cpp src/io/file.cpp) target_include_directories(boost_async PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(boost_async PUBLIC diff --git a/include/boost/async/io/detail/random_access_device.hpp b/include/boost/async/io/detail/random_access_device.hpp new file mode 100644 index 00000000..938bc27a --- /dev/null +++ b/include/boost/async/io/detail/random_access_device.hpp @@ -0,0 +1,175 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_DETAIL_RANDOM_ACCESS_DEVICE_HPP +#define BOOST_ASYNC_IO_DETAIL_RANDOM_ACCESS_DEVICE_HPP + +#include + +namespace boost::async::io +{ + +struct random_access_device::read_some_at_op_ : detail::deferred_op_resource_base +{ + read_some_at_op_(read_some_at_op_ && ) noexcept = default; + + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + random_access_device_.async_read_some_at_impl_(offset_, {&buffer_, 1u}, + completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + + read_some_at_op_(random_access_device & rs, std::uint64_t offset, buffers::mutable_buffer buffer) + : random_access_device_(rs), offset_(offset), buffer_(buffer) {} + + private: + random_access_device & random_access_device_; + std::uint64_t offset_; + buffers::mutable_buffer buffer_; + std::exception_ptr error; + std::optional> result_; +}; + + +struct random_access_device::read_some_at_op_seq_ : detail::deferred_op_resource_base +{ + constexpr bool await_ready() noexcept {return false;}; + + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + random_access_device_.async_read_some_at_impl_(offset_, buffer_, completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + + read_some_at_op_seq_(random_access_device & rs, std::uint64_t offset, buffers::mutable_buffer_span buffer) + : random_access_device_(rs), offset_(offset), buffer_(buffer) {} + + private: + random_access_device & random_access_device_; + std::uint64_t offset_; + buffers::mutable_buffer_span buffer_; + std::exception_ptr error; + std::optional> result_; +}; +struct random_access_device::write_some_at_op_ : detail::deferred_op_resource_base +{ + write_some_at_op_(write_some_at_op_ && ) noexcept = default; + + constexpr bool await_ready() noexcept {return false;}; + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + random_access_device_.async_write_some_at_impl_(offset_, {&buffer_, 1}, + completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + + write_some_at_op_(random_access_device & rs, std::uint64_t offset, buffers::const_buffer buffer) + : random_access_device_(rs), offset_(offset), buffer_(buffer) {} + + private: + random_access_device & random_access_device_; + std::uint64_t offset_; + buffers::const_buffer buffer_; + std::exception_ptr error; + std::optional> result_; +}; + + +struct random_access_device::write_some_at_op_seq_ : detail::deferred_op_resource_base +{ + constexpr bool await_writey() noexcept {return false;}; + + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + random_access_device_.async_write_some_at_impl_(offset_, buffer_, completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + const auto & [ec, n] = *result_; + return transfer_result{ec, n}; + } + + write_some_at_op_seq_(random_access_device & rs, std::uint64_t offset, buffers::const_buffer_span buffer) + : random_access_device_(rs), offset_(offset), buffer_(buffer) {} + + private: + random_access_device & random_access_device_; + std::uint64_t offset_; + buffers::const_buffer_span buffer_; + std::exception_ptr error; + std::optional> result_; +}; + +} + +#endif //BOOST_ASYNC_IO_DETAIL_RANDOM_ACCESS_DEVICE_HPP diff --git a/include/boost/async/io/file.hpp b/include/boost/async/io/file.hpp new file mode 100644 index 00000000..09fdc0f0 --- /dev/null +++ b/include/boost/async/io/file.hpp @@ -0,0 +1,55 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_FILE_HPP +#define BOOST_ASYNC_IO_FILE_HPP + +#include + +#if defined(BOOST_ASIO_HAS_FILE) + +#include +#include +#include + +namespace boost::async::io +{ + + +struct file +{ + using seek_basis = boost::asio::file_base::seek_basis; + using flags = boost::asio::file_base::flags; + + [[nodiscard]] BOOST_ASYNC_DECL system::result open(core::string_view file, + flags open_flags = flags::read_write); + [[nodiscard]] BOOST_ASYNC_DECL system::result close(); + [[nodiscard]] BOOST_ASYNC_DECL system::result cancel(); + [[nodiscard]] BOOST_ASYNC_DECL bool is_open() const; + [[nodiscard]] BOOST_ASYNC_DECL system::result resize(std::uint64_t size); + [[nodiscard]] BOOST_ASYNC_DECL system::result size() const; + + [[nodiscard]] BOOST_ASYNC_DECL system::result sync_all(); + [[nodiscard]] BOOST_ASYNC_DECL system::result sync_data(); + + + using native_handle_type = asio::basic_file::native_handle_type; + BOOST_ASYNC_DECL native_handle_type native_handle(); + + BOOST_ASYNC_DECL system::result assign(native_handle_type native_handle); + BOOST_ASYNC_DECL system::result release(); + + private: + asio::basic_file & file_; + public: + file(asio::basic_file & file) : file_(file) {} +}; + +} + +#endif +#endif //BOOST_ASYNC_IO_FILE_HPP diff --git a/include/boost/async/io/random_access_device.hpp b/include/boost/async/io/random_access_device.hpp new file mode 100644 index 00000000..39591164 --- /dev/null +++ b/include/boost/async/io/random_access_device.hpp @@ -0,0 +1,41 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_RANDOM_ACCESS_DEVICE_HPP +#define BOOST_ASYNC_IO_RANDOM_ACCESS_DEVICE_HPP + +#include + +namespace boost::async::io +{ + +struct random_access_device +{ + [[nodiscard]] virtual system::result close() = 0; + [[nodiscard]] virtual system::result cancel() = 0; + [[nodiscard]] virtual bool is_open() const = 0; + + virtual ~random_access_device() = default; + protected: + virtual void async_read_some_at_impl_ (std::uint64_t offset, buffers::mutable_buffer_span buffer, async::completion_handler h) = 0; + virtual void async_write_some_at_impl_(std::uint64_t offset, buffers:: const_buffer_span buffer, async::completion_handler h) = 0; + private: + struct read_some_at_op_; + struct read_some_at_op_seq_; + struct write_some_at_op_; + struct write_some_at_op_seq_; + public: + BOOST_ASYNC_DECL [[nodiscard]] read_some_at_op_seq_ read_some_at(std::uint64_t offset, buffers::mutable_buffer_span buffers); + BOOST_ASYNC_DECL [[nodiscard]] read_some_at_op_ read_some_at(std::uint64_t offset, buffers::mutable_buffer buffer); + BOOST_ASYNC_DECL [[nodiscard]] write_some_at_op_seq_ write_some_at(std::uint64_t offset, buffers::const_buffer_span buffers); + BOOST_ASYNC_DECL [[nodiscard]] write_some_at_op_ write_some_at(std::uint64_t offset, buffers::const_buffer buffer); +}; + +} + +#include +#endif //BOOST_ASYNC_IO_STREAM_HPP diff --git a/include/boost/async/io/random_access_file.hpp b/include/boost/async/io/random_access_file.hpp new file mode 100644 index 00000000..6bfcc82a --- /dev/null +++ b/include/boost/async/io/random_access_file.hpp @@ -0,0 +1,40 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_RANDOM_ACCESS_FILE_HPP +#define BOOST_ASYNC_RANDOM_ACCESS_FILE_HPP + +#include +#if defined(BOOST_ASIO_HAS_FILE) + +#include +#include + +namespace boost::async::io +{ + +struct random_access_file : file, random_access_device +{ + BOOST_ASYNC_DECL system::result duplicate(); + + [[nodiscard]] BOOST_ASYNC_DECL system::result close() override; + [[nodiscard]] BOOST_ASYNC_DECL system::result cancel() override; + [[nodiscard]] BOOST_ASYNC_DECL bool is_open() const override; + + BOOST_ASYNC_DECL random_access_file(); + BOOST_ASYNC_DECL random_access_file(random_access_file && lhs); + BOOST_ASYNC_DECL random_access_file(native_handle_type h); + BOOST_ASYNC_DECL random_access_file(core::string_view file, flags open_flags = flags::read_write); + private: + BOOST_ASYNC_DECL void async_read_some_at_impl_ (std::uint64_t offset, buffers::mutable_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_write_some_at_impl_(std::uint64_t offset, buffers::const_buffer_span buffer, async::completion_handler h) override; + asio::basic_random_access_file random_access_file_; + +}; +} +#endif +#endif //BOOST_ASYNC_RANDOM_ACCESS_FILE_HPP diff --git a/include/boost/async/io/stream_file.hpp b/include/boost/async/io/stream_file.hpp new file mode 100644 index 00000000..9e96debf --- /dev/null +++ b/include/boost/async/io/stream_file.hpp @@ -0,0 +1,42 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_STREAM_FILE_HPP +#define BOOST_ASYNC_IO_STREAM_FILE_HPP + +#include +#if defined(BOOST_ASIO_HAS_FILE) + +#include +#include + +namespace boost::async::io +{ + +struct stream_file : file, stream +{ + BOOST_ASYNC_DECL system::result duplicate(); + + [[nodiscard]] BOOST_ASYNC_DECL system::result close() override; + [[nodiscard]] BOOST_ASYNC_DECL system::result cancel() override; + [[nodiscard]] BOOST_ASYNC_DECL bool is_open() const override; + + BOOST_ASYNC_DECL stream_file(); + BOOST_ASYNC_DECL stream_file(stream_file && lhs); + BOOST_ASYNC_DECL stream_file(native_handle_type h); + BOOST_ASYNC_DECL stream_file(core::string_view file, flags open_flags = flags::read_write); + private: + BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + asio::basic_stream_file stream_file_; + +}; + +} + +#endif +#endif //BOOST_ASYNC_IO_STREAM_FILE_HPP diff --git a/src/io/file.cpp b/src/io/file.cpp new file mode 100644 index 00000000..4d27acc6 --- /dev/null +++ b/src/io/file.cpp @@ -0,0 +1,86 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#if defined(BOOST_ASIO_HAS_FILE) + +namespace boost::async::io +{ + + +system::result file::open(core::string_view file, flags open_flags) +{ + system::error_code ec; + file_.open(std::string(file), open_flags, ec); + return ec ? ec : system::result{}; +} + + +system::result file::close() +{ + system::error_code ec; + file_.close(ec); + return ec ? ec : system::result{}; +} + +system::result file::cancel() +{ + system::error_code ec; + file_.cancel(ec); + return ec ? ec : system::result{}; +} + + +bool file::is_open() const +{ + return file_.is_open(); +} +system::result file::resize(std::uint64_t size) +{ + system::error_code ec; + file_.resize(size, ec); + return ec ? ec : system::result{}; +} + + +system::result file::size() const +{ + system::error_code ec; + auto res = file_.size(ec); + return ec ? ec : system::result(res); +} + +system::result file::sync_all() +{ + system::error_code ec; + file_.sync_all(ec); + return ec ? ec : system::result{}; +} + +system::result file::sync_data() +{ + system::error_code ec; + file_.sync_data(ec); + return ec ? ec : system::result{}; +} + +system::result file::assign(native_handle_type native_handle) +{ + system::error_code ec; + file_.assign(native_handle, ec); + return ec ? ec : system::result{}; +} + +system::result file::release() +{ + system::error_code ec; + auto h = file_.release(ec); + return ec ? ec : system::result(h); +} + +} +#endif \ No newline at end of file diff --git a/src/io/pipe.cpp b/src/io/pipe.cpp index 3f77bcd2..9bb85e36 100644 --- a/src/io/pipe.cpp +++ b/src/io/pipe.cpp @@ -38,7 +38,7 @@ void readable_pipe::async_read_some_impl_( buffers::mutable_buffer_span buffer, async::completion_handler h) { - pipe_.async_read_some(buffers::mutable_buffer_span(buffer), std::move(h)); + pipe_.async_read_some(buffer, std::move(h)); } void readable_pipe::async_write_some_impl_( diff --git a/src/io/random_access_file.cpp b/src/io/random_access_file.cpp new file mode 100644 index 00000000..d7d54075 --- /dev/null +++ b/src/io/random_access_file.cpp @@ -0,0 +1,70 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include + +#if defined(BOOST_ASIO_HAS_FILE) +#include + +namespace boost::async::io +{ + +system::result random_access_file::duplicate() +{ + auto res = detail::duplicate_handle(random_access_file_.native_handle()); + if (!res) + return res.error(); + + return {system::in_place_value, random_access_file(*res)}; +} + + + +random_access_file::random_access_file() + : file(random_access_file_), random_access_file_(this_thread::get_executor()) +{ +} + +random_access_file::random_access_file(native_handle_type h) + : file(random_access_file_), random_access_file_(this_thread::get_executor()) +{ +} + +random_access_file::random_access_file(random_access_file && lhs) + : file(random_access_file_), random_access_file_(std::move(lhs.random_access_file_)) +{ +} + +random_access_file::random_access_file(core::string_view file_, flags open_flags) + : file(random_access_file_), random_access_file_(this_thread::get_executor(), std::string(file_), open_flags) +{ +} + + +void random_access_file::async_read_some_at_impl_( + std::uint64_t offset, + buffers::mutable_buffer_span buffer, + async::completion_handler h) +{ + random_access_file_.async_read_some_at(offset, buffer, std::move(h)); +} + +void random_access_file::async_write_some_at_impl_( + std::uint64_t offset, + buffers::const_buffer_span buffer, + async::completion_handler h) +{ + random_access_file_.async_write_some_at(offset, buffer, std::move(h)); +} + +system::result random_access_file::close() { return file::close(); } +system::result random_access_file::cancel() { return file::cancel(); } +bool random_access_file::is_open() const {return file::is_open();} + +} + +#endif \ No newline at end of file diff --git a/src/io/serial_port.cpp b/src/io/serial_port.cpp index 4b73e7d7..1c631297 100644 --- a/src/io/serial_port.cpp +++ b/src/io/serial_port.cpp @@ -126,7 +126,7 @@ void serial_port::async_read_some_impl_( buffers::mutable_buffer_span buffer, async::completion_handler h) { - serial_port_.async_read_some(buffers::mutable_buffer_span(buffer), std::move(h)); + serial_port_.async_read_some(buffer, std::move(h)); } void serial_port::async_write_some_impl_( diff --git a/src/io/ssl.cpp b/src/io/ssl.cpp index 46b52f1e..b9fc0c6d 100644 --- a/src/io/ssl.cpp +++ b/src/io/ssl.cpp @@ -54,7 +54,7 @@ void ssl_stream::async_read_some_impl_( buffers::mutable_buffer_span buffer, async::completion_handler h) { - ssl_stream_.async_read_some(buffers::mutable_buffer_span(buffer), std::move(h)); + ssl_stream_.async_read_some(buffer, std::move(h)); } void ssl_stream::async_write_some_impl_( diff --git a/src/io/stream_file.cpp b/src/io/stream_file.cpp new file mode 100644 index 00000000..5811428f --- /dev/null +++ b/src/io/stream_file.cpp @@ -0,0 +1,68 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include + +#if defined(BOOST_ASIO_HAS_FILE) +#include + +namespace boost::async::io +{ + +system::result stream_file::duplicate() +{ + auto res = detail::duplicate_handle(stream_file_.native_handle()); + if (!res) + return res.error(); + + return {system::in_place_value, stream_file(*res)}; +} + + + +stream_file::stream_file() + : file(stream_file_), stream_file_(this_thread::get_executor()) +{ +} + +stream_file::stream_file(native_handle_type h) + : file(stream_file_), stream_file_(this_thread::get_executor()) +{ +} + +stream_file::stream_file(stream_file && lhs) + : file(stream_file_), stream_file_(std::move(lhs.stream_file_)) +{ +} + +stream_file::stream_file(core::string_view file_, flags open_flags) + : file(stream_file_), stream_file_(this_thread::get_executor(), std::string(file_), open_flags) +{ +} + + +void stream_file::async_read_some_impl_( + buffers::mutable_buffer_span buffer, + async::completion_handler h) +{ + stream_file_.async_read_some(buffer, std::move(h)); +} + +void stream_file::async_write_some_impl_( + buffers::const_buffer_span buffer, + async::completion_handler h) +{ + stream_file_.async_write_some(buffer, std::move(h)); +} + +system::result stream_file::close() { return file::close(); } +system::result stream_file::cancel() { return file::cancel(); } +bool stream_file::is_open() const {return file::is_open();} + +} + +#endif \ No newline at end of file diff --git a/src/io/stream_socket.cpp b/src/io/stream_socket.cpp index 908192b0..860da486 100644 --- a/src/io/stream_socket.cpp +++ b/src/io/stream_socket.cpp @@ -45,7 +45,7 @@ void stream_socket::async_read_some_impl_( buffers::mutable_buffer_span buffer, async::completion_handler h) { - stream_socket_.async_read_some(buffers::mutable_buffer_span(buffer), std::move(h)); + stream_socket_.async_read_some(buffer, std::move(h)); } void stream_socket::async_write_some_impl_( From 3c833d68ed5182e67e61eb90c3dcb4ccf87ed385 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 16:20:27 +0800 Subject: [PATCH 15/43] added buffer_register.. --- CMakeLists.txt | 6 ++++- include/boost/async/io/buffers/register.hpp | 27 +++++++++++++++++++ src/io/buffers/register.cpp | 29 +++++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 include/boost/async/io/buffers/register.hpp create mode 100644 src/io/buffers/register.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b1b2ac81..be459bb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,7 +105,11 @@ add_library(boost_async src/io/ssl.cpp src/io/steady_timer.cpp src/io/stream_socket.cpp - src/io/system_timer.cpp src/io/stream_file.cpp src/io/random_access_file.cpp src/io/file.cpp) + src/io/system_timer.cpp + src/io/stream_file.cpp + src/io/random_access_file.cpp + src/io/file.cpp + src/io/buffers/register.cpp) target_include_directories(boost_async PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(boost_async PUBLIC diff --git a/include/boost/async/io/buffers/register.hpp b/include/boost/async/io/buffers/register.hpp new file mode 100644 index 00000000..01411faa --- /dev/null +++ b/include/boost/async/io/buffers/register.hpp @@ -0,0 +1,27 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_BUFFERS_REGISTER_HPP +#define BOOST_ASYNC_IO_BUFFERS_REGISTER_HPP + +#include + +#include +#include + +namespace boost::async::io::buffers +{ + +using buffer_registration = asio::buffer_registration>; + +BOOST_ASYNC_DECL buffer_registration register_(buffers::mutable_buffer mutable_buffer); +BOOST_ASYNC_DECL buffer_registration register_(buffers::mutable_buffer_span mutable_buffers); + +} + +#endif //BOOST_ASYNC_IO_BUFFERS_REGISTER_HPP diff --git a/src/io/buffers/register.cpp b/src/io/buffers/register.cpp new file mode 100644 index 00000000..b39acd33 --- /dev/null +++ b/src/io/buffers/register.cpp @@ -0,0 +1,29 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include +#include + +namespace boost::async::io::buffers +{ + +using buffer_registration = asio::buffer_registration>; + +buffer_registration register_(buffers::mutable_buffer buffer) +{ + return register_(buffers::mutable_buffer_span{&buffer, 1u}); + +} +buffer_registration register_(buffers::mutable_buffer_span buffer) +{ + return asio::register_buffers(this_thread::get_executor().context(), + buffer, this_thread::get_allocator()); +} + +} \ No newline at end of file From fc5af63e6a98dc8b706156c7157cc3f7d5e1b9fd Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 17:04:46 +0800 Subject: [PATCH 16/43] conceptified buffers. --- include/boost/async/detail/type_traits.hpp | 91 -------- include/boost/async/io/buffers/algorithm.hpp | 41 +--- .../async/io/buffers/any_dynamic_buffer.hpp | 10 +- .../boost/async/io/buffers/buffer_copy.hpp | 19 +- .../boost/async/io/buffers/buffer_size.hpp | 11 +- .../async/io/buffers/const_buffer_span.hpp | 18 +- .../async/io/buffers/mutable_buffer_span.hpp | 18 +- .../boost/async/io/buffers/type_traits.hpp | 217 ++++-------------- src/io/buffers/circular_buffer.cpp | 4 +- test/io/buffers/algorithm.cpp | 16 +- test/io/buffers/any_dynamic_buffer.cpp | 4 +- test/io/buffers/flat_buffer.cpp | 4 +- test/io/buffers/string_buffer.cpp | 3 +- test/io/buffers/test_helpers.hpp | 4 +- 14 files changed, 77 insertions(+), 383 deletions(-) delete mode 100644 include/boost/async/detail/type_traits.hpp diff --git a/include/boost/async/detail/type_traits.hpp b/include/boost/async/detail/type_traits.hpp deleted file mode 100644 index c9883401..00000000 --- a/include/boost/async/detail/type_traits.hpp +++ /dev/null @@ -1,91 +0,0 @@ -// -// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/CPPAlliance/http_proto -// - -#ifndef BOOST_ASYNC_DETAIL_TYPE_TRAITS_HPP -#define BOOST_ASYNC_DETAIL_TYPE_TRAITS_HPP - -#include -#include -#include - -namespace boost::async::detail { - -// is bidirectional iterator -template -struct is_bidirectional_iterator : std::false_type -{ -}; - -template -struct is_bidirectional_iterator() - ), - // LegacyIterator - typename std::iterator_traits::value_type, - typename std::iterator_traits::difference_type, - typename std::iterator_traits::reference, - typename std::iterator_traits::pointer, - typename std::iterator_traits::iterator_category, - typename std::enable_if< - // LegacyIterator - std::is_copy_constructible::value && - std::is_copy_assignable::value && - std::is_destructible::value && - std::is_same())>::value && - // Swappable - // VFALCO TODO - // EqualityComparable - std::is_convertible() == - std::declval()), - bool>::value && - // LegacyInputIterator - std::is_convertible::reference, typename - std::iterator_traits::value_type>::value && - std::is_same::reference, - decltype(*std::declval())>::value && - std::is_convertible() != - std::declval()), - bool>::value && - std::is_same())>::value && - // VFALCO (void)r++ (void)++r - std::is_convertible()++), typename - std::iterator_traits::value_type>::value && - // LegacyForwardIterator - std::is_default_constructible::value && - std::is_same()++)>::value && - std::is_same::reference, - decltype(*std::declval()++) - >::value && - // LegacyBidirectionalIterator - std::is_same())>::value && - std::is_convertible()--), - T const&>::value && - std::is_same::reference, - decltype(*std::declval()--)>::value - >::type >> - : std::true_type -{ -}; - -} // boost::buffers::detail - -#endif diff --git a/include/boost/async/io/buffers/algorithm.hpp b/include/boost/async/io/buffers/algorithm.hpp index 9e45320c..9c69ea2c 100644 --- a/include/boost/async/io/buffers/algorithm.hpp +++ b/include/boost/async/io/buffers/algorithm.hpp @@ -106,17 +106,12 @@ namespace detail { struct prefix_impl { - template + template prefix_type operator()( BufferSequence const& b, std::size_t n) const { - static_assert( - is_const_buffer_sequence< - BufferSequence>::value, - "Type requirements not met"); - return tag_invoke( prefix_tag{}, b, n); } @@ -141,17 +136,12 @@ struct sans_suffix_impl struct suffix_impl { - template + template suffix_type operator()( BufferSequence const& b, std::size_t n) const { - static_assert( - is_const_buffer_sequence< - BufferSequence>::value, - "Type requirements not met"); - return tag_invoke( suffix_tag{}, b, n); } @@ -159,17 +149,12 @@ struct suffix_impl struct sans_prefix_impl { - template + template suffix_type operator()( BufferSequence const& b, std::size_t n) const { - static_assert( - is_const_buffer_sequence< - BufferSequence>::value, - "Type requirements not met"); - auto const n0 = buffer_size(b); if(n < n0) return tag_invoke( @@ -181,12 +166,7 @@ struct sans_prefix_impl struct front_impl { - template< - class MutableBufferSequence - , class = typename std::enable_if< - is_mutable_buffer_sequence< - MutableBufferSequence>::value - >::type> + template mutable_buffer operator()( MutableBufferSequence const& bs) const noexcept @@ -197,21 +177,12 @@ struct front_impl return {}; } - template< - class ConstBufferSequence - , class = typename std::enable_if< - ! is_mutable_buffer_sequence< - ConstBufferSequence>::value - >::type> + template + requires (!mutable_buffer_sequence) const_buffer operator()( ConstBufferSequence const& bs) const noexcept { - static_assert( - is_const_buffer_sequence< - ConstBufferSequence>::value, - "Type requirements not met"); - auto const it = bs.begin(); if(it != bs.end()) return *it; diff --git a/include/boost/async/io/buffers/any_dynamic_buffer.hpp b/include/boost/async/io/buffers/any_dynamic_buffer.hpp index d36171af..6dacd252 100644 --- a/include/boost/async/io/buffers/any_dynamic_buffer.hpp +++ b/include/boost/async/io/buffers/any_dynamic_buffer.hpp @@ -150,15 +150,7 @@ class any_dynamic_buffer_impl } }; -template< - class DynamicBuffer -#ifndef BOOST_BUFFERS_DOCS - , class = typename std::enable_if< - is_dynamic_buffer< - typename std::decay::type - >::value>::type -#endif -> +template auto make_any(DynamicBuffer&& b) -> any_dynamic_buffer_impl + mutable_buffer_sequence MutableBuffers, + const_buffer_sequence ConstBuffers> std::size_t operator()( MutableBuffers const& to, @@ -49,18 +52,6 @@ struct buffer_copy_impl std::size_t at_most = std::size_t(-1)) const noexcept { - // If you get a compile error here it - // means that one or both of your types - // do not meet the requirements. - static_assert( - is_mutable_buffer_sequence< - MutableBuffers>::value, - "Type requirements not met"); - static_assert( - is_const_buffer_sequence< - ConstBuffers>::value, - "Type requirements not met"); - std::size_t total = 0; std::size_t pos0 = 0; std::size_t pos1 = 0; diff --git a/include/boost/async/io/buffers/buffer_size.hpp b/include/boost/async/io/buffers/buffer_size.hpp index caba6b10..89ad5f26 100644 --- a/include/boost/async/io/buffers/buffer_size.hpp +++ b/include/boost/async/io/buffers/buffer_size.hpp @@ -51,17 +51,14 @@ namespace detail { struct buffer_size_impl { - template + // If you get a compile error here it + // means that your type does not meet + // the requirements. + template std::size_t operator()( Buffers const& bs) const noexcept { - // If you get a compile error here it - // means that your type does not meet - // the requirements. - static_assert( - is_const_buffer_sequence::value, - "Type requirements not met."); return tag_invoke(size_tag{}, bs); } diff --git a/include/boost/async/io/buffers/const_buffer_span.hpp b/include/boost/async/io/buffers/const_buffer_span.hpp index c25fc26c..c179ae6d 100644 --- a/include/boost/async/io/buffers/const_buffer_span.hpp +++ b/include/boost/async/io/buffers/const_buffer_span.hpp @@ -54,22 +54,8 @@ class const_buffer_span /** Constructor. */ - template< - class ConstBufferSequence -#ifndef BOOST_BUFFERS_DOCS - , class = typename std::enable_if< - ! std::is_same< - ConstBufferSequence, - const_buffer_span>::value && - is_const_buffer_sequence< - ConstBufferSequence>::value && - std::is_same().begin()), - const_buffer const*>::value - >::type -#endif - > + template + requires requires (const ConstBufferSequence & seq) {{seq.begin()} -> std::same_as;} explicit const_buffer_span( ConstBufferSequence const& bs) noexcept diff --git a/include/boost/async/io/buffers/mutable_buffer_span.hpp b/include/boost/async/io/buffers/mutable_buffer_span.hpp index e3abec84..75202b1e 100644 --- a/include/boost/async/io/buffers/mutable_buffer_span.hpp +++ b/include/boost/async/io/buffers/mutable_buffer_span.hpp @@ -54,22 +54,8 @@ class mutable_buffer_span /** Constructor. */ - template< - class MutableBufferSequence -#ifndef BOOST_BUFFERS_DOCS - , class = typename std::enable_if< - ! std::is_same< - MutableBufferSequence, - mutable_buffer_span>::value && - is_mutable_buffer_sequence< - MutableBufferSequence>::value && - std::is_same().begin()), - mutable_buffer const*>::value - >::type -#endif - > + template + requires requires (const MutableBufferSequence & seq) {{seq.begin()} -> std::same_as;} explicit mutable_buffer_span( MutableBufferSequence const& bs) noexcept diff --git a/include/boost/async/io/buffers/type_traits.hpp b/include/boost/async/io/buffers/type_traits.hpp index 0d837169..688045c0 100644 --- a/include/boost/async/io/buffers/type_traits.hpp +++ b/include/boost/async/io/buffers/type_traits.hpp @@ -11,7 +11,6 @@ #define BOOST_BUFFERS_TYPE_TRAITS_HPP #include -#include #include namespace boost::async::io::buffers { @@ -31,84 +30,25 @@ struct is_const_buffer_sequence : std::integral_constant{}; #else -template -struct is_const_buffer_sequence - : std::false_type -{ -}; -template -struct is_const_buffer_sequence - : is_const_buffer_sequence::type> -{ -}; -template -struct is_const_buffer_sequence - : is_const_buffer_sequence::type> -{ -}; +template +concept const_buffer_sequence = + std::same_as || + std::same_as || + ((std::same_as || + std::same_as) && + std::bidirectional_iterator && + requires (const T & buf) + { + {buf.begin()} -> std::same_as; + {buf.end()} -> std::same_as; -template -struct is_const_buffer_sequence - : is_const_buffer_sequence::type> -{ -}; - -template<> -struct is_const_buffer_sequence< - const_buffer> - : std::true_type -{ -}; - -template<> -struct is_const_buffer_sequence< - mutable_buffer> - : std::true_type -{ -}; + } && + (std::same_as::value_type, const_buffer> || + std::same_as::value_type, mutable_buffer>)) +; -template -struct is_const_buffer_sequence::value - || std::is_same::value - ) && - detail::is_bidirectional_iterator::value && - std::is_same().begin()) - >::value && - std::is_same().end()) - >::value && ( - std::is_same::value_type>::type - >::value || - std::is_same::value_type>::type - >::value) - // VFALCO This causes problems when the - // trait is used to constrain ctors - // && std::is_move_constructible::value - >::type - > > : std::true_type -{ -}; #endif @@ -119,68 +59,19 @@ template struct is_mutable_buffer_sequence : std::integral_constant{}; #else +template +concept mutable_buffer_sequence = + std::same_as || + (std::same_as && + std::bidirectional_iterator && + requires (const T &buf) + { + {buf.begin()} -> std::same_as; + {buf.end()} -> std::same_as; + } && + std::same_as::value_type, mutable_buffer>) +; -template -struct is_mutable_buffer_sequence : std::false_type -{ -}; - -template -struct is_mutable_buffer_sequence - : is_mutable_buffer_sequence::type> -{ -}; - -template -struct is_mutable_buffer_sequence - : is_mutable_buffer_sequence::type> -{ -}; - -template -struct is_mutable_buffer_sequence - : is_mutable_buffer_sequence::type> -{ -}; - -template<> -struct is_mutable_buffer_sequence< - mutable_buffer> - : std::true_type -{ -}; - -template -struct is_mutable_buffer_sequence::value && - detail::is_bidirectional_iterator::value && - std::is_same().begin()) - >::value && - std::is_same().end()) - >::value && - std::is_same::value_type>::type - >::value - // VFALCO This causes problems when the - // trait is used to constrain ctors - // && std::is_move_constructible::value - >::type - >> : std::true_type -{ -}; #endif @@ -194,56 +85,36 @@ struct is_dynamic_buffer : std::integral_constant{}; #else -template< - class T, - class = void> -struct is_dynamic_buffer : std::false_type {}; +template +concept dynamic_buffer = + requires (T & buf, std::size_t n) + { + {buf.size()} -> std::same_as; + {buf.max_size()} -> std::same_as; + {buf.capacity()} -> std::same_as; + {buf.commit(n)}; + {buf.consume(n)}; + {buf.data()} -> const_buffer_sequence; + {buf.prepare(n)}-> mutable_buffer_sequence; + } + && const_buffer_sequence + && mutable_buffer_sequence + ; -template -struct is_dynamic_buffer< - T, std::void_t() = - std::declval().size() - ,std::declval() = - std::declval().max_size() - ,std::declval() = - std::declval().capacity() - ,std::declval().commit( - std::declval()) - ,std::declval().consume( - std::declval()) - ) - ,typename std::enable_if< - is_const_buffer_sequence::value - && is_mutable_buffer_sequence::value - >::type - ,typename std::enable_if< - std::is_same().data()), - typename T::const_buffers_type>::value - && std::is_same().prepare( - std::declval())), - typename T::mutable_buffers_type>::value - >::type - > > : std::true_type -{ -}; /** Return the underlying buffer type of a sequence. */ template using value_type = typename std::conditional< - is_mutable_buffer_sequence::value, + mutable_buffer_sequence, mutable_buffer, const_buffer >::type; #endif + } // boost::buffers #endif diff --git a/src/io/buffers/circular_buffer.cpp b/src/io/buffers/circular_buffer.cpp index 9f59efb8..d36c542e 100644 --- a/src/io/buffers/circular_buffer.cpp +++ b/src/io/buffers/circular_buffer.cpp @@ -15,9 +15,7 @@ namespace boost::async::io::buffers { -BOOST_STATIC_ASSERT( - is_dynamic_buffer< - circular_buffer>::value); +BOOST_STATIC_ASSERT(dynamic_buffer); auto circular_buffer:: diff --git a/test/io/buffers/algorithm.cpp b/test/io/buffers/algorithm.cpp index 54bcaa6a..3e6335be 100644 --- a/test/io/buffers/algorithm.cpp +++ b/test/io/buffers/algorithm.cpp @@ -50,20 +50,20 @@ struct asio_const_buffers asio_const_buffer const* end() const noexcept; }; -BOOST_STATIC_ASSERT( is_const_buffer_sequence ::value); -BOOST_STATIC_ASSERT( is_const_buffer_sequence ::value); -BOOST_STATIC_ASSERT(! is_mutable_buffer_sequence ::value); -BOOST_STATIC_ASSERT( is_mutable_buffer_sequence ::value); +BOOST_STATIC_ASSERT( const_buffer_sequence ); +BOOST_STATIC_ASSERT( const_buffer_sequence ); +BOOST_STATIC_ASSERT(! mutable_buffer_sequence ); +BOOST_STATIC_ASSERT( mutable_buffer_sequence ); //BOOST_STATIC_ASSERT( is_const_buffer_sequence ::value); //BOOST_STATIC_ASSERT( is_const_buffer_sequence ::value); //BOOST_STATIC_ASSERT( is_mutable_buffer_sequence ::value); //BOOST_STATIC_ASSERT(! is_mutable_buffer_sequence ::value); -BOOST_STATIC_ASSERT( is_const_buffer_sequence ::value); -BOOST_STATIC_ASSERT( is_const_buffer_sequence ::value); -BOOST_STATIC_ASSERT(! is_mutable_buffer_sequence ::value); -BOOST_STATIC_ASSERT( is_mutable_buffer_sequence ::value); +BOOST_STATIC_ASSERT( const_buffer_sequence ); +BOOST_STATIC_ASSERT( const_buffer_sequence ); +BOOST_STATIC_ASSERT(! mutable_buffer_sequence ); +BOOST_STATIC_ASSERT( mutable_buffer_sequence ); struct algorithm_test { diff --git a/test/io/buffers/any_dynamic_buffer.cpp b/test/io/buffers/any_dynamic_buffer.cpp index 9108d93f..b771c1ca 100644 --- a/test/io/buffers/any_dynamic_buffer.cpp +++ b/test/io/buffers/any_dynamic_buffer.cpp @@ -18,9 +18,7 @@ namespace boost::async::io::buffers { struct any_dynamic_buffer_test { - BOOST_STATIC_ASSERT( - is_dynamic_buffer< - any_dynamic_buffer>::value); + BOOST_STATIC_ASSERT(dynamic_buffer); void testAny() diff --git a/test/io/buffers/flat_buffer.cpp b/test/io/buffers/flat_buffer.cpp index ad3c182e..f37f4523 100644 --- a/test/io/buffers/flat_buffer.cpp +++ b/test/io/buffers/flat_buffer.cpp @@ -18,9 +18,7 @@ namespace boost::async::io::buffers { struct flat_buffer_test { - BOOST_STATIC_ASSERT( - is_dynamic_buffer< - flat_buffer>::value); + BOOST_STATIC_ASSERT(dynamic_buffer); void testMembers() diff --git a/test/io/buffers/string_buffer.cpp b/test/io/buffers/string_buffer.cpp index 728b7034..afd59da5 100644 --- a/test/io/buffers/string_buffer.cpp +++ b/test/io/buffers/string_buffer.cpp @@ -17,8 +17,7 @@ namespace boost::async::io::buffers { struct string_buffer_test { - BOOST_STATIC_ASSERT( - is_dynamic_buffer::value); + BOOST_STATIC_ASSERT(dynamic_buffer); void testMembers() diff --git a/test/io/buffers/test_helpers.hpp b/test/io/buffers/test_helpers.hpp index 3de9f8b5..645b6c6c 100644 --- a/test/io/buffers/test_helpers.hpp +++ b/test/io/buffers/test_helpers.hpp @@ -45,9 +45,7 @@ template void test_buffer_sequence(T&& t) { - static_assert( - is_const_buffer_sequence::value, - ""); + static_assert(const_buffer_sequence>); auto const& pat = test_pattern(); auto const& ct = t; From 1571d643bde9a13e3c9fa92659eb7b49996dc988 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 20:40:39 +0800 Subject: [PATCH 17/43] added subspan overloads to all io functions. --- CMakeLists.txt | 3 +- .../async/io/buffers/const_buffer_span.hpp | 18 +++++++- .../async/io/buffers/mutable_buffer_span.hpp | 14 ++++++ include/boost/async/io/buffers/register.hpp | 3 +- include/boost/async/io/datagram_socket.hpp | 20 +++++---- .../boost/async/io/detail/datagram_socket.hpp | 28 +++++++++--- .../async/io/detail/random_access_device.hpp | 8 +++- .../async/io/detail/seq_packet_socket.hpp | 12 +++-- include/boost/async/io/detail/ssl.hpp | 4 +- include/boost/async/io/detail/stream.hpp | 9 ++-- include/boost/async/io/pipe.hpp | 12 ++--- .../boost/async/io/random_access_device.hpp | 14 +++--- include/boost/async/io/random_access_file.hpp | 4 +- include/boost/async/io/seq_packet_socket.hpp | 10 +++-- include/boost/async/io/serial_port.hpp | 4 +- include/boost/async/io/ssl.hpp | 5 ++- include/boost/async/io/stream.hpp | 14 +++--- include/boost/async/io/stream_file.hpp | 4 +- include/boost/async/io/stream_socket.hpp | 4 +- src/io/buffers/register.cpp | 10 +++-- src/io/datagram_socket.cpp | 24 ++++++++-- src/io/detail/random_access_device.cpp | 44 +++++++++++++++++++ src/io/detail/stream.cpp | 10 +++-- src/io/pipe.cpp | 8 ++-- src/io/random_access_file.cpp | 4 +- src/io/seq_packet_socket.cpp | 12 ++++- src/io/serial_port.cpp | 4 +- src/io/ssl.cpp | 11 +++-- src/io/stream_file.cpp | 4 +- src/io/stream_socket.cpp | 4 +- 30 files changed, 236 insertions(+), 89 deletions(-) create mode 100644 src/io/detail/random_access_device.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index be459bb5..a5f7f975 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,7 +109,8 @@ add_library(boost_async src/io/stream_file.cpp src/io/random_access_file.cpp src/io/file.cpp - src/io/buffers/register.cpp) + src/io/buffers/register.cpp + src/io/detail/random_access_device.cpp) target_include_directories(boost_async PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(boost_async PUBLIC diff --git a/include/boost/async/io/buffers/const_buffer_span.hpp b/include/boost/async/io/buffers/const_buffer_span.hpp index c179ae6d..9ffdd2b2 100644 --- a/include/boost/async/io/buffers/const_buffer_span.hpp +++ b/include/boost/async/io/buffers/const_buffer_span.hpp @@ -64,7 +64,23 @@ class const_buffer_span { } - /** Constructor. + template + requires requires (const ConstBufferSequence & seq) + { + {seq.data()} -> std::same_as; + {seq.size()} -> std::same_as; + } + explicit + const_buffer_span( + ConstBufferSequence const& bs) noexcept + : p_(bs.data()) + , n_(bs.size()) + { + } + + + + /** Constructor. */ const_buffer_span( const_buffer_span const&) = default; diff --git a/include/boost/async/io/buffers/mutable_buffer_span.hpp b/include/boost/async/io/buffers/mutable_buffer_span.hpp index 75202b1e..742d7b1a 100644 --- a/include/boost/async/io/buffers/mutable_buffer_span.hpp +++ b/include/boost/async/io/buffers/mutable_buffer_span.hpp @@ -64,6 +64,20 @@ class mutable_buffer_span { } + template + requires requires (const MutableBufferSequence & seq) + { + {seq.data()} -> std::same_as; + {seq.size()} -> std::same_as; + } + explicit + mutable_buffer_span( + MutableBufferSequence const& bs) noexcept + : p_(bs.data()) + , n_(bs.size()) + { + } + /** Constructor. */ mutable_buffer_span( diff --git a/include/boost/async/io/buffers/register.hpp b/include/boost/async/io/buffers/register.hpp index 01411faa..56596326 100644 --- a/include/boost/async/io/buffers/register.hpp +++ b/include/boost/async/io/buffers/register.hpp @@ -16,11 +16,12 @@ namespace boost::async::io::buffers { -using buffer_registration = asio::buffer_registration>; BOOST_ASYNC_DECL buffer_registration register_(buffers::mutable_buffer mutable_buffer); BOOST_ASYNC_DECL buffer_registration register_(buffers::mutable_buffer_span mutable_buffers); +BOOST_ASYNC_DECL buffer_registration register_(buffers::mutable_buffer_subspan mutable_buffers); } diff --git a/include/boost/async/io/datagram_socket.hpp b/include/boost/async/io/datagram_socket.hpp index 8e7f0231..5fc449ae 100644 --- a/include/boost/async/io/datagram_socket.hpp +++ b/include/boost/async/io/datagram_socket.hpp @@ -39,14 +39,18 @@ struct [[nodiscard]] datagram_socket final : socket public: - [[nodiscard]] receive_op_seq_ receive(buffers::mutable_buffer_span buffers); - [[nodiscard]] receive_op_ receive(buffers::mutable_buffer buffer); - [[nodiscard]] receive_from_op_seq_ receive_from(buffers::mutable_buffer_span buffers, endpoint & ep); - [[nodiscard]] receive_from_op_ receive_from(buffers::mutable_buffer buffer, endpoint & ep); - [[nodiscard]] send_op_seq_ send(buffers::const_buffer_span buffers); - [[nodiscard]] send_op_ send(buffers::const_buffer buffer); - [[nodiscard]] send_to_op_seq_ send_to(buffers::const_buffer_span buffers, const endpoint & target); - [[nodiscard]] send_to_op_ send_to(buffers::const_buffer buffer, const endpoint & target); + [[nodiscard]] receive_op_seq_ receive(buffers::mutable_buffer_subspan buffers); + [[nodiscard]] receive_op_seq_ receive(buffers::mutable_buffer_span buffers); + [[nodiscard]] receive_op_ receive(buffers::mutable_buffer buffer); + [[nodiscard]] receive_from_op_seq_ receive_from(buffers::mutable_buffer_subspan buffers, endpoint & ep); + [[nodiscard]] receive_from_op_seq_ receive_from(buffers::mutable_buffer_span buffers, endpoint & ep); + [[nodiscard]] receive_from_op_ receive_from(buffers::mutable_buffer buffer, endpoint & ep); + [[nodiscard]] send_op_seq_ send(buffers::const_buffer_subspan buffers); + [[nodiscard]] send_op_seq_ send(buffers::const_buffer_span buffers); + [[nodiscard]] send_op_ send(buffers::const_buffer buffer); + [[nodiscard]] send_to_op_seq_ send_to(buffers::const_buffer_subspan buffers, const endpoint & target); + [[nodiscard]] send_to_op_seq_ send_to(buffers::const_buffer_span buffers, const endpoint & target); + [[nodiscard]] send_to_op_ send_to(buffers::const_buffer buffer, const endpoint & target); asio::basic_datagram_socket datagram_socket_; }; diff --git a/include/boost/async/io/detail/datagram_socket.hpp b/include/boost/async/io/detail/datagram_socket.hpp index 67688c2f..0341d46d 100644 --- a/include/boost/async/io/detail/datagram_socket.hpp +++ b/include/boost/async/io/detail/datagram_socket.hpp @@ -76,13 +76,17 @@ struct datagram_socket::receive_op_seq_ : detail::deferred_op_resource_base const auto & [ec, n] = *result_; return transfer_result{ec, n}; } + receive_op_seq_(asio::basic_datagram_socket & rs, + buffers::mutable_buffer_subspan buffer) + : datagram_socket_(rs), buffer_(buffer) {} + receive_op_seq_(asio::basic_datagram_socket & rs, buffers::mutable_buffer_span buffer) : datagram_socket_(rs), buffer_(buffer) {} private: void initiate_(async::completion_handler h); asio::basic_datagram_socket &datagram_socket_; - buffers::mutable_buffer_span buffer_; + buffers::mutable_buffer_subspan buffer_; std::exception_ptr error; std::optional> result_; }; @@ -153,12 +157,15 @@ struct datagram_socket::receive_from_op_seq_ : detail::deferred_op_resource_base return transfer_result{ec, n}; } receive_from_op_seq_(asio::basic_datagram_socket & rs, - buffers::mutable_buffer_span buffer, endpoint & ep) + buffers::mutable_buffer_subspan buffer, endpoint & ep) + : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} + receive_from_op_seq_(asio::basic_datagram_socket & rs, + buffers::mutable_buffer_span buffer, endpoint & ep) : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} private: void initiate_(async::completion_handler h); asio::basic_datagram_socket &datagram_socket_; - buffers::mutable_buffer_span buffer_; + buffers::mutable_buffer_subspan buffer_; endpoint & ep_; std::exception_ptr error; std::optional> result_; @@ -227,12 +234,15 @@ struct datagram_socket::send_op_seq_ : detail::deferred_op_resource_base return transfer_result{ec, n}; } send_op_seq_(asio::basic_datagram_socket & rs, - buffers::const_buffer_span buffer) + buffers::const_buffer_subspan buffer) + : datagram_socket_(rs), buffer_(buffer) {} + send_op_seq_(asio::basic_datagram_socket & rs, + buffers::const_buffer_span buffer) : datagram_socket_(rs), buffer_(buffer) {} private: void initiate_(async::completion_handler h); asio::basic_datagram_socket &datagram_socket_; - buffers::const_buffer_span buffer_; + buffers::const_buffer_subspan buffer_; std::exception_ptr error; std::optional> result_; }; @@ -303,12 +313,16 @@ struct datagram_socket::send_to_op_seq_ : detail::deferred_op_resource_base return transfer_result{ec, n}; } send_to_op_seq_(asio::basic_datagram_socket & rs, - buffers::const_buffer_span buffer, const endpoint & ep) + buffers::const_buffer_subspan buffer, const endpoint & ep) + : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} + + send_to_op_seq_(asio::basic_datagram_socket & rs, + buffers::const_buffer_span buffer, const endpoint & ep) : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} private: void initiate_(async::completion_handler h); asio::basic_datagram_socket &datagram_socket_; - buffers::const_buffer_span buffer_; + buffers::const_buffer_subspan buffer_; const endpoint & ep_; std::exception_ptr error; std::optional> result_; diff --git a/include/boost/async/io/detail/random_access_device.hpp b/include/boost/async/io/detail/random_access_device.hpp index 938bc27a..8af0fdb5 100644 --- a/include/boost/async/io/detail/random_access_device.hpp +++ b/include/boost/async/io/detail/random_access_device.hpp @@ -81,13 +81,15 @@ struct random_access_device::read_some_at_op_seq_ : detail::deferred_op_resource return transfer_result{ec, n}; } + read_some_at_op_seq_(random_access_device & rs, std::uint64_t offset, buffers::mutable_buffer_subspan buffer) + : random_access_device_(rs), offset_(offset), buffer_(buffer) {} read_some_at_op_seq_(random_access_device & rs, std::uint64_t offset, buffers::mutable_buffer_span buffer) : random_access_device_(rs), offset_(offset), buffer_(buffer) {} private: random_access_device & random_access_device_; std::uint64_t offset_; - buffers::mutable_buffer_span buffer_; + buffers::mutable_buffer_subspan buffer_; std::exception_ptr error; std::optional> result_; }; @@ -159,13 +161,15 @@ struct random_access_device::write_some_at_op_seq_ : detail::deferred_op_resourc return transfer_result{ec, n}; } + write_some_at_op_seq_(random_access_device & rs, std::uint64_t offset, buffers::const_buffer_subspan buffer) + : random_access_device_(rs), offset_(offset), buffer_(buffer) {} write_some_at_op_seq_(random_access_device & rs, std::uint64_t offset, buffers::const_buffer_span buffer) : random_access_device_(rs), offset_(offset), buffer_(buffer) {} private: random_access_device & random_access_device_; std::uint64_t offset_; - buffers::const_buffer_span buffer_; + buffers::const_buffer_subspan buffer_; std::exception_ptr error; std::optional> result_; }; diff --git a/include/boost/async/io/detail/seq_packet_socket.hpp b/include/boost/async/io/detail/seq_packet_socket.hpp index 9ced5cd9..6133faeb 100644 --- a/include/boost/async/io/detail/seq_packet_socket.hpp +++ b/include/boost/async/io/detail/seq_packet_socket.hpp @@ -77,13 +77,16 @@ struct seq_packet_socket::receive_op_seq_ : detail::deferred_op_resource_base const auto & [ec, n] = *result_; return transfer_result{ec, n}; } + receive_op_seq_(asio::basic_seq_packet_socket & rs, + buffers::mutable_buffer_subspan buffer, message_flags &out_flags) + : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} receive_op_seq_(asio::basic_seq_packet_socket & rs, buffers::mutable_buffer_span buffer, message_flags &out_flags) : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} private: void initiate_(async::completion_handler h); asio::basic_seq_packet_socket &seq_packet_socket_; - buffers::mutable_buffer_span buffer_; + buffers::mutable_buffer_subspan buffer_; message_flags &out_flags_; std::exception_ptr error; std::optional> result_; @@ -153,12 +156,15 @@ struct seq_packet_socket::send_op_seq_ : detail::deferred_op_resource_base return transfer_result{ec, n}; } send_op_seq_(asio::basic_seq_packet_socket & rs, - buffers::const_buffer_span buffer, message_flags out_flags) + buffers::const_buffer_subspan buffer, message_flags out_flags) + : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} + send_op_seq_(asio::basic_seq_packet_socket & rs, + buffers::const_buffer_span buffer, message_flags out_flags) : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} private: void initiate_(async::completion_handler h); asio::basic_seq_packet_socket &seq_packet_socket_; - buffers::const_buffer_span buffer_; + buffers::const_buffer_subspan buffer_; message_flags out_flags_; std::exception_ptr error; std::optional> result_; diff --git a/include/boost/async/io/detail/ssl.hpp b/include/boost/async/io/detail/ssl.hpp index 56029288..d3208660 100644 --- a/include/boost/async/io/detail/ssl.hpp +++ b/include/boost/async/io/detail/ssl.hpp @@ -120,11 +120,11 @@ struct ssl_stream::handshake_op_buf_seq_ : detail::deferred_op_resource_base } handshake_op_buf_seq_(ssl_stream & stream, handshake_type ht, - buffers::const_buffer_span buf) : stream(stream), ht(ht), buf(buf) {} + buffers::const_buffer_subspan buf) : stream(stream), ht(ht), buf(buf) {} private: ssl_stream & stream; handshake_type ht; - buffers::const_buffer_span buf; + buffers::const_buffer_subspan buf; std::exception_ptr error; std::optional> result_; }; diff --git a/include/boost/async/io/detail/stream.hpp b/include/boost/async/io/detail/stream.hpp index 371d1e6e..15ec7059 100644 --- a/include/boost/async/io/detail/stream.hpp +++ b/include/boost/async/io/detail/stream.hpp @@ -80,12 +80,14 @@ struct stream::read_some_op_seq_ : detail::deferred_op_resource_base return transfer_result{ec, n}; } + read_some_op_seq_(stream & rs, buffers::mutable_buffer_subspan buffer) + : rstream_(rs), buffer_(buffer) {} read_some_op_seq_(stream & rs, buffers::mutable_buffer_span buffer) : rstream_(rs), buffer_(buffer) {} private: stream & rstream_; - buffers::mutable_buffer_span buffer_; + buffers::mutable_buffer_subspan buffer_; std::exception_ptr error; std::optional> result_; }; @@ -156,12 +158,13 @@ struct stream::write_some_op_seq_ : detail::deferred_op_resource_base return transfer_result{ec, n}; } + write_some_op_seq_(stream & rs, buffers::const_buffer_subspan buffer) + : rstream_(rs), buffer_(buffer) {} write_some_op_seq_(stream & rs, buffers::const_buffer_span buffer) : rstream_(rs), buffer_(buffer) {} - private: stream & rstream_; - buffers::const_buffer_span buffer_; + buffers::const_buffer_subspan buffer_; std::exception_ptr error; std::optional> result_; }; diff --git a/include/boost/async/io/pipe.hpp b/include/boost/async/io/pipe.hpp index e78e6b07..1573a514 100644 --- a/include/boost/async/io/pipe.hpp +++ b/include/boost/async/io/pipe.hpp @@ -35,12 +35,12 @@ struct readable_pipe final : stream BOOST_ASYNC_DECL system::result duplicate(); - void write_some(buffers::mutable_buffer_span buffers) = delete; + void write_some(buffers::mutable_buffer_subspan buffers) = delete; void write_some(buffers::mutable_buffer buffer) = delete; private: - BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; - BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; friend system::result> make_pipe(); asio::basic_readable_pipe pipe_; @@ -62,11 +62,11 @@ struct writable_pipe final : stream BOOST_ASYNC_DECL system::result release(); BOOST_ASYNC_DECL system::result duplicate(); - void read_some(buffers::mutable_buffer_span buffers) = delete; + void read_some(buffers::mutable_buffer_subspan buffers) = delete; void read_some(buffers::mutable_buffer buffer) = delete; private: - BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; - BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; friend system::result> make_pipe(); asio::basic_writable_pipe pipe_; }; diff --git a/include/boost/async/io/random_access_device.hpp b/include/boost/async/io/random_access_device.hpp index 39591164..a9fd8f2d 100644 --- a/include/boost/async/io/random_access_device.hpp +++ b/include/boost/async/io/random_access_device.hpp @@ -21,18 +21,20 @@ struct random_access_device virtual ~random_access_device() = default; protected: - virtual void async_read_some_at_impl_ (std::uint64_t offset, buffers::mutable_buffer_span buffer, async::completion_handler h) = 0; - virtual void async_write_some_at_impl_(std::uint64_t offset, buffers:: const_buffer_span buffer, async::completion_handler h) = 0; + virtual void async_read_some_at_impl_ (std::uint64_t offset, buffers::mutable_buffer_subspan buffer, async::completion_handler h) = 0; + virtual void async_write_some_at_impl_(std::uint64_t offset, buffers:: const_buffer_subspan buffer, async::completion_handler h) = 0; private: struct read_some_at_op_; struct read_some_at_op_seq_; struct write_some_at_op_; struct write_some_at_op_seq_; public: - BOOST_ASYNC_DECL [[nodiscard]] read_some_at_op_seq_ read_some_at(std::uint64_t offset, buffers::mutable_buffer_span buffers); - BOOST_ASYNC_DECL [[nodiscard]] read_some_at_op_ read_some_at(std::uint64_t offset, buffers::mutable_buffer buffer); - BOOST_ASYNC_DECL [[nodiscard]] write_some_at_op_seq_ write_some_at(std::uint64_t offset, buffers::const_buffer_span buffers); - BOOST_ASYNC_DECL [[nodiscard]] write_some_at_op_ write_some_at(std::uint64_t offset, buffers::const_buffer buffer); + BOOST_ASYNC_DECL [[nodiscard]] read_some_at_op_seq_ read_some_at(std::uint64_t offset, buffers::mutable_buffer_span buffers); + BOOST_ASYNC_DECL [[nodiscard]] read_some_at_op_seq_ read_some_at(std::uint64_t offset, buffers::mutable_buffer_subspan buffers); + BOOST_ASYNC_DECL [[nodiscard]] read_some_at_op_ read_some_at(std::uint64_t offset, buffers::mutable_buffer buffer); + BOOST_ASYNC_DECL [[nodiscard]] write_some_at_op_seq_ write_some_at(std::uint64_t offset, buffers::const_buffer_span buffers); + BOOST_ASYNC_DECL [[nodiscard]] write_some_at_op_seq_ write_some_at(std::uint64_t offset, buffers::const_buffer_subspan buffers); + BOOST_ASYNC_DECL [[nodiscard]] write_some_at_op_ write_some_at(std::uint64_t offset, buffers::const_buffer buffer); }; } diff --git a/include/boost/async/io/random_access_file.hpp b/include/boost/async/io/random_access_file.hpp index 6bfcc82a..98760178 100644 --- a/include/boost/async/io/random_access_file.hpp +++ b/include/boost/async/io/random_access_file.hpp @@ -30,8 +30,8 @@ struct random_access_file : file, random_access_device BOOST_ASYNC_DECL random_access_file(native_handle_type h); BOOST_ASYNC_DECL random_access_file(core::string_view file, flags open_flags = flags::read_write); private: - BOOST_ASYNC_DECL void async_read_some_at_impl_ (std::uint64_t offset, buffers::mutable_buffer_span buffer, async::completion_handler h) override; - BOOST_ASYNC_DECL void async_write_some_at_impl_(std::uint64_t offset, buffers::const_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_read_some_at_impl_ (std::uint64_t offset, buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_write_some_at_impl_(std::uint64_t offset, buffers::const_buffer_subspan buffer, async::completion_handler h) override; asio::basic_random_access_file random_access_file_; }; diff --git a/include/boost/async/io/seq_packet_socket.hpp b/include/boost/async/io/seq_packet_socket.hpp index 110875ca..4a424815 100644 --- a/include/boost/async/io/seq_packet_socket.hpp +++ b/include/boost/async/io/seq_packet_socket.hpp @@ -46,10 +46,12 @@ struct [[nodiscard]] seq_packet_socket final : socket BOOST_ASYNC_DECL void adopt_endpoint_(endpoint & ep) override; public: - [[nodiscard]] BOOST_ASYNC_DECL receive_op_seq_ receive(buffers::mutable_buffer_span buffers, message_flags & out_flags); - [[nodiscard]] BOOST_ASYNC_DECL receive_op_ receive(buffers::mutable_buffer buffer, message_flags & out_flags); - [[nodiscard]] BOOST_ASYNC_DECL send_op_seq_ send(buffers::const_buffer_span buffers, message_flags out_flags); - [[nodiscard]] BOOST_ASYNC_DECL send_op_ send(buffers::const_buffer buffer, message_flags out_flags); + [[nodiscard]] BOOST_ASYNC_DECL receive_op_seq_ receive(buffers::mutable_buffer_subspan buffers, message_flags & out_flags); + [[nodiscard]] BOOST_ASYNC_DECL receive_op_seq_ receive(buffers::mutable_buffer_span buffers, message_flags & out_flags); + [[nodiscard]] BOOST_ASYNC_DECL receive_op_ receive(buffers::mutable_buffer buffer, message_flags & out_flags); + [[nodiscard]] BOOST_ASYNC_DECL send_op_seq_ send(buffers::const_buffer_subspan buffers, message_flags out_flags); + [[nodiscard]] BOOST_ASYNC_DECL send_op_seq_ send(buffers::const_buffer_span buffers, message_flags out_flags); + [[nodiscard]] BOOST_ASYNC_DECL send_op_ send(buffers::const_buffer buffer, message_flags out_flags); asio::basic_seq_packet_socket seq_packet_socket_; }; diff --git a/include/boost/async/io/serial_port.hpp b/include/boost/async/io/serial_port.hpp index 512e705e..18096cf1 100644 --- a/include/boost/async/io/serial_port.hpp +++ b/include/boost/async/io/serial_port.hpp @@ -55,8 +55,8 @@ struct [[nodiscard]] serial_port final : stream BOOST_ASYNC_DECL [[nodiscard]] system::result open(core::string_view device); private: - BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; - BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; asio::basic_serial_port serial_port_; }; diff --git a/include/boost/async/io/ssl.hpp b/include/boost/async/io/ssl.hpp index 86fbabb8..e10d5b04 100644 --- a/include/boost/async/io/ssl.hpp +++ b/include/boost/async/io/ssl.hpp @@ -46,8 +46,8 @@ struct ssl_stream : private detail::ssl_stream_base, stream, socket BOOST_ASYNC_DECL ssl_stream(asio::ssl::context & ctx, stream_socket && socket); private: - BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; - BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; struct handshake_op_; struct handshake_op_buf_; @@ -58,6 +58,7 @@ struct ssl_stream : private detail::ssl_stream_base, stream, socket using handshake_type = boost::asio::ssl::stream_base::handshake_type; BOOST_ASYNC_DECL handshake_op_ async_handshake(handshake_type ht); BOOST_ASYNC_DECL handshake_op_buf_ async_handshake(handshake_type ht, buffers::const_buffer buf); + BOOST_ASYNC_DECL handshake_op_buf_seq_ async_handshake(handshake_type ht, buffers::const_buffer_subspan buf); BOOST_ASYNC_DECL handshake_op_buf_seq_ async_handshake(handshake_type ht, buffers::const_buffer_span buf); BOOST_ASYNC_DECL shutdown_op_ async_shutdown(); private: diff --git a/include/boost/async/io/stream.hpp b/include/boost/async/io/stream.hpp index 3aac76b1..f4722959 100644 --- a/include/boost/async/io/stream.hpp +++ b/include/boost/async/io/stream.hpp @@ -52,18 +52,20 @@ struct stream virtual ~stream() = default; protected: - virtual void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) = 0; - virtual void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) = 0; + virtual void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) = 0; + virtual void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) = 0; private: struct read_some_op_; struct read_some_op_seq_; struct write_some_op_; struct write_some_op_seq_; public: - BOOST_ASYNC_DECL [[nodiscard]] read_some_op_seq_ read_some(buffers::mutable_buffer_span buffers); - BOOST_ASYNC_DECL [[nodiscard]] read_some_op_ read_some(buffers::mutable_buffer buffer); - BOOST_ASYNC_DECL [[nodiscard]] write_some_op_seq_ write_some(buffers::const_buffer_span buffers); - BOOST_ASYNC_DECL [[nodiscard]] write_some_op_ write_some(buffers::const_buffer buffer); + BOOST_ASYNC_DECL [[nodiscard]] read_some_op_seq_ read_some(buffers::mutable_buffer_subspan buffers); + BOOST_ASYNC_DECL [[nodiscard]] read_some_op_seq_ read_some(buffers::mutable_buffer_span buffers); + BOOST_ASYNC_DECL [[nodiscard]] read_some_op_ read_some(buffers::mutable_buffer buffer); + BOOST_ASYNC_DECL [[nodiscard]] write_some_op_seq_ write_some(buffers::const_buffer_subspan buffers); + BOOST_ASYNC_DECL [[nodiscard]] write_some_op_seq_ write_some(buffers::const_buffer_span buffers); + BOOST_ASYNC_DECL [[nodiscard]] write_some_op_ write_some(buffers::const_buffer buffer); }; } diff --git a/include/boost/async/io/stream_file.hpp b/include/boost/async/io/stream_file.hpp index 9e96debf..1ec20b9b 100644 --- a/include/boost/async/io/stream_file.hpp +++ b/include/boost/async/io/stream_file.hpp @@ -30,8 +30,8 @@ struct stream_file : file, stream BOOST_ASYNC_DECL stream_file(native_handle_type h); BOOST_ASYNC_DECL stream_file(core::string_view file, flags open_flags = flags::read_write); private: - BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; - BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; asio::basic_stream_file stream_file_; }; diff --git a/include/boost/async/io/stream_socket.hpp b/include/boost/async/io/stream_socket.hpp index 43e6690d..5f39af1f 100644 --- a/include/boost/async/io/stream_socket.hpp +++ b/include/boost/async/io/stream_socket.hpp @@ -30,8 +30,8 @@ struct [[nodiscard]] stream_socket final : stream, socket BOOST_ASYNC_DECL stream_socket(native_handle_type h, protocol_type protocol = protocol_type()); BOOST_ASYNC_DECL stream_socket(endpoint ep); private: - BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_span buffer, async::completion_handler h) override; - BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_span buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; + BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; asio::basic_stream_socket stream_socket_; friend struct ssl_stream; BOOST_ASYNC_DECL void adopt_endpoint_(endpoint & ep) override; diff --git a/src/io/buffers/register.cpp b/src/io/buffers/register.cpp index b39acd33..094e6392 100644 --- a/src/io/buffers/register.cpp +++ b/src/io/buffers/register.cpp @@ -12,15 +12,17 @@ namespace boost::async::io::buffers { -using buffer_registration = asio::buffer_registration>; - buffer_registration register_(buffers::mutable_buffer buffer) { - return register_(buffers::mutable_buffer_span{&buffer, 1u}); + return register_(buffers::mutable_buffer_subspan{&buffer, 1u}); } buffer_registration register_(buffers::mutable_buffer_span buffer) +{ + return register_(buffers::mutable_buffer_subspan{buffer}); +} + +buffer_registration register_(buffers::mutable_buffer_subspan buffer) { return asio::register_buffers(this_thread::get_executor().context(), buffer, this_thread::get_allocator()); diff --git a/src/io/datagram_socket.cpp b/src/io/datagram_socket.cpp index f77b95f3..ff793c28 100644 --- a/src/io/datagram_socket.cpp +++ b/src/io/datagram_socket.cpp @@ -41,6 +41,10 @@ datagram_socket::datagram_socket(endpoint ep) { } +auto datagram_socket::receive(buffers::mutable_buffer_subspan buffers) -> receive_op_seq_ +{ + return receive_op_seq_{datagram_socket_, buffers}; +} auto datagram_socket::receive(buffers::mutable_buffer_span buffers) -> receive_op_seq_ { return receive_op_seq_{datagram_socket_, buffers}; @@ -49,6 +53,10 @@ auto datagram_socket::receive(buffers::mutable_buffer buffer) -> receive_op { return receive_op_{datagram_socket_, buffer}; } +auto datagram_socket::receive_from(buffers::mutable_buffer_subspan buffers, endpoint & ep) -> receive_from_op_seq_ +{ + return receive_from_op_seq_{datagram_socket_, buffers, ep}; +} auto datagram_socket::receive_from(buffers::mutable_buffer_span buffers, endpoint & ep) -> receive_from_op_seq_ { return receive_from_op_seq_{datagram_socket_, buffers, ep}; @@ -57,6 +65,10 @@ auto datagram_socket::receive_from(buffers::mutable_buffer buffer, endpoin { return receive_from_op_{datagram_socket_, buffer, ep}; } +auto datagram_socket::send(buffers::const_buffer_subspan buffers) -> send_op_seq_ +{ + return send_op_seq_{datagram_socket_, buffers}; +} auto datagram_socket::send(buffers::const_buffer_span buffers) -> send_op_seq_ { return send_op_seq_{datagram_socket_, buffers}; @@ -65,6 +77,10 @@ auto datagram_socket::send(buffers::const_buffer buffer) -> send_op_ { return send_op_{datagram_socket_, buffer}; } +auto datagram_socket::send_to(buffers::const_buffer_subspan buffers, const endpoint & target) -> send_to_op_seq_ +{ + return send_to_op_seq_{datagram_socket_, buffers, target}; +} auto datagram_socket::send_to(buffers::const_buffer_span buffers, const endpoint & target) -> send_to_op_seq_ { return send_to_op_seq_{datagram_socket_, buffers, target}; @@ -76,7 +92,7 @@ auto datagram_socket::send_to(buffers::const_buffer buffer, const endpoint void datagram_socket::receive_op_::initiate_(async::completion_handler h) { - this->datagram_socket_.async_receive(buffers::mutable_buffer_span{&buffer_, 1u}, std::move(h)); + this->datagram_socket_.async_receive(buffers::mutable_buffer_subspan{&buffer_, 1u}, std::move(h)); } void datagram_socket::receive_op_seq_::initiate_(async::completion_handler h) @@ -86,7 +102,7 @@ void datagram_socket::receive_op_seq_::initiate_(async::completion_handler h) { - this->datagram_socket_.async_receive_from(buffers::mutable_buffer_span{&buffer_, 1u}, ep_, std::move(h)); + this->datagram_socket_.async_receive_from(buffers::mutable_buffer_subspan{&buffer_, 1u}, ep_, std::move(h)); } void datagram_socket::receive_from_op_seq_::initiate_(async::completion_handler h) @@ -96,7 +112,7 @@ void datagram_socket::receive_from_op_seq_::initiate_(async::completion_handler< void datagram_socket::send_op_::initiate_(async::completion_handler h) { - this->datagram_socket_.async_send(buffers::const_buffer_span{&buffer_, 1u}, std::move(h)); + this->datagram_socket_.async_send(buffers::const_buffer_subspan{&buffer_, 1u}, std::move(h)); } void datagram_socket::send_op_seq_::initiate_(async::completion_handler h) @@ -106,7 +122,7 @@ void datagram_socket::send_op_seq_::initiate_(async::completion_handler h) { - this->datagram_socket_.async_send_to(buffers::const_buffer_span{&buffer_, 1u}, ep_, std::move(h)); + this->datagram_socket_.async_send_to(buffers::const_buffer_subspan{&buffer_, 1u}, ep_, std::move(h)); } void datagram_socket::send_to_op_seq_::initiate_(async::completion_handler h) diff --git a/src/io/detail/random_access_device.cpp b/src/io/detail/random_access_device.cpp new file mode 100644 index 00000000..1f8558d9 --- /dev/null +++ b/src/io/detail/random_access_device.cpp @@ -0,0 +1,44 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include + +namespace boost::async::io +{ +auto random_access_device:: read_some_at(std::uint64_t offset, buffers::mutable_buffer_span buffers) + -> read_some_at_op_seq_ +{ + return read_some_at_op_seq_{*this, offset, buffers}; +} +auto random_access_device:: read_some_at(std::uint64_t offset, buffers::mutable_buffer_subspan buffers) + -> read_some_at_op_seq_ +{ + return read_some_at_op_seq_{*this, offset, buffers}; +} +auto random_access_device:: read_some_at(std::uint64_t offset, buffers::mutable_buffer buffer) + -> read_some_at_op_ +{ + return read_some_at_op_{*this, offset, buffer}; +} +auto random_access_device::write_some_at(std::uint64_t offset, buffers::const_buffer_span buffers) + -> write_some_at_op_seq_ +{ + return write_some_at_op_seq_{*this, offset, buffers}; +} +auto random_access_device::write_some_at(std::uint64_t offset, buffers::const_buffer_subspan buffers) + -> write_some_at_op_seq_ +{ + return write_some_at_op_seq_{*this, offset, buffers}; +} +auto random_access_device::write_some_at(std::uint64_t offset, buffers::const_buffer buffer) + -> write_some_at_op_ +{ + return write_some_at_op_{*this, offset, buffer}; +} + + +} \ No newline at end of file diff --git a/src/io/detail/stream.cpp b/src/io/detail/stream.cpp index bbfb839c..d34aeb7f 100644 --- a/src/io/detail/stream.cpp +++ b/src/io/detail/stream.cpp @@ -10,10 +10,12 @@ namespace boost::async::io { -auto stream:: read_some(buffers::mutable_buffer_span buffers) -> read_some_op_seq_ { return read_some_op_seq_{*this, buffers};} -auto stream:: read_some(buffers::mutable_buffer buffer) -> read_some_op_ { return read_some_op_{*this, buffer};} -auto stream::write_some(buffers::const_buffer_span buffers) -> write_some_op_seq_ { return write_some_op_seq_{*this, buffers};} -auto stream::write_some(buffers::const_buffer buffer) -> write_some_op_ { return write_some_op_{*this, buffer};} +auto stream:: read_some(buffers::mutable_buffer_subspan buffers) -> read_some_op_seq_ { return read_some_op_seq_{*this, buffers};} +auto stream:: read_some(buffers::mutable_buffer_span buffers) -> read_some_op_seq_ { return read_some_op_seq_{*this, buffers};} +auto stream:: read_some(buffers::mutable_buffer buffer) -> read_some_op_ { return read_some_op_{*this, buffer};} +auto stream::write_some(buffers::const_buffer_subspan buffers) -> write_some_op_seq_ { return write_some_op_seq_{*this, buffers};} +auto stream::write_some(buffers::const_buffer_span buffers) -> write_some_op_seq_ { return write_some_op_seq_{*this, buffers};} +auto stream::write_some(buffers::const_buffer buffer) -> write_some_op_ { return write_some_op_{*this, buffer};} } \ No newline at end of file diff --git a/src/io/pipe.cpp b/src/io/pipe.cpp index 9bb85e36..59470938 100644 --- a/src/io/pipe.cpp +++ b/src/io/pipe.cpp @@ -35,14 +35,14 @@ system::result readable_pipe::cancel() bool readable_pipe::is_open() const { return pipe_.is_open(); } void readable_pipe::async_read_some_impl_( - buffers::mutable_buffer_span buffer, + buffers::mutable_buffer_subspan buffer, async::completion_handler h) { pipe_.async_read_some(buffer, std::move(h)); } void readable_pipe::async_write_some_impl_( - buffers::const_buffer_span buffer, + buffers::const_buffer_subspan buffer, async::completion_handler h) { constexpr static source_location loc{BOOST_CURRENT_LOCATION}; @@ -104,7 +104,7 @@ system::result writable_pipe::cancel() bool writable_pipe::is_open() const { return pipe_.is_open(); } void writable_pipe::async_write_some_impl_( - buffers::const_buffer_span buffer, + buffers::const_buffer_subspan buffer, async::completion_handler h) { pipe_.async_write_some(buffer, std::move(h)); @@ -112,7 +112,7 @@ void writable_pipe::async_write_some_impl_( void writable_pipe::async_read_some_impl_( - buffers::mutable_buffer_span buffer, + buffers::mutable_buffer_subspan buffer, async::completion_handler h) { constexpr static source_location loc{BOOST_CURRENT_LOCATION}; diff --git a/src/io/random_access_file.cpp b/src/io/random_access_file.cpp index d7d54075..ba82a3ef 100644 --- a/src/io/random_access_file.cpp +++ b/src/io/random_access_file.cpp @@ -47,7 +47,7 @@ random_access_file::random_access_file(core::string_view file_, flags open_flags void random_access_file::async_read_some_at_impl_( std::uint64_t offset, - buffers::mutable_buffer_span buffer, + buffers::mutable_buffer_subspan buffer, async::completion_handler h) { random_access_file_.async_read_some_at(offset, buffer, std::move(h)); @@ -55,7 +55,7 @@ void random_access_file::async_read_some_at_impl_( void random_access_file::async_write_some_at_impl_( std::uint64_t offset, - buffers::const_buffer_span buffer, + buffers::const_buffer_subspan buffer, async::completion_handler h) { random_access_file_.async_write_some_at(offset, buffer, std::move(h)); diff --git a/src/io/seq_packet_socket.cpp b/src/io/seq_packet_socket.cpp index 47e48148..3461b973 100644 --- a/src/io/seq_packet_socket.cpp +++ b/src/io/seq_packet_socket.cpp @@ -41,6 +41,10 @@ seq_packet_socket::seq_packet_socket(endpoint ep) { } +auto seq_packet_socket::receive(buffers::mutable_buffer_subspan buffers, message_flags &out_flags) -> receive_op_seq_ +{ + return receive_op_seq_{seq_packet_socket_, buffers, out_flags}; +} auto seq_packet_socket::receive(buffers::mutable_buffer_span buffers, message_flags &out_flags) -> receive_op_seq_ { return receive_op_seq_{seq_packet_socket_, buffers, out_flags}; @@ -49,6 +53,10 @@ auto seq_packet_socket::receive(buffers::mutable_buffer buffer, message_fla { return receive_op_{seq_packet_socket_, buffer, out_flags}; } +auto seq_packet_socket::send(buffers::const_buffer_subspan buffers, message_flags out_flags) -> send_op_seq_ +{ + return send_op_seq_{seq_packet_socket_, buffers, out_flags}; +} auto seq_packet_socket::send(buffers::const_buffer_span buffers, message_flags out_flags) -> send_op_seq_ { return send_op_seq_{seq_packet_socket_, buffers, out_flags}; @@ -60,7 +68,7 @@ auto seq_packet_socket::send(buffers::const_buffer buffer,message_flags out void seq_packet_socket::receive_op_::initiate_(async::completion_handler h) { - this->seq_packet_socket_.async_receive(buffers::mutable_buffer_span{&buffer_, 1u}, out_flags_, std::move(h)); + this->seq_packet_socket_.async_receive(buffers::mutable_buffer_subspan{&buffer_, 1u}, out_flags_, std::move(h)); } void seq_packet_socket::receive_op_seq_::initiate_(async::completion_handler h) @@ -70,7 +78,7 @@ void seq_packet_socket::receive_op_seq_::initiate_(async::completion_handler h) { - this->seq_packet_socket_.async_send(buffers::const_buffer_span{&buffer_, 1u}, out_flags_, std::move(h)); + this->seq_packet_socket_.async_send(buffers::const_buffer_subspan{&buffer_, 1u}, out_flags_, std::move(h)); } void seq_packet_socket::send_op_seq_::initiate_(async::completion_handler h) diff --git a/src/io/serial_port.cpp b/src/io/serial_port.cpp index 1c631297..aa59c67f 100644 --- a/src/io/serial_port.cpp +++ b/src/io/serial_port.cpp @@ -123,14 +123,14 @@ system::result serial_port::assign(native_handle_type native_handle) void serial_port::async_read_some_impl_( - buffers::mutable_buffer_span buffer, + buffers::mutable_buffer_subspan buffer, async::completion_handler h) { serial_port_.async_read_some(buffer, std::move(h)); } void serial_port::async_write_some_impl_( - buffers::const_buffer_span buffer, + buffers::const_buffer_subspan buffer, async::completion_handler h) { serial_port_.async_write_some(buffer, std::move(h)); diff --git a/src/io/ssl.cpp b/src/io/ssl.cpp index b9fc0c6d..a02c1648 100644 --- a/src/io/ssl.cpp +++ b/src/io/ssl.cpp @@ -51,14 +51,14 @@ ssl_stream::ssl_stream(asio::ssl::context & ctx, stream_socket && socket_) void ssl_stream::async_read_some_impl_( - buffers::mutable_buffer_span buffer, + buffers::mutable_buffer_subspan buffer, async::completion_handler h) { ssl_stream_.async_read_some(buffer, std::move(h)); } void ssl_stream::async_write_some_impl_( - buffers::const_buffer_span buffer, + buffers::const_buffer_subspan buffer, async::completion_handler h) { ssl_stream_.async_write_some(buffer, std::move(h)); @@ -77,9 +77,14 @@ ssl_stream::handshake_op_buf_ ssl_stream::async_handshake(handshake_type ht, return handshake_op_buf_{*this, ht, buf}; } ssl_stream::handshake_op_buf_seq_ ssl_stream::async_handshake(handshake_type ht, buffers::const_buffer_span buf) +{ + return handshake_op_buf_seq_{*this, ht, buffers::const_buffer_subspan{buf}}; +} +ssl_stream::handshake_op_buf_seq_ ssl_stream::async_handshake(handshake_type ht, buffers::const_buffer_subspan buf) { return handshake_op_buf_seq_{*this, ht, buf}; } + ssl_stream::shutdown_op_ ssl_stream::async_shutdown() { return shutdown_op_{*this}; @@ -108,7 +113,7 @@ void ssl_stream::handshake_op_::init_op(completion_handler h void ssl_stream::handshake_op_buf_::init_op(completion_handler handler) { - stream.ssl_stream_.async_handshake(ht, io::buffers::const_buffer_span{&buf, 1u}, std::move(handler)); + stream.ssl_stream_.async_handshake(ht, io::buffers::const_buffer_subspan{&buf, 1u}, std::move(handler)); } void ssl_stream::handshake_op_buf_seq_::init_op(completion_handler handler) diff --git a/src/io/stream_file.cpp b/src/io/stream_file.cpp index 5811428f..8a085346 100644 --- a/src/io/stream_file.cpp +++ b/src/io/stream_file.cpp @@ -46,14 +46,14 @@ stream_file::stream_file(core::string_view file_, flags open_flags) void stream_file::async_read_some_impl_( - buffers::mutable_buffer_span buffer, + buffers::mutable_buffer_subspan buffer, async::completion_handler h) { stream_file_.async_read_some(buffer, std::move(h)); } void stream_file::async_write_some_impl_( - buffers::const_buffer_span buffer, + buffers::const_buffer_subspan buffer, async::completion_handler h) { stream_file_.async_write_some(buffer, std::move(h)); diff --git a/src/io/stream_socket.cpp b/src/io/stream_socket.cpp index 860da486..7f25b56c 100644 --- a/src/io/stream_socket.cpp +++ b/src/io/stream_socket.cpp @@ -42,14 +42,14 @@ stream_socket::stream_socket(endpoint ep) } void stream_socket::async_read_some_impl_( - buffers::mutable_buffer_span buffer, + buffers::mutable_buffer_subspan buffer, async::completion_handler h) { stream_socket_.async_read_some(buffer, std::move(h)); } void stream_socket::async_write_some_impl_( - buffers::const_buffer_span buffer, + buffers::const_buffer_subspan buffer, async::completion_handler h) { stream_socket_.async_write_some(buffer, std::move(h)); From 4aeb89a13151cd20604048706706fb68aa4605d9 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 23:26:32 +0800 Subject: [PATCH 18/43] added read & write. --- CMakeLists.txt | 5 ++ .../async/io/detail/random_access_device.hpp | 3 +- include/boost/async/io/detail/stream.hpp | 2 +- include/boost/async/io/read.hpp | 47 ++++++++++ include/boost/async/io/read_at.hpp | 36 ++++++++ include/boost/async/io/read_until.hpp | 46 ++++++++++ include/boost/async/io/stream.hpp | 2 +- include/boost/async/io/write.hpp | 36 ++++++++ include/boost/async/io/write_at.hpp | 37 ++++++++ src/io/read.cpp | 64 ++++++++++++++ src/io/read_at.cpp | 51 +++++++++++ src/io/read_until.cpp | 72 +++++++++++++++ src/io/write.cpp | 49 +++++++++++ src/io/write_at.cpp | 51 +++++++++++ test/io/CMakeLists.txt | 4 +- test/io/read.cpp | 53 +++++++++++ test/io/read_until.cpp | 88 +++++++++++++++++++ 17 files changed, 641 insertions(+), 5 deletions(-) create mode 100644 include/boost/async/io/read.hpp create mode 100644 include/boost/async/io/read_at.hpp create mode 100644 include/boost/async/io/read_until.hpp create mode 100644 include/boost/async/io/write.hpp create mode 100644 include/boost/async/io/write_at.hpp create mode 100644 src/io/read.cpp create mode 100644 src/io/read_at.cpp create mode 100644 src/io/read_until.cpp create mode 100644 src/io/write.cpp create mode 100644 src/io/write_at.cpp create mode 100644 test/io/read.cpp create mode 100644 test/io/read_until.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a5f7f975..eb062a41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,7 +109,12 @@ add_library(boost_async src/io/stream_file.cpp src/io/random_access_file.cpp src/io/file.cpp + src/io/read.cpp + src/io/read_at.cpp + src/io/read_until.cpp src/io/buffers/register.cpp + src/io/write.cpp + src/io/write_at.cpp src/io/detail/random_access_device.cpp) target_include_directories(boost_async PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") diff --git a/include/boost/async/io/detail/random_access_device.hpp b/include/boost/async/io/detail/random_access_device.hpp index 8af0fdb5..6e44f677 100644 --- a/include/boost/async/io/detail/random_access_device.hpp +++ b/include/boost/async/io/detail/random_access_device.hpp @@ -136,8 +136,7 @@ struct random_access_device::write_some_at_op_ : detail::deferred_op_resource_ba struct random_access_device::write_some_at_op_seq_ : detail::deferred_op_resource_base { - constexpr bool await_writey() noexcept {return false;}; - + constexpr bool await_ready() noexcept {return false;}; template bool await_suspend(std::coroutine_handle h) diff --git a/include/boost/async/io/detail/stream.hpp b/include/boost/async/io/detail/stream.hpp index 15ec7059..04989f63 100644 --- a/include/boost/async/io/detail/stream.hpp +++ b/include/boost/async/io/detail/stream.hpp @@ -133,7 +133,7 @@ struct stream::write_some_op_ : detail::deferred_op_resource_base struct stream::write_some_op_seq_ : detail::deferred_op_resource_base { - constexpr bool await_writey() noexcept {return false;}; + constexpr bool await_ready() noexcept {return false;}; template diff --git a/include/boost/async/io/read.hpp b/include/boost/async/io/read.hpp new file mode 100644 index 00000000..fc598dab --- /dev/null +++ b/include/boost/async/io/read.hpp @@ -0,0 +1,47 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_READ_HPP +#define BOOST_ASYNC_IO_READ_HPP + +#include +#include +#include +#include +#include + +namespace boost::async::io +{ + +BOOST_ASYNC_DECL promise read(stream & source, buffers::mutable_buffer buffer); +BOOST_ASYNC_DECL promise read(stream & source, buffers::mutable_buffer_span buffer); +BOOST_ASYNC_DECL promise read(stream & source, buffers::mutable_buffer_subspan buffer); +BOOST_ASYNC_DECL promise read(stream & source, buffers::any_dynamic_buffer & buffer, + std::size_t chunk_size = 4096); + +template + requires (!std::convertible_to) +promise read(stream & source, MutableBufferSequence && buffer) +{ + buffers::mutable_buffer buf[32]; + container::pmr::monotonic_buffer_resource res{buf, sizeof(buf), this_thread::get_default_resource()}; + container::pmr::vector buf_span{buffer.begin(), buffer.end(), &res}; + co_return co_await read(source, buffers::mutable_buffer_span{buf_span}); +} + +template +promise read(stream & source, DynamicBuffer && buffer, std::size_t chunk_size = 4096) +{ + auto any = buffers::make_any(std::forward(buffer)); + buffers::any_dynamic_buffer & ab = any; + co_return co_await read(source, ab, chunk_size); +} + + +} + +#endif //BOOST_ASYNC_IO_READ_HPP diff --git a/include/boost/async/io/read_at.hpp b/include/boost/async/io/read_at.hpp new file mode 100644 index 00000000..e0c62f0d --- /dev/null +++ b/include/boost/async/io/read_at.hpp @@ -0,0 +1,36 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_READ_AT_HPP +#define BOOST_ASYNC_READ_AT_HPP + +#include +#include +#include +#include + +namespace boost::async::io +{ + +BOOST_ASYNC_DECL promise read_at(random_access_device & source, std::uint64_t offset, buffers::mutable_buffer buffer); +BOOST_ASYNC_DECL promise read_at(random_access_device & source, std::uint64_t offset, buffers::mutable_buffer_span buffer); +BOOST_ASYNC_DECL promise read_at(random_access_device & source, std::uint64_t offset, buffers::mutable_buffer_subspan buffer); +template + requires (!std::convertible_to) +promise read(random_access_device & source, std::uint64_t offset, MutableBufferSequence && buffer) +{ + buffers::mutable_buffer buf[32]; + container::pmr::monotonic_buffer_resource res{buf, sizeof(buf), this_thread::get_default_resource()}; + container::pmr::vector buf_span{buffer.begin(), buffer.end(), &res}; + co_return co_await read_at(source, offset, buffers::mutable_buffer_span{buf_span}); +} + + +} + + +#endif //BOOST_ASYNC_READ_AT_HPP diff --git a/include/boost/async/io/read_until.hpp b/include/boost/async/io/read_until.hpp new file mode 100644 index 00000000..d295ccd7 --- /dev/null +++ b/include/boost/async/io/read_until.hpp @@ -0,0 +1,46 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_READ_UNTIL_HPP +#define BOOST_ASYNC_IO_READ_UNTIL_HPP + +#include +#include +#include +#include +#include + +namespace boost::async::io +{ + +BOOST_ASYNC_DECL promise read_until(stream & source, buffers::any_dynamic_buffer & buffer, + char delim, std::size_t chunk_size = 4096); +BOOST_ASYNC_DECL promise read_until(stream & source, buffers::any_dynamic_buffer & buffer, + core::string_view delim, std::size_t chunk_size = 4096); + + +template +promise read_until(stream & source, DynamicBuffer &&buffer, + char delim, std::size_t chunk_size = 4096) +{ + auto any = buffers::make_any(std::forward(buffer)); + buffers::any_dynamic_buffer & ab = any; + co_return co_await read_until(source, ab, delim, chunk_size); +} + +template +promise read_until(stream & source, DynamicBuffer &&buffer, + core::string_view delim, std::size_t chunk_size = 4096) +{ + auto any = buffers::make_any(std::forward(buffer)); + buffers::any_dynamic_buffer & ab = any; + co_return co_await read_until(source, ab, delim, chunk_size); +} + +} + +#endif //BOOST_ASYNC_IO_READ_UNTIL_HPP diff --git a/include/boost/async/io/stream.hpp b/include/boost/async/io/stream.hpp index f4722959..72e76dd0 100644 --- a/include/boost/async/io/stream.hpp +++ b/include/boost/async/io/stream.hpp @@ -22,7 +22,7 @@ namespace boost::async::io struct [[nodiscard]] transfer_result { system::error_code error; - std::size_t transferred; + std::size_t transferred{0u}; using value_type = std::size_t; using error_type = system::error_code; diff --git a/include/boost/async/io/write.hpp b/include/boost/async/io/write.hpp new file mode 100644 index 00000000..92db61b7 --- /dev/null +++ b/include/boost/async/io/write.hpp @@ -0,0 +1,36 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_WRITE_HPP +#define BOOST_ASYNC_IO_WRITE_HPP + +#include +#include +#include +#include +#include + +namespace boost::async::io +{ + +BOOST_ASYNC_DECL promise write(stream & source, buffers::const_buffer buffer); +BOOST_ASYNC_DECL promise write(stream & source, buffers::const_buffer_span buffer); +BOOST_ASYNC_DECL promise write(stream & source, buffers::const_buffer_subspan buffer); + +template + requires (!std::convertible_to) +promise write(stream & source, MutableBufferSequence && buffer) +{ + buffers::const_buffer buf[32]; + container::pmr::monotonic_buffer_resource res{buf, sizeof(buf), this_thread::get_default_resource()}; + container::pmr::vector buf_span{buffer.begin(), buffer.end(), &res}; + co_return co_await write(source, buffers::const_buffer_span{buf_span}); +} + +} + +#endif //BOOST_ASYNC_IO_WRITE_HPP diff --git a/include/boost/async/io/write_at.hpp b/include/boost/async/io/write_at.hpp new file mode 100644 index 00000000..55d7b1ed --- /dev/null +++ b/include/boost/async/io/write_at.hpp @@ -0,0 +1,37 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_WRITE_AT_HPP +#define BOOST_ASYNC_WRITE_AT_HPP + +#include +#include +#include +#include + +namespace boost::async::io +{ + +BOOST_ASYNC_DECL promise write_at(random_access_device & source, std::uint64_t offset, buffers::const_buffer buffer); +BOOST_ASYNC_DECL promise write_at(random_access_device & source, std::uint64_t offset, buffers::const_buffer_span buffer); +BOOST_ASYNC_DECL promise write_at(random_access_device & source, std::uint64_t offset, buffers::const_buffer_subspan buffer); + +template + requires (!std::convertible_to) +promise write(random_access_device & source, std::uint64_t offset, MutableBufferSequence && buffer) +{ + buffers::const_buffer buf[32]; + container::pmr::monotonic_buffer_resource res{buf, sizeof(buf), this_thread::get_default_resource()}; + container::pmr::vector buf_span{buffer.begin(), buffer.end(), &res}; + co_return co_await write_at(source, offset, buffers::const_buffer_span{buf_span}); +} + + +} + + +#endif //BOOST_ASYNC_WRITE_AT_HPP diff --git a/src/io/read.cpp b/src/io/read.cpp new file mode 100644 index 00000000..613038ef --- /dev/null +++ b/src/io/read.cpp @@ -0,0 +1,64 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include + +namespace boost::async::io +{ + +promise read(stream & source, buffers::mutable_buffer buffer) +{ + transfer_result tr; + + do + { + auto rd = co_await source.read_some(buffer); + tr.transferred += rd.transferred; + tr.error = rd.error; + buffer += rd.transferred; + } + while (buffer.size() > 0 && !tr.has_error()); + co_return tr; +} + +promise read(stream & source, buffers::mutable_buffer_subspan buffer) +{ + transfer_result tr; + do + { + auto rd = co_await source.read_some(buffer); + tr.transferred += rd.transferred; + tr.error = rd.error; + buffer = buffers::sans_prefix(buffer, rd.transferred); + } + while (buffers::buffer_size(buffer) > 0 && !tr.has_error()); + co_return tr; +} + +promise read(stream & source, buffers::mutable_buffer_span buffer) +{ + return read(source, buffers::mutable_buffer_subspan(buffer)); +} + + +promise read(stream & source, buffers::any_dynamic_buffer & buffer, std::size_t chunk_size) +{ + transfer_result tr; + + do + { + auto rd = co_await source.read_some(buffer.prepare(chunk_size)); + tr.transferred += rd.transferred; + tr.error = rd.error; + buffer.commit(rd.transferred); + } + while (buffer.size() >= 0 && !tr.has_error()); + co_return tr; +} + +} \ No newline at end of file diff --git a/src/io/read_at.cpp b/src/io/read_at.cpp new file mode 100644 index 00000000..0e6abb91 --- /dev/null +++ b/src/io/read_at.cpp @@ -0,0 +1,51 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include + +namespace boost::async::io +{ + +promise read_at(random_access_device & source, std::uint64_t offset,buffers::mutable_buffer buffer) +{ + transfer_result tr; + + do + { + auto rd = co_await source.read_some_at(offset, buffer); + tr.transferred += rd.transferred; + offset += rd.transferred; + tr.error = rd.error; + buffer += rd.transferred; + } + while (buffer.size() > 0 && !tr.has_error()); + co_return tr; +} + +promise read_at(random_access_device & source, std::uint64_t offset, buffers::mutable_buffer_subspan buffer) +{ + transfer_result tr; + do + { + auto rd = co_await source.read_some_at(offset, buffer); + tr.transferred += rd.transferred; + offset += rd.transferred; + tr.error = rd.error; + buffer = buffers::sans_prefix(buffer, rd.transferred); + } + while (buffers::buffer_size(buffer) > 0 && !tr.has_error()); + co_return tr; +} + +promise read_at(random_access_device & source, std::uint64_t offset, buffers::mutable_buffer_span buffer) +{ + return read_at(source, offset, buffers::mutable_buffer_subspan(buffer)); +} + + +} \ No newline at end of file diff --git a/src/io/read_until.cpp b/src/io/read_until.cpp new file mode 100644 index 00000000..ee87ef5b --- /dev/null +++ b/src/io/read_until.cpp @@ -0,0 +1,72 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include +#include +#include + +#include +#include +#include + +namespace boost::async::io +{ + +promise read_until(stream & source, buffers::any_dynamic_buffer & buffer, + char delim, std::size_t chunk_size) +{ + transfer_result tr{}; + + bool matched = false; + do + { + auto buf = buffer.prepare(chunk_size); + auto rd = co_await source.read_some(buf); + + auto begin = asio::buffers_begin(buf); + auto end = std::next(asio::buffers_begin(buf), rd.transferred); + matched = std::find(begin, end, delim) != end; + tr.transferred += rd.transferred; + tr.error = rd.error; + buffer.commit(rd.transferred); + } + while (buffer.max_size() > buffer.size() && !tr.has_error() && !matched); + co_return tr; +} + +promise read_until(stream & source, buffers::any_dynamic_buffer & buffer, + core::string_view delim, std::size_t chunk_size) +{ + transfer_result tr; + if (delim.empty()) + co_return tr; + + std::size_t offset = 0; + + bool matched = false; + do + { + auto buf = buffer.prepare(chunk_size); + auto rd = co_await source.read_some(buf); + tr.transferred += rd.transferred; + tr.error = rd.error; + buffer.commit(rd.transferred); + + auto relevant_memory = (std::min)(delim.size() + rd.transferred, buffers::buffer_size(buf)); + auto begin = std::prev(asio::buffers_end(buffer.data()), relevant_memory); + auto end = asio::buffers_end(buffer.data()); + auto itr = std::search(begin, end, delim.begin(), delim.end()); + matched = (itr != end); + } + while (buffer.size() > 0 && !tr.has_error() && !matched); + co_return tr; +} + + + +} \ No newline at end of file diff --git a/src/io/write.cpp b/src/io/write.cpp new file mode 100644 index 00000000..d5976185 --- /dev/null +++ b/src/io/write.cpp @@ -0,0 +1,49 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include + +namespace boost::async::io +{ + +promise write(stream & source, buffers::const_buffer buffer) +{ + transfer_result tr; + + do + { + auto rd = co_await source.write_some(buffer); + tr.transferred += rd.transferred; + tr.error = rd.error; + buffer += rd.transferred; + } + while (buffer.size() > 0 && !tr.has_error()); + co_return tr; +} + +promise write(stream & source, buffers::const_buffer_subspan buffer) +{ + transfer_result tr; + do + { + auto rd = co_await source.write_some(buffer); + tr.transferred += rd.transferred; + tr.error = rd.error; + buffer = buffers::sans_prefix(buffer, rd.transferred); + } + while (buffers::buffer_size(buffer) > 0 && !tr.has_error()); + co_return tr; +} + +promise write(stream & source, buffers::const_buffer_span buffer) +{ + return write(source, buffers::const_buffer_subspan(buffer)); +} + + +} \ No newline at end of file diff --git a/src/io/write_at.cpp b/src/io/write_at.cpp new file mode 100644 index 00000000..e8a5f11f --- /dev/null +++ b/src/io/write_at.cpp @@ -0,0 +1,51 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include + +namespace boost::async::io +{ + +promise write_at(random_access_device & source, std::uint64_t offset,buffers::const_buffer buffer) +{ + transfer_result tr; + + do + { + auto rd = co_await source.write_some_at(offset, buffer); + tr.transferred += rd.transferred; + offset += rd.transferred; + tr.error = rd.error; + buffer += rd.transferred; + } + while (buffer.size() > 0 && !tr.has_error()); + co_return tr; +} + +promise write_at(random_access_device & source, std::uint64_t offset, buffers::const_buffer_subspan buffer) +{ + transfer_result tr; + do + { + auto rd = co_await source.write_some_at(offset, buffer); + tr.transferred += rd.transferred; + offset += rd.transferred; + tr.error = rd.error; + buffer = buffers::sans_prefix(buffer, rd.transferred); + } + while (buffers::buffer_size(buffer) > 0 && !tr.has_error()); + co_return tr; +} + +promise write_at(random_access_device & source, std::uint64_t offset, buffers::const_buffer_span buffer) +{ + return write_at(source, offset, buffers::const_buffer_subspan(buffer)); +} + + +} \ No newline at end of file diff --git a/test/io/CMakeLists.txt b/test/io/CMakeLists.txt index 35464121..0a8179d3 100644 --- a/test/io/CMakeLists.txt +++ b/test/io/CMakeLists.txt @@ -10,6 +10,8 @@ add_executable(boost_async_io_tests resolver.cpp sleep.cpp ssl.cpp - ../doctest.cpp) + ../doctest.cpp + read.cpp + read_until.cpp) target_link_libraries(boost_async_io_tests Boost::container Boost::async OpenSSL::SSL) add_test(NAME boost_async-io COMMAND boost_async_io_tests) diff --git a/test/io/read.cpp b/test/io/read.cpp new file mode 100644 index 00000000..abb55fc0 --- /dev/null +++ b/test/io/read.cpp @@ -0,0 +1,53 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include "../doctest.h" +#include "../test.hpp" +#include +#include +#include +#include +#include +#include + +#include + +using namespace boost::async; + +promise do_write(io::stream & str, std::string & input ) +{ + boost::ignore_unused(co_await io::write(str, {input.data(), input.size()})); +}; + +CO_TEST_CASE("read") +{ + auto [r, w] = io::make_pipe().value(); + + std::string input; + + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution distPrintable(32,126); + + input.resize(1024*1024); + std::generate(input.begin(), input.end(), [&]{return static_cast(distPrintable(rng));}); + + auto p = do_write(w, input); + + std::string output; + output.resize(1024*16); + auto res = co_await io::read(r, io::buffers::buffer(output.data(), output.size())); + + CHECK(res.transferred == output.size()); + CHECK(!res.has_error()); + + CHECK(std::equal(output.begin(), output.end(), input.begin())); + + CHECK(!r.close().has_error()); + co_await p; +} + diff --git a/test/io/read_until.cpp b/test/io/read_until.cpp new file mode 100644 index 00000000..aec8d668 --- /dev/null +++ b/test/io/read_until.cpp @@ -0,0 +1,88 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include "../doctest.h" +#include "../test.hpp" +#include +#include +#include +#include +#include +#include + +#include + +using namespace boost::async; + +promise do_write_(io::stream & str, std::string & input ) +{ + boost::ignore_unused(co_await io::write(str, {input.data(), input.size()})); +}; + + +CO_TEST_CASE("read_until char") +{ + auto [r, w] = io::make_pipe().value(); + + std::string input; + + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution distPrintable(32,126); + + input.resize(1024*1024); + std::generate(input.begin(), input.end(), [&]{return static_cast(distPrintable(rng));}); + input[4242] = '\n'; + + auto p = do_write_(w, input); + + + std::string output; + auto res = co_await io::read_until(r, io::buffers::string_buffer(&output), '\n'); + + CHECK(res.transferred >= 4242); + CHECK(res.transferred < 10000); + CHECK(!res.has_error()); + + CHECK(std::equal(output.begin(), output.end(), input.begin())); + + CHECK(!r.close().has_error()); + co_await p; +} + + +CO_TEST_CASE("read_until string") +{ + auto [r, w] = io::make_pipe().value(); + + std::string input; + + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution distPrintable(32,126); + + input.resize(1024*1024); + std::generate(input.begin(), input.end(), [&]{return static_cast(distPrintable(rng));}); + input[4242] = '\n'; + input[8000] = '\r'; + input[8001] = '\n'; + + auto p = do_write_(w, input); + + + std::string output; + auto res = co_await io::read_until(r, io::buffers::string_buffer(&output), "\r\n"); + + CHECK(res.transferred >= 8001); + CHECK(res.transferred < 16000); + CHECK(!res.has_error()); + + CHECK(std::equal(output.begin(), output.end(), input.begin())); + + CHECK(!r.close().has_error()); + co_await p; +} \ No newline at end of file From f776ce484616bc7ce89e89ac9ee425f27f90d4b9 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 23:47:02 +0800 Subject: [PATCH 19/43] added copy. --- CMakeLists.txt | 2 +- include/boost/async/io/copy.hpp | 35 +++++++++++ include/boost/async/io/signal_set.hpp | 2 - src/io/copy.cpp | 86 +++++++++++++++++++++++++++ test/io/CMakeLists.txt | 1 + test/io/copy.cpp | 65 ++++++++++++++++++++ 6 files changed, 188 insertions(+), 3 deletions(-) create mode 100644 include/boost/async/io/copy.hpp create mode 100644 src/io/copy.cpp create mode 100644 test/io/copy.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index eb062a41..541c2aad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,7 +115,7 @@ add_library(boost_async src/io/buffers/register.cpp src/io/write.cpp src/io/write_at.cpp - src/io/detail/random_access_device.cpp) + src/io/detail/random_access_device.cpp src/io/copy.cpp) target_include_directories(boost_async PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(boost_async PUBLIC diff --git a/include/boost/async/io/copy.hpp b/include/boost/async/io/copy.hpp new file mode 100644 index 00000000..1be5f4b6 --- /dev/null +++ b/include/boost/async/io/copy.hpp @@ -0,0 +1,35 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_COPY_HPP +#define BOOST_ASYNC_IO_COPY_HPP + +#include +#include +#include + +namespace boost::async::io +{ + +BOOST_ASYNC_DECL promise> +copy(stream & source, stream & sink); + +BOOST_ASYNC_DECL promise> +copy(stream & source, stream & sink, buffers::any_dynamic_buffer & buffer, std::size_t chunk_size = 4096); + + +template +promise read(stream & source, stream & sink, DynamicBuffer & buffer, std::size_t chunk_size = 4096) +{ + auto any = buffers::make_any(buffer); + buffers::any_dynamic_buffer & ab = any; + co_return co_await copy(source, sink, ab, chunk_size); +} + +} + +#endif //BOOST_ASYNC_IO_COPY_HPP diff --git a/include/boost/async/io/signal_set.hpp b/include/boost/async/io/signal_set.hpp index ad869b7f..22e66dbf 100644 --- a/include/boost/async/io/signal_set.hpp +++ b/include/boost/async/io/signal_set.hpp @@ -68,8 +68,6 @@ struct signal_set boost::asio::basic_signal_set & signal_set_; std::exception_ptr error; std::optional> result_; - char buffer[256]; - std::optional resource; }; public: [[nodiscard]] wait_op_ wait() { return wait_op_{signal_set_}; } diff --git a/src/io/copy.cpp b/src/io/copy.cpp new file mode 100644 index 00000000..c0a51d58 --- /dev/null +++ b/src/io/copy.cpp @@ -0,0 +1,86 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include +#include +#include + +namespace boost::async::io +{ + +promise> +copy(stream & source, stream & sink) +{ + constexpr std::size_t chunk_size = 4096; + char mem[chunk_size * 2]; + buffers::circular_buffer buf{mem, sizeof(mem)}; + + transfer_result r = co_await source.read_some(buffers::mutable_buffer_span(buf.prepare(chunk_size))), + w = {}; + + buf.commit(r.transferred); + + while (!r.has_error() && !w.has_error()) + { + auto [r2, w2] = co_await join( + source.read_some(buffers::mutable_buffer_span(buf.prepare(chunk_size))), + sink.write_some(buffers::const_buffer_span(buf.data()))); + buf.commit(r2.transferred); + buf.consume(w2.transferred); + r.transferred += r2.transferred; + w.transferred += w2.transferred; + r.error = r2.error; + w.error = w2.error; + } + // remaining readable stuff + while (r.has_error() && !w.has_error() && buffers::buffer_size(buf.data()) > 0u) + { + assert(false); + auto w2 = co_await sink.write_some(buffers::const_buffer_span(buf.data())); + buf.consume(w2.transferred); + w.transferred = w2.transferred; + w.error = w2.error; + } + + co_return {r, w}; +} + +promise> +copy(stream & source, stream & sink, buffers::any_dynamic_buffer & buf, std::size_t chunk_size) +{ + transfer_result r = co_await source.read_some(buffers::mutable_buffer_span(buf.prepare(chunk_size))), + w = {}; + + buf.commit(r.transferred); + + while (!r.has_error() && !w.has_error()) + { + auto [r2, w2] = co_await join( + source.read_some(buffers::mutable_buffer_span(buf.prepare(chunk_size))), + sink.write_some(buffers::const_buffer_span(buf.data()))); + buf.commit(r2.transferred); + buf.consume(w2.transferred); + r.transferred += r2.transferred; + w.transferred += w2.transferred; + r.error = r2.error; + w.error = w2.error; + } + // remaining readable stuff + while (r.has_error() && !w.has_error() && buffers::buffer_size(buf.data()) > 0u) + { + assert(false); + auto w2 = co_await sink.write_some(buffers::const_buffer_span(buf.data())); + buf.consume(w2.transferred); + w.transferred = w2.transferred; + w.error = w2.error; + } + co_return {r, w}; +} + + +} diff --git a/test/io/CMakeLists.txt b/test/io/CMakeLists.txt index 0a8179d3..4e7aa4d9 100644 --- a/test/io/CMakeLists.txt +++ b/test/io/CMakeLists.txt @@ -12,6 +12,7 @@ add_executable(boost_async_io_tests ssl.cpp ../doctest.cpp read.cpp + copy.cpp read_until.cpp) target_link_libraries(boost_async_io_tests Boost::container Boost::async OpenSSL::SSL) add_test(NAME boost_async-io COMMAND boost_async_io_tests) diff --git a/test/io/copy.cpp b/test/io/copy.cpp new file mode 100644 index 00000000..7a5af44b --- /dev/null +++ b/test/io/copy.cpp @@ -0,0 +1,65 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include "../doctest.h" +#include "../test.hpp" +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace boost::async; + +promise do_write__(io::stream & str, std::string & input ) +{ + boost::ignore_unused(co_await io::write(str, {input.data(), input.size()})); + str.close().value(); +}; + +promise do_copy(io::stream & in, io::stream & out) +{ + auto [r, w] = co_await io::copy(in, out); + CHECK(r.transferred == (1024*1024)); + CHECK(w.value() == (1024*1024)); + out.close().value(); + +}; + +CO_TEST_CASE("copy") +{ + auto [r, wi] = io::make_pipe().value(); + auto [ri, w] = io::make_pipe().value(); + + std::string input; + + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution distPrintable(32,126); + + input.resize(1024*1024); + std::generate(input.begin(), input.end(), [&]{return static_cast(distPrintable(rng));}); + + auto p = do_write__(w, input); + auto c = do_copy(ri, wi); + std::string output; + auto res = co_await io::read(r, io::buffers::string_buffer(&output)); + + CHECK(res.transferred == output.size()); + CHECK(res.transferred == input.size()); + + CHECK(std::equal(output.begin(), output.end(), input.begin())); + + CHECK(!r.close().has_error()); + co_await p; + co_await c; +} + From f96d893e99569f9ed917ff9e44b0d504131862a4 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Sat, 1 Jul 2023 16:26:13 +0800 Subject: [PATCH 20/43] renamed executor_type to executor for io. --- include/boost/async/io/acceptor.hpp | 10 ++--- include/boost/async/io/datagram_socket.hpp | 2 +- .../boost/async/io/detail/datagram_socket.hpp | 40 +++++++++---------- .../async/io/detail/seq_packet_socket.hpp | 20 +++++----- include/boost/async/io/detail/socket.hpp | 4 +- include/boost/async/io/file.hpp | 6 +-- include/boost/async/io/pipe.hpp | 8 ++-- include/boost/async/io/random_access_file.hpp | 2 +- include/boost/async/io/resolver.hpp | 8 ++-- include/boost/async/io/seq_packet_socket.hpp | 2 +- include/boost/async/io/serial_port.hpp | 4 +- include/boost/async/io/signal_set.hpp | 6 +-- include/boost/async/io/socket.hpp | 6 +-- include/boost/async/io/ssl.hpp | 2 +- include/boost/async/io/steady_timer.hpp | 2 +- include/boost/async/io/stream_file.hpp | 2 +- include/boost/async/io/stream_socket.hpp | 2 +- include/boost/async/io/system_timer.hpp | 2 +- src/io/pipe.cpp | 4 +- 19 files changed, 66 insertions(+), 66 deletions(-) diff --git a/include/boost/async/io/acceptor.hpp b/include/boost/async/io/acceptor.hpp index ddb2d88c..01353fd5 100644 --- a/include/boost/async/io/acceptor.hpp +++ b/include/boost/async/io/acceptor.hpp @@ -55,10 +55,10 @@ struct acceptor else return std::move(socket_); } - accept_op_( asio::basic_socket_acceptor & acceptor) + accept_op_( asio::basic_socket_acceptor & acceptor) : acceptor_(acceptor) {} private: - asio::basic_socket_acceptor & acceptor_; + asio::basic_socket_acceptor & acceptor_; stream_socket socket_; std::exception_ptr error; std::optional> result_; @@ -93,10 +93,10 @@ struct acceptor else return std::move(socket_); } - accept_seq_op_(asio::basic_socket_acceptor & acceptor) + accept_seq_op_(asio::basic_socket_acceptor & acceptor) : acceptor_(acceptor) {} private: - asio::basic_socket_acceptor & acceptor_; + asio::basic_socket_acceptor & acceptor_; seq_packet_socket socket_; std::exception_ptr error; std::optional> result_; @@ -105,7 +105,7 @@ struct acceptor [[nodiscard]] BOOST_ASYNC_DECL accept_op_ accept(); [[nodiscard]] BOOST_ASYNC_DECL accept_seq_op_ accept_seq_packet(); private: - asio::basic_socket_acceptor acceptor_; + asio::basic_socket_acceptor acceptor_; }; } diff --git a/include/boost/async/io/datagram_socket.hpp b/include/boost/async/io/datagram_socket.hpp index 5fc449ae..4d9a0933 100644 --- a/include/boost/async/io/datagram_socket.hpp +++ b/include/boost/async/io/datagram_socket.hpp @@ -52,7 +52,7 @@ struct [[nodiscard]] datagram_socket final : socket [[nodiscard]] send_to_op_seq_ send_to(buffers::const_buffer_span buffers, const endpoint & target); [[nodiscard]] send_to_op_ send_to(buffers::const_buffer buffer, const endpoint & target); - asio::basic_datagram_socket datagram_socket_; + asio::basic_datagram_socket datagram_socket_; }; inline system::result> make_pair(decltype(local_datagram) protocol) diff --git a/include/boost/async/io/detail/datagram_socket.hpp b/include/boost/async/io/detail/datagram_socket.hpp index 0341d46d..1631c923 100644 --- a/include/boost/async/io/detail/datagram_socket.hpp +++ b/include/boost/async/io/detail/datagram_socket.hpp @@ -39,12 +39,12 @@ struct datagram_socket::receive_op_ : detail::deferred_op_resource_base const auto & [ec, n] = *result_; return transfer_result{ec, n}; } - receive_op_(asio::basic_datagram_socket & rs, + receive_op_(asio::basic_datagram_socket & rs, buffers::mutable_buffer buffer) : datagram_socket_(rs), buffer_(buffer) {} private: void initiate_(async::completion_handler h); - asio::basic_datagram_socket &datagram_socket_; + asio::basic_datagram_socket &datagram_socket_; buffers::mutable_buffer buffer_; std::exception_ptr error; std::optional> result_; @@ -76,16 +76,16 @@ struct datagram_socket::receive_op_seq_ : detail::deferred_op_resource_base const auto & [ec, n] = *result_; return transfer_result{ec, n}; } - receive_op_seq_(asio::basic_datagram_socket & rs, + receive_op_seq_(asio::basic_datagram_socket & rs, buffers::mutable_buffer_subspan buffer) : datagram_socket_(rs), buffer_(buffer) {} - receive_op_seq_(asio::basic_datagram_socket & rs, + receive_op_seq_(asio::basic_datagram_socket & rs, buffers::mutable_buffer_span buffer) : datagram_socket_(rs), buffer_(buffer) {} private: void initiate_(async::completion_handler h); - asio::basic_datagram_socket &datagram_socket_; + asio::basic_datagram_socket &datagram_socket_; buffers::mutable_buffer_subspan buffer_; std::exception_ptr error; std::optional> result_; @@ -117,12 +117,12 @@ struct datagram_socket::receive_from_op_ : detail::deferred_op_resource_base const auto & [ec, n] = *result_; return transfer_result{ec, n}; } - receive_from_op_(asio::basic_datagram_socket & rs, + receive_from_op_(asio::basic_datagram_socket & rs, buffers::mutable_buffer buffer, endpoint & ep) : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} private: void initiate_(async::completion_handler h); - asio::basic_datagram_socket &datagram_socket_; + asio::basic_datagram_socket &datagram_socket_; buffers::mutable_buffer buffer_; endpoint &ep_; @@ -156,15 +156,15 @@ struct datagram_socket::receive_from_op_seq_ : detail::deferred_op_resource_base const auto & [ec, n] = *result_; return transfer_result{ec, n}; } - receive_from_op_seq_(asio::basic_datagram_socket & rs, + receive_from_op_seq_(asio::basic_datagram_socket & rs, buffers::mutable_buffer_subspan buffer, endpoint & ep) : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} - receive_from_op_seq_(asio::basic_datagram_socket & rs, + receive_from_op_seq_(asio::basic_datagram_socket & rs, buffers::mutable_buffer_span buffer, endpoint & ep) : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} private: void initiate_(async::completion_handler h); - asio::basic_datagram_socket &datagram_socket_; + asio::basic_datagram_socket &datagram_socket_; buffers::mutable_buffer_subspan buffer_; endpoint & ep_; std::exception_ptr error; @@ -196,12 +196,12 @@ struct datagram_socket::send_op_ : detail::deferred_op_resource_base const auto & [ec, n] = *result_; return transfer_result{ec, n}; } - send_op_(asio::basic_datagram_socket & rs, + send_op_(asio::basic_datagram_socket & rs, buffers::const_buffer buffer) : datagram_socket_(rs), buffer_(buffer) {} private: void initiate_(async::completion_handler h); - asio::basic_datagram_socket &datagram_socket_; + asio::basic_datagram_socket &datagram_socket_; buffers::const_buffer buffer_; std::exception_ptr error; std::optional> result_; @@ -233,15 +233,15 @@ struct datagram_socket::send_op_seq_ : detail::deferred_op_resource_base const auto & [ec, n] = *result_; return transfer_result{ec, n}; } - send_op_seq_(asio::basic_datagram_socket & rs, + send_op_seq_(asio::basic_datagram_socket & rs, buffers::const_buffer_subspan buffer) : datagram_socket_(rs), buffer_(buffer) {} - send_op_seq_(asio::basic_datagram_socket & rs, + send_op_seq_(asio::basic_datagram_socket & rs, buffers::const_buffer_span buffer) : datagram_socket_(rs), buffer_(buffer) {} private: void initiate_(async::completion_handler h); - asio::basic_datagram_socket &datagram_socket_; + asio::basic_datagram_socket &datagram_socket_; buffers::const_buffer_subspan buffer_; std::exception_ptr error; std::optional> result_; @@ -273,12 +273,12 @@ struct datagram_socket::send_to_op_ : detail::deferred_op_resource_base const auto & [ec, n] = *result_; return transfer_result{ec, n}; } - send_to_op_(asio::basic_datagram_socket & rs, + send_to_op_(asio::basic_datagram_socket & rs, buffers::const_buffer buffer, const endpoint & ep) : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} private: void initiate_(async::completion_handler h); - asio::basic_datagram_socket &datagram_socket_; + asio::basic_datagram_socket &datagram_socket_; buffers::const_buffer buffer_; const endpoint &ep_; @@ -312,16 +312,16 @@ struct datagram_socket::send_to_op_seq_ : detail::deferred_op_resource_base const auto & [ec, n] = *result_; return transfer_result{ec, n}; } - send_to_op_seq_(asio::basic_datagram_socket & rs, + send_to_op_seq_(asio::basic_datagram_socket & rs, buffers::const_buffer_subspan buffer, const endpoint & ep) : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} - send_to_op_seq_(asio::basic_datagram_socket & rs, + send_to_op_seq_(asio::basic_datagram_socket & rs, buffers::const_buffer_span buffer, const endpoint & ep) : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} private: void initiate_(async::completion_handler h); - asio::basic_datagram_socket &datagram_socket_; + asio::basic_datagram_socket &datagram_socket_; buffers::const_buffer_subspan buffer_; const endpoint & ep_; std::exception_ptr error; diff --git a/include/boost/async/io/detail/seq_packet_socket.hpp b/include/boost/async/io/detail/seq_packet_socket.hpp index 6133faeb..0d3213f7 100644 --- a/include/boost/async/io/detail/seq_packet_socket.hpp +++ b/include/boost/async/io/detail/seq_packet_socket.hpp @@ -39,12 +39,12 @@ struct seq_packet_socket::receive_op_ : detail::deferred_op_resource_base const auto & [ec, n] = *result_; return transfer_result{ec, n}; } - receive_op_(asio::basic_seq_packet_socket & rs, + receive_op_(asio::basic_seq_packet_socket & rs, buffers::mutable_buffer buffer, message_flags &out_flags) : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} private: void initiate_(async::completion_handler h); - asio::basic_seq_packet_socket &seq_packet_socket_; + asio::basic_seq_packet_socket &seq_packet_socket_; buffers::mutable_buffer buffer_; message_flags &out_flags_; std::exception_ptr error; @@ -77,15 +77,15 @@ struct seq_packet_socket::receive_op_seq_ : detail::deferred_op_resource_base const auto & [ec, n] = *result_; return transfer_result{ec, n}; } - receive_op_seq_(asio::basic_seq_packet_socket & rs, + receive_op_seq_(asio::basic_seq_packet_socket & rs, buffers::mutable_buffer_subspan buffer, message_flags &out_flags) : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} - receive_op_seq_(asio::basic_seq_packet_socket & rs, + receive_op_seq_(asio::basic_seq_packet_socket & rs, buffers::mutable_buffer_span buffer, message_flags &out_flags) : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} private: void initiate_(async::completion_handler h); - asio::basic_seq_packet_socket &seq_packet_socket_; + asio::basic_seq_packet_socket &seq_packet_socket_; buffers::mutable_buffer_subspan buffer_; message_flags &out_flags_; std::exception_ptr error; @@ -117,12 +117,12 @@ struct seq_packet_socket::send_op_ : detail::deferred_op_resource_base const auto & [ec, n] = *result_; return transfer_result{ec, n}; } - send_op_(asio::basic_seq_packet_socket & rs, + send_op_(asio::basic_seq_packet_socket & rs, buffers::const_buffer buffer, message_flags out_flags) : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} private: void initiate_(async::completion_handler h); - asio::basic_seq_packet_socket &seq_packet_socket_; + asio::basic_seq_packet_socket &seq_packet_socket_; buffers::const_buffer buffer_; message_flags out_flags_; std::exception_ptr error; @@ -155,15 +155,15 @@ struct seq_packet_socket::send_op_seq_ : detail::deferred_op_resource_base const auto & [ec, n] = *result_; return transfer_result{ec, n}; } - send_op_seq_(asio::basic_seq_packet_socket & rs, + send_op_seq_(asio::basic_seq_packet_socket & rs, buffers::const_buffer_subspan buffer, message_flags out_flags) : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} - send_op_seq_(asio::basic_seq_packet_socket & rs, + send_op_seq_(asio::basic_seq_packet_socket & rs, buffers::const_buffer_span buffer, message_flags out_flags) : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} private: void initiate_(async::completion_handler h); - asio::basic_seq_packet_socket &seq_packet_socket_; + asio::basic_seq_packet_socket &seq_packet_socket_; buffers::const_buffer_subspan buffer_; message_flags out_flags_; std::exception_ptr error; diff --git a/include/boost/async/io/detail/socket.hpp b/include/boost/async/io/detail/socket.hpp index 3f01bb80..ebeaaf0c 100644 --- a/include/boost/async/io/detail/socket.hpp +++ b/include/boost/async/io/detail/socket.hpp @@ -46,10 +46,10 @@ struct socket::wait_op_ : detail::deferred_op_resource_base else return {}; } - wait_op_(asio::basic_socket & socket, + wait_op_(asio::basic_socket & socket, asio::socket_base::wait_type wt) : socket_(socket), wt_(wt) {} private: - asio::basic_socket & socket_; + asio::basic_socket & socket_; asio::socket_base::wait_type wt_; std::exception_ptr error; std::optional> result_; diff --git a/include/boost/async/io/file.hpp b/include/boost/async/io/file.hpp index 09fdc0f0..81537b6d 100644 --- a/include/boost/async/io/file.hpp +++ b/include/boost/async/io/file.hpp @@ -37,16 +37,16 @@ struct file [[nodiscard]] BOOST_ASYNC_DECL system::result sync_data(); - using native_handle_type = asio::basic_file::native_handle_type; + using native_handle_type = asio::basic_file::native_handle_type; BOOST_ASYNC_DECL native_handle_type native_handle(); BOOST_ASYNC_DECL system::result assign(native_handle_type native_handle); BOOST_ASYNC_DECL system::result release(); private: - asio::basic_file & file_; + asio::basic_file & file_; public: - file(asio::basic_file & file) : file_(file) {} + file(asio::basic_file & file) : file_(file) {} }; } diff --git a/include/boost/async/io/pipe.hpp b/include/boost/async/io/pipe.hpp index 1573a514..e53bd144 100644 --- a/include/boost/async/io/pipe.hpp +++ b/include/boost/async/io/pipe.hpp @@ -24,7 +24,7 @@ struct readable_pipe final : stream BOOST_ASYNC_DECL system::result cancel() override; BOOST_ASYNC_DECL bool is_open() const override; - using native_handle_type = typename asio::basic_readable_pipe::native_handle_type; + using native_handle_type = typename asio::basic_readable_pipe::native_handle_type; native_handle_type native_handle() {return pipe_.native_handle();} BOOST_ASYNC_DECL readable_pipe(); @@ -43,7 +43,7 @@ struct readable_pipe final : stream BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; friend system::result> make_pipe(); - asio::basic_readable_pipe pipe_; + asio::basic_readable_pipe pipe_; }; struct writable_pipe final : stream @@ -52,7 +52,7 @@ struct writable_pipe final : stream BOOST_ASYNC_DECL system::result cancel() override; BOOST_ASYNC_DECL bool is_open() const override; - using native_handle_type = typename asio::basic_readable_pipe::native_handle_type; + using native_handle_type = typename asio::basic_readable_pipe::native_handle_type; native_handle_type native_handle() {return pipe_.native_handle();} BOOST_ASYNC_DECL writable_pipe(); @@ -68,7 +68,7 @@ struct writable_pipe final : stream BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; friend system::result> make_pipe(); - asio::basic_writable_pipe pipe_; + asio::basic_writable_pipe pipe_; }; system::result> make_pipe(); diff --git a/include/boost/async/io/random_access_file.hpp b/include/boost/async/io/random_access_file.hpp index 98760178..a34873b1 100644 --- a/include/boost/async/io/random_access_file.hpp +++ b/include/boost/async/io/random_access_file.hpp @@ -32,7 +32,7 @@ struct random_access_file : file, random_access_device private: BOOST_ASYNC_DECL void async_read_some_at_impl_ (std::uint64_t offset, buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; BOOST_ASYNC_DECL void async_write_some_at_impl_(std::uint64_t offset, buffers::const_buffer_subspan buffer, async::completion_handler h) override; - asio::basic_random_access_file random_access_file_; + asio::basic_random_access_file random_access_file_; }; } diff --git a/include/boost/async/io/resolver.hpp b/include/boost/async/io/resolver.hpp index 3d3f32f7..76ef5716 100644 --- a/include/boost/async/io/resolver.hpp +++ b/include/boost/async/io/resolver.hpp @@ -33,7 +33,7 @@ struct resolver struct resolve_op_ : detail::deferred_op_resource_base { - using result_type = asio::ip::basic_resolver::results_type; + using result_type = asio::ip::basic_resolver::results_type; constexpr static bool await_ready() { return false; } @@ -53,11 +53,11 @@ struct resolver } [[nodiscard]] resolve_result await_resume(); - resolve_op_(asio::ip::basic_resolver & resolver, + resolve_op_(asio::ip::basic_resolver & resolver, core::string_view host, core::string_view service) : resolver_(resolver), host_(host), service_(service) {} private: - asio::ip::basic_resolver & resolver_; + asio::ip::basic_resolver & resolver_; core::string_view host_; core::string_view service_; std::exception_ptr error; @@ -76,7 +76,7 @@ struct resolver private: - asio::ip::basic_resolver resolver_; + asio::ip::basic_resolver resolver_; }; // NOTE: Doesn't need to be a promise, can be optimized. diff --git a/include/boost/async/io/seq_packet_socket.hpp b/include/boost/async/io/seq_packet_socket.hpp index 4a424815..f18c96e0 100644 --- a/include/boost/async/io/seq_packet_socket.hpp +++ b/include/boost/async/io/seq_packet_socket.hpp @@ -53,7 +53,7 @@ struct [[nodiscard]] seq_packet_socket final : socket [[nodiscard]] BOOST_ASYNC_DECL send_op_seq_ send(buffers::const_buffer_span buffers, message_flags out_flags); [[nodiscard]] BOOST_ASYNC_DECL send_op_ send(buffers::const_buffer buffer, message_flags out_flags); - asio::basic_seq_packet_socket seq_packet_socket_; + asio::basic_seq_packet_socket seq_packet_socket_; }; diff --git a/include/boost/async/io/serial_port.hpp b/include/boost/async/io/serial_port.hpp index 18096cf1..96615546 100644 --- a/include/boost/async/io/serial_port.hpp +++ b/include/boost/async/io/serial_port.hpp @@ -40,7 +40,7 @@ struct [[nodiscard]] serial_port final : stream [[nodiscard]] BOOST_ASYNC_DECL system::result set_parity(parity rate); [[nodiscard]] BOOST_ASYNC_DECL system::result get_parity(); - using native_handle_type = typename asio::basic_serial_port::native_handle_type; + using native_handle_type = typename asio::basic_serial_port::native_handle_type; native_handle_type native_handle() {return serial_port_.native_handle();} BOOST_ASYNC_DECL serial_port(); @@ -58,7 +58,7 @@ struct [[nodiscard]] serial_port final : stream BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; - asio::basic_serial_port serial_port_; + asio::basic_serial_port serial_port_; }; diff --git a/include/boost/async/io/signal_set.hpp b/include/boost/async/io/signal_set.hpp index 22e66dbf..3761cbf7 100644 --- a/include/boost/async/io/signal_set.hpp +++ b/include/boost/async/io/signal_set.hpp @@ -63,9 +63,9 @@ struct signal_set else return sig; } - wait_op_(boost::asio::basic_signal_set & signal_set) : signal_set_(signal_set) {} + wait_op_(boost::asio::basic_signal_set & signal_set) : signal_set_(signal_set) {} private: - boost::asio::basic_signal_set & signal_set_; + boost::asio::basic_signal_set & signal_set_; std::exception_ptr error; std::optional> result_; }; @@ -73,7 +73,7 @@ struct signal_set [[nodiscard]] wait_op_ wait() { return wait_op_{signal_set_}; } wait_op_ operator co_await () { return wait(); } private: - boost::asio::basic_signal_set signal_set_; + boost::asio::basic_signal_set signal_set_; }; diff --git a/include/boost/async/io/socket.hpp b/include/boost/async/io/socket.hpp index 516f0f47..2d154dba 100644 --- a/include/boost/async/io/socket.hpp +++ b/include/boost/async/io/socket.hpp @@ -34,7 +34,7 @@ struct socket constexpr static int message_do_not_route = asio::socket_base::message_do_not_route; constexpr static int message_end_of_record = asio::socket_base::message_end_of_record; - using native_handle_type = asio::basic_socket::native_handle_type; + using native_handle_type = asio::basic_socket::native_handle_type; native_handle_type native_handle(); [[nodiscard]] BOOST_ASYNC_DECL system::result shutdown(shutdown_type = shutdown_type::shutdown_both); @@ -85,10 +85,10 @@ struct socket struct connect_op_; struct wait_op_; friend struct acceptor; - asio::basic_socket & socket_; + asio::basic_socket & socket_; public: - socket(asio::basic_socket & socket) : socket_(socket) {} + socket(asio::basic_socket & socket) : socket_(socket) {} BOOST_ASYNC_DECL connect_op_ connect(endpoint ep); BOOST_ASYNC_DECL wait_op_ wait(wait_type = wait_type::wait_read); diff --git a/include/boost/async/io/ssl.hpp b/include/boost/async/io/ssl.hpp index e10d5b04..fb4f265b 100644 --- a/include/boost/async/io/ssl.hpp +++ b/include/boost/async/io/ssl.hpp @@ -22,7 +22,7 @@ struct ssl_stream_base template ssl_stream_base(Args && ...args) : ssl_stream_(std::forward(args)...) {} - asio::ssl::stream> ssl_stream_; + asio::ssl::stream> ssl_stream_; }; } diff --git a/include/boost/async/io/steady_timer.hpp b/include/boost/async/io/steady_timer.hpp index 7942cb5b..bd056d02 100644 --- a/include/boost/async/io/steady_timer.hpp +++ b/include/boost/async/io/steady_timer.hpp @@ -82,7 +82,7 @@ struct steady_timer private: boost::asio::basic_waitable_timer, - executor_type> timer_; + executor> timer_; }; } diff --git a/include/boost/async/io/stream_file.hpp b/include/boost/async/io/stream_file.hpp index 1ec20b9b..1737d9b9 100644 --- a/include/boost/async/io/stream_file.hpp +++ b/include/boost/async/io/stream_file.hpp @@ -32,7 +32,7 @@ struct stream_file : file, stream private: BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; - asio::basic_stream_file stream_file_; + asio::basic_stream_file stream_file_; }; diff --git a/include/boost/async/io/stream_socket.hpp b/include/boost/async/io/stream_socket.hpp index 5f39af1f..c27ede75 100644 --- a/include/boost/async/io/stream_socket.hpp +++ b/include/boost/async/io/stream_socket.hpp @@ -32,7 +32,7 @@ struct [[nodiscard]] stream_socket final : stream, socket private: BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; - asio::basic_stream_socket stream_socket_; + asio::basic_stream_socket stream_socket_; friend struct ssl_stream; BOOST_ASYNC_DECL void adopt_endpoint_(endpoint & ep) override; }; diff --git a/include/boost/async/io/system_timer.hpp b/include/boost/async/io/system_timer.hpp index 49aff730..c4aafe5f 100644 --- a/include/boost/async/io/system_timer.hpp +++ b/include/boost/async/io/system_timer.hpp @@ -80,7 +80,7 @@ struct system_timer final private: boost::asio::basic_waitable_timer, - executor_type> timer_; + executor> timer_; }; } diff --git a/src/io/pipe.cpp b/src/io/pipe.cpp index 59470938..1bb67d9e 100644 --- a/src/io/pipe.cpp +++ b/src/io/pipe.cpp @@ -53,7 +53,7 @@ void readable_pipe::async_write_some_impl_( h(ec, 0ul); } else - asio::post(h.executor, asio::append(std::move(h), ec, 0ul)); + asio::post(h.executor_, asio::append(std::move(h), ec, 0ul)); } @@ -123,7 +123,7 @@ void writable_pipe::async_read_some_impl_( h(ec, 0ul); } else - asio::post(h.executor, asio::append(std::move(h), ec, 0ul)); + asio::post(h.executor_, asio::append(std::move(h), ec, 0ul)); } system::result writable_pipe::assign(native_handle_type native_handle) From 5e1375f7b883e1df26c7b604ccbbd9ad28b8fe9e Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Sat, 1 Jul 2023 13:41:23 +0800 Subject: [PATCH 21/43] added process support. --- CMakeLists.txt | 5 +- include/boost/async/io/popen.hpp | 62 +++++++++++++++ include/boost/async/io/process.hpp | 115 ++++++++++++++++++++++++++++ include/boost/async/io/resolver.hpp | 1 - src/io/popen.cpp | 109 ++++++++++++++++++++++++++ src/io/process.cpp | 87 +++++++++++++++++++++ test/io/CMakeLists.txt | 3 +- test/io/process.cpp | 39 ++++++++++ 8 files changed, 418 insertions(+), 3 deletions(-) create mode 100644 include/boost/async/io/popen.hpp create mode 100644 include/boost/async/io/process.hpp create mode 100644 src/io/popen.cpp create mode 100644 src/io/process.cpp create mode 100644 test/io/process.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 541c2aad..f5ec30ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,10 +112,13 @@ add_library(boost_async src/io/read.cpp src/io/read_at.cpp src/io/read_until.cpp + src/io/popen.cpp + src/io/process.cpp src/io/buffers/register.cpp src/io/write.cpp src/io/write_at.cpp - src/io/detail/random_access_device.cpp src/io/copy.cpp) + src/io/detail/random_access_device.cpp + src/io/copy.cpp) target_include_directories(boost_async PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(boost_async PUBLIC diff --git a/include/boost/async/io/popen.hpp b/include/boost/async/io/popen.hpp new file mode 100644 index 00000000..59097572 --- /dev/null +++ b/include/boost/async/io/popen.hpp @@ -0,0 +1,62 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_POPEN_HPP +#define BOOST_ASYNC_IO_POPEN_HPP + +#include +#include +#include +#include + +namespace boost::async::io +{ + +struct popen : stream +{ + using wait_result = system::result; + using handle_type = typename boost::process::v2::basic_process::handle_type; + using native_handle_type = typename boost::process::v2::basic_process::native_handle_type; + + BOOST_ASYNC_DECL popen(boost::process::v2::filesystem::path executable, + std::initializer_list args, + process_initializer initializer = {}); + + + BOOST_ASYNC_DECL popen(boost::process::v2::filesystem::path executable, + std::span args, + process_initializer initializer = {}); + + [[nodiscard]] BOOST_ASYNC_DECL system::result interrupt(); + [[nodiscard]] BOOST_ASYNC_DECL system::result request_exit(); + [[nodiscard]] BOOST_ASYNC_DECL system::result suspend(); + [[nodiscard]] BOOST_ASYNC_DECL system::result resume(); + [[nodiscard]] BOOST_ASYNC_DECL system::result terminate(); + [[nodiscard]] BOOST_ASYNC_DECL handle_type detach(); + [[nodiscard]] BOOST_ASYNC_DECL system::result running(); + + + [[nodiscard]] pid_type id() const; + + [[nodiscard]] system::result close() override; + [[nodiscard]] system::result cancel() override; + [[nodiscard]] bool is_open() const override; + + private: + void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h)override; + void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; + public: + [[nodiscard]] process::wait_op_ wait() { return process::wait_op_{popen_}; } + process::wait_op_ operator co_await () { return wait(); } + private: + boost::process::v2::basic_popen popen_; +}; + + +} + +#endif //BOOST_ASYNC_IO_POPEN_HPP diff --git a/include/boost/async/io/process.hpp b/include/boost/async/io/process.hpp new file mode 100644 index 00000000..6c6401cb --- /dev/null +++ b/include/boost/async/io/process.hpp @@ -0,0 +1,115 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_PROCESS_HPP +#define BOOST_ASYNC_IO_PROCESS_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost::async::io +{ + +using boost::process::v2::pid_type; + +struct process_initializer +{ + process::v2::process_stdio stdio; + process::v2::process_start_dir start_dir{process::v2::filesystem::current_path()}; + process::v2::process_environment env{process::v2::environment::current()}; +}; + +struct process +{ + using wait_result = system::result; + using handle_type = typename boost::process::v2::basic_process::handle_type; + using native_handle_type = typename boost::process::v2::basic_process::native_handle_type; + + BOOST_ASYNC_DECL process(boost::process::v2::filesystem::path executable, + std::initializer_list args, + process_initializer initializer = {}); + + + BOOST_ASYNC_DECL process(boost::process::v2::filesystem::path executable, + std::span args, + process_initializer initializer = {}); + + BOOST_ASYNC_DECL process(pid_type pid); + BOOST_ASYNC_DECL process(pid_type pid, native_handle_type native_handle); + + [[nodiscard]] BOOST_ASYNC_DECL system::result interrupt(); + [[nodiscard]] BOOST_ASYNC_DECL system::result request_exit(); + [[nodiscard]] BOOST_ASYNC_DECL system::result suspend(); + [[nodiscard]] BOOST_ASYNC_DECL system::result resume(); + [[nodiscard]] BOOST_ASYNC_DECL system::result terminate(); + [[nodiscard]] BOOST_ASYNC_DECL handle_type detach(); + [[nodiscard]] BOOST_ASYNC_DECL system::result running(); + + + [[nodiscard]] pid_type id() const; + + private: + struct wait_op_ : detail::deferred_op_resource_base + { + constexpr static bool await_ready() { return false; } + + BOOST_ASYNC_DECL void init_op(completion_handler handler); + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + init_op(completion_handler{h, result_, get_resource(h)}); + return true; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] wait_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + auto [ec, sig] = result_.value_or(std::make_tuple(system::error_code{}, 0)); + if (ec) + return ec; + else + return sig; + } + wait_op_(boost::process::v2::basic_process & process) : process_(process) {} + private: + boost::process::v2::basic_process & process_; + std::exception_ptr error; + std::optional> result_; + char buffer[256]; + std::optional resource; + }; + public: + [[nodiscard]] wait_op_ wait() { return wait_op_{process_}; } + wait_op_ operator co_await () { return wait(); } + private: + boost::process::v2::basic_process process_; + friend struct popen; +}; + + +} + +#endif //BOOST_ASYNC_IO_PROCESS_HPP diff --git a/include/boost/async/io/resolver.hpp b/include/boost/async/io/resolver.hpp index 76ef5716..f2be328a 100644 --- a/include/boost/async/io/resolver.hpp +++ b/include/boost/async/io/resolver.hpp @@ -79,7 +79,6 @@ struct resolver asio::ip::basic_resolver resolver_; }; -// NOTE: Doesn't need to be a promise, can be optimized. struct lookup { lookup(core::string_view host, core::string_view service) diff --git a/src/io/popen.cpp b/src/io/popen.cpp new file mode 100644 index 00000000..fadf8bfb --- /dev/null +++ b/src/io/popen.cpp @@ -0,0 +1,109 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include + +namespace boost::async::io +{ + +popen::popen(boost::process::v2::filesystem::path executable, + std::initializer_list args, + process_initializer initializer) + : popen_(this_thread::get_executor(), + executable, + args, + initializer.stdio, + initializer.start_dir, + initializer.env) {} + + +popen::popen(boost::process::v2::filesystem::path executable, + std::span args, + process_initializer initializer) + : popen_(this_thread::get_executor(), + executable, + args, + initializer.stdio, + initializer.start_dir, + initializer.env) {} + +pid_type popen::id() const {return popen_.id();} + +system::result popen::interrupt() +{ + system::error_code ec; + popen_.interrupt(ec); + return ec ? ec : system::result(); +} +system::result popen::request_exit() +{ + system::error_code ec; + popen_.request_exit(ec); + return ec ? ec : system::result(); +} +system::result popen::suspend() +{ + system::error_code ec; + popen_.suspend(ec); + return ec ? ec : system::result(); +} +system::result popen::resume() +{ + system::error_code ec; + popen_.resume(ec); + return ec ? ec : system::result(); +} +system::result popen::terminate() +{ + system::error_code ec; + popen_.terminate(ec); + return ec ? ec : system::result(); +} +popen::handle_type popen::detach() +{ + return popen_.detach(); +} +system::result popen::running() +{ + system::error_code ec; + auto res = popen_.running(ec); + return ec ? ec : system::result(res); +} + +system::result popen::close() +{ + return this->terminate(); +} + +system::result popen::cancel() +{ + system::error_code ec; + popen_.get_stdin().cancel(ec); + if (ec) + return ec; + popen_.get_stdout().cancel(ec); + if (ec) + return ec; + return {}; +} + +bool popen::is_open() const +{ + return this->popen_.is_open(); +} + +void popen::async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) +{ + popen_.async_read_some(buffer, std::move(h)); +} +void popen::async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) +{ + popen_.async_write_some(buffer, std::move(h)); +} + + +} \ No newline at end of file diff --git a/src/io/process.cpp b/src/io/process.cpp new file mode 100644 index 00000000..ed5e140a --- /dev/null +++ b/src/io/process.cpp @@ -0,0 +1,87 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include + +namespace boost::async::io +{ + +process::process(boost::process::v2::filesystem::path executable, + std::initializer_list args, + process_initializer initializer) + : process_(this_thread::get_executor(), + executable, + args, + initializer.stdio, + initializer.start_dir, + initializer.env) {} + + +process::process(boost::process::v2::filesystem::path executable, + std::span args, + process_initializer initializer) + : process_(this_thread::get_executor(), + executable, + args, + initializer.stdio, + initializer.start_dir, + initializer.env) {} + + +process::process(pid_type pid) : process_(this_thread::get_executor(), pid) {} +process::process(pid_type pid, native_handle_type native_handle) + : process_(this_thread::get_executor(), pid, native_handle) {} + +void process::wait_op_::init_op(completion_handler handler) +{ + process_.async_wait(std::move(handler)); +} + +pid_type process::id() const {return process_.id();} + +system::result process::interrupt() +{ + system::error_code ec; + process_.interrupt(ec); + return ec ? ec : system::result(); +} +system::result process::request_exit() +{ + system::error_code ec; + process_.request_exit(ec); + return ec ? ec : system::result(); +} +system::result process::suspend() +{ + system::error_code ec; + process_.suspend(ec); + return ec ? ec : system::result(); +} +system::result process::resume() +{ + system::error_code ec; + process_.resume(ec); + return ec ? ec : system::result(); +} +system::result process::terminate() +{ + system::error_code ec; + process_.terminate(ec); + return ec ? ec : system::result(); +} +process::handle_type process::detach() +{ + return process_.detach(); +} +system::result process::running() +{ + system::error_code ec; + auto res = process_.running(ec); + return ec ? ec : system::result(res); +} + +} \ No newline at end of file diff --git a/test/io/CMakeLists.txt b/test/io/CMakeLists.txt index 4e7aa4d9..b0978b4b 100644 --- a/test/io/CMakeLists.txt +++ b/test/io/CMakeLists.txt @@ -13,6 +13,7 @@ add_executable(boost_async_io_tests ../doctest.cpp read.cpp copy.cpp - read_until.cpp) + read_until.cpp + process.cpp) target_link_libraries(boost_async_io_tests Boost::container Boost::async OpenSSL::SSL) add_test(NAME boost_async-io COMMAND boost_async_io_tests) diff --git a/test/io/process.cpp b/test/io/process.cpp new file mode 100644 index 00000000..9acf10b9 --- /dev/null +++ b/test/io/process.cpp @@ -0,0 +1,39 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include "../doctest.h" +#include "../test.hpp" +#include + +#include + +using namespace boost::async; +namespace bpv = boost::process::v2; + +#if defined(BOOST_PROCESS_V2_WINDOWS) +bpv::filesystem::path shell() +{ + return bpv::environment::find_executable("cmd"); +} +#else +bpv::filesystem::path shell() +{ + return bpv::environment::find_executable("sh"); +} +#endif + +CO_TEST_CASE("process") +{ + +#if defined(BOOST_PROCESS_V2_WINDOWS) + CHECK(42 == co_await io::process(bpv::environment::find_executable("cmd"), {"/c", "exit 42"})); + +#else + CHECK(42 == co_await io::process(bpv::environment::find_executable("sh"), {"-c", "exit 42"})); +#endif +} + From 71e072a5c9f2c5f2e7f10e38964f315414250c90 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Sun, 2 Jul 2023 10:45:29 +0800 Subject: [PATCH 22/43] buffer tweaks. --- .../async/io/buffers/any_dynamic_buffer.hpp | 2 +- include/boost/async/io/buffers/buffer.hpp | 18 +++------- .../boost/async/io/buffers/const_buffer.hpp | 34 ++++++++++++++----- .../boost/async/io/buffers/flat_buffer.hpp | 20 +++++++++++ .../boost/async/io/buffers/mutable_buffer.hpp | 29 +++++++++++----- .../boost/async/io/buffers/string_buffer.hpp | 14 ++++---- include/boost/async/io/stream.hpp | 9 ++++- test/io/buffers/string_buffer.cpp | 10 +++++- test/io/pipe.cpp | 4 +-- 9 files changed, 97 insertions(+), 43 deletions(-) diff --git a/include/boost/async/io/buffers/any_dynamic_buffer.hpp b/include/boost/async/io/buffers/any_dynamic_buffer.hpp index 6dacd252..308d226d 100644 --- a/include/boost/async/io/buffers/any_dynamic_buffer.hpp +++ b/include/boost/async/io/buffers/any_dynamic_buffer.hpp @@ -45,7 +45,7 @@ struct any_dynamic_buffer */ template< class DynamicBuffer, - std::size_t N = 8> + std::size_t N = asio::detail::max_iov_len> class any_dynamic_buffer_impl : public any_dynamic_buffer { diff --git a/include/boost/async/io/buffers/buffer.hpp b/include/boost/async/io/buffers/buffer.hpp index 103a0f07..7b933959 100644 --- a/include/boost/async/io/buffers/buffer.hpp +++ b/include/boost/async/io/buffers/buffer.hpp @@ -62,13 +62,8 @@ buffer( /** Return a buffer. */ -template< - class T, std::size_t N -#ifndef BOOST_BUFFERS_DOCS - , class = typename std::enable_if< - std::is_trivially_copyable::value>::type -#endif -> +template + requires std::is_trivially_copyable::value mutable_buffer buffer( T (&data)[N]) noexcept @@ -79,13 +74,8 @@ buffer( /** Return a buffer. */ -template< - class T, std::size_t N -#ifndef BOOST_BUFFERS_DOCS - , class = typename std::enable_if< - std::is_trivially_copyable::value>::type -#endif -> +template + requires std::is_trivially_copyable::value const_buffer buffer( T const (&data)[N]) noexcept diff --git a/include/boost/async/io/buffers/const_buffer.hpp b/include/boost/async/io/buffers/const_buffer.hpp index 4e61000c..5da252b4 100644 --- a/include/boost/async/io/buffers/const_buffer.hpp +++ b/include/boost/async/io/buffers/const_buffer.hpp @@ -38,6 +38,27 @@ class const_buffer { } + /** Constructor + */ + template + requires ( + requires (const Container & ct) + { + {ct.data()} -> std::convertible_to; + {ct.size()} -> std::convertible_to; + } + && std::is_trivial_v) + const_buffer(Container & ct) : const_buffer(ct.data(), ct.size()) {} + + /** Constructor for strings */ + template + const_buffer(const char (&string)[N]) : const_buffer(string, std::strlen(string)) {} + + /** Constructor for strings */ + template + requires std::is_trivial_v + const_buffer(const T (&arr)[N]) : const_buffer(&arr[0], sizeof(T) * N) {} + /** Constructor. */ const_buffer( @@ -60,15 +81,10 @@ class const_buffer #ifndef BOOST_BUFFERS_DOCS // conversion to boost::asio::const_buffer - template< - class T - , class = typename std::enable_if< - std::is_constructible::value && - ! std::is_same::value && - ! std::is_same::value - >::type - > + template + requires (std::constructible_from + && !std::same_as + && !std::same_as) operator T() const noexcept { return T{ data(), size() }; diff --git a/include/boost/async/io/buffers/flat_buffer.hpp b/include/boost/async/io/buffers/flat_buffer.hpp index 8eaefcb3..583c82db 100644 --- a/include/boost/async/io/buffers/flat_buffer.hpp +++ b/include/boost/async/io/buffers/flat_buffer.hpp @@ -54,6 +54,26 @@ class flat_buffer async::detail::throw_invalid_argument(); } + + /** Constructor. + */ + template + requires requires (Container & container) + { + {container.data()} -> std::convertible_to; + {container.size()} -> std::convertible_to; + } + flat_buffer(Container & cont, + std::size_t initial_size = 0) + : data_(cont.data()) + , cap_(cont.size()) + , in_size_(initial_size) + { + // initial size too large + if(in_size_ > cap_) + async::detail::throw_invalid_argument(); + } + /** Constructor. */ explicit diff --git a/include/boost/async/io/buffers/mutable_buffer.hpp b/include/boost/async/io/buffers/mutable_buffer.hpp index 372e7f07..98e3bd29 100644 --- a/include/boost/async/io/buffers/mutable_buffer.hpp +++ b/include/boost/async/io/buffers/mutable_buffer.hpp @@ -49,6 +49,23 @@ class mutable_buffer { } + /** Constructor + */ + template + requires ( + requires (Container & ct) + { + {std::data(ct)} -> std::convertible_to; + {std::size(ct)} -> std::convertible_to; + } + && std::is_trivial_v) + mutable_buffer(Container & ct) : mutable_buffer(std::data(ct), std::size(ct)) {} + + /** Constructor for arrays */ + template + requires std::is_trivial_v + mutable_buffer(T (&arr)[N]) : mutable_buffer(&arr[0], sizeof(T) * N) {} + /** Assignment. */ mutable_buffer& operator=( @@ -56,15 +73,9 @@ class mutable_buffer #ifndef BOOST_BUFFERS_DOCS // conversion to boost::asio::mutable_buffer - template< - class T - , class = typename std::enable_if< - std::is_constructible::value - && ! std::is_same::value - //&& ! std::is_same::value - >::type - > + template + requires (std::constructible_from + && !std::same_as) operator T() const noexcept { return T{ data(), size() }; diff --git a/include/boost/async/io/buffers/string_buffer.hpp b/include/boost/async/io/buffers/string_buffer.hpp index e41a49b2..163e9ae2 100644 --- a/include/boost/async/io/buffers/string_buffer.hpp +++ b/include/boost/async/io/buffers/string_buffer.hpp @@ -87,13 +87,13 @@ class basic_string_buffer std::size_t size() const noexcept { - return in_size_; + return in_size_* sizeof(CharT); } std::size_t max_size() const noexcept { - return max_size_; + return max_size_ * sizeof(CharT); } std::size_t @@ -101,7 +101,7 @@ class basic_string_buffer { if(s_->capacity() <= max_size_) return s_->capacity() - in_size_; - return max_size_ - in_size_; + return (max_size_ - in_size_) * sizeof(CharT); } const_buffers_type @@ -109,12 +109,14 @@ class basic_string_buffer { return { s_->data(), - in_size_ }; + in_size_ * sizeof(CharT)}; } mutable_buffers_type - prepare(std::size_t n) + prepare(std::size_t n_) { + const auto n = (n_ / sizeof(CharT)) + (std::min)(n_ % sizeof(CharT), static_cast(1u)); + // n exceeds available space if(n > max_size_ - in_size_) async::detail::throw_invalid_argument(); @@ -124,7 +126,7 @@ class basic_string_buffer out_size_ = n; return { &(*s_)[in_size_], - out_size_ }; + out_size_ * sizeof(CharT)}; } void diff --git a/include/boost/async/io/stream.hpp b/include/boost/async/io/stream.hpp index 72e76dd0..494b42fd 100644 --- a/include/boost/async/io/stream.hpp +++ b/include/boost/async/io/stream.hpp @@ -41,9 +41,16 @@ struct [[nodiscard]] transfer_result bool operator==(const system::error_code &ec) const { return error == ec;} bool operator!=(const system::error_code &ec) const { return error != ec;} - }; +inline transfer_result & operator+=(transfer_result & lhs, const transfer_result & rhs) +{ + lhs.transferred += rhs.transferred; + if (!lhs.error) + lhs.error = rhs.error; + return lhs; +} + struct stream { [[nodiscard]] virtual system::result close() = 0; diff --git a/test/io/buffers/string_buffer.cpp b/test/io/buffers/string_buffer.cpp index afd59da5..86b6711d 100644 --- a/test/io/buffers/string_buffer.cpp +++ b/test/io/buffers/string_buffer.cpp @@ -22,7 +22,8 @@ struct string_buffer_test void testMembers() { - std::string s; + std::string s; + std::wstring ws = L"1234"; // ~string_buffer { @@ -69,6 +70,13 @@ struct string_buffer_test BOOST_TEST_EQ(b.size(), 4); } + // ws.size() + { + std::u16string ws = u"1234"; + basic_string_buffer b(&ws); + BOOST_TEST_EQ(b.size(), 8); + } + // capacity() { { diff --git a/test/io/pipe.cpp b/test/io/pipe.cpp index 509762da..a0795f69 100644 --- a/test/io/pipe.cpp +++ b/test/io/pipe.cpp @@ -29,8 +29,8 @@ CO_TEST_CASE("pipe") char data[7] = "nodata"; auto [written, read] = - co_await join(w.write_some(io::buffers::buffer("foobar", 6)), - r.read_some(io::buffers::buffer(data))); + co_await join(w.write_some("foobar"), + r.read_some(data)); CHECK(written.transferred == 6u); CHECK(read.transferred == 6u); From 03cfeb7df3cc980278ae8e457ded2951736f3290 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Thu, 29 Jun 2023 21:47:17 +0800 Subject: [PATCH 23/43] removed interrupt_await constant. --- include/boost/async/detail/forward_cancellation.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/async/detail/forward_cancellation.hpp b/include/boost/async/detail/forward_cancellation.hpp index 58157000..35d0c5d1 100644 --- a/include/boost/async/detail/forward_cancellation.hpp +++ b/include/boost/async/detail/forward_cancellation.hpp @@ -15,6 +15,7 @@ namespace boost::async { + // Requests cancellation where a successful cancellation results // in no apparent side effects and where the op can re-awaited. template From 10be212d4ec1f0de879db3207642756c5498d199 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Thu, 29 Jun 2023 21:47:17 +0800 Subject: [PATCH 24/43] added result_op to io. --- include/boost/async/io/result.hpp | 187 ++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 include/boost/async/io/result.hpp diff --git a/include/boost/async/io/result.hpp b/include/boost/async/io/result.hpp new file mode 100644 index 00000000..650a503b --- /dev/null +++ b/include/boost/async/io/result.hpp @@ -0,0 +1,187 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_RESULT_HPP +#define BOOST_ASYNC_IO_RESULT_HPP + +#include +#include +#include + +#include + +namespace boost::async::io +{ + +template +struct result_op +{ + using value_type = T; + using error_type = Error; + + virtual void ready(async::handler h) {}; + virtual void initiate(async::completion_handler complete) = 0 ; + virtual ~result_op() = default; + + result_op() = default; + result_op(result_op && lhs) + : error(std::move(lhs.error)) + , result(std::move(lhs.result)) + { + BOOST_ASSERT(!lhs.resource); + } + + bool await_ready() + { + ready(handler(result)); + return result.has_value(); + } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + auto & res = resource.emplace(buffer, sizeof(buffer), + asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); + initiate(completion_handler{h, result, &res, &completed_immediately}); + return !completed_immediately; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] system::result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + if (std::get<0>(*this->result)) + return system::result(system::in_place_error, std::get<0>(std::move(*this->result))); + else + return system::result(system::in_place_value, std::get<1>(std::move(*this->result))); + } + + struct vawaitable + { + vawaitable(result_op * op_) : op_(op_) {} + + bool await_ready() { return op_->await_ready();} + + template + bool await_suspend(std::coroutine_handle h) + { + return op_->await_suspend(h); + } + + T await_resume(const boost::source_location & loc = BOOST_CURRENT_LOCATION) + { + return op_->await_resume().value(loc); + } + private: + result_op * op_; + }; + + vawaitable value() { return vawaitable{this}; } + private: + std::exception_ptr error; + std::optional> result; + char buffer[2048]; + std::optional resource; + bool completed_immediately = false; +}; + + + +template +struct result_op +{ + using value_type = void; + using error_type = Error; + + virtual void ready(async::handler h) {}; + virtual void initiate(async::completion_handler complete) = 0 ; + virtual ~result_op() = default; + + result_op() noexcept = default; + result_op(result_op && lhs) + : error(std::move(lhs.error)) + , result(std::move(lhs.result)) + { + BOOST_ASSERT(!lhs.resource); + } + + bool await_ready() + { + ready(handler(result)); + return result.has_value(); + } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + auto & res = resource.emplace(buffer, sizeof(buffer), + asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); + initiate(completion_handler{h, result, &res, &completed_immediately}); + return !completed_immediately; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] system::result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + if (std::get<0>(*this->result)) + return system::result(system::in_place_error, std::get<0>(std::move(*this->result))); + else + return system::in_place_value; + + } + + struct vawaitable + { + vawaitable(result_op * op_) : op_(op_) {} + + bool await_ready() { return op_->await_ready();} + + template + bool await_suspend(std::coroutine_handle h) + { + return op_->await_suspend(h); + } + + void await_resume(const boost::source_location & loc = BOOST_CURRENT_LOCATION) + { + op_->await_resume().value(loc); + } + private: + result_op * op_; + }; + + vawaitable value() { return vawaitable{this}; } + + private: + std::exception_ptr error; + std::optional> result; + char buffer[2048]; + std::optional resource; + bool completed_immediately = false; +}; + + +} + +#endif //BOOST_ASYNC_IO_RESULT_HPP From 79cd4a2023e2bfc76ed9907f263259e70e81b077 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 7 Jul 2023 09:13:12 +0800 Subject: [PATCH 25/43] added transfer_result --- include/boost/async/io/transfer_result.hpp | 135 +++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 include/boost/async/io/transfer_result.hpp diff --git a/include/boost/async/io/transfer_result.hpp b/include/boost/async/io/transfer_result.hpp new file mode 100644 index 00000000..a56893e2 --- /dev/null +++ b/include/boost/async/io/transfer_result.hpp @@ -0,0 +1,135 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_TRANSFER_RESULT_HPP +#define BOOST_ASYNC_TRANSFER_RESULT_HPP + +#include +#include +#include +#include +#include + + +namespace boost::async::io +{ + + +struct [[nodiscard]] transfer_result +{ + system::error_code error; + std::size_t transferred; + + using value_type = std::size_t; + using error_type = system::error_code; + + // queries + constexpr bool has_value() const noexcept { return transferred != 0; } + constexpr bool has_error() const noexcept { return error.failed(); } + constexpr explicit operator bool() const noexcept { return has_value() || !has_error(); } + constexpr std::size_t value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const noexcept + { + if (!has_value() || !has_error()) + throw_exception_from_error(error, loc); + return transferred; + } + constexpr std::size_t operator*() const noexcept { BOOST_ASSERT(has_value()); return transferred; } + + bool operator==(const system::error_code &ec) const { return error == ec;} + bool operator!=(const system::error_code &ec) const { return error != ec;} + + auto operator<=>(std::size_t n) const { return value() <=> n;} + bool operator==(std::size_t n) const { return value() == n;} + + template + requires system::is_error_code_enum::value + bool operator==(E e) const { return error == e;} + + template + requires system::is_error_code_enum::value + bool operator!=(E e) const { return error != e;} +}; + + +struct transfer_op +{ + virtual void ready(async::handler h) {}; + virtual void initiate(async::completion_handler complete) = 0 ; + virtual ~transfer_op() = default; + + transfer_op() = default; + transfer_op(transfer_op && lhs) + : error(std::move(lhs.error)) + , result(std::move(lhs.result)) + { + BOOST_ASSERT(!lhs.resource); + } + + constexpr static bool await_ready() + { + return false; + } + + template + bool await_suspend(std::coroutine_handle h) + { + try + { + auto & res = resource.emplace(buffer, sizeof(buffer), + asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); + initiate(completion_handler{h, result, &res, &completed_immediately}); + return !completed_immediately; + } + catch(...) + { + error = std::current_exception(); + return false; + } + } + + [[nodiscard]] transfer_result await_resume() + { + if (error) + std::rethrow_exception(std::exchange(error, nullptr)); + + return transfer_result{std::get<0>(*result), std::get<1>(*result)}; + } + + struct vawaitable + { + vawaitable(transfer_op * op_) : op_(op_) {} + + bool await_ready() { return op_->await_ready();} + + template + bool await_suspend(std::coroutine_handle h) + { + return op_->await_suspend(h); + } + + std::size_t await_resume(const boost::source_location & loc = BOOST_CURRENT_LOCATION) + { + return op_->await_resume().value(loc); + } + private: + transfer_op * op_; + }; + + vawaitable value() { return vawaitable{this}; } + private: + std::exception_ptr error; + std::optional> result; + char buffer[2048]; + std::optional resource; + bool completed_immediately = false; +}; + + + +} + +#endif //BOOST_ASYNC_TRANSFER_RESULT_HPP From ed5f3543ca0d037fe2f88bad62639a9097f7a521 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 7 Jul 2023 11:09:33 +0800 Subject: [PATCH 26/43] moved to transfer_result & result_op --- include/boost/async/io/acceptor.hpp | 79 +----- .../boost/async/io/detail/datagram_socket.hpp | 234 ++---------------- .../async/io/detail/random_access_device.hpp | 112 +-------- .../async/io/detail/seq_packet_socket.hpp | 116 +-------- include/boost/async/io/detail/socket.hpp | 68 +---- include/boost/async/io/detail/ssl.hpp | 132 +--------- include/boost/async/io/detail/stream.hpp | 127 +--------- include/boost/async/io/endpoint.hpp | 15 +- include/boost/async/io/process.hpp | 39 +-- include/boost/async/io/resolver.hpp | 29 +-- include/boost/async/io/result.hpp | 4 +- include/boost/async/io/signal_set.hpp | 36 +-- include/boost/async/io/sleep.hpp | 8 +- include/boost/async/io/steady_timer.hpp | 40 +-- include/boost/async/io/stream.hpp | 29 --- include/boost/async/io/system_timer.hpp | 39 +-- include/boost/async/io/transfer_result.hpp | 12 +- src/io/acceptor.cpp | 9 +- src/io/datagram_socket.cpp | 16 +- src/io/detail/stream.cpp | 21 ++ src/io/process.cpp | 2 +- src/io/resolver.cpp | 29 +-- src/io/seq_packet_socket.cpp | 8 +- src/io/signal_set.cpp | 2 +- src/io/socket.cpp | 4 +- src/io/ssl.cpp | 10 +- src/io/steady_timer.cpp | 2 +- src/io/system_timer.cpp | 2 +- test/io/acceptor.cpp | 18 +- test/io/copy.cpp | 1 + test/io/sleep.cpp | 8 +- test/io/ssl.cpp | 2 +- 32 files changed, 210 insertions(+), 1043 deletions(-) diff --git a/include/boost/async/io/acceptor.hpp b/include/boost/async/io/acceptor.hpp index 01353fd5..39397f0b 100644 --- a/include/boost/async/io/acceptor.hpp +++ b/include/boost/async/io/acceptor.hpp @@ -8,6 +8,7 @@ #ifndef BOOST_ASYNC_IO_ACCEPTOR_HPP #define BOOST_ASYNC_IO_ACCEPTOR_HPP +#include #include #include #include @@ -26,84 +27,20 @@ struct acceptor private: - struct accept_op_ : detail::deferred_op_resource_base + struct accept_op_ final : result_op { - constexpr static bool await_ready() { return false; } + accept_op_(asio::basic_socket_acceptor & acceptor, + socket &socket) + : acceptor_(acceptor), socket_(socket) {} + BOOST_ASYNC_DECL void initiate(completion_handler h) override; - template - bool await_suspend(std::coroutine_handle h) - { - try - { - acceptor_.template async_accept(socket_.socket_, completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - - [[nodiscard]] system::result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - auto [ec] = result_.value_or(std::make_tuple(system::error_code{})); - if (ec) - return ec; - else - return std::move(socket_); - } - accept_op_( asio::basic_socket_acceptor & acceptor) - : acceptor_(acceptor) {} private: asio::basic_socket_acceptor & acceptor_; - stream_socket socket_; - std::exception_ptr error; - std::optional> result_; + socket &socket_; }; - struct accept_seq_op_ : detail::deferred_op_resource_base - { - constexpr static bool await_ready() { return false; } - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - acceptor_.template async_accept(socket_.socket_, completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - - [[nodiscard]] system::result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - auto [ec] = result_.value_or(std::make_tuple(system::error_code{})); - if (ec) - return ec; - else - return std::move(socket_); - } - accept_seq_op_(asio::basic_socket_acceptor & acceptor) - : acceptor_(acceptor) {} - private: - asio::basic_socket_acceptor & acceptor_; - seq_packet_socket socket_; - std::exception_ptr error; - std::optional> result_; - }; public: - [[nodiscard]] BOOST_ASYNC_DECL accept_op_ accept(); - [[nodiscard]] BOOST_ASYNC_DECL accept_seq_op_ accept_seq_packet(); + [[nodiscard]] BOOST_ASYNC_DECL accept_op_ accept(socket & sock); private: asio::basic_socket_acceptor acceptor_; }; diff --git a/include/boost/async/io/detail/datagram_socket.hpp b/include/boost/async/io/detail/datagram_socket.hpp index 1631c923..74c5a3dc 100644 --- a/include/boost/async/io/detail/datagram_socket.hpp +++ b/include/boost/async/io/detail/datagram_socket.hpp @@ -14,68 +14,20 @@ namespace boost::async::io { -struct datagram_socket::receive_op_ : detail::deferred_op_resource_base +struct datagram_socket::receive_op_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - initiate_(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } receive_op_(asio::basic_datagram_socket & rs, buffers::mutable_buffer buffer) : datagram_socket_(rs), buffer_(buffer) {} + void initiate(async::completion_handler h) override; private: - void initiate_(async::completion_handler h); asio::basic_datagram_socket &datagram_socket_; buffers::mutable_buffer buffer_; - std::exception_ptr error; - std::optional> result_; }; -struct datagram_socket::receive_op_seq_ : detail::deferred_op_resource_base +struct datagram_socket::receive_op_seq_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - initiate_(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } receive_op_seq_(asio::basic_datagram_socket & rs, buffers::mutable_buffer_subspan buffer) : datagram_socket_(rs), buffer_(buffer) {} @@ -83,235 +35,83 @@ struct datagram_socket::receive_op_seq_ : detail::deferred_op_resource_base receive_op_seq_(asio::basic_datagram_socket & rs, buffers::mutable_buffer_span buffer) : datagram_socket_(rs), buffer_(buffer) {} + void initiate(async::completion_handler h) override; private: - void initiate_(async::completion_handler h); asio::basic_datagram_socket &datagram_socket_; buffers::mutable_buffer_subspan buffer_; - std::exception_ptr error; - std::optional> result_; }; -struct datagram_socket::receive_from_op_ : detail::deferred_op_resource_base +struct datagram_socket::receive_from_op_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - initiate_(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } receive_from_op_(asio::basic_datagram_socket & rs, buffers::mutable_buffer buffer, endpoint & ep) : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} + void initiate(async::completion_handler h); private: - void initiate_(async::completion_handler h); asio::basic_datagram_socket &datagram_socket_; buffers::mutable_buffer buffer_; endpoint &ep_; - - std::exception_ptr error; - std::optional> result_; }; -struct datagram_socket::receive_from_op_seq_ : detail::deferred_op_resource_base +struct datagram_socket::receive_from_op_seq_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - initiate_(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } receive_from_op_seq_(asio::basic_datagram_socket & rs, buffers::mutable_buffer_subspan buffer, endpoint & ep) : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} receive_from_op_seq_(asio::basic_datagram_socket & rs, buffers::mutable_buffer_span buffer, endpoint & ep) : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} + void initiate(async::completion_handler h); private: - void initiate_(async::completion_handler h); asio::basic_datagram_socket &datagram_socket_; buffers::mutable_buffer_subspan buffer_; endpoint & ep_; - std::exception_ptr error; - std::optional> result_; }; -struct datagram_socket::send_op_ : detail::deferred_op_resource_base +struct datagram_socket::send_op_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - initiate_(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } send_op_(asio::basic_datagram_socket & rs, buffers::const_buffer buffer) : datagram_socket_(rs), buffer_(buffer) {} + void initiate(async::completion_handler h); private: - void initiate_(async::completion_handler h); asio::basic_datagram_socket &datagram_socket_; buffers::const_buffer buffer_; - std::exception_ptr error; - std::optional> result_; }; -struct datagram_socket::send_op_seq_ : detail::deferred_op_resource_base +struct datagram_socket::send_op_seq_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - initiate_(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } send_op_seq_(asio::basic_datagram_socket & rs, buffers::const_buffer_subspan buffer) : datagram_socket_(rs), buffer_(buffer) {} send_op_seq_(asio::basic_datagram_socket & rs, buffers::const_buffer_span buffer) : datagram_socket_(rs), buffer_(buffer) {} + void initiate(async::completion_handler h); private: - void initiate_(async::completion_handler h); asio::basic_datagram_socket &datagram_socket_; buffers::const_buffer_subspan buffer_; - std::exception_ptr error; - std::optional> result_; }; -struct datagram_socket::send_to_op_ : detail::deferred_op_resource_base +struct datagram_socket::send_to_op_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - initiate_(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } send_to_op_(asio::basic_datagram_socket & rs, buffers::const_buffer buffer, const endpoint & ep) : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} + void initiate(async::completion_handler h); private: - void initiate_(async::completion_handler h); asio::basic_datagram_socket &datagram_socket_; buffers::const_buffer buffer_; const endpoint &ep_; - - std::exception_ptr error; - std::optional> result_; }; -struct datagram_socket::send_to_op_seq_ : detail::deferred_op_resource_base +struct datagram_socket::send_to_op_seq_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - initiate_(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } send_to_op_seq_(asio::basic_datagram_socket & rs, buffers::const_buffer_subspan buffer, const endpoint & ep) : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} @@ -319,13 +119,11 @@ struct datagram_socket::send_to_op_seq_ : detail::deferred_op_resource_base send_to_op_seq_(asio::basic_datagram_socket & rs, buffers::const_buffer_span buffer, const endpoint & ep) : datagram_socket_(rs), buffer_(buffer), ep_(ep) {} + void initiate(async::completion_handler h); private: - void initiate_(async::completion_handler h); asio::basic_datagram_socket &datagram_socket_; buffers::const_buffer_subspan buffer_; const endpoint & ep_; - std::exception_ptr error; - std::optional> result_; }; } diff --git a/include/boost/async/io/detail/random_access_device.hpp b/include/boost/async/io/detail/random_access_device.hpp index 6e44f677..3f963afc 100644 --- a/include/boost/async/io/detail/random_access_device.hpp +++ b/include/boost/async/io/detail/random_access_device.hpp @@ -9,37 +9,18 @@ #define BOOST_ASYNC_IO_DETAIL_RANDOM_ACCESS_DEVICE_HPP #include +#include namespace boost::async::io { -struct random_access_device::read_some_at_op_ : detail::deferred_op_resource_base +struct random_access_device::read_some_at_op_ final : transfer_op { read_some_at_op_(read_some_at_op_ && ) noexcept = default; - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - random_access_device_.async_read_some_at_impl_(offset_, {&buffer_, 1u}, - completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() + void initiate(completion_handler h) override { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; + random_access_device_.async_read_some_at_impl_(offset_, {&buffer_, 1u}, std::move(h)); } read_some_at_op_(random_access_device & rs, std::uint64_t offset, buffers::mutable_buffer buffer) @@ -49,36 +30,15 @@ struct random_access_device::read_some_at_op_ : detail::deferred_op_resource_bas random_access_device & random_access_device_; std::uint64_t offset_; buffers::mutable_buffer buffer_; - std::exception_ptr error; - std::optional> result_; }; -struct random_access_device::read_some_at_op_seq_ : detail::deferred_op_resource_base +struct random_access_device::read_some_at_op_seq_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) + void initiate(completion_handler h) override { - try - { - random_access_device_.async_read_some_at_impl_(offset_, buffer_, completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; + random_access_device_.async_read_some_at_impl_(offset_, buffer_, std::move(h)); } read_some_at_op_seq_(random_access_device & rs, std::uint64_t offset, buffers::mutable_buffer_subspan buffer) @@ -90,36 +50,13 @@ struct random_access_device::read_some_at_op_seq_ : detail::deferred_op_resource random_access_device & random_access_device_; std::uint64_t offset_; buffers::mutable_buffer_subspan buffer_; - std::exception_ptr error; - std::optional> result_; }; -struct random_access_device::write_some_at_op_ : detail::deferred_op_resource_base +struct random_access_device::write_some_at_op_ final : transfer_op { write_some_at_op_(write_some_at_op_ && ) noexcept = default; - - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - random_access_device_.async_write_some_at_impl_(offset_, {&buffer_, 1}, - completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() + void initiate(completion_handler h) override { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; + random_access_device_.async_write_some_at_impl_(offset_, {&buffer_, 1}, std::move(h)); } write_some_at_op_(random_access_device & rs, std::uint64_t offset, buffers::const_buffer buffer) @@ -129,35 +66,14 @@ struct random_access_device::write_some_at_op_ : detail::deferred_op_resource_ba random_access_device & random_access_device_; std::uint64_t offset_; buffers::const_buffer buffer_; - std::exception_ptr error; - std::optional> result_; }; -struct random_access_device::write_some_at_op_seq_ : detail::deferred_op_resource_base +struct random_access_device::write_some_at_op_seq_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - random_access_device_.async_write_some_at_impl_(offset_, buffer_, completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() + void initiate(completion_handler h) override { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; + random_access_device_.async_write_some_at_impl_(offset_, buffer_, std::move(h)); } write_some_at_op_seq_(random_access_device & rs, std::uint64_t offset, buffers::const_buffer_subspan buffer) @@ -169,8 +85,6 @@ struct random_access_device::write_some_at_op_seq_ : detail::deferred_op_resourc random_access_device & random_access_device_; std::uint64_t offset_; buffers::const_buffer_subspan buffer_; - std::exception_ptr error; - std::optional> result_; }; } diff --git a/include/boost/async/io/detail/seq_packet_socket.hpp b/include/boost/async/io/detail/seq_packet_socket.hpp index 0d3213f7..f1d3b20c 100644 --- a/include/boost/async/io/detail/seq_packet_socket.hpp +++ b/include/boost/async/io/detail/seq_packet_socket.hpp @@ -14,160 +14,60 @@ namespace boost::async::io { -struct seq_packet_socket::receive_op_ : detail::deferred_op_resource_base +struct seq_packet_socket::receive_op_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - initiate_(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } receive_op_(asio::basic_seq_packet_socket & rs, buffers::mutable_buffer buffer, message_flags &out_flags) : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} + void initiate(async::completion_handler h) override; private: - void initiate_(async::completion_handler h); asio::basic_seq_packet_socket &seq_packet_socket_; buffers::mutable_buffer buffer_; message_flags &out_flags_; - std::exception_ptr error; - std::optional> result_; }; -struct seq_packet_socket::receive_op_seq_ : detail::deferred_op_resource_base +struct seq_packet_socket::receive_op_seq_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - initiate_(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } receive_op_seq_(asio::basic_seq_packet_socket & rs, buffers::mutable_buffer_subspan buffer, message_flags &out_flags) : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} receive_op_seq_(asio::basic_seq_packet_socket & rs, buffers::mutable_buffer_span buffer, message_flags &out_flags) : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} + void initiate(async::completion_handler h) override; private: - void initiate_(async::completion_handler h); asio::basic_seq_packet_socket &seq_packet_socket_; buffers::mutable_buffer_subspan buffer_; message_flags &out_flags_; - std::exception_ptr error; - std::optional> result_; }; -struct seq_packet_socket::send_op_ : detail::deferred_op_resource_base +struct seq_packet_socket::send_op_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - initiate_(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } send_op_(asio::basic_seq_packet_socket & rs, buffers::const_buffer buffer, message_flags out_flags) : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} + void initiate(async::completion_handler h) override; private: - void initiate_(async::completion_handler h); asio::basic_seq_packet_socket &seq_packet_socket_; buffers::const_buffer buffer_; message_flags out_flags_; - std::exception_ptr error; - std::optional> result_; }; -struct seq_packet_socket::send_op_seq_ : detail::deferred_op_resource_base +struct seq_packet_socket::send_op_seq_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - initiate_(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } send_op_seq_(asio::basic_seq_packet_socket & rs, buffers::const_buffer_subspan buffer, message_flags out_flags) : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} send_op_seq_(asio::basic_seq_packet_socket & rs, buffers::const_buffer_span buffer, message_flags out_flags) : seq_packet_socket_(rs), buffer_(buffer), out_flags_(out_flags) {} + void initiate(async::completion_handler h) override; private: - void initiate_(async::completion_handler h); asio::basic_seq_packet_socket &seq_packet_socket_; buffers::const_buffer_subspan buffer_; message_flags out_flags_; - std::exception_ptr error; - std::optional> result_; }; } diff --git a/include/boost/async/io/detail/socket.hpp b/include/boost/async/io/detail/socket.hpp index ebeaaf0c..6954807e 100644 --- a/include/boost/async/io/detail/socket.hpp +++ b/include/boost/async/io/detail/socket.hpp @@ -9,91 +9,33 @@ #define BOOST_ASYNC_IO_DETAIL_SOCKET_HPP #include -#include +#include #include namespace boost::async::io { -struct socket::wait_op_ : detail::deferred_op_resource_base +struct socket::wait_op_ : result_op { - constexpr static bool await_ready() { return false; } + BOOST_ASYNC_DECL void initiate(completion_handler handler); - BOOST_ASYNC_DECL void init_op(completion_handler handler); - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - init_op(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - - [[nodiscard]] system::result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - auto [ec] = result_.value_or(std::make_tuple(system::error_code{})); - if (ec) - return ec; - else - return {}; - } wait_op_(asio::basic_socket & socket, asio::socket_base::wait_type wt) : socket_(socket), wt_(wt) {} private: asio::basic_socket & socket_; asio::socket_base::wait_type wt_; - std::exception_ptr error; - std::optional> result_; }; -struct socket::connect_op_ : detail::deferred_op_resource_base +struct socket::connect_op_ : result_op { - constexpr static bool await_ready() { return false; } - - BOOST_ASYNC_DECL void init_op(completion_handler handler); - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - init_op(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } + BOOST_ASYNC_DECL void initiate(completion_handler handler); - [[nodiscard]] system::result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - auto [ec] = result_.value_or(std::make_tuple(system::error_code{})); - if (ec) - return ec; - else - return {}; - } connect_op_(socket* socket, endpoint ep) : socket_(socket), ep_(ep) {} private: socket * socket_; endpoint ep_; - std::exception_ptr error; - std::optional> result_; }; diff --git a/include/boost/async/io/detail/ssl.hpp b/include/boost/async/io/detail/ssl.hpp index d3208660..0e337992 100644 --- a/include/boost/async/io/detail/ssl.hpp +++ b/include/boost/async/io/detail/ssl.hpp @@ -13,157 +13,45 @@ namespace boost::async::io { -struct ssl_stream::handshake_op_ : detail::deferred_op_resource_base +struct ssl_stream::handshake_op_ final : result_op { - constexpr static bool await_ready() { return false; } - - BOOST_ASYNC_DECL void init_op(completion_handler handler); - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - init_op(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - - [[nodiscard]] system::result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - auto ec = std::get<0>(result_.value_or(std::make_tuple(system::error_code{}))); - return ec ? system::result(ec) : system::in_place_value; - } - + BOOST_ASYNC_DECL void initiate(completion_handler handler) override; handshake_op_(ssl_stream & stream, handshake_type ht) : stream(stream), ht(ht) {} private: ssl_stream & stream; handshake_type ht; - std::exception_ptr error; - std::optional> result_; }; -struct ssl_stream::handshake_op_buf_ : detail::deferred_op_resource_base +struct ssl_stream::handshake_op_buf_ final : transfer_op { - constexpr static bool await_ready() { return false; } - - BOOST_ASYNC_DECL void init_op(completion_handler handler); - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - init_op(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } - + BOOST_ASYNC_DECL void initiate(completion_handler handler) override; handshake_op_buf_(ssl_stream & stream, - handshake_type ht, - buffers::const_buffer buf) : stream(stream), ht(ht), buf(buf) {} + handshake_type ht, + buffers::const_buffer buf) : stream(stream), ht(ht), buf(buf) {} private: ssl_stream & stream; handshake_type ht; buffers::const_buffer buf; - std::exception_ptr error; - std::optional> result_; }; -struct ssl_stream::handshake_op_buf_seq_ : detail::deferred_op_resource_base +struct ssl_stream::handshake_op_buf_seq_ final : transfer_op { - constexpr static bool await_ready() { return false; } - BOOST_ASYNC_DECL void init_op(completion_handler handler); - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - init_op(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } - + BOOST_ASYNC_DECL void initiate(completion_handler handler) override; handshake_op_buf_seq_(ssl_stream & stream, handshake_type ht, buffers::const_buffer_subspan buf) : stream(stream), ht(ht), buf(buf) {} private: ssl_stream & stream; handshake_type ht; buffers::const_buffer_subspan buf; - std::exception_ptr error; - std::optional> result_; }; -struct ssl_stream::shutdown_op_ : detail::deferred_op_resource_base +struct ssl_stream::shutdown_op_ final : result_op { - constexpr static bool await_ready() { return false; } - - BOOST_ASYNC_DECL void init_op(completion_handler handler); - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - init_op(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - - [[nodiscard]] shutdown_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - auto ec = std::get<0>(result_.value_or(std::make_tuple(system::error_code{}))); - return ec ? shutdown_result(ec) : system::in_place_value; - } - + BOOST_ASYNC_DECL void initiate(completion_handler handler) override; shutdown_op_(ssl_stream & stream) : stream(stream) {} private: - ssl_stream & stream; - std::exception_ptr error; - std::optional> result_; }; } diff --git a/include/boost/async/io/detail/stream.hpp b/include/boost/async/io/detail/stream.hpp index 04989f63..a2f6f181 100644 --- a/include/boost/async/io/detail/stream.hpp +++ b/include/boost/async/io/detail/stream.hpp @@ -8,165 +8,64 @@ #ifndef BOOST_ASYNC_IO_DETAIL_STREAM_HPP #define BOOST_ASYNC_IO_DETAIL_STREAM_HPP +#include #include namespace boost::async::io { -struct stream::read_some_op_ : detail::deferred_op_resource_base +struct stream::read_some_op_ final : transfer_op { read_some_op_(read_some_op_ && ) noexcept = default; - - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - rstream_.async_read_some_impl_({&buffer_, 1u}, - completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } - read_some_op_(stream & rs, buffers::mutable_buffer buffer) : rstream_(rs), buffer_(buffer) {} + BOOST_ASYNC_DECL void initiate(completion_handler h) override; private: stream & rstream_; buffers::mutable_buffer buffer_; - std::exception_ptr error; - std::optional> result_; }; -struct stream::read_some_op_seq_ : detail::deferred_op_resource_base +struct stream::read_some_op_seq_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - rstream_.async_read_some_impl_(buffer_, completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } - read_some_op_seq_(stream & rs, buffers::mutable_buffer_subspan buffer) : rstream_(rs), buffer_(buffer) {} read_some_op_seq_(stream & rs, buffers::mutable_buffer_span buffer) : rstream_(rs), buffer_(buffer) {} + BOOST_ASYNC_DECL void initiate(completion_handler h) override; private: stream & rstream_; buffers::mutable_buffer_subspan buffer_; - std::exception_ptr error; - std::optional> result_; }; -struct stream::write_some_op_ : detail::deferred_op_resource_base + +struct stream::write_some_op_ final : transfer_op { write_some_op_(write_some_op_ && ) noexcept = default; - - constexpr bool await_ready() noexcept {return false;}; - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - rstream_.async_write_some_impl_({&buffer_, 1}, - completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } - write_some_op_(stream & rs, buffers::const_buffer buffer) : rstream_(rs), buffer_(buffer) {} + BOOST_ASYNC_DECL void initiate(completion_handler h) override; + private: stream & rstream_; buffers::const_buffer buffer_; - std::exception_ptr error; - std::optional> result_; }; -struct stream::write_some_op_seq_ : detail::deferred_op_resource_base +struct stream::write_some_op_seq_ final : transfer_op { - constexpr bool await_ready() noexcept {return false;}; - - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - rstream_.async_write_some_impl_(buffer_, completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] transfer_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - const auto & [ec, n] = *result_; - return transfer_result{ec, n}; - } - write_some_op_seq_(stream & rs, buffers::const_buffer_subspan buffer) : rstream_(rs), buffer_(buffer) {} write_some_op_seq_(stream & rs, buffers::const_buffer_span buffer) : rstream_(rs), buffer_(buffer) {} + + BOOST_ASYNC_DECL void initiate(completion_handler h) override; + private: stream & rstream_; buffers::const_buffer_subspan buffer_; - std::exception_ptr error; - std::optional> result_; }; } diff --git a/include/boost/async/io/endpoint.hpp b/include/boost/async/io/endpoint.hpp index 8816a50f..567b15ec 100644 --- a/include/boost/async/io/endpoint.hpp +++ b/include/boost/async/io/endpoint.hpp @@ -31,6 +31,12 @@ namespace boost::async::io struct endpoint; struct stream_socket; + +#if __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsubobject-linkage" +#endif + struct protocol_type { using family_t = decltype(BOOST_ASIO_OS_DEF(AF_INET)); @@ -62,7 +68,7 @@ struct protocol_type friend constexpr auto operator<=>(const protocol_type & , const protocol_type &) noexcept = default; - using endpoint = endpoint; + using endpoint = io::endpoint; // for the asio acceptor using socket = stream_socket; private: @@ -84,7 +90,7 @@ struct static_protocol constexpr type_t type() const noexcept {return Type;}; constexpr protocol_t protocol() const noexcept {return Protocol;}; - using endpoint = endpoint; + using endpoint = io::endpoint; }; @@ -179,6 +185,11 @@ struct endpoint protocol_type::type_t type_ = static_cast(0); }; +#if __GNUC__ +#pragma GCC diagnostic pop +#endif + + class bad_endpoint_access : public std::exception { public: diff --git a/include/boost/async/io/process.hpp b/include/boost/async/io/process.hpp index 6c6401cb..56059981 100644 --- a/include/boost/async/io/process.hpp +++ b/include/boost/async/io/process.hpp @@ -9,7 +9,7 @@ #define BOOST_ASYNC_IO_PROCESS_HPP #include -#include +#include #include #include @@ -62,44 +62,13 @@ struct process [[nodiscard]] pid_type id() const; private: - struct wait_op_ : detail::deferred_op_resource_base + struct wait_op_ final : result_op { - constexpr static bool await_ready() { return false; } - - BOOST_ASYNC_DECL void init_op(completion_handler handler); - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - init_op(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - - [[nodiscard]] wait_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - auto [ec, sig] = result_.value_or(std::make_tuple(system::error_code{}, 0)); - if (ec) - return ec; - else - return sig; - } + BOOST_ASYNC_DECL void initiate(completion_handler handler) override; + wait_op_(boost::process::v2::basic_process & process) : process_(process) {} private: boost::process::v2::basic_process & process_; - std::exception_ptr error; - std::optional> result_; - char buffer[256]; - std::optional resource; }; public: [[nodiscard]] wait_op_ wait() { return wait_op_{process_}; } diff --git a/include/boost/async/io/resolver.hpp b/include/boost/async/io/resolver.hpp index f2be328a..a18ad8fa 100644 --- a/include/boost/async/io/resolver.hpp +++ b/include/boost/async/io/resolver.hpp @@ -9,8 +9,8 @@ #define BOOST_ASYNC_IO_RESOLVER_HPP #include +#include -#include #include #include #include @@ -24,6 +24,7 @@ namespace boost::async::io struct resolver { using resolve_result = system::result>; + BOOST_ASYNC_DECL resolver(); BOOST_ASYNC_DECL resolver(resolver && ) = delete; @@ -31,39 +32,17 @@ struct resolver private: - struct resolve_op_ : detail::deferred_op_resource_base + struct resolve_op_ final : result_op { - using result_type = asio::ip::basic_resolver::results_type; - - constexpr static bool await_ready() { return false; } - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - initiate_(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - - [[nodiscard]] resolve_result await_resume(); resolve_op_(asio::ip::basic_resolver & resolver, core::string_view host, core::string_view service) : resolver_(resolver), host_(host), service_(service) {} + BOOST_ASYNC_DECL void initiate(completion_handler); private: asio::ip::basic_resolver & resolver_; core::string_view host_; core::string_view service_; - std::exception_ptr error; - std::optional> result_; - void initiate_(completion_handler); }; diff --git a/include/boost/async/io/result.hpp b/include/boost/async/io/result.hpp index 650a503b..f4092f41 100644 --- a/include/boost/async/io/result.hpp +++ b/include/boost/async/io/result.hpp @@ -88,7 +88,7 @@ struct result_op result_op * op_; }; - vawaitable value() { return vawaitable{this}; } + vawaitable value() && { return vawaitable{this}; } private: std::exception_ptr error; std::optional> result; @@ -171,7 +171,7 @@ struct result_op result_op * op_; }; - vawaitable value() { return vawaitable{this}; } + vawaitable value() && { return vawaitable{this}; } private: std::exception_ptr error; diff --git a/include/boost/async/io/signal_set.hpp b/include/boost/async/io/signal_set.hpp index 3761cbf7..70063310 100644 --- a/include/boost/async/io/signal_set.hpp +++ b/include/boost/async/io/signal_set.hpp @@ -8,7 +8,7 @@ #ifndef BOOST_ASYNC_IO_SIGNAL_SET_HPP #define BOOST_ASYNC_IO_SIGNAL_SET_HPP -#include +#include #include #include @@ -32,42 +32,12 @@ struct signal_set private: - struct wait_op_ : detail::deferred_op_resource_base + struct wait_op_ final : result_op { - constexpr static bool await_ready() { return false; } - - BOOST_ASYNC_DECL void init_op(completion_handler handler); - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - init_op(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - - [[nodiscard]] wait_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - auto [ec, sig] = result_.value_or(std::make_tuple(system::error_code{}, 0)); - if (ec) - return ec; - else - return sig; - } + BOOST_ASYNC_DECL void initiate(completion_handler handler) override; wait_op_(boost::asio::basic_signal_set & signal_set) : signal_set_(signal_set) {} private: boost::asio::basic_signal_set & signal_set_; - std::exception_ptr error; - std::optional> result_; }; public: [[nodiscard]] wait_op_ wait() { return wait_op_{signal_set_}; } diff --git a/include/boost/async/io/sleep.hpp b/include/boost/async/io/sleep.hpp index 49f07c25..3bcb6beb 100644 --- a/include/boost/async/io/sleep.hpp +++ b/include/boost/async/io/sleep.hpp @@ -21,9 +21,11 @@ struct steady_sleep steady_sleep(const std::chrono::steady_clock::time_point & tp) : tim{tp} {} steady_sleep(const std::chrono::steady_clock::duration & du) : tim{du} {} - auto operator co_await() { return tim.wait(); } + async::io::steady_timer::wait_op_ operator co_await() { return tim.wait(); } + async::io::steady_timer::wait_op_::vawaitable value() { return std::move(op_.emplace(tim.wait())).value(); } private: async::io::steady_timer tim; + std::optional op_; }; @@ -32,9 +34,11 @@ struct system_sleep system_sleep(const std::chrono::system_clock::time_point & tp) : tim{tp} {} system_sleep(const std::chrono::system_clock::duration & du) : tim{du} {} - auto operator co_await() { return tim.wait(); } + async::io::system_timer::wait_op_ operator co_await() { return tim.wait(); } + async::io::system_timer::wait_op_::vawaitable value() { return std::move(op_.emplace(tim.wait())).value(); } private: async::io::system_timer tim; + std::optional op_; }; } diff --git a/include/boost/async/io/steady_timer.hpp b/include/boost/async/io/steady_timer.hpp index bd056d02..d2f76d9c 100644 --- a/include/boost/async/io/steady_timer.hpp +++ b/include/boost/async/io/steady_timer.hpp @@ -8,11 +8,16 @@ #ifndef BOOST_ASYNC_IO_STEADY_TIMER_HPP #define BOOST_ASYNC_IO_STEADY_TIMER_HPP -#include +#include #include #include +namespace boost::async::detail::io +{ +struct steady_sleep; +} + namespace boost::async::io { @@ -41,45 +46,20 @@ struct steady_timer BOOST_ASYNC_DECL bool expired() const; private: - struct wait_op_ : detail::deferred_op_resource_base + struct wait_op_ final : result_op { - bool await_ready() const { return timer_->expired(); } - - BOOST_ASYNC_DECL void init_op(completion_handler handler); - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - init_op(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - - [[nodiscard]] wait_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - auto ec = std::get<0>(result_.value_or(std::make_tuple(system::error_code{}))); - return ec ? wait_result(ec) : system::in_place_value; - } + void ready(async::handler h) {if (timer_->expired()) h({});} + BOOST_ASYNC_DECL void initiate(completion_handler handler) override; wait_op_(steady_timer * timer) : timer_(timer) {} private: steady_timer * timer_; - std::exception_ptr error; - std::optional> result_; }; public: [[nodiscard]] wait_op_ wait() { return wait_op_{this}; } wait_op_ operator co_await () { return wait(); } private: + friend struct detail::io::steady_sleep; boost::asio::basic_waitable_timer, executor> timer_; diff --git a/include/boost/async/io/stream.hpp b/include/boost/async/io/stream.hpp index 494b42fd..1ceaa969 100644 --- a/include/boost/async/io/stream.hpp +++ b/include/boost/async/io/stream.hpp @@ -19,37 +19,8 @@ namespace boost::async::io { -struct [[nodiscard]] transfer_result -{ - system::error_code error; - std::size_t transferred{0u}; - - using value_type = std::size_t; - using error_type = system::error_code; - - // queries - constexpr bool has_value() const noexcept { return transferred != 0; } - constexpr bool has_error() const noexcept { return error.failed(); } - constexpr explicit operator bool() const noexcept { return has_value() || !has_error(); } - constexpr std::size_t value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const noexcept - { - if (!has_value() || has_error()) - throw_exception_from_error(error, loc); - return transferred; - } - constexpr std::size_t operator*() const noexcept { BOOST_ASSERT(has_value()); return transferred; } - bool operator==(const system::error_code &ec) const { return error == ec;} - bool operator!=(const system::error_code &ec) const { return error != ec;} -}; -inline transfer_result & operator+=(transfer_result & lhs, const transfer_result & rhs) -{ - lhs.transferred += rhs.transferred; - if (!lhs.error) - lhs.error = rhs.error; - return lhs; -} struct stream { diff --git a/include/boost/async/io/system_timer.hpp b/include/boost/async/io/system_timer.hpp index c4aafe5f..f1edc173 100644 --- a/include/boost/async/io/system_timer.hpp +++ b/include/boost/async/io/system_timer.hpp @@ -8,11 +8,15 @@ #ifndef BOOST_ASYNC_IO_SYSTEM_TIMER_HPP #define BOOST_ASYNC_IO_SYSTEM_TIMER_HPP -#include +#include #include #include +namespace boost::async::detail::io +{ +struct system_sleep; +} namespace boost::async::io { @@ -39,45 +43,22 @@ struct system_timer final BOOST_ASYNC_DECL void reset(const time_point& expiry_time); BOOST_ASYNC_DECL void reset(const duration& expiry_time); BOOST_ASYNC_DECL bool expired() const; - - struct wait_op_ : detail::deferred_op_resource_base + private: + struct wait_op_ : result_op { - bool await_ready() const { return timer_->expired(); } - BOOST_ASYNC_DECL void init_op(completion_handler handler); - - template - bool await_suspend(std::coroutine_handle h) - { - try - { - init_op(completion_handler{h, result_, get_resource(h)}); - return true; - } - catch(...) - { - error = std::current_exception(); - return false; - } - } - [[nodiscard]] wait_result await_resume() - { - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - auto ec = std::get<0>(result_.value_or(std::make_tuple(system::error_code{}))); - return ec ? wait_result(ec) : system::in_place_value; - } + void ready(async::handler h) {if (timer_->expired()) h({});} + BOOST_ASYNC_DECL void initiate(completion_handler handler) override; wait_op_(system_timer * timer) : timer_(timer) {} private: system_timer * timer_; - std::exception_ptr error; - std::optional> result_; }; public: [[nodiscard]] wait_op_ wait() { return wait_op_{this}; } wait_op_ operator co_await () { return wait(); } private: + friend struct detail::io::system_sleep; boost::asio::basic_waitable_timer, executor> timer_; diff --git a/include/boost/async/io/transfer_result.hpp b/include/boost/async/io/transfer_result.hpp index a56893e2..ecf9a030 100644 --- a/include/boost/async/io/transfer_result.hpp +++ b/include/boost/async/io/transfer_result.hpp @@ -18,11 +18,10 @@ namespace boost::async::io { - struct [[nodiscard]] transfer_result { system::error_code error; - std::size_t transferred; + std::size_t transferred{0u}; using value_type = std::size_t; using error_type = system::error_code; @@ -33,7 +32,7 @@ struct [[nodiscard]] transfer_result constexpr explicit operator bool() const noexcept { return has_value() || !has_error(); } constexpr std::size_t value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const noexcept { - if (!has_value() || !has_error()) + if (!has_value() || has_error()) throw_exception_from_error(error, loc); return transferred; } @@ -54,6 +53,13 @@ struct [[nodiscard]] transfer_result bool operator!=(E e) const { return error != e;} }; +inline transfer_result & operator+=(transfer_result & lhs, const transfer_result & rhs) +{ + lhs.transferred += rhs.transferred; + if (!lhs.error) + lhs.error = rhs.error; + return lhs; +} struct transfer_op { diff --git a/src/io/acceptor.cpp b/src/io/acceptor.cpp index b88c6536..1613b4b7 100644 --- a/src/io/acceptor.cpp +++ b/src/io/acceptor.cpp @@ -31,7 +31,12 @@ endpoint acceptor::local_endpoint() return acceptor_.local_endpoint(); } -auto acceptor::accept() -> accept_op_ { return accept_op_{acceptor_};} -auto acceptor::accept_seq_packet() -> accept_seq_op_ { return accept_seq_op_{acceptor_};} +auto acceptor::accept(socket & sock) -> accept_op_ { return accept_op_{acceptor_, sock};} + +void acceptor::accept_op_::initiate(completion_handler h) +{ + acceptor_.async_accept(socket_.socket_, std::move(h)); +} + } \ No newline at end of file diff --git a/src/io/datagram_socket.cpp b/src/io/datagram_socket.cpp index ff793c28..93cdfbcc 100644 --- a/src/io/datagram_socket.cpp +++ b/src/io/datagram_socket.cpp @@ -90,42 +90,42 @@ auto datagram_socket::send_to(buffers::const_buffer buffer, const endpoint return send_to_op_{datagram_socket_, buffer, target}; } -void datagram_socket::receive_op_::initiate_(async::completion_handler h) +void datagram_socket::receive_op_::initiate(async::completion_handler h) { this->datagram_socket_.async_receive(buffers::mutable_buffer_subspan{&buffer_, 1u}, std::move(h)); } -void datagram_socket::receive_op_seq_::initiate_(async::completion_handler h) +void datagram_socket::receive_op_seq_::initiate(async::completion_handler h) { this->datagram_socket_.async_receive(buffer_, std::move(h)); } -void datagram_socket::receive_from_op_::initiate_(async::completion_handler h) +void datagram_socket::receive_from_op_::initiate(async::completion_handler h) { this->datagram_socket_.async_receive_from(buffers::mutable_buffer_subspan{&buffer_, 1u}, ep_, std::move(h)); } -void datagram_socket::receive_from_op_seq_::initiate_(async::completion_handler h) +void datagram_socket::receive_from_op_seq_::initiate(async::completion_handler h) { this->datagram_socket_.async_receive_from(buffer_, ep_, std::move(h)); } -void datagram_socket::send_op_::initiate_(async::completion_handler h) +void datagram_socket::send_op_::initiate(async::completion_handler h) { this->datagram_socket_.async_send(buffers::const_buffer_subspan{&buffer_, 1u}, std::move(h)); } -void datagram_socket::send_op_seq_::initiate_(async::completion_handler h) +void datagram_socket::send_op_seq_::initiate(async::completion_handler h) { this->datagram_socket_.async_send(buffer_, std::move(h)); } -void datagram_socket::send_to_op_::initiate_(async::completion_handler h) +void datagram_socket::send_to_op_::initiate(async::completion_handler h) { this->datagram_socket_.async_send_to(buffers::const_buffer_subspan{&buffer_, 1u}, ep_, std::move(h)); } -void datagram_socket::send_to_op_seq_::initiate_(async::completion_handler h) +void datagram_socket::send_to_op_seq_::initiate(async::completion_handler h) { this->datagram_socket_.async_send_to(buffer_, ep_, std::move(h)); } diff --git a/src/io/detail/stream.cpp b/src/io/detail/stream.cpp index d34aeb7f..4381a04f 100644 --- a/src/io/detail/stream.cpp +++ b/src/io/detail/stream.cpp @@ -17,5 +17,26 @@ auto stream::write_some(buffers::const_buffer_subspan buffers) -> write_some_o auto stream::write_some(buffers::const_buffer_span buffers) -> write_some_op_seq_ { return write_some_op_seq_{*this, buffers};} auto stream::write_some(buffers::const_buffer buffer) -> write_some_op_ { return write_some_op_{*this, buffer};} +void stream::read_some_op_::initiate(completion_handler h) +{ + rstream_.async_read_some_impl_({&buffer_, 1u}, std::move(h)); +} + +void stream::read_some_op_seq_::initiate(completion_handler h) +{ + rstream_.async_read_some_impl_(buffer_, std::move(h)); +} + +void stream::write_some_op_::initiate(completion_handler h) +{ + rstream_.async_write_some_impl_({&buffer_, 1u}, std::move(h)); +} + +void stream::write_some_op_seq_::initiate(completion_handler h) +{ + rstream_.async_write_some_impl_(buffer_, std::move(h)); +} + + } \ No newline at end of file diff --git a/src/io/process.cpp b/src/io/process.cpp index ed5e140a..937060d2 100644 --- a/src/io/process.cpp +++ b/src/io/process.cpp @@ -36,7 +36,7 @@ process::process(pid_type pid) : process_(this_thread::get_executor(), pid) {} process::process(pid_type pid, native_handle_type native_handle) : process_(this_thread::get_executor(), pid, native_handle) {} -void process::wait_op_::init_op(completion_handler handler) +void process::wait_op_::initiate(completion_handler handler) { process_.async_wait(std::move(handler)); } diff --git a/src/io/resolver.cpp b/src/io/resolver.cpp index aedc03b2..a68650cb 100644 --- a/src/io/resolver.cpp +++ b/src/io/resolver.cpp @@ -14,26 +14,17 @@ namespace boost::async::io resolver::resolver() : resolver_(this_thread::get_executor()) {} void resolver::cancel() { resolver_.cancel(); } - -[[nodiscard]] resolver::resolve_result resolver::resolve_op_::await_resume() -{ - if (error) - std::rethrow_exception(std::exchange(error, nullptr)); - - auto [ec, rr] = result_.value(); - if (ec) - return ec; - else - { - container::pmr::vector r{this_thread::get_allocator()}; - r.assign(rr.begin(), rr.end()); - return r; - } -} - -void resolver::resolve_op_::initiate_(completion_handler h) +void resolver::resolve_op_::initiate(completion_handler h) { - resolver_.async_resolve(async::io::ip, host_, service_, std::move(h)); + using results_type = typename asio::ip::basic_resolver_results; + resolver_.async_resolve( + async::io::ip, host_, service_, + asio::deferred([](system::error_code ec, results_type res) + { + container::pmr::vector r{this_thread::get_allocator()}; + r.assign(res.begin(), res.end()); + return asio::deferred.values(ec, std::move(r)); + }))(std::move(h)); } } \ No newline at end of file diff --git a/src/io/seq_packet_socket.cpp b/src/io/seq_packet_socket.cpp index 3461b973..6b5ce858 100644 --- a/src/io/seq_packet_socket.cpp +++ b/src/io/seq_packet_socket.cpp @@ -66,22 +66,22 @@ auto seq_packet_socket::send(buffers::const_buffer buffer,message_flags out return send_op_{seq_packet_socket_, buffer, out_flags}; } -void seq_packet_socket::receive_op_::initiate_(async::completion_handler h) +void seq_packet_socket::receive_op_::initiate(async::completion_handler h) { this->seq_packet_socket_.async_receive(buffers::mutable_buffer_subspan{&buffer_, 1u}, out_flags_, std::move(h)); } -void seq_packet_socket::receive_op_seq_::initiate_(async::completion_handler h) +void seq_packet_socket::receive_op_seq_::initiate(async::completion_handler h) { this->seq_packet_socket_.async_receive(buffer_, out_flags_, std::move(h)); } -void seq_packet_socket::send_op_::initiate_(async::completion_handler h) +void seq_packet_socket::send_op_::initiate(async::completion_handler h) { this->seq_packet_socket_.async_send(buffers::const_buffer_subspan{&buffer_, 1u}, out_flags_, std::move(h)); } -void seq_packet_socket::send_op_seq_::initiate_(async::completion_handler h) +void seq_packet_socket::send_op_seq_::initiate(async::completion_handler h) { this->seq_packet_socket_.async_send(buffer_, out_flags_, std::move(h)); } diff --git a/src/io/signal_set.cpp b/src/io/signal_set.cpp index 47338bed..0e25ff4a 100644 --- a/src/io/signal_set.cpp +++ b/src/io/signal_set.cpp @@ -46,7 +46,7 @@ system::result signal_set::remove(int signal_number) return ec ? ec : system::result{}; } -void signal_set::wait_op_::init_op(completion_handler handler) +void signal_set::wait_op_::initiate(completion_handler handler) { signal_set_.async_wait(std::move(handler)); } diff --git a/src/io/socket.cpp b/src/io/socket.cpp index 6b3b1304..9601c03a 100644 --- a/src/io/socket.cpp +++ b/src/io/socket.cpp @@ -164,12 +164,12 @@ system::result connect_pair(protocol_type protocol, socket & socket1, sock return {}; } -void socket::wait_op_::init_op(completion_handler handler) +void socket::wait_op_::initiate(completion_handler handler) { return socket_.async_wait(wt_, std::move(handler)); } -void socket::connect_op_::init_op(completion_handler handler) +void socket::connect_op_::initiate(completion_handler handler) { socket_->adopt_endpoint_(ep_); socket_->socket_.async_connect(ep_, std::move(handler)); diff --git a/src/io/ssl.cpp b/src/io/ssl.cpp index a02c1648..882818b7 100644 --- a/src/io/ssl.cpp +++ b/src/io/ssl.cpp @@ -24,7 +24,7 @@ system::result ssl_stream::duplicate() static asio::ssl::context & get_ssl_context() { - thread_local static asio::ssl::context ctx{asio::ssl::context_base::tls}; + thread_local static asio::ssl::context ctx{asio::ssl::context_base::tlsv13}; return ctx; } @@ -105,23 +105,23 @@ void ssl_stream::adopt_endpoint_(endpoint & ep) } } -void ssl_stream::handshake_op_::init_op(completion_handler handler) +void ssl_stream::handshake_op_::initiate(completion_handler handler) { stream.ssl_stream_.async_handshake(ht, std::move(handler)); } -void ssl_stream::handshake_op_buf_::init_op(completion_handler handler) +void ssl_stream::handshake_op_buf_::initiate(completion_handler handler) { stream.ssl_stream_.async_handshake(ht, io::buffers::const_buffer_subspan{&buf, 1u}, std::move(handler)); } -void ssl_stream::handshake_op_buf_seq_::init_op(completion_handler handler) +void ssl_stream::handshake_op_buf_seq_::initiate(completion_handler handler) { stream.ssl_stream_.async_handshake(ht, buf, std::move(handler)); } -void ssl_stream::shutdown_op_::init_op(completion_handler handler) +void ssl_stream::shutdown_op_::initiate(completion_handler handler) { stream.ssl_stream_.async_shutdown(std::move(handler)); } diff --git a/src/io/steady_timer.cpp b/src/io/steady_timer.cpp index 5ee775d6..846c7edd 100644 --- a/src/io/steady_timer.cpp +++ b/src/io/steady_timer.cpp @@ -39,7 +39,7 @@ void steady_timer::reset(const duration &expiry_time) bool steady_timer::expired() const { return timer_.expiry() < clock_type::now(); } -void steady_timer::wait_op_::init_op(completion_handler handler) +void steady_timer::wait_op_::initiate(completion_handler handler) { timer_->timer_.async_wait(std::move(handler)); } diff --git a/src/io/system_timer.cpp b/src/io/system_timer.cpp index 2ce4d791..b27b1572 100644 --- a/src/io/system_timer.cpp +++ b/src/io/system_timer.cpp @@ -39,7 +39,7 @@ void system_timer::reset(const duration &expiry_time) bool system_timer::expired() const { return timer_.expiry() < clock_type::now(); } -void system_timer::wait_op_::init_op(completion_handler handler) +void system_timer::wait_op_::initiate(completion_handler handler) { timer_->timer_.async_wait(std::move(handler)); } diff --git a/test/io/acceptor.cpp b/test/io/acceptor.cpp index f4a57a9d..973b019d 100644 --- a/test/io/acceptor.cpp +++ b/test/io/acceptor.cpp @@ -21,18 +21,18 @@ CO_TEST_CASE("acceptor") io::acceptor acceptor{ep}; io::stream_socket ss{}; - auto [accepted, connected] = - co_await join(acceptor.accept(), + io::stream_socket accepted; + auto [_, connected] = + co_await join(acceptor.accept(accepted).value(), ss.connect(ep)); - CHECK(!accepted.has_error()); CHECK(!connected.has_error()); - CHECK(accepted->remote_endpoint()->protocol() == ss.local_endpoint()->protocol()); - CHECK(accepted->local_endpoint()->protocol() == ss.remote_endpoint()->protocol()); + CHECK(accepted.remote_endpoint()->protocol() == ss.local_endpoint()->protocol()); + CHECK(accepted.local_endpoint()->protocol() == ss.remote_endpoint()->protocol()); - CHECK(get(*accepted->remote_endpoint()).port() == get(*ss.local_endpoint()) .port()); - CHECK(get(*accepted->local_endpoint()) .port() == get(*ss.remote_endpoint()).port()); - CHECK(get(*accepted->remote_endpoint()).addr() == get(*ss.local_endpoint()) .addr()); - CHECK(get(*accepted->local_endpoint()) .addr() == get(*ss.remote_endpoint()).addr()); + CHECK(get(*accepted.remote_endpoint()).port() == get(*ss.local_endpoint()) .port()); + CHECK(get(*accepted.local_endpoint()) .port() == get(*ss.remote_endpoint()).port()); + CHECK(get(*accepted.remote_endpoint()).addr() == get(*ss.local_endpoint()) .addr()); + CHECK(get(*accepted.local_endpoint()) .addr() == get(*ss.remote_endpoint()).addr()); } diff --git a/test/io/copy.cpp b/test/io/copy.cpp index 7a5af44b..f9e1b478 100644 --- a/test/io/copy.cpp +++ b/test/io/copy.cpp @@ -36,6 +36,7 @@ promise do_copy(io::stream & in, io::stream & out) CO_TEST_CASE("copy") { + std::signal(SIGPIPE, SIG_IGN); auto [r, wi] = io::make_pipe().value(); auto [ri, w] = io::make_pipe().value(); diff --git a/test/io/sleep.cpp b/test/io/sleep.cpp index a199a4dc..c2a9c6a0 100644 --- a/test/io/sleep.cpp +++ b/test/io/sleep.cpp @@ -14,10 +14,10 @@ TEST_SUITE_BEGIN("sleep"); CO_TEST_CASE_TEMPLATE("sleep-timepoint", Clock, std::chrono::steady_clock, std::chrono::system_clock) { auto pre = Clock::now(); - (co_await boost::async::io::sleep(pre)).value(); + co_await boost::async::io::sleep(pre).value(); auto post = Clock::now(); CHECK((post - pre) < std::chrono::milliseconds(50)); - (co_await boost::async::io::sleep(pre + std::chrono::milliseconds(50))).value(); + co_await boost::async::io::sleep(pre + std::chrono::milliseconds(50)).value(); post = Clock::now(); CHECK((post - pre) >= std::chrono::milliseconds(50)); } @@ -25,10 +25,10 @@ CO_TEST_CASE_TEMPLATE("sleep-timepoint", Clock, std::chrono::steady_clock, std:: CO_TEST_CASE("sleep-duration") { auto pre = std::chrono::steady_clock::now(); - (co_await boost::async::io::sleep(std::chrono::milliseconds(0))).value(); + co_await boost::async::io::sleep(std::chrono::milliseconds(0)).value(); auto post = std::chrono::steady_clock::now(); CHECK((post - pre) < std::chrono::milliseconds(50)); - (co_await boost::async::io::sleep(std::chrono::milliseconds(50))).value(); + co_await boost::async::io::sleep(std::chrono::milliseconds(50)).value(); post = std::chrono::steady_clock::now(); CHECK((post - pre) >= std::chrono::milliseconds(50)); } diff --git a/test/io/ssl.cpp b/test/io/ssl.cpp index 6079a630..63c7af27 100644 --- a/test/io/ssl.cpp +++ b/test/io/ssl.cpp @@ -27,5 +27,5 @@ CO_TEST_CASE("ssl") CHECK(co_await ss.async_handshake(async::io::ssl_stream::handshake_type::client) == system::in_place_value); - CHECK(co_await ss.async_shutdown() == system::in_place_value); + CHECK_NOTHROW(co_await ss.async_shutdown()); } \ No newline at end of file From ac8b0fcc3e2809f3ebd5e0b6be0a255e3c3e69a9 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 7 Jul 2023 11:33:38 +0800 Subject: [PATCH 27/43] minor fixes. --- include/boost/async/io/sleep.hpp | 6 +++--- test/io/ssl.cpp | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/boost/async/io/sleep.hpp b/include/boost/async/io/sleep.hpp index 3bcb6beb..d8d58063 100644 --- a/include/boost/async/io/sleep.hpp +++ b/include/boost/async/io/sleep.hpp @@ -49,9 +49,9 @@ namespace boost::async::io // NOTE: these don't need to be coros, we can optimize that out. Not sure that's worth it though -BOOST_ASYNC_DECL detail::io::steady_sleep sleep(const std::chrono::steady_clock::duration & d) { return d;} -BOOST_ASYNC_DECL detail::io::steady_sleep sleep(const std::chrono::steady_clock::time_point & tp) { return tp;} -BOOST_ASYNC_DECL detail::io::system_sleep sleep(const std::chrono::system_clock::time_point & tp) { return tp;} +inline detail::io::steady_sleep sleep(const std::chrono::steady_clock::duration & d) { return d;} +inline detail::io::steady_sleep sleep(const std::chrono::steady_clock::time_point & tp) { return tp;} +inline detail::io::system_sleep sleep(const std::chrono::system_clock::time_point & tp) { return tp;} template detail::io::steady_sleep sleep(const std::chrono::time_point & tp) diff --git a/test/io/ssl.cpp b/test/io/ssl.cpp index 63c7af27..b175290b 100644 --- a/test/io/ssl.cpp +++ b/test/io/ssl.cpp @@ -10,22 +10,23 @@ #include "../test.hpp" #include +#include #include CO_TEST_CASE("ssl") { using namespace boost; - + asio::ssl::context ctx{asio::ssl::context_base::tlsv13_client}; auto t = (co_await async::io::lookup("boost.org", "https")).value(); REQUIRE(!t.empty()); - async::io::ssl_stream ss{}; + async::io::ssl_stream ss{ctx}; auto conn = co_await ss.connect(t.front()); CHECK_MESSAGE(conn, conn.error().message()); - CHECK(co_await ss.async_handshake(async::io::ssl_stream::handshake_type::client) - == system::in_place_value); + CHECK_NOTHROW(co_await ss.async_handshake(async::io::ssl_stream::handshake_type::client).value()); + co_await ss; CHECK_NOTHROW(co_await ss.async_shutdown()); } \ No newline at end of file From 8bf293647d2080bb11e2432a6f90396abe1ab5ef Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 7 Jul 2023 13:02:01 +0800 Subject: [PATCH 28/43] buffer improvements. --- include/boost/async/io/buffers.hpp | 2 +- include/boost/async/io/buffers/algorithm.hpp | 8 +++---- .../async/io/buffers/any_dynamic_buffer.hpp | 7 +++--- include/boost/async/io/buffers/buffer.hpp | 4 ++-- .../boost/async/io/buffers/buffer_copy.hpp | 8 +++---- .../boost/async/io/buffers/buffer_size.hpp | 8 +++---- .../async/io/buffers/circular_buffer.hpp | 5 ++-- .../buffers/{type_traits.hpp => concepts.hpp} | 15 +++++++----- .../boost/async/io/buffers/const_buffer.hpp | 10 ++++---- .../async/io/buffers/const_buffer_pair.hpp | 10 +++++--- .../async/io/buffers/const_buffer_span.hpp | 21 ++++------------ .../async/io/buffers/const_buffer_subspan.hpp | 9 ++++--- .../boost/async/io/buffers/flat_buffer.hpp | 5 ++-- .../io/buffers/impl/const_buffer_span.hpp | 4 ++-- .../io/buffers/impl/const_buffer_subspan.hpp | 4 ++-- .../io/buffers/impl/mutable_buffer_span.hpp | 4 ++-- .../buffers/impl/mutable_buffer_subspan.hpp | 4 ++-- .../boost/async/io/buffers/mutable_buffer.hpp | 8 +++---- .../async/io/buffers/mutable_buffer_pair.hpp | 10 +++++--- .../async/io/buffers/mutable_buffer_span.hpp | 21 ++++------------ .../io/buffers/mutable_buffer_subspan.hpp | 9 ++++--- include/boost/async/io/buffers/range.hpp | 8 +++---- .../boost/async/io/buffers/string_buffer.hpp | 24 +++++++++---------- include/boost/async/io/buffers/tag_invoke.hpp | 4 ++-- src/io/buffers/circular_buffer.cpp | 2 +- test/io/buffers/flat_buffer.cpp | 2 +- test/io/buffers/string_buffer.cpp | 7 ------ test/io/buffers/type_traits.cpp | 2 +- 28 files changed, 100 insertions(+), 125 deletions(-) rename include/boost/async/io/buffers/{type_traits.hpp => concepts.hpp} (90%) diff --git a/include/boost/async/io/buffers.hpp b/include/boost/async/io/buffers.hpp index 6f215946..08b15683 100644 --- a/include/boost/async/io/buffers.hpp +++ b/include/boost/async/io/buffers.hpp @@ -27,6 +27,6 @@ #include #include #include -#include +#include #endif diff --git a/include/boost/async/io/buffers/algorithm.hpp b/include/boost/async/io/buffers/algorithm.hpp index 9c69ea2c..a6e29c3d 100644 --- a/include/boost/async/io/buffers/algorithm.hpp +++ b/include/boost/async/io/buffers/algorithm.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_ALGORITHM_HPP -#define BOOST_BUFFERS_ALGORITHM_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_ALGORITHM_HPP +#define BOOST_ASYNC_IO_BUFFERS_ALGORITHM_HPP #include #include @@ -16,12 +16,12 @@ #include #include #include -#include +#include #include namespace boost::async::io::buffers { -#ifdef BOOST_BUFFERS_DOCS +#ifdef BOOST_ASYNC_IO_BUFFERS_DOCS /** Returns the type of a prefix of a buffer sequence. */ diff --git a/include/boost/async/io/buffers/any_dynamic_buffer.hpp b/include/boost/async/io/buffers/any_dynamic_buffer.hpp index 308d226d..a44a2e24 100644 --- a/include/boost/async/io/buffers/any_dynamic_buffer.hpp +++ b/include/boost/async/io/buffers/any_dynamic_buffer.hpp @@ -7,14 +7,14 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_ANY_DYNAMIC_BUFFER_HPP -#define BOOST_BUFFERS_ANY_DYNAMIC_BUFFER_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_ANY_DYNAMIC_BUFFER_HPP +#define BOOST_ASYNC_IO_BUFFERS_ANY_DYNAMIC_BUFFER_HPP #include #include #include #include -#include +#include #include namespace boost::async::io::buffers { @@ -75,7 +75,6 @@ class any_dynamic_buffer_impl public: template - explicit any_dynamic_buffer_impl( DynamicBuffer_&& b) : b_(std::forward< diff --git a/include/boost/async/io/buffers/buffer.hpp b/include/boost/async/io/buffers/buffer.hpp index 7b933959..aa68ac61 100644 --- a/include/boost/async/io/buffers/buffer.hpp +++ b/include/boost/async/io/buffers/buffer.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_BUFFER_HPP -#define BOOST_BUFFERS_BUFFER_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_BUFFER_HPP +#define BOOST_ASYNC_IO_BUFFERS_BUFFER_HPP #include #include diff --git a/include/boost/async/io/buffers/buffer_copy.hpp b/include/boost/async/io/buffers/buffer_copy.hpp index e6a16b9d..d74a0eca 100644 --- a/include/boost/async/io/buffers/buffer_copy.hpp +++ b/include/boost/async/io/buffers/buffer_copy.hpp @@ -7,19 +7,19 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_BUFFER_COPY_HPP -#define BOOST_BUFFERS_BUFFER_COPY_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_BUFFER_COPY_HPP +#define BOOST_ASYNC_IO_BUFFERS_BUFFER_COPY_HPP #include #include -#include +#include #include #include #include namespace boost::async::io::buffers { -#ifdef BOOST_BUFFERS_DOCS +#ifdef BOOST_ASYNC_IO_BUFFERS_DOCS /** Copy buffer contents */ diff --git a/include/boost/async/io/buffers/buffer_size.hpp b/include/boost/async/io/buffers/buffer_size.hpp index 89ad5f26..af8d0d47 100644 --- a/include/boost/async/io/buffers/buffer_size.hpp +++ b/include/boost/async/io/buffers/buffer_size.hpp @@ -7,18 +7,18 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_BUFFER_SIZE_HPP -#define BOOST_BUFFERS_BUFFER_SIZE_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_BUFFER_SIZE_HPP +#define BOOST_ASYNC_IO_BUFFERS_BUFFER_SIZE_HPP #include #include #include #include -#include +#include namespace boost::async::io::buffers { -#ifdef BOOST_BUFFERS_DOCS +#ifdef BOOST_ASYNC_IO_BUFFERS_DOCS /** Return the total octets in a buffer sequence diff --git a/include/boost/async/io/buffers/circular_buffer.hpp b/include/boost/async/io/buffers/circular_buffer.hpp index 88f65df4..1487804f 100644 --- a/include/boost/async/io/buffers/circular_buffer.hpp +++ b/include/boost/async/io/buffers/circular_buffer.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_CIRCULAR_BUFFER_HPP -#define BOOST_BUFFERS_CIRCULAR_BUFFER_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_CIRCULAR_BUFFER_HPP +#define BOOST_ASYNC_IO_BUFFERS_CIRCULAR_BUFFER_HPP #include #include @@ -44,7 +44,6 @@ class circular_buffer #if 0 /** Constructor. */ - explicit circular_buffer( mutable_buffer b) noexcept : base_(static_cast< diff --git a/include/boost/async/io/buffers/type_traits.hpp b/include/boost/async/io/buffers/concepts.hpp similarity index 90% rename from include/boost/async/io/buffers/type_traits.hpp rename to include/boost/async/io/buffers/concepts.hpp index 688045c0..9020086a 100644 --- a/include/boost/async/io/buffers/type_traits.hpp +++ b/include/boost/async/io/buffers/concepts.hpp @@ -7,15 +7,15 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_TYPE_TRAITS_HPP -#define BOOST_BUFFERS_TYPE_TRAITS_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_CONCEPTS_HPP +#define BOOST_ASYNC_IO_BUFFERS_CONCEPTS_HPP #include #include namespace boost::async::io::buffers { -#ifndef BOOST_BUFFERS_DOCS +#ifndef BOOST_ASYNC_IO_BUFFERS_DOCS class const_buffer; class mutable_buffer; #endif @@ -24,7 +24,7 @@ class mutable_buffer; /** Determine if T is a ConstBuffers. */ -#if BOOST_BUFFERS_DOCS +#if BOOST_ASYNC_IO_BUFFERS_DOCS template struct is_const_buffer_sequence : std::integral_constant{}; @@ -54,7 +54,7 @@ concept const_buffer_sequence = /** Determine if T is a MutableBuffers. */ -#if BOOST_BUFFERS_DOCS +#if BOOST_ASYNC_IO_BUFFERS_DOCS template struct is_mutable_buffer_sequence : std::integral_constant{}; @@ -79,7 +79,7 @@ concept mutable_buffer_sequence = /** Determine if T is a DynamicBuffer */ -#if BOOST_BUFFERS_DOCS +#if BOOST_ASYNC_IO_BUFFERS_DOCS template struct is_dynamic_buffer : std::integral_constant{}; @@ -114,6 +114,9 @@ using value_type = typename #endif +template +concept buffer_byte = (sizeof(T) == 1u) && std::is_trivial_v; + } // boost::buffers diff --git a/include/boost/async/io/buffers/const_buffer.hpp b/include/boost/async/io/buffers/const_buffer.hpp index 5da252b4..40cb566d 100644 --- a/include/boost/async/io/buffers/const_buffer.hpp +++ b/include/boost/async/io/buffers/const_buffer.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_CONST_BUFFER_HPP -#define BOOST_BUFFERS_CONST_BUFFER_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_CONST_BUFFER_HPP +#define BOOST_ASYNC_IO_BUFFERS_CONST_BUFFER_HPP #include #include @@ -48,7 +48,7 @@ class const_buffer {ct.size()} -> std::convertible_to; } && std::is_trivial_v) - const_buffer(Container & ct) : const_buffer(ct.data(), ct.size()) {} + const_buffer(Container & ct) : const_buffer(ct.data(), sizeof(typename Container::value_type) * ct.size()) {} /** Constructor for strings */ template @@ -79,7 +79,7 @@ class const_buffer const_buffer& operator=( const_buffer const&) = default; -#ifndef BOOST_BUFFERS_DOCS +#ifndef BOOST_ASYNC_IO_BUFFERS_DOCS // conversion to boost::asio::const_buffer template requires (std::constructible_from @@ -141,7 +141,7 @@ class const_buffer return b += n; } -#ifndef BOOST_BUFFERS_DOCS +#ifndef BOOST_ASYNC_IO_BUFFERS_DOCS friend const_buffer tag_invoke( diff --git a/include/boost/async/io/buffers/const_buffer_pair.hpp b/include/boost/async/io/buffers/const_buffer_pair.hpp index 65b7cc8c..a8fced7e 100644 --- a/include/boost/async/io/buffers/const_buffer_pair.hpp +++ b/include/boost/async/io/buffers/const_buffer_pair.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_CONST_BUFFER_PAIR_HPP -#define BOOST_BUFFERS_CONST_BUFFER_PAIR_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_CONST_BUFFER_PAIR_HPP +#define BOOST_ASYNC_IO_BUFFERS_CONST_BUFFER_PAIR_HPP #include #include @@ -93,7 +93,11 @@ class const_buffer_pair return b_ + 2; } -#ifndef BOOST_BUFFERS_DOCS + const_buffer * data() { return b_; } + const const_buffer * data() const { return b_; } + std::size_t size() const {return 2u;} + +#ifndef BOOST_ASYNC_IO_BUFFERS_DOCS friend const_buffer_pair tag_invoke( diff --git a/include/boost/async/io/buffers/const_buffer_span.hpp b/include/boost/async/io/buffers/const_buffer_span.hpp index 9ffdd2b2..f3089fe4 100644 --- a/include/boost/async/io/buffers/const_buffer_span.hpp +++ b/include/boost/async/io/buffers/const_buffer_span.hpp @@ -7,13 +7,13 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_CONST_BUFFER_SPAN_HPP -#define BOOST_BUFFERS_CONST_BUFFER_SPAN_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_CONST_BUFFER_SPAN_HPP +#define BOOST_ASYNC_IO_BUFFERS_CONST_BUFFER_SPAN_HPP #include #include #include -#include +#include namespace boost::async::io::buffers { @@ -54,23 +54,12 @@ class const_buffer_span /** Constructor. */ - template - requires requires (const ConstBufferSequence & seq) {{seq.begin()} -> std::same_as;} - explicit - const_buffer_span( - ConstBufferSequence const& bs) noexcept - : p_(bs.begin()) - , n_(bs.end() - bs.begin()) - { - } - template requires requires (const ConstBufferSequence & seq) { - {seq.data()} -> std::same_as; + {seq.data()} -> std::convertible_to; {seq.size()} -> std::same_as; } - explicit const_buffer_span( ConstBufferSequence const& bs) noexcept : p_(bs.data()) @@ -106,7 +95,7 @@ class const_buffer_span return p_ + n_; } -#ifndef BOOST_BUFFERS_DOCS +#ifndef BOOST_ASYNC_IO_BUFFERS_DOCS friend const_buffer_subspan tag_invoke( diff --git a/include/boost/async/io/buffers/const_buffer_subspan.hpp b/include/boost/async/io/buffers/const_buffer_subspan.hpp index 303be352..09892067 100644 --- a/include/boost/async/io/buffers/const_buffer_subspan.hpp +++ b/include/boost/async/io/buffers/const_buffer_subspan.hpp @@ -7,15 +7,15 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_CONST_BUFFER_SUBSPAN_HPP -#define BOOST_BUFFERS_CONST_BUFFER_SUBSPAN_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_CONST_BUFFER_SUBSPAN_HPP +#define BOOST_ASYNC_IO_BUFFERS_CONST_BUFFER_SUBSPAN_HPP #include #include namespace boost::async::io::buffers { -#ifndef BOOST_BUFFERS_DOCS +#ifndef BOOST_ASYNC_IO_BUFFERS_DOCS class const_buffer_span; #endif @@ -61,7 +61,6 @@ class const_buffer_subspan /** Constructor. */ - explicit const_buffer_subspan( const_buffer_span const& s) noexcept; @@ -85,7 +84,7 @@ class const_buffer_subspan const_iterator end() const noexcept; -#ifndef BOOST_BUFFERS_DOCS +#ifndef BOOST_ASYNC_IO_BUFFERS_DOCS friend const_buffer_subspan tag_invoke( diff --git a/include/boost/async/io/buffers/flat_buffer.hpp b/include/boost/async/io/buffers/flat_buffer.hpp index 583c82db..247267a9 100644 --- a/include/boost/async/io/buffers/flat_buffer.hpp +++ b/include/boost/async/io/buffers/flat_buffer.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_FLAT_BUFFER_HPP -#define BOOST_BUFFERS_FLAT_BUFFER_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_FLAT_BUFFER_HPP +#define BOOST_ASYNC_IO_BUFFERS_FLAT_BUFFER_HPP #include #include @@ -76,7 +76,6 @@ class flat_buffer /** Constructor. */ - explicit flat_buffer( mutable_buffer const& b, std::size_t initial_size = 0) diff --git a/include/boost/async/io/buffers/impl/const_buffer_span.hpp b/include/boost/async/io/buffers/impl/const_buffer_span.hpp index 61016a90..5d3dc0c0 100644 --- a/include/boost/async/io/buffers/impl/const_buffer_span.hpp +++ b/include/boost/async/io/buffers/impl/const_buffer_span.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_IMPL_CONST_BUFFER_SPAN_HPP -#define BOOST_BUFFERS_IMPL_CONST_BUFFER_SPAN_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_IMPL_CONST_BUFFER_SPAN_HPP +#define BOOST_ASYNC_IO_BUFFERS_IMPL_CONST_BUFFER_SPAN_HPP namespace boost::async::io::buffers { diff --git a/include/boost/async/io/buffers/impl/const_buffer_subspan.hpp b/include/boost/async/io/buffers/impl/const_buffer_subspan.hpp index e48d0bb0..6b67dc5e 100644 --- a/include/boost/async/io/buffers/impl/const_buffer_subspan.hpp +++ b/include/boost/async/io/buffers/impl/const_buffer_subspan.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_IMPL_CONST_BUFFER_SUBSPAN_HPP -#define BOOST_BUFFERS_IMPL_CONST_BUFFER_SUBSPAN_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_IMPL_CONST_BUFFER_SUBSPAN_HPP +#define BOOST_ASYNC_IO_BUFFERS_IMPL_CONST_BUFFER_SUBSPAN_HPP #include #include diff --git a/include/boost/async/io/buffers/impl/mutable_buffer_span.hpp b/include/boost/async/io/buffers/impl/mutable_buffer_span.hpp index 75df2660..fab18dd1 100644 --- a/include/boost/async/io/buffers/impl/mutable_buffer_span.hpp +++ b/include/boost/async/io/buffers/impl/mutable_buffer_span.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_IMPL_MUTABLE_BUFFER_SPAN_HPP -#define BOOST_BUFFERS_IMPL_MUTABLE_BUFFER_SPAN_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_IMPL_MUTABLE_BUFFER_SPAN_HPP +#define BOOST_ASYNC_IO_BUFFERS_IMPL_MUTABLE_BUFFER_SPAN_HPP namespace boost::async::io::buffers { diff --git a/include/boost/async/io/buffers/impl/mutable_buffer_subspan.hpp b/include/boost/async/io/buffers/impl/mutable_buffer_subspan.hpp index 9ddf17bc..ec7ae9a2 100644 --- a/include/boost/async/io/buffers/impl/mutable_buffer_subspan.hpp +++ b/include/boost/async/io/buffers/impl/mutable_buffer_subspan.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_IMPL_MUTABLE_BUFFER_SUBSPAN_HPP -#define BOOST_BUFFERS_IMPL_MUTABLE_BUFFER_SUBSPAN_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_IMPL_MUTABLE_BUFFER_SUBSPAN_HPP +#define BOOST_ASYNC_IO_BUFFERS_IMPL_MUTABLE_BUFFER_SUBSPAN_HPP #include #include diff --git a/include/boost/async/io/buffers/mutable_buffer.hpp b/include/boost/async/io/buffers/mutable_buffer.hpp index 98e3bd29..f02c9d43 100644 --- a/include/boost/async/io/buffers/mutable_buffer.hpp +++ b/include/boost/async/io/buffers/mutable_buffer.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_MUTABLE_BUFFER_HPP -#define BOOST_BUFFERS_MUTABLE_BUFFER_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_MUTABLE_BUFFER_HPP +#define BOOST_ASYNC_IO_BUFFERS_MUTABLE_BUFFER_HPP #include #include @@ -59,7 +59,7 @@ class mutable_buffer {std::size(ct)} -> std::convertible_to; } && std::is_trivial_v) - mutable_buffer(Container & ct) : mutable_buffer(std::data(ct), std::size(ct)) {} + mutable_buffer(Container & ct) : mutable_buffer(std::data(ct), sizeof(typename Container::value_type) * std::size(ct)) {} /** Constructor for arrays */ template @@ -71,7 +71,7 @@ class mutable_buffer mutable_buffer& operator=( mutable_buffer const&) = default; -#ifndef BOOST_BUFFERS_DOCS +#ifndef BOOST_ASYNC_IO_BUFFERS_DOCS // conversion to boost::asio::mutable_buffer template requires (std::constructible_from diff --git a/include/boost/async/io/buffers/mutable_buffer_pair.hpp b/include/boost/async/io/buffers/mutable_buffer_pair.hpp index 326c7c24..354bca21 100644 --- a/include/boost/async/io/buffers/mutable_buffer_pair.hpp +++ b/include/boost/async/io/buffers/mutable_buffer_pair.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_MUTABLE_BUFFER_PAIR_HPP -#define BOOST_BUFFERS_MUTABLE_BUFFER_PAIR_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_MUTABLE_BUFFER_PAIR_HPP +#define BOOST_ASYNC_IO_BUFFERS_MUTABLE_BUFFER_PAIR_HPP #include #include @@ -74,7 +74,11 @@ class mutable_buffer_pair return b_ + 2; } -#ifndef BOOST_BUFFERS_DOCS + mutable_buffer * data() { return b_; } + const mutable_buffer * data() const { return b_; } + std::size_t size() const {return 2u;} + +#ifndef BOOST_ASYNC_IO_BUFFERS_DOCS friend mutable_buffer_pair tag_invoke( diff --git a/include/boost/async/io/buffers/mutable_buffer_span.hpp b/include/boost/async/io/buffers/mutable_buffer_span.hpp index 742d7b1a..179b9d50 100644 --- a/include/boost/async/io/buffers/mutable_buffer_span.hpp +++ b/include/boost/async/io/buffers/mutable_buffer_span.hpp @@ -7,13 +7,13 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_MUTABLE_BUFFER_SPAN_HPP -#define BOOST_BUFFERS_MUTABLE_BUFFER_SPAN_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_MUTABLE_BUFFER_SPAN_HPP +#define BOOST_ASYNC_IO_BUFFERS_MUTABLE_BUFFER_SPAN_HPP #include #include #include -#include +#include namespace boost::async::io::buffers { @@ -54,23 +54,12 @@ class mutable_buffer_span /** Constructor. */ - template - requires requires (const MutableBufferSequence & seq) {{seq.begin()} -> std::same_as;} - explicit - mutable_buffer_span( - MutableBufferSequence const& bs) noexcept - : p_(bs.begin()) - , n_(bs.end() - bs.begin()) - { - } - template requires requires (const MutableBufferSequence & seq) { - {seq.data()} -> std::same_as; + {seq.data()} -> std::convertible_to; {seq.size()} -> std::same_as; } - explicit mutable_buffer_span( MutableBufferSequence const& bs) noexcept : p_(bs.data()) @@ -104,7 +93,7 @@ class mutable_buffer_span return p_ + n_; } -#ifndef BOOST_BUFFERS_DOCS +#ifndef BOOST_ASYNC_IO_BUFFERS_DOCS friend mutable_buffer_subspan tag_invoke( diff --git a/include/boost/async/io/buffers/mutable_buffer_subspan.hpp b/include/boost/async/io/buffers/mutable_buffer_subspan.hpp index e3c53399..e14c3623 100644 --- a/include/boost/async/io/buffers/mutable_buffer_subspan.hpp +++ b/include/boost/async/io/buffers/mutable_buffer_subspan.hpp @@ -7,15 +7,15 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_MUTABLE_BUFFER_SUBSPAN_HPP -#define BOOST_BUFFERS_MUTABLE_BUFFER_SUBSPAN_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_MUTABLE_BUFFER_SUBSPAN_HPP +#define BOOST_ASYNC_IO_BUFFERS_MUTABLE_BUFFER_SUBSPAN_HPP #include #include namespace boost::async::io::buffers { -#ifndef BOOST_BUFFERS_DOCS +#ifndef BOOST_ASYNC_IO_BUFFERS_DOCS class mutable_buffer_span; #endif @@ -61,7 +61,6 @@ class mutable_buffer_subspan /** Constructor. */ - explicit mutable_buffer_subspan( mutable_buffer_span const& s) noexcept; @@ -85,7 +84,7 @@ class mutable_buffer_subspan const_iterator end() const noexcept; -#ifndef BOOST_BUFFERS_DOCS +#ifndef BOOST_ASYNC_IO_BUFFERS_DOCS friend mutable_buffer_subspan tag_invoke( diff --git a/include/boost/async/io/buffers/range.hpp b/include/boost/async/io/buffers/range.hpp index b446144c..c9758b77 100644 --- a/include/boost/async/io/buffers/range.hpp +++ b/include/boost/async/io/buffers/range.hpp @@ -7,18 +7,18 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_RANGE_HPP -#define BOOST_BUFFERS_RANGE_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_RANGE_HPP +#define BOOST_ASYNC_IO_BUFFERS_RANGE_HPP #include #include #include -#include +#include #include namespace boost::async::io::buffers { -#ifdef BOOST_BUFFERS_DOCS +#ifdef BOOST_ASYNC_IO_BUFFERS_DOCS /** Return an iterator to the beginning of the buffer sequence. */ diff --git a/include/boost/async/io/buffers/string_buffer.hpp b/include/boost/async/io/buffers/string_buffer.hpp index 163e9ae2..2f7eaed8 100644 --- a/include/boost/async/io/buffers/string_buffer.hpp +++ b/include/boost/async/io/buffers/string_buffer.hpp @@ -7,11 +7,12 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_STRING_BUFFER_HPP -#define BOOST_BUFFERS_STRING_BUFFER_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_STRING_BUFFER_HPP +#define BOOST_ASYNC_IO_BUFFERS_STRING_BUFFER_HPP #include #include +#include #include #include #include @@ -21,7 +22,7 @@ namespace boost::async::io::buffers { /** A dynamic buffer using an underlying string */ template< - class CharT, + buffer_byte CharT, class Traits = std::char_traits, class Allocator = std::allocator> class basic_string_buffer @@ -63,7 +64,6 @@ class basic_string_buffer /** Constructor. */ - explicit basic_string_buffer( string_type* s, std::size_t max_size = @@ -87,13 +87,13 @@ class basic_string_buffer std::size_t size() const noexcept { - return in_size_* sizeof(CharT); + return in_size_; } std::size_t max_size() const noexcept { - return max_size_ * sizeof(CharT); + return max_size_; } std::size_t @@ -101,7 +101,7 @@ class basic_string_buffer { if(s_->capacity() <= max_size_) return s_->capacity() - in_size_; - return (max_size_ - in_size_) * sizeof(CharT); + return max_size_ - in_size_; } const_buffers_type @@ -109,14 +109,12 @@ class basic_string_buffer { return { s_->data(), - in_size_ * sizeof(CharT)}; + in_size_ }; } mutable_buffers_type - prepare(std::size_t n_) + prepare(std::size_t n) { - const auto n = (n_ / sizeof(CharT)) + (std::min)(n_ % sizeof(CharT), static_cast(1u)); - // n exceeds available space if(n > max_size_ - in_size_) async::detail::throw_invalid_argument(); @@ -126,7 +124,7 @@ class basic_string_buffer out_size_ = n; return { &(*s_)[in_size_], - out_size_ * sizeof(CharT)}; + out_size_ }; } void @@ -159,6 +157,6 @@ class basic_string_buffer using string_buffer = basic_string_buffer; -} // boost::buffers +} // boost::async::io::buffers #endif diff --git a/include/boost/async/io/buffers/tag_invoke.hpp b/include/boost/async/io/buffers/tag_invoke.hpp index 1d1742a1..47badf5a 100644 --- a/include/boost/async/io/buffers/tag_invoke.hpp +++ b/include/boost/async/io/buffers/tag_invoke.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/CPPAlliance/buffers // -#ifndef BOOST_BUFFERS_TAG_INVOKE_HPP -#define BOOST_BUFFERS_TAG_INVOKE_HPP +#ifndef BOOST_ASYNC_IO_BUFFERS_TAG_INVOKE_HPP +#define BOOST_ASYNC_IO_BUFFERS_TAG_INVOKE_HPP #include diff --git a/src/io/buffers/circular_buffer.cpp b/src/io/buffers/circular_buffer.cpp index d36c542e..9a10f671 100644 --- a/src/io/buffers/circular_buffer.cpp +++ b/src/io/buffers/circular_buffer.cpp @@ -8,7 +8,7 @@ // #include -#include +#include #include #include #include diff --git a/test/io/buffers/flat_buffer.cpp b/test/io/buffers/flat_buffer.cpp index f37f4523..84e990d3 100644 --- a/test/io/buffers/flat_buffer.cpp +++ b/test/io/buffers/flat_buffer.cpp @@ -10,7 +10,7 @@ // Test that header file is self-contained. #include -#include +#include #include #include "test_helpers.hpp" diff --git a/test/io/buffers/string_buffer.cpp b/test/io/buffers/string_buffer.cpp index 86b6711d..4243ce53 100644 --- a/test/io/buffers/string_buffer.cpp +++ b/test/io/buffers/string_buffer.cpp @@ -70,13 +70,6 @@ struct string_buffer_test BOOST_TEST_EQ(b.size(), 4); } - // ws.size() - { - std::u16string ws = u"1234"; - basic_string_buffer b(&ws); - BOOST_TEST_EQ(b.size(), 8); - } - // capacity() { { diff --git a/test/io/buffers/type_traits.cpp b/test/io/buffers/type_traits.cpp index 7a9d9e6d..68445987 100644 --- a/test/io/buffers/type_traits.cpp +++ b/test/io/buffers/type_traits.cpp @@ -8,4 +8,4 @@ // // Test that header file is self-contained. -#include +#include From cd7e6ac99576290d976f4924afd77998f78a4967 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 7 Jul 2023 14:30:58 +0800 Subject: [PATCH 29/43] improved read, write & copy algos. --- CMakeLists.txt | 4 +- include/boost/async/io/copy_n.hpp | 37 ++++++++++++ include/boost/async/io/read.hpp | 24 ++++---- include/boost/async/io/read_all.hpp | 34 +++++++++++ include/boost/async/io/read_at.hpp | 19 ++++-- include/boost/async/io/write.hpp | 24 +++++--- src/io/copy_n.cpp | 89 +++++++++++++++++++++++++++++ src/io/read.cpp | 14 ----- src/io/read_all.cpp | 38 ++++++++++++ test/io/copy.cpp | 3 +- test/io/read_all.cpp | 53 +++++++++++++++++ 11 files changed, 301 insertions(+), 38 deletions(-) create mode 100644 include/boost/async/io/copy_n.hpp create mode 100644 include/boost/async/io/read_all.hpp create mode 100644 src/io/copy_n.cpp create mode 100644 src/io/read_all.cpp create mode 100644 test/io/read_all.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f5ec30ad..028222de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,6 +110,7 @@ add_library(boost_async src/io/random_access_file.cpp src/io/file.cpp src/io/read.cpp + src/io/read_all.cpp src/io/read_at.cpp src/io/read_until.cpp src/io/popen.cpp @@ -118,7 +119,8 @@ add_library(boost_async src/io/write.cpp src/io/write_at.cpp src/io/detail/random_access_device.cpp - src/io/copy.cpp) + src/io/copy.cpp + src/io/copy_n.cpp) target_include_directories(boost_async PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(boost_async PUBLIC diff --git a/include/boost/async/io/copy_n.hpp b/include/boost/async/io/copy_n.hpp new file mode 100644 index 00000000..434675bc --- /dev/null +++ b/include/boost/async/io/copy_n.hpp @@ -0,0 +1,37 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_COPY_N_HPP +#define BOOST_ASYNC_IO_COPY_N_HPP + +#include +#include +#include + +namespace boost::async::io +{ + +BOOST_ASYNC_DECL promise> +copy_n(stream & source, stream & sink, std::size_t n); + +BOOST_ASYNC_DECL promise> +copy_n(stream & source, stream & sink, buffers::any_dynamic_buffer & buffer, + std::size_t n, std::size_t chunk_size = 4096); + + +template +promise copy_n(stream & source, stream & sink, DynamicBuffer & buffer, + std::size_t n, std::size_t chunk_size = 4096) +{ + auto any = buffers::make_any(buffer); + buffers::any_dynamic_buffer & ab = any; + co_return co_await copy_n(source, sink, ab, n, chunk_size); +} + +} + +#endif //BOOST_ASYNC_IO_COPY_N_HPP diff --git a/include/boost/async/io/read.hpp b/include/boost/async/io/read.hpp index fc598dab..0524670d 100644 --- a/include/boost/async/io/read.hpp +++ b/include/boost/async/io/read.hpp @@ -27,18 +27,20 @@ template requires (!std::convertible_to) promise read(stream & source, MutableBufferSequence && buffer) { - buffers::mutable_buffer buf[32]; - container::pmr::monotonic_buffer_resource res{buf, sizeof(buf), this_thread::get_default_resource()}; - container::pmr::vector buf_span{buffer.begin(), buffer.end(), &res}; - co_return co_await read(source, buffers::mutable_buffer_span{buf_span}); -} + buffers::mutable_buffer buf[asio::detail::max_iov_len]; -template -promise read(stream & source, DynamicBuffer && buffer, std::size_t chunk_size = 4096) -{ - auto any = buffers::make_any(std::forward(buffer)); - buffers::any_dynamic_buffer & ab = any; - co_return co_await read(source, ab, chunk_size); + transfer_result tr{}; + + for (auto itr = buffers::begin(buffer), end = buffers::end(buffer); itr != end;) + { + auto ie = (std::min)(end, std::next(itr, asio::detail::max_iov_len)); + auto oe = std::copy(itr, ie, buf); + + buffers::mutable_buffer_span cbs{buf, std::distance(buf, oe)}; + tr += co_await read(source, cbs); + itr = ie; + } + co_return tr; } diff --git a/include/boost/async/io/read_all.hpp b/include/boost/async/io/read_all.hpp new file mode 100644 index 00000000..82e096f0 --- /dev/null +++ b/include/boost/async/io/read_all.hpp @@ -0,0 +1,34 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_READ_ALL_HPP +#define BOOST_ASYNC_IO_READ_ALL_HPP + +#include +#include +#include +#include +#include + +namespace boost::async::io +{ + +BOOST_ASYNC_DECL promise read_all(stream & source, buffers::any_dynamic_buffer & buffer, + std::size_t chunk_size = 4096); + +template +promise read_all(stream & source, DynamicBuffer &&buffer, std::size_t chunk_size = 4096) +{ + auto any = buffers::make_any(std::forward(buffer)); + buffers::any_dynamic_buffer & ab = any; + co_return co_await read_all(source, ab, chunk_size); +} + + +} + +#endif //BOOST_ASYNC_IO_READ_ALL_HPP diff --git a/include/boost/async/io/read_at.hpp b/include/boost/async/io/read_at.hpp index e0c62f0d..5798dd53 100644 --- a/include/boost/async/io/read_at.hpp +++ b/include/boost/async/io/read_at.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -23,10 +24,20 @@ template requires (!std::convertible_to) promise read(random_access_device & source, std::uint64_t offset, MutableBufferSequence && buffer) { - buffers::mutable_buffer buf[32]; - container::pmr::monotonic_buffer_resource res{buf, sizeof(buf), this_thread::get_default_resource()}; - container::pmr::vector buf_span{buffer.begin(), buffer.end(), &res}; - co_return co_await read_at(source, offset, buffers::mutable_buffer_span{buf_span}); + buffers::mutable_buffer buf[asio::detail::max_iov_len]; + + transfer_result tr{}; + + for (auto itr = buffers::begin(buffer), end = buffers::end(buffer); itr != end;) + { + auto ie = (std::min)(end, std::next(itr, asio::detail::max_iov_len)); + auto oe = std::copy(itr, ie, buf); + + buffers::mutable_buffer_span cbs{buf, std::distance(buf, oe)}; + tr += co_await read_at(source, offset + tr.transferred, cbs); + itr = ie; + } + co_return tr; } diff --git a/include/boost/async/io/write.hpp b/include/boost/async/io/write.hpp index 92db61b7..a69e6fde 100644 --- a/include/boost/async/io/write.hpp +++ b/include/boost/async/io/write.hpp @@ -21,14 +21,24 @@ BOOST_ASYNC_DECL promise write(stream & source, buffers::const_ BOOST_ASYNC_DECL promise write(stream & source, buffers::const_buffer_span buffer); BOOST_ASYNC_DECL promise write(stream & source, buffers::const_buffer_subspan buffer); -template - requires (!std::convertible_to) -promise write(stream & source, MutableBufferSequence && buffer) +template + requires (!std::convertible_to) +promise write(stream & source, ConstBufferSequence && buffer) { - buffers::const_buffer buf[32]; - container::pmr::monotonic_buffer_resource res{buf, sizeof(buf), this_thread::get_default_resource()}; - container::pmr::vector buf_span{buffer.begin(), buffer.end(), &res}; - co_return co_await write(source, buffers::const_buffer_span{buf_span}); + buffers::const_buffer buf[asio::detail::max_iov_len]; + + transfer_result tr{}; + + for (auto itr = buffers::begin(buffer), end = buffers::end(buffer); itr != end;) + { + auto ie = (std::min)(end, std::next(itr, asio::detail::max_iov_len)); + auto oe = std::copy(itr, ie, buf); + + buffers::const_buffer_span cbs{buf, std::distance(buf, oe)}; + tr += co_await write(source, cbs); + itr = ie; + } + co_return tr; } } diff --git a/src/io/copy_n.cpp b/src/io/copy_n.cpp new file mode 100644 index 00000000..3b85f1c2 --- /dev/null +++ b/src/io/copy_n.cpp @@ -0,0 +1,89 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include +#include +#include + +namespace boost::async::io +{ + +promise> +copy_n(stream & source, stream & sink, std::size_t n) +{ + constexpr std::size_t chunk_size = 4096; + char mem[chunk_size * 2]; + buffers::circular_buffer buf{mem, sizeof(mem)}; + + transfer_result r = co_await source.read_some(buffers::mutable_buffer_span(buf.prepare(chunk_size))), + w = {}; + + buf.commit(r.transferred); + + while (!r.has_error() && !w.has_error() && (n > 0u)) + { + auto [r2, w2] = co_await join( + source.read_some(buffers::mutable_buffer_span(buf.prepare((std::min)(chunk_size, n)))), + sink.write_some(buffers::const_buffer_span(buf.data()))); + buf.commit(r2.transferred); + n -= r2.transferred; + buf.consume(w2.transferred); + r.transferred += r2.transferred; + w.transferred += w2.transferred; + r.error = r2.error; + w.error = w2.error; + } + // remaining readable stuff + while (r.has_error() && !w.has_error() && buffers::buffer_size(buf.data()) > 0u) + { + assert(false); + auto w2 = co_await sink.write_some(buffers::const_buffer_span(buf.data())); + buf.consume(w2.transferred); + w.transferred = w2.transferred; + w.error = w2.error; + } + + co_return {r, w}; +} + +promise> +copy_n(stream & source, stream & sink, buffers::any_dynamic_buffer & buf, + std::size_t n, std::size_t chunk_size) +{ + transfer_result r = co_await source.read_some(buffers::mutable_buffer_span(buf.prepare(chunk_size))), + w = {}; + + buf.commit(r.transferred); + + while (!r.has_error() && !w.has_error()) + { + auto [r2, w2] = co_await join( + source.read_some(buffers::mutable_buffer_span(buf.prepare((std::min)(chunk_size, n)))), + sink.write_some(buffers::const_buffer_span(buf.data()))); + buf.commit(r2.transferred); + buf.consume(w2.transferred); + n -= r2.transferred; + r.transferred += r2.transferred; + w.transferred += w2.transferred; + r.error = r2.error; + w.error = w2.error; + } + // remaining readable stuff + while (r.has_error() && !w.has_error() && buffers::buffer_size(buf.data()) > 0u) + { + assert(false); + auto w2 = co_await sink.write_some(buffers::const_buffer_span(buf.data())); + buf.consume(w2.transferred); + w.transferred = w2.transferred; + w.error = w2.error; + } + co_return {r, w}; +} + + +} diff --git a/src/io/read.cpp b/src/io/read.cpp index 613038ef..8cf9b3d4 100644 --- a/src/io/read.cpp +++ b/src/io/read.cpp @@ -46,19 +46,5 @@ promise read(stream & source, buffers::mutable_buffer_span buff } -promise read(stream & source, buffers::any_dynamic_buffer & buffer, std::size_t chunk_size) -{ - transfer_result tr; - - do - { - auto rd = co_await source.read_some(buffer.prepare(chunk_size)); - tr.transferred += rd.transferred; - tr.error = rd.error; - buffer.commit(rd.transferred); - } - while (buffer.size() >= 0 && !tr.has_error()); - co_return tr; -} } \ No newline at end of file diff --git a/src/io/read_all.cpp b/src/io/read_all.cpp new file mode 100644 index 00000000..4f8c3ca5 --- /dev/null +++ b/src/io/read_all.cpp @@ -0,0 +1,38 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include +#include +#include +#include + +#include +#include +#include + +namespace boost::async::io +{ + +promise read_all(stream & source, buffers::any_dynamic_buffer & buffer, std::size_t chunk_size) +{ + transfer_result tr; + + do + { + auto rd = co_await source.read_some(buffer.prepare(chunk_size)); + tr.transferred += rd.transferred; + tr.error = rd.error; + buffer.commit(rd.transferred); + } + while (buffer.size() >= 0 && !tr.has_error()); + co_return tr; +} + + + + +} \ No newline at end of file diff --git a/test/io/copy.cpp b/test/io/copy.cpp index f9e1b478..e437862a 100644 --- a/test/io/copy.cpp +++ b/test/io/copy.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -52,7 +53,7 @@ CO_TEST_CASE("copy") auto p = do_write__(w, input); auto c = do_copy(ri, wi); std::string output; - auto res = co_await io::read(r, io::buffers::string_buffer(&output)); + auto res = co_await io::read_all(r, io::buffers::string_buffer(&output)); CHECK(res.transferred == output.size()); CHECK(res.transferred == input.size()); diff --git a/test/io/read_all.cpp b/test/io/read_all.cpp new file mode 100644 index 00000000..1a9b1d76 --- /dev/null +++ b/test/io/read_all.cpp @@ -0,0 +1,53 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#include "../doctest.h" +#include "../test.hpp" +#include +#include +#include +#include +#include +#include + +#include + +using namespace boost::async; + +static promise do_write_2(io::stream & str, std::string & input ) +{ + boost::ignore_unused(co_await io::write(str, {input.data(), input.size()})); +}; + +CO_TEST_CASE("read") +{ + auto [r, w] = io::make_pipe().value(); + + std::string input; + + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution distPrintable(32,126); + + input.resize(1024*1024); + std::generate(input.begin(), input.end(), [&]{return static_cast(distPrintable(rng));}); + + auto p = do_write_2(w, input); + + std::string output; + output.resize(1024*16); + auto res = co_await io::read_all(r, io::buffers::string_buffer(&output)); + + CHECK(res.transferred == output.size()); + CHECK(!res.has_error()); + + CHECK(std::equal(output.begin(), output.end(), input.begin())); + + CHECK(!r.close().has_error()); + co_await p; +} + From 0f32c6dd54e041b2b90d0b1e2779638bdcf0cd54 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Wed, 5 Jul 2023 01:16:38 +0800 Subject: [PATCH 30/43] dynamic_buffer_view --- include/boost/async/io/buffers/concepts.hpp | 10 +- .../boost/async/io/buffers/const_buffer.hpp | 8 +- .../async/io/buffers/dynamic_buffer_view.hpp | 102 ++++++++ .../io/buffers/impl/dynamic_buffer_view.hpp | 246 ++++++++++++++++++ .../boost/async/io/buffers/mutable_buffer.hpp | 6 + .../boost/async/io/buffers/string_buffer.hpp | 1 + test/io/buffers/CMakeLists.txt | 1 + test/io/buffers/dynamic_buffer_view.cpp | 245 +++++++++++++++++ 8 files changed, 615 insertions(+), 4 deletions(-) create mode 100644 include/boost/async/io/buffers/dynamic_buffer_view.hpp create mode 100644 include/boost/async/io/buffers/impl/dynamic_buffer_view.hpp create mode 100644 test/io/buffers/dynamic_buffer_view.cpp diff --git a/include/boost/async/io/buffers/concepts.hpp b/include/boost/async/io/buffers/concepts.hpp index 9020086a..ee72e264 100644 --- a/include/boost/async/io/buffers/concepts.hpp +++ b/include/boost/async/io/buffers/concepts.hpp @@ -87,11 +87,15 @@ struct is_dynamic_buffer template concept dynamic_buffer = + requires (const T & buf, std::size_t n) + { + { buf.size() } -> std::same_as; + { buf.max_size() } -> std::same_as; + { buf.capacity() } -> std::same_as; + } && requires (T & buf, std::size_t n) { - {buf.size()} -> std::same_as; - {buf.max_size()} -> std::same_as; - {buf.capacity()} -> std::same_as; + {buf.commit(n)}; {buf.consume(n)}; {buf.data()} -> const_buffer_sequence; diff --git a/include/boost/async/io/buffers/const_buffer.hpp b/include/boost/async/io/buffers/const_buffer.hpp index 40cb566d..ba9c7f14 100644 --- a/include/boost/async/io/buffers/const_buffer.hpp +++ b/include/boost/async/io/buffers/const_buffer.hpp @@ -59,7 +59,13 @@ class const_buffer requires std::is_trivial_v const_buffer(const T (&arr)[N]) : const_buffer(&arr[0], sizeof(T) * N) {} - /** Constructor. + /** Constructor for arrays */ + template + requires std::is_trivial_v + const_buffer(std::pair p) : const_buffer(p.first, sizeof(T) * p.second) {} + + + /** Constructor. */ const_buffer( const_buffer const&) = default; diff --git a/include/boost/async/io/buffers/dynamic_buffer_view.hpp b/include/boost/async/io/buffers/dynamic_buffer_view.hpp new file mode 100644 index 00000000..f7157849 --- /dev/null +++ b/include/boost/async/io/buffers/dynamic_buffer_view.hpp @@ -0,0 +1,102 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_BUFFER_DYNAMIC_BUFFER_VIEW_HPP +#define BOOST_ASYNC_IO_BUFFER_DYNAMIC_BUFFER_VIEW_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace boost::async::io::buffers +{ + +struct dynamic_buffer_view +{ + using mutable_buffers_type = container::static_vector; + using const_buffers_type = container::static_vector< const_buffer, boost::asio::detail::max_iov_len>; + + std::size_t size () const { return vtable_.size (this_, position_); } + std::size_t max_size() const { return vtable_.max_size(this_); } + std::size_t capacity() const { return vtable_.capacity(this_); } + const_buffers_type data () const { return vtable_.data (this_, position_); } + mutable_buffers_type prepare (std::size_t n) { return vtable_.prepare (this_, n, position_); } + void commit (std::size_t n) { return vtable_.commit (this_, n, position_); } + void consume (std::size_t n) { return vtable_.consume (this_, n, position_); } + + dynamic_buffer_view(const dynamic_buffer_view&) noexcept = default; + dynamic_buffer_view(dynamic_buffer_view&&) noexcept =default; + + template + dynamic_buffer_view(Buffer &other); + + template + requires ( + requires (const Container & ct) + { + {ct.data()} -> std::convertible_to; + {ct.size()} -> std::convertible_to; + {ct.max_size()} -> std::convertible_to; + {ct.capacity()} -> std::convertible_to; + } + && requires (Container & ct) + { + {ct.data()} -> std::convertible_to; + {ct.resize(std::size_t())}; + {ct.erase(ct.begin(), ct.end())}; + } + && std::is_trivial_v + && sizeof(typename Container::value_type) == 1u) + dynamic_buffer_view(Container &other); + + template + requires (std::is_trivial_v && sizeof(T) == 1u) + dynamic_buffer_view(boost::circular_buffer &other); + + template + requires (std::is_trivial_v && sizeof(T) == 1u) + dynamic_buffer_view(boost::container::deque &other); + + private: + struct vtable_t + { + std::size_t (*size) (const void * this_, std::size_t pos) = 0; + std::size_t (*max_size)(const void * this_) = 0; + std::size_t (*capacity)(const void * this_) = 0; + const_buffers_type (*data) (const void * this_, std::size_t pos) = 0; + mutable_buffers_type (*prepare) (void * this_, std::size_t n, std::size_t pos) = 0; + void (*commit) (void * this_, std::size_t n, std::size_t & pos) = 0; + void (*consume) (void * this_, std::size_t n, std::size_t & pos) = 0; + }; + struct vtables; + + void* this_; + const vtable_t & vtable_; + std::size_t position_{0u}; +}; + + + + + + +} + +#include + +#endif //BOOST_ASYNC_IO_BUFFER_DYNAMIC_BUFFER_VIEW_HPP diff --git a/include/boost/async/io/buffers/impl/dynamic_buffer_view.hpp b/include/boost/async/io/buffers/impl/dynamic_buffer_view.hpp new file mode 100644 index 00000000..592b14d7 --- /dev/null +++ b/include/boost/async/io/buffers/impl/dynamic_buffer_view.hpp @@ -0,0 +1,246 @@ +// +// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// 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) +// + +#ifndef BOOST_ASYNC_IO_BUFFERS_IMPL_DYNAMIC_BUFFER_VIEW_HPP +#define BOOST_ASYNC_IO_BUFFERS_IMPL_DYNAMIC_BUFFER_VIEW_HPP + +#include + +namespace boost::async::io::buffers +{ + +struct dynamic_buffer_view::vtables +{ + + template + constexpr static dynamic_buffer_view::vtable_t dynamic_buffer_vtable_{ + .size =[](const void *this_, std::size_t) { return static_cast(this_)->size(); }, + .max_size =[](const void *this_) { return static_cast(this_)->max_size(); }, + .capacity =[](const void *this_) { return static_cast(this_)->capacity(); }, + .data =[](const void *this_, std::size_t) + { + auto d = static_cast(this_)->data(); + dynamic_buffer_view::const_buffers_type cbt{begin(d), end(d)}; + return cbt; + }, + .prepare =[](void *this_, std::size_t n, std::size_t) + { + auto p = static_cast(this_)->prepare(n); + dynamic_buffer_view::mutable_buffers_type mbt{begin(p), end(p)}; + return mbt; + }, + .commit =[](void *this_, std::size_t n, std::size_t &) { static_cast(this_)->commit(n); }, + .consume =[](void *this_, std::size_t n, std::size_t &) { static_cast(this_)->consume(n); } + }; + + + template + constexpr static dynamic_buffer_view::vtable_t contiguous_vtable_{ + .size = [](const void *this_, std::size_t pos) { return pos; }, + .max_size = [](const void *this_) { return static_cast(this_)->max_size(); }, + .capacity = [](const void *this_) { return static_cast(this_)->capacity(); }, + .data =[](const void *this_, std::size_t position) + { + auto self = static_cast(this_); + const auto p = self->data(); + const_buffer cb{p, position}; + dynamic_buffer_view::const_buffers_type cbt{cb}; + return cbt; + }, + .prepare =[](void *this_, std::size_t n, std::size_t position) + { + auto self = static_cast(this_); + auto sz = position + n; + if (sz > self->size()) + self->resize(sz); + + mutable_buffer buf{self->data(), position + n}; + buf += position; + return mutable_buffers_type{buf}; + }, + .commit =[](void *this_, std::size_t n, std::size_t &position) + { + position += n; + static_cast(this_)->resize(position); + }, + .consume =[](void *this_, std::size_t n, std::size_t &position) + { + auto self = static_cast(this_); + std::size_t consume_length = (std::min)(n, position); + self->erase(self->begin(), std::next(self->begin(), consume_length)); + position -= consume_length; + } + }; + + + template + constexpr static dynamic_buffer_view::vtable_t circular_vtable_{ + .size = [](const void *this_, std::size_t pos) { return pos; }, + .max_size = [](const void *this_) { return static_cast(this_)->max_size(); }, + .capacity = [](const void *this_) { return static_cast(this_)->capacity(); }, + .data = [](const void *this_, std::size_t position) + { + auto self = static_cast(this_); + const_buffers_type res; + + const_buffer_pair tmp{ + self->array_one(), + self->array_two() + }; + auto cb = prefix(tmp, position); + + for (auto val: cb) + if (val.size() > 0u) + res.push_back(val); + return res; + }, + .prepare = [](void *this_, std::size_t n, std::size_t position) + { + auto self = static_cast(this_); + + auto sz = (std::min)(position + n, self->max_size()); + if (sz > self->size()) + self->resize(sz); + + mutable_buffer_pair buf{self->array_one(), self->array_two()}; + mutable_buffers_type res; + for (auto val: sans_prefix(buf, position)) + if (val.size() > 0u) + res.push_back(val); + return res; + }, + .commit =[](void *this_, std::size_t n, std::size_t &position) + { + position += n; + static_cast(this_)->resize(position); + }, + .consume =[](void *this_, std::size_t n, std::size_t &position) + { + auto self = static_cast(this_); + self->erase_begin(n); + position -= n; + } + }; + + template + constexpr static dynamic_buffer_view::vtable_t deque_vtable_{ + .size = [](const void *this_, std::size_t pos) { return pos; }, + .max_size = [](const void *this_) { return static_cast(this_)->max_size(); }, + .capacity = [](const void *this_) { return static_cast(this_)->size(); }, + .data = [](const void *this_, std::size_t position) + { + auto self = static_cast< const Buffer *>(this_); + position = (std::min)(position, self->size()); + const_buffers_type res; + + const auto bs = self->get_block_size(); + auto itr = self->begin(); + auto fbs = (std::min)(static_cast(itr.get_last() - itr.get_cur()), position); + + res.emplace_back(itr.get_cur(), fbs); + position -= fbs; + itr = std::next(itr, fbs); + while (position > 0u && itr != self->end() && (res.size() < res.capacity())) + { + auto seg = (std::min)(position, bs); + res.emplace_back(itr.get_cur(), seg); + position -= seg; + itr = std::next(itr, seg); + } + return res; + }, + .prepare = [](void *this_, std::size_t n, std::size_t position) + { + auto self = static_cast< Buffer *>(this_); + mutable_buffers_type res; + + auto sz = (std::min)(position + n, self->max_size()); + if (sz > self->size()) + self->resize(sz); + + auto itr = (std::min)(std::next(self->begin(), position), self->end()); + auto seg = itr, end = self->end(); + + while (itr != self->end()) + { + auto ptr = itr++; + position--; + if (itr == end) + { + res.emplace_back(&*seg, std::distance(seg, itr)); + break; + } + + if ((&*ptr + 1) == &*itr) // aligned + continue; + + res.emplace_back(&*seg, std::distance(seg, itr)); + seg = itr; + if (res.size() == res.capacity()) + break ; + } + // segment the thingy. + return res; + }, + .commit =[](void *this_, std::size_t n, std::size_t &position) + { + position += n; + static_cast(this_)->resize(position); + }, + .consume =[](void *this_, std::size_t n, std::size_t &position) + { + auto self = static_cast(this_); + using type = typename Buffer::value_type; + self->erase(self->begin(), (std::min)(std::next(self->begin(), n), self->end())); + position -= n; + } + }; + +}; + +template +dynamic_buffer_view::dynamic_buffer_view(Buffer &other) + : this_(&other), vtable_(vtables::dynamic_buffer_vtable_) +{} + +template + requires ( + requires (const Container & ct) + { + {ct.data()} -> std::convertible_to; + {ct.size()} -> std::convertible_to; + {ct.max_size()} -> std::convertible_to; + {ct.capacity()} -> std::convertible_to; + } + && requires (Container & ct) + { + {ct.data()} -> std::convertible_to; + {ct.resize(std::size_t())}; + {ct.erase(ct.begin(), ct.end())}; + } + && std::is_trivial_v + && sizeof(typename Container::value_type) == 1u) +dynamic_buffer_view::dynamic_buffer_view(Container &other) + : this_(&other), vtable_(vtables::contiguous_vtable_) +{ +} + +template + requires (std::is_trivial_v && sizeof(T) == 1u) +dynamic_buffer_view::dynamic_buffer_view(boost::circular_buffer &other) + : this_(&other), vtable_(vtables::circular_vtable_>) +{ +} + +template +requires (std::is_trivial_v && sizeof(T) == 1u) +dynamic_buffer_view::dynamic_buffer_view(boost::container::deque &other) + : this_(&other), vtable_(vtables::deque_vtable_>) {} + +} + +#endif //BOOST_ASYNC_IO_BUFFERS_IMPL_DYNAMIC_BUFFER_VIEW_HPP diff --git a/include/boost/async/io/buffers/mutable_buffer.hpp b/include/boost/async/io/buffers/mutable_buffer.hpp index f02c9d43..6aceee86 100644 --- a/include/boost/async/io/buffers/mutable_buffer.hpp +++ b/include/boost/async/io/buffers/mutable_buffer.hpp @@ -66,6 +66,12 @@ class mutable_buffer requires std::is_trivial_v mutable_buffer(T (&arr)[N]) : mutable_buffer(&arr[0], sizeof(T) * N) {} + /** Constructor for arrays */ + template + requires std::is_trivial_v + mutable_buffer(std::pair p) : mutable_buffer(p.first, sizeof(T) * p.second) {} + + /** Assignment. */ mutable_buffer& operator=( diff --git a/include/boost/async/io/buffers/string_buffer.hpp b/include/boost/async/io/buffers/string_buffer.hpp index 2f7eaed8..12c029d5 100644 --- a/include/boost/async/io/buffers/string_buffer.hpp +++ b/include/boost/async/io/buffers/string_buffer.hpp @@ -25,6 +25,7 @@ template< buffer_byte CharT, class Traits = std::char_traits, class Allocator = std::allocator> + requires (sizeof(CharT) == 1u) class basic_string_buffer { std::basic_string< diff --git a/test/io/buffers/CMakeLists.txt b/test/io/buffers/CMakeLists.txt index b5574172..6ed2ea17 100644 --- a/test/io/buffers/CMakeLists.txt +++ b/test/io/buffers/CMakeLists.txt @@ -22,6 +22,7 @@ set(PFILES const_buffer_pair.cpp const_buffer_span.cpp const_buffer_subspan.cpp + dynamic_buffer_view.cpp flat_buffer.cpp mutable_buffer.cpp mutable_buffer_pair.cpp diff --git a/test/io/buffers/dynamic_buffer_view.cpp b/test/io/buffers/dynamic_buffer_view.cpp new file mode 100644 index 00000000..8945fef5 --- /dev/null +++ b/test/io/buffers/dynamic_buffer_view.cpp @@ -0,0 +1,245 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +// Test that header file is self-contained. +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "test_helpers.hpp" + +namespace boost::async::io::buffers { + +struct dynamic_buffer_view_test +{ + BOOST_STATIC_ASSERT( const_buffer_sequence); + BOOST_STATIC_ASSERT(mutable_buffer_sequence); + BOOST_STATIC_ASSERT(dynamic_buffer); + + void testOther() + { + char cc[64]; + flat_buffer fb{cc, 64}; + dynamic_buffer_view dbv{fb}; + + std::string data; + data.resize(64); + char c = ' '; + std::generate(data.begin(), data.end(), [&]{return c++;}); + + BOOST_TEST_EQ(dbv.capacity(), fb.capacity()); + BOOST_TEST_EQ(dbv.capacity(), 64u); + BOOST_TEST_EQ(asio::buffer_copy(dbv.prepare(64), asio::buffer(data)), 64); + BOOST_TEST_EQ(dbv.capacity(), fb.capacity()); + BOOST_TEST_EQ(dbv.capacity(), 64u); + dbv.commit(64); + BOOST_TEST_EQ(dbv.capacity(), fb.size()); + BOOST_TEST_EQ(dbv.size(), 64u); + BOOST_TEST_EQ(fb.data().size(), 64u); + BOOST_TEST_EQ(buffer_size(dbv.data()), 64u); + + dbv.consume(32); + BOOST_TEST_EQ(dbv.capacity(), fb.size()); + BOOST_TEST_EQ(dbv.size(), 32u); + BOOST_TEST_EQ(buffer_size(fb.data()), 32u); + BOOST_TEST_EQ(buffer_size(dbv.data()), 32u); + BOOST_TEST( + std::equal(asio::buffers_begin(dbv.data()), + asio::buffers_end(dbv.data()), + data.begin() + 32, + data.end())); + + BOOST_TEST(std::memcmp(fb.data().data(), data.data(), fb.data().size())); + } + + + void testString() + { + std::vector vec; + dynamic_buffer_view dbv{vec}; + + std::string data; + data.resize(64); + char c = ' '; + std::generate(data.begin(), data.end(), [&]{return c++;}); + + BOOST_TEST_EQ(dbv.capacity(), vec.size()); + BOOST_TEST_EQ(dbv.capacity(), 0u); + BOOST_TEST_EQ(asio::buffer_copy(dbv.prepare(64), asio::buffer(data)), 64); + BOOST_TEST_EQ(dbv.capacity(), vec.size()); + BOOST_TEST_GE(dbv.capacity(), 64u); + dbv.commit(64); + BOOST_TEST_EQ(dbv.capacity(), vec.size()); + BOOST_TEST_GE(dbv.size(), 64u); + BOOST_TEST_EQ(buffer_size(dbv.data()), 64u); + + BOOST_TEST_EQ(dbv.size(), 64u); + dbv.consume(32); + BOOST_TEST_GE(dbv.capacity(), vec.size()); + BOOST_TEST_EQ(dbv.size(), 32u); + BOOST_TEST_EQ(buffer_size(dbv.data()), 32u); + + BOOST_TEST( + std::equal(asio::buffers_begin(dbv.data()), + asio::buffers_end(dbv.data()), + data.begin() + 32, + data.end())); + + BOOST_TEST_EQ(asio::buffer_copy(dbv.prepare(64), asio::buffer(data)), 64); + BOOST_TEST_EQ(dbv.capacity(), vec.capacity()); + BOOST_TEST_GE(dbv.capacity(), 64u); + dbv.commit(64); + BOOST_TEST_EQ(dbv.capacity(), vec.capacity()); + BOOST_TEST_GE(dbv.size(), 64u); + BOOST_TEST_EQ(buffer_size(dbv.data()), 96u); + + BOOST_TEST_EQ(dbv.size(), 96u); + dbv.consume(32); + BOOST_TEST_GE(dbv.capacity(), vec.size()); + BOOST_TEST_EQ(dbv.size(), 64); + BOOST_TEST_EQ(buffer_size(dbv.data()), 64u); + + BOOST_TEST( + std::equal(asio::buffers_begin(dbv.data()), + asio::buffers_end(dbv.data()), + data.begin(), + data.end())); + } + + void testCircular() + { + boost::circular_buffer vec{64u}; + dynamic_buffer_view dbv{vec}; + + std::string data; + data.resize(64); + char c = ' '; + std::generate(data.begin(), data.end(), [&]{return c++;}); + + BOOST_TEST_EQ(buffer_size(dbv.prepare(64)), 64u); + BOOST_TEST_EQ(dbv.capacity(), vec.capacity()); + BOOST_TEST_EQ(dbv.capacity(), 64u); + BOOST_TEST_EQ(asio::buffer_copy(dbv.prepare(64), asio::buffer(data)), 64); + BOOST_TEST_EQ(dbv.capacity(), vec.size()); + BOOST_TEST_GE(dbv.capacity(), 64u); + dbv.commit(64); + BOOST_TEST_EQ(dbv.capacity(), vec.size()); + BOOST_TEST_GE(dbv.size(), 64u); + BOOST_TEST_EQ(buffer_size(dbv.data()), 64u); + + BOOST_TEST_EQ(dbv.size(), 64u); + dbv.consume(32); + BOOST_TEST_GE(dbv.capacity(), vec.size()); + BOOST_TEST_EQ(dbv.size(), 32u); + BOOST_TEST_EQ(buffer_size(dbv.data()), 32u); + + BOOST_TEST( + std::equal(asio::buffers_begin(dbv.data()), + asio::buffers_end(dbv.data()), + data.begin() + 32, + data.end())); + + BOOST_TEST_EQ(asio::buffer_copy(dbv.prepare(64), asio::buffer(data)), 64); + BOOST_TEST_EQ(dbv.capacity(), vec.size()); + BOOST_TEST_GE(dbv.capacity(), 64u); + dbv.commit(64); + BOOST_TEST_EQ(dbv.capacity(), vec.size()); + BOOST_TEST_GE(dbv.size(), 64u); + BOOST_TEST_EQ(buffer_size(dbv.data()), 96u); + + BOOST_TEST_EQ(dbv.size(), 96u); + dbv.consume(32); + BOOST_TEST_GE(dbv.capacity(), vec.size()); + BOOST_TEST_EQ(dbv.size(), 64); + BOOST_TEST_EQ(buffer_size(dbv.data()), 64u); + + BOOST_TEST( + std::equal(asio::buffers_begin(dbv.data()), + asio::buffers_end(dbv.data()), + data.begin(), + data.end())); + } + + + void testQueue() + { + boost::container::deque>> vec; + dynamic_buffer_view dbv{vec}; + + std::string data; + data.resize(64); + char c = ' '; + std::generate(data.begin(), data.end(), [&]{return c++;}); + + BOOST_TEST_EQ(buffer_size(dbv.prepare(64)), 64u); + BOOST_TEST_EQ(dbv.capacity(), vec.size()); + BOOST_TEST_EQ(dbv.capacity(), 64u); + BOOST_TEST_EQ(asio::buffer_copy(dbv.prepare(64), asio::buffer(data)), 64); + BOOST_TEST_EQ(dbv.capacity(), vec.size()); + BOOST_TEST_GE(dbv.capacity(), 64u); + dbv.commit(64); + BOOST_TEST_EQ(dbv.capacity(), vec.size()); + BOOST_TEST_GE(dbv.size(), 64u); + BOOST_TEST_EQ(buffer_size(dbv.data()), 64u); + + BOOST_TEST_EQ(dbv.size(), 64u); + dbv.consume(32); + BOOST_TEST_GE(dbv.capacity(), vec.size()); + BOOST_TEST_EQ(dbv.size(), 32u); + BOOST_TEST_EQ(buffer_size(dbv.data()), 32u); + + BOOST_TEST( + std::equal(asio::buffers_begin(dbv.data()), + asio::buffers_end(dbv.data()), + data.begin() + 32, + data.end())); + + BOOST_TEST_EQ(asio::buffer_copy(dbv.prepare(64), asio::buffer(data)), 64); + BOOST_TEST_EQ(dbv.capacity(), vec.size()); + BOOST_TEST_GE(dbv.capacity(), 64u); + dbv.commit(64); + BOOST_TEST_EQ(dbv.capacity(), vec.size()); + BOOST_TEST_GE(dbv.size(), 64u); + BOOST_TEST_EQ(buffer_size(dbv.data()), 96u); + + BOOST_TEST_EQ(dbv.size(), 96u); + dbv.consume(32); + BOOST_TEST_GE(dbv.capacity(), vec.size()); + BOOST_TEST_EQ(dbv.size(), 64); + BOOST_TEST_EQ(buffer_size(dbv.data()), 64u); + + BOOST_TEST( + std::equal(asio::buffers_begin(dbv.data()), + asio::buffers_end(dbv.data()), + data.begin(), + data.end())); + } + + void + run() + { + testOther(); + testString(); + testCircular(); + testQueue(); + } +}; + +TEST_SUITE( + dynamic_buffer_view_test, + "boost.buffers.dynamic_buffer_view"); + +} // boost::buffers From 0fb458cc042141aac9e0899b95ca84d8c573e8e8 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 7 Jul 2023 15:47:31 +0800 Subject: [PATCH 31/43] algos use dynamic_buffer_view --- include/boost/async/io/copy.hpp | 11 ++--------- include/boost/async/io/copy_n.hpp | 14 ++------------ include/boost/async/io/read.hpp | 4 +--- include/boost/async/io/read_all.hpp | 13 ++----------- include/boost/async/io/read_until.hpp | 25 +++---------------------- include/boost/async/io/write.hpp | 2 +- src/io/copy.cpp | 8 ++++---- src/io/copy_n.cpp | 2 +- src/io/read_all.cpp | 6 +++--- src/io/read_until.cpp | 10 +++++----- src/io/write.cpp | 5 ++--- test/io/copy.cpp | 9 +++++---- test/io/read_until.cpp | 4 ++-- 13 files changed, 33 insertions(+), 80 deletions(-) diff --git a/include/boost/async/io/copy.hpp b/include/boost/async/io/copy.hpp index 1be5f4b6..8ecff75d 100644 --- a/include/boost/async/io/copy.hpp +++ b/include/boost/async/io/copy.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include namespace boost::async::io { @@ -19,16 +19,9 @@ BOOST_ASYNC_DECL promise> copy(stream & source, stream & sink); BOOST_ASYNC_DECL promise> -copy(stream & source, stream & sink, buffers::any_dynamic_buffer & buffer, std::size_t chunk_size = 4096); +copy(stream & source, stream & sink, buffers::dynamic_buffer_view buffer, std::size_t chunk_size = 4096); -template -promise read(stream & source, stream & sink, DynamicBuffer & buffer, std::size_t chunk_size = 4096) -{ - auto any = buffers::make_any(buffer); - buffers::any_dynamic_buffer & ab = any; - co_return co_await copy(source, sink, ab, chunk_size); -} } diff --git a/include/boost/async/io/copy_n.hpp b/include/boost/async/io/copy_n.hpp index 434675bc..e1778ce0 100644 --- a/include/boost/async/io/copy_n.hpp +++ b/include/boost/async/io/copy_n.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include namespace boost::async::io { @@ -19,19 +19,9 @@ BOOST_ASYNC_DECL promise> copy_n(stream & source, stream & sink, std::size_t n); BOOST_ASYNC_DECL promise> -copy_n(stream & source, stream & sink, buffers::any_dynamic_buffer & buffer, +copy_n(stream & source, stream & sink, buffers::dynamic_buffer_view buffer, std::size_t n, std::size_t chunk_size = 4096); - -template -promise copy_n(stream & source, stream & sink, DynamicBuffer & buffer, - std::size_t n, std::size_t chunk_size = 4096) -{ - auto any = buffers::make_any(buffer); - buffers::any_dynamic_buffer & ab = any; - co_return co_await copy_n(source, sink, ab, n, chunk_size); -} - } #endif //BOOST_ASYNC_IO_COPY_N_HPP diff --git a/include/boost/async/io/read.hpp b/include/boost/async/io/read.hpp index 0524670d..00f88da9 100644 --- a/include/boost/async/io/read.hpp +++ b/include/boost/async/io/read.hpp @@ -10,8 +10,8 @@ #include #include -#include #include +#include #include namespace boost::async::io @@ -20,8 +20,6 @@ namespace boost::async::io BOOST_ASYNC_DECL promise read(stream & source, buffers::mutable_buffer buffer); BOOST_ASYNC_DECL promise read(stream & source, buffers::mutable_buffer_span buffer); BOOST_ASYNC_DECL promise read(stream & source, buffers::mutable_buffer_subspan buffer); -BOOST_ASYNC_DECL promise read(stream & source, buffers::any_dynamic_buffer & buffer, - std::size_t chunk_size = 4096); template requires (!std::convertible_to) diff --git a/include/boost/async/io/read_all.hpp b/include/boost/async/io/read_all.hpp index 82e096f0..c34d209d 100644 --- a/include/boost/async/io/read_all.hpp +++ b/include/boost/async/io/read_all.hpp @@ -10,25 +10,16 @@ #include #include -#include +#include #include #include namespace boost::async::io { -BOOST_ASYNC_DECL promise read_all(stream & source, buffers::any_dynamic_buffer & buffer, +BOOST_ASYNC_DECL promise read_all(stream & source, buffers::dynamic_buffer_view buffer, std::size_t chunk_size = 4096); -template -promise read_all(stream & source, DynamicBuffer &&buffer, std::size_t chunk_size = 4096) -{ - auto any = buffers::make_any(std::forward(buffer)); - buffers::any_dynamic_buffer & ab = any; - co_return co_await read_all(source, ab, chunk_size); -} - - } #endif //BOOST_ASYNC_IO_READ_ALL_HPP diff --git a/include/boost/async/io/read_until.hpp b/include/boost/async/io/read_until.hpp index d295ccd7..3726bc7d 100644 --- a/include/boost/async/io/read_until.hpp +++ b/include/boost/async/io/read_until.hpp @@ -10,37 +10,18 @@ #include #include -#include +#include #include #include namespace boost::async::io { -BOOST_ASYNC_DECL promise read_until(stream & source, buffers::any_dynamic_buffer & buffer, +BOOST_ASYNC_DECL promise read_until(stream & source, buffers::dynamic_buffer_view buffer, char delim, std::size_t chunk_size = 4096); -BOOST_ASYNC_DECL promise read_until(stream & source, buffers::any_dynamic_buffer & buffer, +BOOST_ASYNC_DECL promise read_until(stream & source, buffers::dynamic_buffer_view buffer, core::string_view delim, std::size_t chunk_size = 4096); - -template -promise read_until(stream & source, DynamicBuffer &&buffer, - char delim, std::size_t chunk_size = 4096) -{ - auto any = buffers::make_any(std::forward(buffer)); - buffers::any_dynamic_buffer & ab = any; - co_return co_await read_until(source, ab, delim, chunk_size); -} - -template -promise read_until(stream & source, DynamicBuffer &&buffer, - core::string_view delim, std::size_t chunk_size = 4096) -{ - auto any = buffers::make_any(std::forward(buffer)); - buffers::any_dynamic_buffer & ab = any; - co_return co_await read_until(source, ab, delim, chunk_size); -} - } #endif //BOOST_ASYNC_IO_READ_UNTIL_HPP diff --git a/include/boost/async/io/write.hpp b/include/boost/async/io/write.hpp index a69e6fde..704e70aa 100644 --- a/include/boost/async/io/write.hpp +++ b/include/boost/async/io/write.hpp @@ -10,8 +10,8 @@ #include #include -#include #include +#include #include namespace boost::async::io diff --git a/src/io/copy.cpp b/src/io/copy.cpp index c0a51d58..ddede11c 100644 --- a/src/io/copy.cpp +++ b/src/io/copy.cpp @@ -24,6 +24,7 @@ copy(stream & source, stream & sink) w = {}; buf.commit(r.transferred); + printf("Copy 1 %ld/%ld ==> \n", r.transferred, w.transferred, 1024 * 1024); while (!r.has_error() && !w.has_error()) { @@ -40,18 +41,17 @@ copy(stream & source, stream & sink) // remaining readable stuff while (r.has_error() && !w.has_error() && buffers::buffer_size(buf.data()) > 0u) { - assert(false); auto w2 = co_await sink.write_some(buffers::const_buffer_span(buf.data())); buf.consume(w2.transferred); w.transferred = w2.transferred; w.error = w2.error; } - + printf("Copy %ld/%ld ==> \n", r.transferred, w.transferred, 1024 * 1024); co_return {r, w}; } promise> -copy(stream & source, stream & sink, buffers::any_dynamic_buffer & buf, std::size_t chunk_size) +copy(stream & source, stream & sink, buffers::dynamic_buffer_view buf, std::size_t chunk_size) { transfer_result r = co_await source.read_some(buffers::mutable_buffer_span(buf.prepare(chunk_size))), w = {}; @@ -73,12 +73,12 @@ copy(stream & source, stream & sink, buffers::any_dynamic_buffer & buf, std::siz // remaining readable stuff while (r.has_error() && !w.has_error() && buffers::buffer_size(buf.data()) > 0u) { - assert(false); auto w2 = co_await sink.write_some(buffers::const_buffer_span(buf.data())); buf.consume(w2.transferred); w.transferred = w2.transferred; w.error = w2.error; } + printf("Copy %ld/%ld\n", r.transferred, w.transferred); co_return {r, w}; } diff --git a/src/io/copy_n.cpp b/src/io/copy_n.cpp index 3b85f1c2..bd3efe29 100644 --- a/src/io/copy_n.cpp +++ b/src/io/copy_n.cpp @@ -52,7 +52,7 @@ copy_n(stream & source, stream & sink, std::size_t n) } promise> -copy_n(stream & source, stream & sink, buffers::any_dynamic_buffer & buf, +copy_n(stream & source, stream & sink, buffers::dynamic_buffer_view buf, std::size_t n, std::size_t chunk_size) { transfer_result r = co_await source.read_some(buffers::mutable_buffer_span(buf.prepare(chunk_size))), diff --git a/src/io/read_all.cpp b/src/io/read_all.cpp index 4f8c3ca5..11c78efa 100644 --- a/src/io/read_all.cpp +++ b/src/io/read_all.cpp @@ -17,18 +17,18 @@ namespace boost::async::io { -promise read_all(stream & source, buffers::any_dynamic_buffer & buffer, std::size_t chunk_size) +promise read_all(stream & source, buffers::dynamic_buffer_view buffer, std::size_t chunk_size) { transfer_result tr; do { - auto rd = co_await source.read_some(buffer.prepare(chunk_size)); + auto rd = co_await source.read_some(buffer.prepare((std::min)(chunk_size, buffer.max_size() - buffer.size()))); tr.transferred += rd.transferred; tr.error = rd.error; buffer.commit(rd.transferred); } - while (buffer.size() >= 0 && !tr.has_error()); + while (buffer.max_size() > buffer.size() && !tr.has_error()); co_return tr; } diff --git a/src/io/read_until.cpp b/src/io/read_until.cpp index ee87ef5b..bd1c64d7 100644 --- a/src/io/read_until.cpp +++ b/src/io/read_until.cpp @@ -17,7 +17,7 @@ namespace boost::async::io { -promise read_until(stream & source, buffers::any_dynamic_buffer & buffer, +promise read_until(stream & source, buffers::dynamic_buffer_view buffer, char delim, std::size_t chunk_size) { transfer_result tr{}; @@ -25,7 +25,7 @@ promise read_until(stream & source, buffers::any_dynamic_buffer bool matched = false; do { - auto buf = buffer.prepare(chunk_size); + auto buf = buffer.prepare((std::min)(chunk_size, buffer.max_size() - buffer.size())); auto rd = co_await source.read_some(buf); auto begin = asio::buffers_begin(buf); @@ -39,7 +39,7 @@ promise read_until(stream & source, buffers::any_dynamic_buffer co_return tr; } -promise read_until(stream & source, buffers::any_dynamic_buffer & buffer, +promise read_until(stream & source, buffers::dynamic_buffer_view buffer, core::string_view delim, std::size_t chunk_size) { transfer_result tr; @@ -51,7 +51,7 @@ promise read_until(stream & source, buffers::any_dynamic_buffer bool matched = false; do { - auto buf = buffer.prepare(chunk_size); + auto buf = buffer.prepare((std::min)(chunk_size, buffer.max_size() - buffer.size())); auto rd = co_await source.read_some(buf); tr.transferred += rd.transferred; tr.error = rd.error; @@ -63,7 +63,7 @@ promise read_until(stream & source, buffers::any_dynamic_buffer auto itr = std::search(begin, end, delim.begin(), delim.end()); matched = (itr != end); } - while (buffer.size() > 0 && !tr.has_error() && !matched); + while (buffer.max_size() >= buffer.size() && !tr.has_error() && !matched); co_return tr; } diff --git a/src/io/write.cpp b/src/io/write.cpp index d5976185..54bb8746 100644 --- a/src/io/write.cpp +++ b/src/io/write.cpp @@ -13,13 +13,12 @@ namespace boost::async::io promise write(stream & source, buffers::const_buffer buffer) { - transfer_result tr; + transfer_result tr{}; do { auto rd = co_await source.write_some(buffer); - tr.transferred += rd.transferred; - tr.error = rd.error; + tr += rd; buffer += rd.transferred; } while (buffer.size() > 0 && !tr.has_error()); diff --git a/test/io/copy.cpp b/test/io/copy.cpp index e437862a..fa4b725c 100644 --- a/test/io/copy.cpp +++ b/test/io/copy.cpp @@ -20,9 +20,10 @@ using namespace boost::async; -promise do_write__(io::stream & str, std::string & input ) +promise do_write__(io::stream & str, const std::string & input ) { - boost::ignore_unused(co_await io::write(str, {input.data(), input.size()})); + auto w = co_await io::write(str, input); + CHECK(w.transferred == input.size()); str.close().value(); }; @@ -53,12 +54,12 @@ CO_TEST_CASE("copy") auto p = do_write__(w, input); auto c = do_copy(ri, wi); std::string output; - auto res = co_await io::read_all(r, io::buffers::string_buffer(&output)); + auto res = co_await io::read_all(r, output); CHECK(res.transferred == output.size()); CHECK(res.transferred == input.size()); - CHECK(std::equal(output.begin(), output.end(), input.begin())); + CHECK(std::equal(output.begin(), std::next(output.begin(), res.transferred), input.begin())); CHECK(!r.close().has_error()); co_await p; diff --git a/test/io/read_until.cpp b/test/io/read_until.cpp index aec8d668..89f001b5 100644 --- a/test/io/read_until.cpp +++ b/test/io/read_until.cpp @@ -42,7 +42,7 @@ CO_TEST_CASE("read_until char") std::string output; - auto res = co_await io::read_until(r, io::buffers::string_buffer(&output), '\n'); + auto res = co_await io::read_until(r, output, '\n'); CHECK(res.transferred >= 4242); CHECK(res.transferred < 10000); @@ -75,7 +75,7 @@ CO_TEST_CASE("read_until string") std::string output; - auto res = co_await io::read_until(r, io::buffers::string_buffer(&output), "\r\n"); + auto res = co_await io::read_until(r, output, "\r\n"); CHECK(res.transferred >= 8001); CHECK(res.transferred < 16000); From 4b264a4f86f730297ead424f93470f10cbcbad41 Mon Sep 17 00:00:00 2001 From: Klemens Date: Sat, 22 Jul 2023 13:42:08 +0800 Subject: [PATCH 32/43] include & warning fixes Closes #12 & #13 --- CMakeLists.txt | 1 + .../async/io/buffers/any_dynamic_buffer.hpp | 4 +++ include/boost/async/io/endpoint.hpp | 6 ++-- src/io/popen.cpp | 2 +- src/io/process.cpp | 2 +- src/io/resolver.cpp | 3 ++ src/io/socket.cpp | 30 ++++++++++--------- test/io/ssl.cpp | 3 +- 8 files changed, 31 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 028222de..e3aea90c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,6 +127,7 @@ target_link_libraries(boost_async PUBLIC Boost::system Threads::Threads) target_compile_definitions(boost_async PRIVATE BOOST_ASYNC_SOURCE=1 ) +target_compile_definitions(boost_async PUBLIC BOOST_PROCESS_USE_STD_FS=1) if (BOOST_ASYNC_USE_BOOST_CONTAINER) target_link_libraries(boost_async PUBLIC Boost::container) diff --git a/include/boost/async/io/buffers/any_dynamic_buffer.hpp b/include/boost/async/io/buffers/any_dynamic_buffer.hpp index a44a2e24..87475d81 100644 --- a/include/boost/async/io/buffers/any_dynamic_buffer.hpp +++ b/include/boost/async/io/buffers/any_dynamic_buffer.hpp @@ -15,6 +15,10 @@ #include #include #include + +#include + + #include namespace boost::async::io::buffers { diff --git a/include/boost/async/io/endpoint.hpp b/include/boost/async/io/endpoint.hpp index 567b15ec..0e1d86ce 100644 --- a/include/boost/async/io/endpoint.hpp +++ b/include/boost/async/io/endpoint.hpp @@ -16,6 +16,8 @@ #include #include +#include + namespace boost::async::detail { @@ -32,7 +34,7 @@ struct endpoint; struct stream_socket; -#if __GNUC__ +#if __GNUC__ && !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsubobject-linkage" #endif @@ -185,7 +187,7 @@ struct endpoint protocol_type::type_t type_ = static_cast(0); }; -#if __GNUC__ +#if __GNUC__ && !defined(__clang__) #pragma GCC diagnostic pop #endif diff --git a/src/io/popen.cpp b/src/io/popen.cpp index fadf8bfb..46c2f952 100644 --- a/src/io/popen.cpp +++ b/src/io/popen.cpp @@ -71,7 +71,7 @@ system::result popen::running() { system::error_code ec; auto res = popen_.running(ec); - return ec ? ec : system::result(res); + return ec ? system::result(system::in_place_error, ec) : system::result(res); } system::result popen::close() diff --git a/src/io/process.cpp b/src/io/process.cpp index 937060d2..20e1ad45 100644 --- a/src/io/process.cpp +++ b/src/io/process.cpp @@ -81,7 +81,7 @@ system::result process::running() { system::error_code ec; auto res = process_.running(ec); - return ec ? ec : system::result(res); + return ec ? system::result(system::in_place_error, ec) : system::result(res); } } \ No newline at end of file diff --git a/src/io/resolver.cpp b/src/io/resolver.cpp index a68650cb..1190bdd0 100644 --- a/src/io/resolver.cpp +++ b/src/io/resolver.cpp @@ -7,6 +7,9 @@ #include +#include +#include + namespace boost::async::io { diff --git a/src/io/socket.cpp b/src/io/socket.cpp index 9601c03a..5b84df1c 100644 --- a/src/io/socket.cpp +++ b/src/io/socket.cpp @@ -86,20 +86,22 @@ system::result socket::bytes_readable() return ec ? ec : system::result(opt.get()); } -#define DEFINE_OPTION(Name, Type) \ -system::result socket::set_##Name(Type value) \ -{ \ - system::error_code ec; \ - socket_.set_option(asio::socket_base::Name(value), ec); \ - return ec ? ec : system::result{}; \ -} \ - \ -system::result socket::get_##Name() const \ -{ \ - system::error_code ec; \ - asio::socket_base::Name opt; \ - socket_.get_option(opt, ec); \ - return ec ? ec : system::result(opt.value()); \ +#define DEFINE_OPTION(Name, Type) \ +system::result socket::set_##Name(Type value) \ +{ \ + system::error_code ec; \ + socket_.set_option(asio::socket_base::Name(value), ec); \ + return ec ? ec : system::result{}; \ +} \ + \ +system::result socket::get_##Name() const \ +{ \ + system::error_code ec; \ + asio::socket_base::Name opt; \ + socket_.get_option(opt, ec); \ + return ec \ + ? system::result(system::in_place_error, ec) \ + : system::result(system::in_place_value, opt.value()); \ } DEFINE_OPTION(debug, bool); diff --git a/test/io/ssl.cpp b/test/io/ssl.cpp index b175290b..bd03ba3f 100644 --- a/test/io/ssl.cpp +++ b/test/io/ssl.cpp @@ -26,7 +26,6 @@ CO_TEST_CASE("ssl") CHECK_MESSAGE(conn, conn.error().message()); CHECK_NOTHROW(co_await ss.async_handshake(async::io::ssl_stream::handshake_type::client).value()); - co_await ss; - + co_await ss.write_some("GET"); CHECK_NOTHROW(co_await ss.async_shutdown()); } \ No newline at end of file From 8ce55567c0ad6783fd28ac91da38589387a7c143 Mon Sep 17 00:00:00 2001 From: Klemens Date: Mon, 24 Jul 2023 23:15:43 +0800 Subject: [PATCH 33/43] remove printf from copy. --- src/io/copy.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/io/copy.cpp b/src/io/copy.cpp index ddede11c..21070c19 100644 --- a/src/io/copy.cpp +++ b/src/io/copy.cpp @@ -24,7 +24,6 @@ copy(stream & source, stream & sink) w = {}; buf.commit(r.transferred); - printf("Copy 1 %ld/%ld ==> \n", r.transferred, w.transferred, 1024 * 1024); while (!r.has_error() && !w.has_error()) { @@ -46,7 +45,6 @@ copy(stream & source, stream & sink) w.transferred = w2.transferred; w.error = w2.error; } - printf("Copy %ld/%ld ==> \n", r.transferred, w.transferred, 1024 * 1024); co_return {r, w}; } @@ -78,7 +76,6 @@ copy(stream & source, stream & sink, buffers::dynamic_buffer_view buf, std::size w.transferred = w2.transferred; w.error = w2.error; } - printf("Copy %ld/%ld\n", r.transferred, w.transferred); co_return {r, w}; } From 7b0f14f5a2660b89732a0409f21e897ed3f497c8 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Wed, 28 Jun 2023 21:51:22 +0800 Subject: [PATCH 34/43] ported boost.buffers --- include/boost/async/detail/type_traits.hpp | 91 +++++++ .../boost/async/io/buffers/type_traits.hpp | 249 ++++++++++++++++++ 2 files changed, 340 insertions(+) create mode 100644 include/boost/async/detail/type_traits.hpp create mode 100644 include/boost/async/io/buffers/type_traits.hpp diff --git a/include/boost/async/detail/type_traits.hpp b/include/boost/async/detail/type_traits.hpp new file mode 100644 index 00000000..c9883401 --- /dev/null +++ b/include/boost/async/detail/type_traits.hpp @@ -0,0 +1,91 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/http_proto +// + +#ifndef BOOST_ASYNC_DETAIL_TYPE_TRAITS_HPP +#define BOOST_ASYNC_DETAIL_TYPE_TRAITS_HPP + +#include +#include +#include + +namespace boost::async::detail { + +// is bidirectional iterator +template +struct is_bidirectional_iterator : std::false_type +{ +}; + +template +struct is_bidirectional_iterator() + ), + // LegacyIterator + typename std::iterator_traits::value_type, + typename std::iterator_traits::difference_type, + typename std::iterator_traits::reference, + typename std::iterator_traits::pointer, + typename std::iterator_traits::iterator_category, + typename std::enable_if< + // LegacyIterator + std::is_copy_constructible::value && + std::is_copy_assignable::value && + std::is_destructible::value && + std::is_same())>::value && + // Swappable + // VFALCO TODO + // EqualityComparable + std::is_convertible() == + std::declval()), + bool>::value && + // LegacyInputIterator + std::is_convertible::reference, typename + std::iterator_traits::value_type>::value && + std::is_same::reference, + decltype(*std::declval())>::value && + std::is_convertible() != + std::declval()), + bool>::value && + std::is_same())>::value && + // VFALCO (void)r++ (void)++r + std::is_convertible()++), typename + std::iterator_traits::value_type>::value && + // LegacyForwardIterator + std::is_default_constructible::value && + std::is_same()++)>::value && + std::is_same::reference, + decltype(*std::declval()++) + >::value && + // LegacyBidirectionalIterator + std::is_same())>::value && + std::is_convertible()--), + T const&>::value && + std::is_same::reference, + decltype(*std::declval()--)>::value + >::type >> + : std::true_type +{ +}; + +} // boost::buffers::detail + +#endif diff --git a/include/boost/async/io/buffers/type_traits.hpp b/include/boost/async/io/buffers/type_traits.hpp new file mode 100644 index 00000000..0d837169 --- /dev/null +++ b/include/boost/async/io/buffers/type_traits.hpp @@ -0,0 +1,249 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/CPPAlliance/buffers +// + +#ifndef BOOST_BUFFERS_TYPE_TRAITS_HPP +#define BOOST_BUFFERS_TYPE_TRAITS_HPP + +#include +#include +#include + +namespace boost::async::io::buffers { + +#ifndef BOOST_BUFFERS_DOCS +class const_buffer; +class mutable_buffer; +#endif + +// https://www.boost.org/doc/libs/1_65_0/doc/html/boost_asio/reference/ConstBufferSequence.html + +/** Determine if T is a ConstBuffers. +*/ +#if BOOST_BUFFERS_DOCS +template +struct is_const_buffer_sequence + : std::integral_constant{}; +#else + +template +struct is_const_buffer_sequence + : std::false_type +{ +}; + +template +struct is_const_buffer_sequence + : is_const_buffer_sequence::type> +{ +}; + +template +struct is_const_buffer_sequence + : is_const_buffer_sequence::type> +{ +}; + +template +struct is_const_buffer_sequence + : is_const_buffer_sequence::type> +{ +}; + +template<> +struct is_const_buffer_sequence< + const_buffer> + : std::true_type +{ +}; + +template<> +struct is_const_buffer_sequence< + mutable_buffer> + : std::true_type +{ +}; + +template +struct is_const_buffer_sequence::value + || std::is_same::value + ) && + detail::is_bidirectional_iterator::value && + std::is_same().begin()) + >::value && + std::is_same().end()) + >::value && ( + std::is_same::value_type>::type + >::value || + std::is_same::value_type>::type + >::value) + // VFALCO This causes problems when the + // trait is used to constrain ctors + // && std::is_move_constructible::value + >::type + > > : std::true_type +{ +}; + +#endif + +/** Determine if T is a MutableBuffers. +*/ +#if BOOST_BUFFERS_DOCS +template +struct is_mutable_buffer_sequence + : std::integral_constant{}; +#else + +template +struct is_mutable_buffer_sequence : std::false_type +{ +}; + +template +struct is_mutable_buffer_sequence + : is_mutable_buffer_sequence::type> +{ +}; + +template +struct is_mutable_buffer_sequence + : is_mutable_buffer_sequence::type> +{ +}; + +template +struct is_mutable_buffer_sequence + : is_mutable_buffer_sequence::type> +{ +}; + +template<> +struct is_mutable_buffer_sequence< + mutable_buffer> + : std::true_type +{ +}; + +template +struct is_mutable_buffer_sequence::value && + detail::is_bidirectional_iterator::value && + std::is_same().begin()) + >::value && + std::is_same().end()) + >::value && + std::is_same::value_type>::type + >::value + // VFALCO This causes problems when the + // trait is used to constrain ctors + // && std::is_move_constructible::value + >::type + >> : std::true_type +{ +}; + +#endif + +//------------------------------------------------ + +/** Determine if T is a DynamicBuffer +*/ +#if BOOST_BUFFERS_DOCS +template +struct is_dynamic_buffer + : std::integral_constant{}; +#else + +template< + class T, + class = void> +struct is_dynamic_buffer : std::false_type {}; + +template +struct is_dynamic_buffer< + T, std::void_t() = + std::declval().size() + ,std::declval() = + std::declval().max_size() + ,std::declval() = + std::declval().capacity() + ,std::declval().commit( + std::declval()) + ,std::declval().consume( + std::declval()) + ) + ,typename std::enable_if< + is_const_buffer_sequence::value + && is_mutable_buffer_sequence::value + >::type + ,typename std::enable_if< + std::is_same().data()), + typename T::const_buffers_type>::value + && std::is_same().prepare( + std::declval())), + typename T::mutable_buffers_type>::value + >::type + > > : std::true_type +{ +}; + +/** Return the underlying buffer type of a sequence. +*/ +template +using value_type = typename + std::conditional< + is_mutable_buffer_sequence::value, + mutable_buffer, + const_buffer + >::type; + +#endif + +} // boost::buffers + +#endif From c7ebb5da9e7e4e7c75cdfe56332f00cd668b6593 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 17:04:46 +0800 Subject: [PATCH 35/43] conceptified buffers. --- include/boost/async/detail/type_traits.hpp | 91 -------- .../boost/async/io/buffers/type_traits.hpp | 217 ++++-------------- 2 files changed, 44 insertions(+), 264 deletions(-) delete mode 100644 include/boost/async/detail/type_traits.hpp diff --git a/include/boost/async/detail/type_traits.hpp b/include/boost/async/detail/type_traits.hpp deleted file mode 100644 index c9883401..00000000 --- a/include/boost/async/detail/type_traits.hpp +++ /dev/null @@ -1,91 +0,0 @@ -// -// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/CPPAlliance/http_proto -// - -#ifndef BOOST_ASYNC_DETAIL_TYPE_TRAITS_HPP -#define BOOST_ASYNC_DETAIL_TYPE_TRAITS_HPP - -#include -#include -#include - -namespace boost::async::detail { - -// is bidirectional iterator -template -struct is_bidirectional_iterator : std::false_type -{ -}; - -template -struct is_bidirectional_iterator() - ), - // LegacyIterator - typename std::iterator_traits::value_type, - typename std::iterator_traits::difference_type, - typename std::iterator_traits::reference, - typename std::iterator_traits::pointer, - typename std::iterator_traits::iterator_category, - typename std::enable_if< - // LegacyIterator - std::is_copy_constructible::value && - std::is_copy_assignable::value && - std::is_destructible::value && - std::is_same())>::value && - // Swappable - // VFALCO TODO - // EqualityComparable - std::is_convertible() == - std::declval()), - bool>::value && - // LegacyInputIterator - std::is_convertible::reference, typename - std::iterator_traits::value_type>::value && - std::is_same::reference, - decltype(*std::declval())>::value && - std::is_convertible() != - std::declval()), - bool>::value && - std::is_same())>::value && - // VFALCO (void)r++ (void)++r - std::is_convertible()++), typename - std::iterator_traits::value_type>::value && - // LegacyForwardIterator - std::is_default_constructible::value && - std::is_same()++)>::value && - std::is_same::reference, - decltype(*std::declval()++) - >::value && - // LegacyBidirectionalIterator - std::is_same())>::value && - std::is_convertible()--), - T const&>::value && - std::is_same::reference, - decltype(*std::declval()--)>::value - >::type >> - : std::true_type -{ -}; - -} // boost::buffers::detail - -#endif diff --git a/include/boost/async/io/buffers/type_traits.hpp b/include/boost/async/io/buffers/type_traits.hpp index 0d837169..688045c0 100644 --- a/include/boost/async/io/buffers/type_traits.hpp +++ b/include/boost/async/io/buffers/type_traits.hpp @@ -11,7 +11,6 @@ #define BOOST_BUFFERS_TYPE_TRAITS_HPP #include -#include #include namespace boost::async::io::buffers { @@ -31,84 +30,25 @@ struct is_const_buffer_sequence : std::integral_constant{}; #else -template -struct is_const_buffer_sequence - : std::false_type -{ -}; -template -struct is_const_buffer_sequence - : is_const_buffer_sequence::type> -{ -}; -template -struct is_const_buffer_sequence - : is_const_buffer_sequence::type> -{ -}; +template +concept const_buffer_sequence = + std::same_as || + std::same_as || + ((std::same_as || + std::same_as) && + std::bidirectional_iterator && + requires (const T & buf) + { + {buf.begin()} -> std::same_as; + {buf.end()} -> std::same_as; -template -struct is_const_buffer_sequence - : is_const_buffer_sequence::type> -{ -}; - -template<> -struct is_const_buffer_sequence< - const_buffer> - : std::true_type -{ -}; - -template<> -struct is_const_buffer_sequence< - mutable_buffer> - : std::true_type -{ -}; + } && + (std::same_as::value_type, const_buffer> || + std::same_as::value_type, mutable_buffer>)) +; -template -struct is_const_buffer_sequence::value - || std::is_same::value - ) && - detail::is_bidirectional_iterator::value && - std::is_same().begin()) - >::value && - std::is_same().end()) - >::value && ( - std::is_same::value_type>::type - >::value || - std::is_same::value_type>::type - >::value) - // VFALCO This causes problems when the - // trait is used to constrain ctors - // && std::is_move_constructible::value - >::type - > > : std::true_type -{ -}; #endif @@ -119,68 +59,19 @@ template struct is_mutable_buffer_sequence : std::integral_constant{}; #else +template +concept mutable_buffer_sequence = + std::same_as || + (std::same_as && + std::bidirectional_iterator && + requires (const T &buf) + { + {buf.begin()} -> std::same_as; + {buf.end()} -> std::same_as; + } && + std::same_as::value_type, mutable_buffer>) +; -template -struct is_mutable_buffer_sequence : std::false_type -{ -}; - -template -struct is_mutable_buffer_sequence - : is_mutable_buffer_sequence::type> -{ -}; - -template -struct is_mutable_buffer_sequence - : is_mutable_buffer_sequence::type> -{ -}; - -template -struct is_mutable_buffer_sequence - : is_mutable_buffer_sequence::type> -{ -}; - -template<> -struct is_mutable_buffer_sequence< - mutable_buffer> - : std::true_type -{ -}; - -template -struct is_mutable_buffer_sequence::value && - detail::is_bidirectional_iterator::value && - std::is_same().begin()) - >::value && - std::is_same().end()) - >::value && - std::is_same::value_type>::type - >::value - // VFALCO This causes problems when the - // trait is used to constrain ctors - // && std::is_move_constructible::value - >::type - >> : std::true_type -{ -}; #endif @@ -194,56 +85,36 @@ struct is_dynamic_buffer : std::integral_constant{}; #else -template< - class T, - class = void> -struct is_dynamic_buffer : std::false_type {}; +template +concept dynamic_buffer = + requires (T & buf, std::size_t n) + { + {buf.size()} -> std::same_as; + {buf.max_size()} -> std::same_as; + {buf.capacity()} -> std::same_as; + {buf.commit(n)}; + {buf.consume(n)}; + {buf.data()} -> const_buffer_sequence; + {buf.prepare(n)}-> mutable_buffer_sequence; + } + && const_buffer_sequence + && mutable_buffer_sequence + ; -template -struct is_dynamic_buffer< - T, std::void_t() = - std::declval().size() - ,std::declval() = - std::declval().max_size() - ,std::declval() = - std::declval().capacity() - ,std::declval().commit( - std::declval()) - ,std::declval().consume( - std::declval()) - ) - ,typename std::enable_if< - is_const_buffer_sequence::value - && is_mutable_buffer_sequence::value - >::type - ,typename std::enable_if< - std::is_same().data()), - typename T::const_buffers_type>::value - && std::is_same().prepare( - std::declval())), - typename T::mutable_buffers_type>::value - >::type - > > : std::true_type -{ -}; /** Return the underlying buffer type of a sequence. */ template using value_type = typename std::conditional< - is_mutable_buffer_sequence::value, + mutable_buffer_sequence, mutable_buffer, const_buffer >::type; #endif + } // boost::buffers #endif From 6d45d57a076bffc0f0526bc4cea5f4035855b65a Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 30 Jun 2023 20:40:39 +0800 Subject: [PATCH 36/43] added subspan overloads to all io functions. --- .../boost/async/io/buffers/mutable_buffer_span.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/boost/async/io/buffers/mutable_buffer_span.hpp b/include/boost/async/io/buffers/mutable_buffer_span.hpp index 179b9d50..b0ca33bc 100644 --- a/include/boost/async/io/buffers/mutable_buffer_span.hpp +++ b/include/boost/async/io/buffers/mutable_buffer_span.hpp @@ -67,6 +67,20 @@ class mutable_buffer_span { } + template + requires requires (const MutableBufferSequence & seq) + { + {seq.data()} -> std::same_as; + {seq.size()} -> std::same_as; + } + explicit + mutable_buffer_span( + MutableBufferSequence const& bs) noexcept + : p_(bs.data()) + , n_(bs.size()) + { + } + /** Constructor. */ mutable_buffer_span( From a4342f8e4ff6c59d21438f647b7e8d6d59c9a8b7 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Sun, 2 Jul 2023 10:45:29 +0800 Subject: [PATCH 37/43] buffer tweaks. --- include/boost/async/io/buffers/string_buffer.hpp | 14 ++++++++------ test/io/buffers/string_buffer.cpp | 7 +++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/boost/async/io/buffers/string_buffer.hpp b/include/boost/async/io/buffers/string_buffer.hpp index 12c029d5..fc87352b 100644 --- a/include/boost/async/io/buffers/string_buffer.hpp +++ b/include/boost/async/io/buffers/string_buffer.hpp @@ -88,13 +88,13 @@ class basic_string_buffer std::size_t size() const noexcept { - return in_size_; + return in_size_* sizeof(CharT); } std::size_t max_size() const noexcept { - return max_size_; + return max_size_ * sizeof(CharT); } std::size_t @@ -102,7 +102,7 @@ class basic_string_buffer { if(s_->capacity() <= max_size_) return s_->capacity() - in_size_; - return max_size_ - in_size_; + return (max_size_ - in_size_) * sizeof(CharT); } const_buffers_type @@ -110,12 +110,14 @@ class basic_string_buffer { return { s_->data(), - in_size_ }; + in_size_ * sizeof(CharT)}; } mutable_buffers_type - prepare(std::size_t n) + prepare(std::size_t n_) { + const auto n = (n_ / sizeof(CharT)) + (std::min)(n_ % sizeof(CharT), static_cast(1u)); + // n exceeds available space if(n > max_size_ - in_size_) async::detail::throw_invalid_argument(); @@ -125,7 +127,7 @@ class basic_string_buffer out_size_ = n; return { &(*s_)[in_size_], - out_size_ }; + out_size_ * sizeof(CharT)}; } void diff --git a/test/io/buffers/string_buffer.cpp b/test/io/buffers/string_buffer.cpp index 4243ce53..86b6711d 100644 --- a/test/io/buffers/string_buffer.cpp +++ b/test/io/buffers/string_buffer.cpp @@ -70,6 +70,13 @@ struct string_buffer_test BOOST_TEST_EQ(b.size(), 4); } + // ws.size() + { + std::u16string ws = u"1234"; + basic_string_buffer b(&ws); + BOOST_TEST_EQ(b.size(), 8); + } + // capacity() { { From 1c0c81875297ec4fac17b53adc6e97359c3b131c Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 7 Jul 2023 13:02:01 +0800 Subject: [PATCH 38/43] buffer improvements. --- .../boost/async/io/buffers/string_buffer.hpp | 14 +- .../boost/async/io/buffers/type_traits.hpp | 120 ------------------ test/io/buffers/string_buffer.cpp | 7 - 3 files changed, 6 insertions(+), 135 deletions(-) delete mode 100644 include/boost/async/io/buffers/type_traits.hpp diff --git a/include/boost/async/io/buffers/string_buffer.hpp b/include/boost/async/io/buffers/string_buffer.hpp index fc87352b..12c029d5 100644 --- a/include/boost/async/io/buffers/string_buffer.hpp +++ b/include/boost/async/io/buffers/string_buffer.hpp @@ -88,13 +88,13 @@ class basic_string_buffer std::size_t size() const noexcept { - return in_size_* sizeof(CharT); + return in_size_; } std::size_t max_size() const noexcept { - return max_size_ * sizeof(CharT); + return max_size_; } std::size_t @@ -102,7 +102,7 @@ class basic_string_buffer { if(s_->capacity() <= max_size_) return s_->capacity() - in_size_; - return (max_size_ - in_size_) * sizeof(CharT); + return max_size_ - in_size_; } const_buffers_type @@ -110,14 +110,12 @@ class basic_string_buffer { return { s_->data(), - in_size_ * sizeof(CharT)}; + in_size_ }; } mutable_buffers_type - prepare(std::size_t n_) + prepare(std::size_t n) { - const auto n = (n_ / sizeof(CharT)) + (std::min)(n_ % sizeof(CharT), static_cast(1u)); - // n exceeds available space if(n > max_size_ - in_size_) async::detail::throw_invalid_argument(); @@ -127,7 +125,7 @@ class basic_string_buffer out_size_ = n; return { &(*s_)[in_size_], - out_size_ * sizeof(CharT)}; + out_size_ }; } void diff --git a/include/boost/async/io/buffers/type_traits.hpp b/include/boost/async/io/buffers/type_traits.hpp deleted file mode 100644 index 688045c0..00000000 --- a/include/boost/async/io/buffers/type_traits.hpp +++ /dev/null @@ -1,120 +0,0 @@ -// -// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/CPPAlliance/buffers -// - -#ifndef BOOST_BUFFERS_TYPE_TRAITS_HPP -#define BOOST_BUFFERS_TYPE_TRAITS_HPP - -#include -#include - -namespace boost::async::io::buffers { - -#ifndef BOOST_BUFFERS_DOCS -class const_buffer; -class mutable_buffer; -#endif - -// https://www.boost.org/doc/libs/1_65_0/doc/html/boost_asio/reference/ConstBufferSequence.html - -/** Determine if T is a ConstBuffers. -*/ -#if BOOST_BUFFERS_DOCS -template -struct is_const_buffer_sequence - : std::integral_constant{}; -#else - - - -template -concept const_buffer_sequence = - std::same_as || - std::same_as || - ((std::same_as || - std::same_as) && - std::bidirectional_iterator && - requires (const T & buf) - { - {buf.begin()} -> std::same_as; - {buf.end()} -> std::same_as; - - } && - (std::same_as::value_type, const_buffer> || - std::same_as::value_type, mutable_buffer>)) -; - - -#endif - -/** Determine if T is a MutableBuffers. -*/ -#if BOOST_BUFFERS_DOCS -template -struct is_mutable_buffer_sequence - : std::integral_constant{}; -#else -template -concept mutable_buffer_sequence = - std::same_as || - (std::same_as && - std::bidirectional_iterator && - requires (const T &buf) - { - {buf.begin()} -> std::same_as; - {buf.end()} -> std::same_as; - } && - std::same_as::value_type, mutable_buffer>) -; - - -#endif - -//------------------------------------------------ - -/** Determine if T is a DynamicBuffer -*/ -#if BOOST_BUFFERS_DOCS -template -struct is_dynamic_buffer - : std::integral_constant{}; -#else - -template -concept dynamic_buffer = - requires (T & buf, std::size_t n) - { - {buf.size()} -> std::same_as; - {buf.max_size()} -> std::same_as; - {buf.capacity()} -> std::same_as; - {buf.commit(n)}; - {buf.consume(n)}; - {buf.data()} -> const_buffer_sequence; - {buf.prepare(n)}-> mutable_buffer_sequence; - } - && const_buffer_sequence - && mutable_buffer_sequence - ; - - -/** Return the underlying buffer type of a sequence. -*/ -template -using value_type = typename - std::conditional< - mutable_buffer_sequence, - mutable_buffer, - const_buffer - >::type; - -#endif - - -} // boost::buffers - -#endif diff --git a/test/io/buffers/string_buffer.cpp b/test/io/buffers/string_buffer.cpp index 86b6711d..4243ce53 100644 --- a/test/io/buffers/string_buffer.cpp +++ b/test/io/buffers/string_buffer.cpp @@ -70,13 +70,6 @@ struct string_buffer_test BOOST_TEST_EQ(b.size(), 4); } - // ws.size() - { - std::u16string ws = u"1234"; - basic_string_buffer b(&ws); - BOOST_TEST_EQ(b.size(), 8); - } - // capacity() { { From 2b2a506b423ca730d3c59caf73359f8adb028e25 Mon Sep 17 00:00:00 2001 From: Klemens Date: Sat, 29 Jul 2023 00:21:31 +0800 Subject: [PATCH 39/43] io buffer adjustments --- include/boost/async/io/buffers/concepts.hpp | 15 ++++++++++++--- include/boost/async/io/buffers/const_buffer.hpp | 2 +- .../boost/async/io/buffers/mutable_buffer.hpp | 2 +- .../async/io/buffers/mutable_buffer_span.hpp | 16 +--------------- include/boost/async/io/steady_timer.hpp | 5 ++++- include/boost/async/io/system_timer.hpp | 2 +- src/io/copy.cpp | 6 +++--- src/io/copy_n.cpp | 8 ++++---- src/io/read_until.cpp | 1 + 9 files changed, 28 insertions(+), 29 deletions(-) diff --git a/include/boost/async/io/buffers/concepts.hpp b/include/boost/async/io/buffers/concepts.hpp index ee72e264..5e7e05cc 100644 --- a/include/boost/async/io/buffers/concepts.hpp +++ b/include/boost/async/io/buffers/concepts.hpp @@ -45,8 +45,14 @@ concept const_buffer_sequence = {buf.end()} -> std::same_as; } && - (std::same_as::value_type, const_buffer> || - std::same_as::value_type, mutable_buffer>)) + (std::same_as::value_type>, + const_buffer> + || + std::same_as::value_type>, + mutable_buffer>) + ) ; @@ -69,7 +75,10 @@ concept mutable_buffer_sequence = {buf.begin()} -> std::same_as; {buf.end()} -> std::same_as; } && - std::same_as::value_type, mutable_buffer>) + std::same_as< + std::remove_const_t::value_type>, + mutable_buffer> + ) ; diff --git a/include/boost/async/io/buffers/const_buffer.hpp b/include/boost/async/io/buffers/const_buffer.hpp index ba9c7f14..b3ad65ed 100644 --- a/include/boost/async/io/buffers/const_buffer.hpp +++ b/include/boost/async/io/buffers/const_buffer.hpp @@ -48,7 +48,7 @@ class const_buffer {ct.size()} -> std::convertible_to; } && std::is_trivial_v) - const_buffer(Container & ct) : const_buffer(ct.data(), sizeof(typename Container::value_type) * ct.size()) {} + const_buffer(const Container & ct) : const_buffer(ct.data(), sizeof(typename Container::value_type) * ct.size()) {} /** Constructor for strings */ template diff --git a/include/boost/async/io/buffers/mutable_buffer.hpp b/include/boost/async/io/buffers/mutable_buffer.hpp index 6aceee86..05b91708 100644 --- a/include/boost/async/io/buffers/mutable_buffer.hpp +++ b/include/boost/async/io/buffers/mutable_buffer.hpp @@ -59,7 +59,7 @@ class mutable_buffer {std::size(ct)} -> std::convertible_to; } && std::is_trivial_v) - mutable_buffer(Container & ct) : mutable_buffer(std::data(ct), sizeof(typename Container::value_type) * std::size(ct)) {} + mutable_buffer(Container & ct) : mutable_buffer(std::data(ct), sizeof(typename Container::value_type) * std::size(ct)) {} /** Constructor for arrays */ template diff --git a/include/boost/async/io/buffers/mutable_buffer_span.hpp b/include/boost/async/io/buffers/mutable_buffer_span.hpp index b0ca33bc..ea4cfcc8 100644 --- a/include/boost/async/io/buffers/mutable_buffer_span.hpp +++ b/include/boost/async/io/buffers/mutable_buffer_span.hpp @@ -61,21 +61,7 @@ class mutable_buffer_span {seq.size()} -> std::same_as; } mutable_buffer_span( - MutableBufferSequence const& bs) noexcept - : p_(bs.data()) - , n_(bs.size()) - { - } - - template - requires requires (const MutableBufferSequence & seq) - { - {seq.data()} -> std::same_as; - {seq.size()} -> std::same_as; - } - explicit - mutable_buffer_span( - MutableBufferSequence const& bs) noexcept + const MutableBufferSequence & bs) noexcept : p_(bs.data()) , n_(bs.size()) { diff --git a/include/boost/async/io/steady_timer.hpp b/include/boost/async/io/steady_timer.hpp index d2f76d9c..258aef3e 100644 --- a/include/boost/async/io/steady_timer.hpp +++ b/include/boost/async/io/steady_timer.hpp @@ -48,7 +48,10 @@ struct steady_timer private: struct wait_op_ final : result_op { - void ready(async::handler h) {if (timer_->expired()) h({});} + void ready(async::handler h) override + { + if (timer_->expired()) h({}); + } BOOST_ASYNC_DECL void initiate(completion_handler handler) override; wait_op_(steady_timer * timer) : timer_(timer) {} private: diff --git a/include/boost/async/io/system_timer.hpp b/include/boost/async/io/system_timer.hpp index f1edc173..5aa3339d 100644 --- a/include/boost/async/io/system_timer.hpp +++ b/include/boost/async/io/system_timer.hpp @@ -46,7 +46,7 @@ struct system_timer final private: struct wait_op_ : result_op { - void ready(async::handler h) {if (timer_->expired()) h({});} + void ready(async::handler h) override {if (timer_->expired()) h({});} BOOST_ASYNC_DECL void initiate(completion_handler handler) override; wait_op_(system_timer * timer) : timer_(timer) {} diff --git a/src/io/copy.cpp b/src/io/copy.cpp index 21070c19..9c657a1e 100644 --- a/src/io/copy.cpp +++ b/src/io/copy.cpp @@ -20,7 +20,7 @@ copy(stream & source, stream & sink) char mem[chunk_size * 2]; buffers::circular_buffer buf{mem, sizeof(mem)}; - transfer_result r = co_await source.read_some(buffers::mutable_buffer_span(buf.prepare(chunk_size))), + transfer_result r = co_await source.read_some(buf.prepare(chunk_size)), w = {}; buf.commit(r.transferred); @@ -28,8 +28,8 @@ copy(stream & source, stream & sink) while (!r.has_error() && !w.has_error()) { auto [r2, w2] = co_await join( - source.read_some(buffers::mutable_buffer_span(buf.prepare(chunk_size))), - sink.write_some(buffers::const_buffer_span(buf.data()))); + source.read_some(buf.prepare(chunk_size)), + sink.write_some(buf.data())); buf.commit(r2.transferred); buf.consume(w2.transferred); r.transferred += r2.transferred; diff --git a/src/io/copy_n.cpp b/src/io/copy_n.cpp index bd3efe29..b395b9a9 100644 --- a/src/io/copy_n.cpp +++ b/src/io/copy_n.cpp @@ -20,7 +20,7 @@ copy_n(stream & source, stream & sink, std::size_t n) char mem[chunk_size * 2]; buffers::circular_buffer buf{mem, sizeof(mem)}; - transfer_result r = co_await source.read_some(buffers::mutable_buffer_span(buf.prepare(chunk_size))), + transfer_result r = co_await source.read_some(buf.prepare(chunk_size)), w = {}; buf.commit(r.transferred); @@ -28,7 +28,7 @@ copy_n(stream & source, stream & sink, std::size_t n) while (!r.has_error() && !w.has_error() && (n > 0u)) { auto [r2, w2] = co_await join( - source.read_some(buffers::mutable_buffer_span(buf.prepare((std::min)(chunk_size, n)))), + source.read_some(buf.prepare((std::min)(chunk_size, n))), sink.write_some(buffers::const_buffer_span(buf.data()))); buf.commit(r2.transferred); n -= r2.transferred; @@ -55,7 +55,7 @@ promise> copy_n(stream & source, stream & sink, buffers::dynamic_buffer_view buf, std::size_t n, std::size_t chunk_size) { - transfer_result r = co_await source.read_some(buffers::mutable_buffer_span(buf.prepare(chunk_size))), + transfer_result r = co_await source.read_some(buf.prepare(chunk_size)), w = {}; buf.commit(r.transferred); @@ -63,7 +63,7 @@ copy_n(stream & source, stream & sink, buffers::dynamic_buffer_view buf, while (!r.has_error() && !w.has_error()) { auto [r2, w2] = co_await join( - source.read_some(buffers::mutable_buffer_span(buf.prepare((std::min)(chunk_size, n)))), + source.read_some(buf.prepare((std::min)(chunk_size, n))), sink.write_some(buffers::const_buffer_span(buf.data()))); buf.commit(r2.transferred); buf.consume(w2.transferred); diff --git a/src/io/read_until.cpp b/src/io/read_until.cpp index bd1c64d7..4945bf3a 100644 --- a/src/io/read_until.cpp +++ b/src/io/read_until.cpp @@ -26,6 +26,7 @@ promise read_until(stream & source, buffers::dynamic_buffer_vie do { auto buf = buffer.prepare((std::min)(chunk_size, buffer.max_size() - buffer.size())); + async::io::buffers::mutable_buffer_span cb{buf}; auto rd = co_await source.read_some(buf); auto begin = asio::buffers_begin(buf); From 1244794bc414d94f7bc54c9c67b71523db8ef6ce Mon Sep 17 00:00:00 2001 From: Klemens Date: Tue, 1 Aug 2023 13:13:24 +0800 Subject: [PATCH 40/43] rebased. --- include/boost/async/io/detail/duplicate.hpp | 2 +- include/boost/async/io/result.hpp | 8 ++++---- include/boost/async/io/transfer_result.hpp | 4 ++-- src/io/datagram_socket.cpp | 2 +- src/io/detail/duplicate.cpp | 2 +- src/io/pipe.cpp | 8 ++++---- src/io/random_access_file.cpp | 2 +- src/io/seq_packet_socket.cpp | 2 +- src/io/serial_port.cpp | 2 +- src/io/ssl.cpp | 2 +- src/io/stream_file.cpp | 2 +- src/io/stream_socket.cpp | 2 +- test/io/ssl.cpp | 3 +-- 13 files changed, 20 insertions(+), 21 deletions(-) diff --git a/include/boost/async/io/detail/duplicate.hpp b/include/boost/async/io/detail/duplicate.hpp index c3b22d23..0f3451a6 100644 --- a/include/boost/async/io/detail/duplicate.hpp +++ b/include/boost/async/io/detail/duplicate.hpp @@ -12,7 +12,7 @@ #include #include -namespace boost::async::io::detail +namespace boost::async::detail::io { #if defined(BOOST_ASIO_WINDOWS) diff --git a/include/boost/async/io/result.hpp b/include/boost/async/io/result.hpp index f4092f41..b0b4cb6d 100644 --- a/include/boost/async/io/result.hpp +++ b/include/boost/async/io/result.hpp @@ -49,7 +49,7 @@ struct result_op auto & res = resource.emplace(buffer, sizeof(buffer), asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); initiate(completion_handler{h, result, &res, &completed_immediately}); - return !completed_immediately; + return completed_immediately != detail::completed_immediately_t::yes; } catch(...) { @@ -94,7 +94,7 @@ struct result_op std::optional> result; char buffer[2048]; std::optional resource; - bool completed_immediately = false; + detail::completed_immediately_t completed_immediately = detail::completed_immediately_t::no; }; @@ -131,7 +131,7 @@ struct result_op auto & res = resource.emplace(buffer, sizeof(buffer), asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); initiate(completion_handler{h, result, &res, &completed_immediately}); - return !completed_immediately; + return completed_immediately != detail::completed_immediately_t::yes; } catch(...) { @@ -178,7 +178,7 @@ struct result_op std::optional> result; char buffer[2048]; std::optional resource; - bool completed_immediately = false; + detail::completed_immediately_t completed_immediately = detail::completed_immediately_t::no; }; diff --git a/include/boost/async/io/transfer_result.hpp b/include/boost/async/io/transfer_result.hpp index ecf9a030..b17d6a1a 100644 --- a/include/boost/async/io/transfer_result.hpp +++ b/include/boost/async/io/transfer_result.hpp @@ -88,7 +88,7 @@ struct transfer_op auto & res = resource.emplace(buffer, sizeof(buffer), asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); initiate(completion_handler{h, result, &res, &completed_immediately}); - return !completed_immediately; + return completed_immediately != detail::completed_immediately_t::yes; } catch(...) { @@ -131,7 +131,7 @@ struct transfer_op std::optional> result; char buffer[2048]; std::optional resource; - bool completed_immediately = false; + detail::completed_immediately_t completed_immediately = detail::completed_immediately_t::no; }; diff --git a/src/io/datagram_socket.cpp b/src/io/datagram_socket.cpp index 93cdfbcc..f4d13b1c 100644 --- a/src/io/datagram_socket.cpp +++ b/src/io/datagram_socket.cpp @@ -13,7 +13,7 @@ namespace boost::async::io system::result datagram_socket::duplicate() { - auto res = detail::duplicate_socket(datagram_socket_.native_handle()); + auto res = detail::io::duplicate_handle(datagram_socket_.native_handle()); if (!res) return res.error(); diff --git a/src/io/detail/duplicate.cpp b/src/io/detail/duplicate.cpp index 0db4a02e..08a80458 100644 --- a/src/io/detail/duplicate.cpp +++ b/src/io/detail/duplicate.cpp @@ -14,7 +14,7 @@ #include #endif -namespace boost::async::io::detail +namespace boost::async::detail::io { #if defined(BOOST_ASIO_WINDOWS) diff --git a/src/io/pipe.cpp b/src/io/pipe.cpp index 1bb67d9e..7c46cc26 100644 --- a/src/io/pipe.cpp +++ b/src/io/pipe.cpp @@ -49,7 +49,7 @@ void readable_pipe::async_write_some_impl_( system::error_code ec{asio::error::operation_not_supported, &loc}; if (h.completed_immediately) { - *h.completed_immediately = true; + *h.completed_immediately = detail::completed_immediately_t::maybe; h(ec, 0ul); } else @@ -75,7 +75,7 @@ auto readable_pipe::release() -> system::result system::result readable_pipe::duplicate() { - auto res = detail::duplicate_handle(pipe_.native_handle()); + auto res = detail::io::duplicate_handle(pipe_.native_handle()); if (!res) return res.error(); @@ -119,7 +119,7 @@ void writable_pipe::async_read_some_impl_( system::error_code ec{asio::error::operation_not_supported, &loc}; if (h.completed_immediately) { - *h.completed_immediately = true; + *h.completed_immediately = detail::completed_immediately_t::maybe; h(ec, 0ul); } else @@ -144,7 +144,7 @@ auto writable_pipe::release() -> system::result system::result writable_pipe::duplicate() { - auto res = detail::duplicate_handle(pipe_.native_handle()); + auto res = detail::io::duplicate_handle(pipe_.native_handle()); if (!res) return res.error(); diff --git a/src/io/random_access_file.cpp b/src/io/random_access_file.cpp index ba82a3ef..bdbbc363 100644 --- a/src/io/random_access_file.cpp +++ b/src/io/random_access_file.cpp @@ -15,7 +15,7 @@ namespace boost::async::io system::result random_access_file::duplicate() { - auto res = detail::duplicate_handle(random_access_file_.native_handle()); + auto res = detail::io::duplicate_handle(random_access_file_.native_handle()); if (!res) return res.error(); diff --git a/src/io/seq_packet_socket.cpp b/src/io/seq_packet_socket.cpp index 6b5ce858..c9651dff 100644 --- a/src/io/seq_packet_socket.cpp +++ b/src/io/seq_packet_socket.cpp @@ -13,7 +13,7 @@ namespace boost::async::io system::result seq_packet_socket::duplicate() { - auto res = detail::duplicate_socket(seq_packet_socket_.native_handle()); + auto res = detail::io::duplicate_handle(seq_packet_socket_.native_handle()); if (!res) return res.error(); diff --git a/src/io/serial_port.cpp b/src/io/serial_port.cpp index aa59c67f..25a3ebfd 100644 --- a/src/io/serial_port.cpp +++ b/src/io/serial_port.cpp @@ -145,7 +145,7 @@ auto serial_port::release() -> system::result } auto serial_port::duplicate() -> system::result { - auto fd = detail::duplicate_handle(serial_port_.native_handle()); + auto fd = detail::io::duplicate_handle(serial_port_.native_handle()); if (fd.has_error()) return fd.error(); return serial_port(*fd); diff --git a/src/io/ssl.cpp b/src/io/ssl.cpp index 882818b7..043f3866 100644 --- a/src/io/ssl.cpp +++ b/src/io/ssl.cpp @@ -15,7 +15,7 @@ namespace boost::async::io system::result ssl_stream::duplicate() { SSL_dup(ssl_stream_.native_handle()); - auto res = detail::duplicate_socket(ssl_stream_.native_handle()); + auto res = detail::io::duplicate_handle(ssl_stream_.native_handle()); if (!res) return res.error(); diff --git a/src/io/stream_file.cpp b/src/io/stream_file.cpp index 8a085346..2bb1c6e4 100644 --- a/src/io/stream_file.cpp +++ b/src/io/stream_file.cpp @@ -15,7 +15,7 @@ namespace boost::async::io system::result stream_file::duplicate() { - auto res = detail::duplicate_handle(stream_file_.native_handle()); + auto res = detail::io::duplicate_handle(stream_file_.native_handle()); if (!res) return res.error(); diff --git a/src/io/stream_socket.cpp b/src/io/stream_socket.cpp index 7f25b56c..7d96b8bf 100644 --- a/src/io/stream_socket.cpp +++ b/src/io/stream_socket.cpp @@ -13,7 +13,7 @@ namespace boost::async::io system::result stream_socket::duplicate() { - auto res = detail::duplicate_socket(stream_socket_.native_handle()); + auto res = detail::io::duplicate_handle(stream_socket_.native_handle()); if (!res) return res.error(); diff --git a/test/io/ssl.cpp b/test/io/ssl.cpp index bd03ba3f..fa5f37bc 100644 --- a/test/io/ssl.cpp +++ b/test/io/ssl.cpp @@ -16,7 +16,7 @@ CO_TEST_CASE("ssl") { using namespace boost; - asio::ssl::context ctx{asio::ssl::context_base::tlsv13_client}; + asio::ssl::context ctx{asio::ssl::context_base::tls_client}; auto t = (co_await async::io::lookup("boost.org", "https")).value(); REQUIRE(!t.empty()); @@ -26,6 +26,5 @@ CO_TEST_CASE("ssl") CHECK_MESSAGE(conn, conn.error().message()); CHECK_NOTHROW(co_await ss.async_handshake(async::io::ssl_stream::handshake_type::client).value()); - co_await ss.write_some("GET"); CHECK_NOTHROW(co_await ss.async_shutdown()); } \ No newline at end of file From ade95f362590f0845d9ccffb8e6c26dd5e80d6cc Mon Sep 17 00:00:00 2001 From: Klemens Date: Fri, 4 Aug 2023 11:31:09 +0800 Subject: [PATCH 41/43] added completed_immediately::initiating to io ops. --- include/boost/async/io/result.hpp | 3 +++ include/boost/async/io/transfer_result.hpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/include/boost/async/io/result.hpp b/include/boost/async/io/result.hpp index b0b4cb6d..4ec7c604 100644 --- a/include/boost/async/io/result.hpp +++ b/include/boost/async/io/result.hpp @@ -48,7 +48,10 @@ struct result_op { auto & res = resource.emplace(buffer, sizeof(buffer), asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); + completed_immediately = detail::completed_immediately_t::initiating; initiate(completion_handler{h, result, &res, &completed_immediately}); + if (completed_immediately == detail::completed_immediately_t::initiating) + completed_immediately = detail::completed_immediately_t::no; return completed_immediately != detail::completed_immediately_t::yes; } catch(...) diff --git a/include/boost/async/io/transfer_result.hpp b/include/boost/async/io/transfer_result.hpp index b17d6a1a..f9c458e7 100644 --- a/include/boost/async/io/transfer_result.hpp +++ b/include/boost/async/io/transfer_result.hpp @@ -87,7 +87,10 @@ struct transfer_op { auto & res = resource.emplace(buffer, sizeof(buffer), asio::get_associated_allocator(h.promise(), this_thread::get_allocator()).resource()); + completed_immediately = detail::completed_immediately_t::initiating; initiate(completion_handler{h, result, &res, &completed_immediately}); + if (completed_immediately == detail::completed_immediately_t::initiating) + completed_immediately = detail::completed_immediately_t::no; return completed_immediately != detail::completed_immediately_t::yes; } catch(...) From 4619c05ce730bb53d7b0a34acb1b42008f6d7403 Mon Sep 17 00:00:00 2001 From: Klemens Date: Fri, 4 Aug 2023 12:43:29 +0800 Subject: [PATCH 42/43] enabled custom executors in io. --- CMakeLists.txt | 4 +- include/boost/async/io/acceptor.hpp | 4 +- include/boost/async/io/datagram_socket.hpp | 10 +++-- include/boost/async/io/pipe.hpp | 23 ++++++----- include/boost/async/io/popen.hpp | 10 +++-- include/boost/async/io/process.hpp | 11 +++-- include/boost/async/io/resolver.hpp | 19 ++++----- include/boost/async/io/sleep.hpp | 48 ++++++++++++++-------- include/boost/async/io/ssl.hpp | 4 +- include/boost/async/io/steady_timer.hpp | 6 +-- include/boost/async/io/stream_file.hpp | 10 +++-- include/boost/async/io/stream_socket.hpp | 9 ++-- include/boost/async/io/system_timer.hpp | 6 +-- src/io/acceptor.cpp | 6 ++- src/io/datagram_socket.cpp | 17 ++++---- src/io/pipe.cpp | 26 ++++++------ src/io/popen.cpp | 34 +++++++-------- src/io/process.cpp | 16 ++++---- src/io/resolver.cpp | 34 +++++++++++---- src/io/sleep.cpp | 34 +++++++++++++++ src/io/ssl.cpp | 8 ++-- src/io/steady_timer.cpp | 9 ++-- src/io/stream_file.cpp | 16 ++++---- src/io/stream_socket.cpp | 16 ++++---- src/io/system_timer.cpp | 9 ++-- 25 files changed, 237 insertions(+), 152 deletions(-) create mode 100644 src/io/sleep.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e3aea90c..95fe8de6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html add_custom_target(boost_async_doc DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html) +add_compile_definitions(BOOST_ASIO_HAS_IO_URING=1) if(BOOST_ASYNC_IS_ROOT) #include(CTest) @@ -120,7 +121,8 @@ add_library(boost_async src/io/write_at.cpp src/io/detail/random_access_device.cpp src/io/copy.cpp - src/io/copy_n.cpp) + src/io/copy_n.cpp + src/io/sleep.cpp) target_include_directories(boost_async PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(boost_async PUBLIC diff --git a/include/boost/async/io/acceptor.hpp b/include/boost/async/io/acceptor.hpp index 39397f0b..66741a6a 100644 --- a/include/boost/async/io/acceptor.hpp +++ b/include/boost/async/io/acceptor.hpp @@ -19,8 +19,8 @@ namespace boost::async::io struct acceptor { - BOOST_ASYNC_DECL acceptor(); - BOOST_ASYNC_DECL acceptor(endpoint ep); + BOOST_ASYNC_DECL acceptor(const async::executor & executor = this_thread::get_executor()); + BOOST_ASYNC_DECL acceptor(endpoint ep, const async::executor & executor = this_thread::get_executor()); BOOST_ASYNC_DECL system::result bind(endpoint ep); BOOST_ASYNC_DECL system::result listen(int backlog = asio::socket_base::max_listen_connections); // int backlog = asio::max_backlog() BOOST_ASYNC_DECL endpoint local_endpoint(); diff --git a/include/boost/async/io/datagram_socket.hpp b/include/boost/async/io/datagram_socket.hpp index 4d9a0933..85bd7ec4 100644 --- a/include/boost/async/io/datagram_socket.hpp +++ b/include/boost/async/io/datagram_socket.hpp @@ -20,12 +20,14 @@ namespace boost::async::io struct [[nodiscard]] datagram_socket final : socket { // duplicate onto another thread - system::result duplicate(); + system::result duplicate(const async::executor & executor = this_thread::get_executor()); - datagram_socket(); + datagram_socket(const async::executor & executor = this_thread::get_executor()); datagram_socket(datagram_socket && lhs); - datagram_socket(native_handle_type h, protocol_type protocol = protocol_type()); - datagram_socket(endpoint ep); + datagram_socket(native_handle_type h, protocol_type protocol = protocol_type(), + const async::executor & executor = this_thread::get_executor()); + datagram_socket(endpoint ep, + const async::executor & executor = this_thread::get_executor()); private: struct receive_op_; struct receive_op_seq_; diff --git a/include/boost/async/io/pipe.hpp b/include/boost/async/io/pipe.hpp index e53bd144..8156dd22 100644 --- a/include/boost/async/io/pipe.hpp +++ b/include/boost/async/io/pipe.hpp @@ -16,7 +16,9 @@ namespace boost::async::io { -system::result> make_pipe(); +system::result> make_pipe( + const async::executor & executor = this_thread::get_executor() + ); struct readable_pipe final : stream { @@ -27,13 +29,13 @@ struct readable_pipe final : stream using native_handle_type = typename asio::basic_readable_pipe::native_handle_type; native_handle_type native_handle() {return pipe_.native_handle();} - BOOST_ASYNC_DECL readable_pipe(); - BOOST_ASYNC_DECL readable_pipe(native_handle_type native_handle); + BOOST_ASYNC_DECL readable_pipe(const async::executor & executor = this_thread::get_executor()); + BOOST_ASYNC_DECL readable_pipe(native_handle_type native_handle, const async::executor & executor = this_thread::get_executor()); BOOST_ASYNC_DECL system::result assign(native_handle_type native_handle); BOOST_ASYNC_DECL system::result release(); - BOOST_ASYNC_DECL system::result duplicate(); + BOOST_ASYNC_DECL system::result duplicate(const async::executor & executor = this_thread::get_executor()); void write_some(buffers::mutable_buffer_subspan buffers) = delete; void write_some(buffers::mutable_buffer buffer) = delete; @@ -42,7 +44,7 @@ struct readable_pipe final : stream BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; - friend system::result> make_pipe(); + friend system::result> make_pipe(const async::executor & exec); asio::basic_readable_pipe pipe_; }; @@ -55,24 +57,23 @@ struct writable_pipe final : stream using native_handle_type = typename asio::basic_readable_pipe::native_handle_type; native_handle_type native_handle() {return pipe_.native_handle();} - BOOST_ASYNC_DECL writable_pipe(); - BOOST_ASYNC_DECL writable_pipe(native_handle_type native_handle); + BOOST_ASYNC_DECL writable_pipe(const async::executor & executor = this_thread::get_executor()); + BOOST_ASYNC_DECL writable_pipe(native_handle_type native_handle, + const async::executor & executor = this_thread::get_executor()); BOOST_ASYNC_DECL system::result assign(native_handle_type native_handle); BOOST_ASYNC_DECL system::result release(); - BOOST_ASYNC_DECL system::result duplicate(); + BOOST_ASYNC_DECL system::result duplicate(const async::executor & executor = this_thread::get_executor()); void read_some(buffers::mutable_buffer_subspan buffers) = delete; void read_some(buffers::mutable_buffer buffer) = delete; private: BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; - friend system::result> make_pipe(); + friend system::result> make_pipe(const async::executor & exec); asio::basic_writable_pipe pipe_; }; -system::result> make_pipe(); - } diff --git a/include/boost/async/io/popen.hpp b/include/boost/async/io/popen.hpp index 59097572..733c4c7a 100644 --- a/include/boost/async/io/popen.hpp +++ b/include/boost/async/io/popen.hpp @@ -23,13 +23,15 @@ struct popen : stream using native_handle_type = typename boost::process::v2::basic_process::native_handle_type; BOOST_ASYNC_DECL popen(boost::process::v2::filesystem::path executable, - std::initializer_list args, - process_initializer initializer = {}); + std::initializer_list args, + process_initializer initializer = {}, + const async::executor & executor = this_thread::get_executor()); BOOST_ASYNC_DECL popen(boost::process::v2::filesystem::path executable, - std::span args, - process_initializer initializer = {}); + std::span args, + process_initializer initializer = {}, + const async::executor & executor = this_thread::get_executor()); [[nodiscard]] BOOST_ASYNC_DECL system::result interrupt(); [[nodiscard]] BOOST_ASYNC_DECL system::result request_exit(); diff --git a/include/boost/async/io/process.hpp b/include/boost/async/io/process.hpp index 56059981..db09ea30 100644 --- a/include/boost/async/io/process.hpp +++ b/include/boost/async/io/process.hpp @@ -40,15 +40,18 @@ struct process BOOST_ASYNC_DECL process(boost::process::v2::filesystem::path executable, std::initializer_list args, - process_initializer initializer = {}); + process_initializer initializer = {}, + const async::executor & executor = this_thread::get_executor()); BOOST_ASYNC_DECL process(boost::process::v2::filesystem::path executable, std::span args, - process_initializer initializer = {}); + process_initializer initializer = {}, + const async::executor & executor = this_thread::get_executor()); - BOOST_ASYNC_DECL process(pid_type pid); - BOOST_ASYNC_DECL process(pid_type pid, native_handle_type native_handle); + BOOST_ASYNC_DECL process(pid_type pid, const async::executor & executor = this_thread::get_executor()); + BOOST_ASYNC_DECL process(pid_type pid, native_handle_type native_handle, + const async::executor & executor = this_thread::get_executor()); [[nodiscard]] BOOST_ASYNC_DECL system::result interrupt(); [[nodiscard]] BOOST_ASYNC_DECL system::result request_exit(); diff --git a/include/boost/async/io/resolver.hpp b/include/boost/async/io/resolver.hpp index a18ad8fa..0f2ee03f 100644 --- a/include/boost/async/io/resolver.hpp +++ b/include/boost/async/io/resolver.hpp @@ -25,7 +25,7 @@ struct resolver { using resolve_result = system::result>; - BOOST_ASYNC_DECL resolver(); + BOOST_ASYNC_DECL resolver(const async::executor & executor = this_thread::get_executor()); BOOST_ASYNC_DECL resolver(resolver && ) = delete; BOOST_ASYNC_DECL void cancel(); @@ -42,32 +42,29 @@ struct resolver asio::ip::basic_resolver & resolver_; core::string_view host_; core::string_view service_; - - }; - public: [[nodiscard]] resolve_op_ resolve(core::string_view host, core::string_view service) { return resolve_op_{resolver_, host, service}; } - - private: asio::ip::basic_resolver resolver_; }; -struct lookup +struct lookup final : result_op { lookup(core::string_view host, core::string_view service) : host_(host), service_(service) {} - auto operator co_await() {return resolver_.resolve(host_, service_);} - private: + + BOOST_ASYNC_DECL + void initiate(completion_handler); + + private: core::string_view host_; core::string_view service_; - resolver resolver_; - + std::optional> resolver_; }; } diff --git a/include/boost/async/io/sleep.hpp b/include/boost/async/io/sleep.hpp index d8d58063..33c9b55b 100644 --- a/include/boost/async/io/sleep.hpp +++ b/include/boost/async/io/sleep.hpp @@ -8,37 +8,49 @@ #ifndef BOOST_ASYNC_IO_SLEEP_HPP #define BOOST_ASYNC_IO_SLEEP_HPP -#include + #include +#include + +#include -#include +#include namespace boost::async::detail::io { -struct steady_sleep + +struct steady_sleep final : async::io::result_op<> { - steady_sleep(const std::chrono::steady_clock::time_point & tp) : tim{tp} {} - steady_sleep(const std::chrono::steady_clock::duration & du) : tim{du} {} + steady_sleep(const std::chrono::steady_clock::time_point & tp) : time_{tp} {} + steady_sleep(const std::chrono::steady_clock::duration & du) + : time_{std::chrono::steady_clock::now() + du} {} + + BOOST_ASYNC_DECL void ready(async::handler h); + BOOST_ASYNC_DECL void initiate(async::completion_handler complete); - async::io::steady_timer::wait_op_ operator co_await() { return tim.wait(); } - async::io::steady_timer::wait_op_::vawaitable value() { return std::move(op_.emplace(tim.wait())).value(); } private: - async::io::steady_timer tim; - std::optional op_; + std::chrono::steady_clock::time_point time_; + std::optional, + executor>> timer_; }; -struct system_sleep +struct system_sleep final : async::io::result_op<> { - system_sleep(const std::chrono::system_clock::time_point & tp) : tim{tp} {} - system_sleep(const std::chrono::system_clock::duration & du) : tim{du} {} - - async::io::system_timer::wait_op_ operator co_await() { return tim.wait(); } - async::io::system_timer::wait_op_::vawaitable value() { return std::move(op_.emplace(tim.wait())).value(); } - private: - async::io::system_timer tim; - std::optional op_; + system_sleep(const std::chrono::system_clock::time_point & tp) : time_{tp} {} + system_sleep(const std::chrono::system_clock::duration & du) + : time_{std::chrono::system_clock::now() + du} {} + + BOOST_ASYNC_DECL void ready(async::handler h); + BOOST_ASYNC_DECL void initiate(async::completion_handler complete); + + private: + std::chrono::system_clock::time_point time_; + std::optional, + executor>> timer_; }; } diff --git a/include/boost/async/io/ssl.hpp b/include/boost/async/io/ssl.hpp index fb4f265b..ade9dc48 100644 --- a/include/boost/async/io/ssl.hpp +++ b/include/boost/async/io/ssl.hpp @@ -38,11 +38,11 @@ struct ssl_stream : private detail::ssl_stream_base, stream, socket [[nodiscard]] BOOST_ASYNC_DECL system::result cancel() override; [[nodiscard]] BOOST_ASYNC_DECL bool is_open() const override; - BOOST_ASYNC_DECL ssl_stream(); + BOOST_ASYNC_DECL ssl_stream(const async::executor & executor = this_thread::get_executor()); BOOST_ASYNC_DECL ssl_stream(ssl_stream && steam); BOOST_ASYNC_DECL ssl_stream(stream_socket && socket); - BOOST_ASYNC_DECL ssl_stream(asio::ssl::context & ctx); + BOOST_ASYNC_DECL ssl_stream(asio::ssl::context & ctx, const async::executor & executor = this_thread::get_executor()); BOOST_ASYNC_DECL ssl_stream(asio::ssl::context & ctx, stream_socket && socket); private: diff --git a/include/boost/async/io/steady_timer.hpp b/include/boost/async/io/steady_timer.hpp index 258aef3e..9ba6cd2f 100644 --- a/include/boost/async/io/steady_timer.hpp +++ b/include/boost/async/io/steady_timer.hpp @@ -34,9 +34,9 @@ struct steady_timer /// The time point type of the clock. typedef typename clock_type::time_point time_point; - BOOST_ASYNC_DECL steady_timer(); - BOOST_ASYNC_DECL steady_timer(const time_point& expiry_time); - BOOST_ASYNC_DECL steady_timer(const duration& expiry_time); + BOOST_ASYNC_DECL steady_timer(const async::executor & executor = this_thread::get_executor()); + BOOST_ASYNC_DECL steady_timer(const time_point& expiry_time, const async::executor & executor = this_thread::get_executor()); + BOOST_ASYNC_DECL steady_timer(const duration& expiry_time, const async::executor & executor = this_thread::get_executor()); BOOST_ASYNC_DECL void cancel(); diff --git a/include/boost/async/io/stream_file.hpp b/include/boost/async/io/stream_file.hpp index 1737d9b9..b2da4751 100644 --- a/include/boost/async/io/stream_file.hpp +++ b/include/boost/async/io/stream_file.hpp @@ -19,16 +19,18 @@ namespace boost::async::io struct stream_file : file, stream { - BOOST_ASYNC_DECL system::result duplicate(); + BOOST_ASYNC_DECL + system::result duplicate(const async::executor & executor = this_thread::get_executor()); [[nodiscard]] BOOST_ASYNC_DECL system::result close() override; [[nodiscard]] BOOST_ASYNC_DECL system::result cancel() override; [[nodiscard]] BOOST_ASYNC_DECL bool is_open() const override; - BOOST_ASYNC_DECL stream_file(); + BOOST_ASYNC_DECL stream_file(const async::executor & executor = this_thread::get_executor()); BOOST_ASYNC_DECL stream_file(stream_file && lhs); - BOOST_ASYNC_DECL stream_file(native_handle_type h); - BOOST_ASYNC_DECL stream_file(core::string_view file, flags open_flags = flags::read_write); + BOOST_ASYNC_DECL stream_file(native_handle_type h, const async::executor & executor = this_thread::get_executor()); + BOOST_ASYNC_DECL stream_file(core::string_view file, flags open_flags = flags::read_write, + const async::executor & executor = this_thread::get_executor()); private: BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; diff --git a/include/boost/async/io/stream_socket.hpp b/include/boost/async/io/stream_socket.hpp index c27ede75..64565471 100644 --- a/include/boost/async/io/stream_socket.hpp +++ b/include/boost/async/io/stream_socket.hpp @@ -19,16 +19,17 @@ namespace boost::async::io struct [[nodiscard]] stream_socket final : stream, socket { // duplicate onto another thread - BOOST_ASYNC_DECL system::result duplicate(); + BOOST_ASYNC_DECL system::result duplicate(const async::executor & executor = this_thread::get_executor()); [[nodiscard]] BOOST_ASYNC_DECL system::result close() override; [[nodiscard]] BOOST_ASYNC_DECL system::result cancel() override; [[nodiscard]] BOOST_ASYNC_DECL bool is_open() const override; - BOOST_ASYNC_DECL stream_socket(); + BOOST_ASYNC_DECL stream_socket(const async::executor & executor = this_thread::get_executor()); BOOST_ASYNC_DECL stream_socket(stream_socket && lhs); - BOOST_ASYNC_DECL stream_socket(native_handle_type h, protocol_type protocol = protocol_type()); - BOOST_ASYNC_DECL stream_socket(endpoint ep); + BOOST_ASYNC_DECL stream_socket(native_handle_type h, protocol_type protocol = protocol_type(), + const async::executor & executor = this_thread::get_executor()); + BOOST_ASYNC_DECL stream_socket(endpoint ep, const async::executor & executor = this_thread::get_executor()); private: BOOST_ASYNC_DECL void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler h) override; BOOST_ASYNC_DECL void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler h) override; diff --git a/include/boost/async/io/system_timer.hpp b/include/boost/async/io/system_timer.hpp index 5aa3339d..2e8e2317 100644 --- a/include/boost/async/io/system_timer.hpp +++ b/include/boost/async/io/system_timer.hpp @@ -33,9 +33,9 @@ struct system_timer final /// The time point type of the clock. typedef typename clock_type::time_point time_point; - BOOST_ASYNC_DECL system_timer(); - BOOST_ASYNC_DECL system_timer(const time_point& expiry_time); - BOOST_ASYNC_DECL system_timer(const duration& expiry_time); + BOOST_ASYNC_DECL system_timer(const async::executor & executor = this_thread::get_executor()); + BOOST_ASYNC_DECL system_timer(const time_point& expiry_time, const async::executor & executor = this_thread::get_executor()); + BOOST_ASYNC_DECL system_timer(const duration& expiry_time, const async::executor & executor = this_thread::get_executor()); BOOST_ASYNC_DECL void cancel(); diff --git a/src/io/acceptor.cpp b/src/io/acceptor.cpp index 1613b4b7..9fcfb167 100644 --- a/src/io/acceptor.cpp +++ b/src/io/acceptor.cpp @@ -9,8 +9,10 @@ namespace boost::async::io { -acceptor::acceptor() : acceptor_{this_thread::get_executor()} {} -acceptor::acceptor(endpoint ep) : acceptor_{this_thread::get_executor(), ep} {} +acceptor::acceptor(const async::executor & exec) + : acceptor_{exec} {} +acceptor::acceptor(endpoint ep, const async::executor & exec) + : acceptor_{exec, ep} {} system::result acceptor::bind(endpoint ep) diff --git a/src/io/datagram_socket.cpp b/src/io/datagram_socket.cpp index f4d13b1c..21ad53be 100644 --- a/src/io/datagram_socket.cpp +++ b/src/io/datagram_socket.cpp @@ -11,24 +11,23 @@ namespace boost::async::io { -system::result datagram_socket::duplicate() +system::result datagram_socket::duplicate(const async::executor & exec) { auto res = detail::io::duplicate_handle(datagram_socket_.native_handle()); if (!res) return res.error(); - - return {system::in_place_value, datagram_socket(*res)}; + return {system::in_place_value, datagram_socket(*res, local_endpoint()->protocol(), exec)}; } -datagram_socket::datagram_socket() - : socket(datagram_socket_), datagram_socket_(this_thread::get_executor()) +datagram_socket::datagram_socket(const async::executor & exec) + : socket(datagram_socket_), datagram_socket_(exec) { } -datagram_socket::datagram_socket(native_handle_type h, protocol_type protocol) - : socket(datagram_socket_), datagram_socket_(this_thread::get_executor(), protocol, h) +datagram_socket::datagram_socket(native_handle_type h, protocol_type protocol, const async::executor & exec) + : socket(datagram_socket_), datagram_socket_(exec, protocol, h) { } @@ -36,8 +35,8 @@ datagram_socket::datagram_socket(datagram_socket && lhs) : socket(datagram_socket_), datagram_socket_(std::move(lhs.datagram_socket_)) { } -datagram_socket::datagram_socket(endpoint ep) - : socket(datagram_socket_), datagram_socket_(this_thread::get_executor(), ep) +datagram_socket::datagram_socket(endpoint ep, const async::executor & exec) + : socket(datagram_socket_), datagram_socket_(exec, ep) { } diff --git a/src/io/pipe.cpp b/src/io/pipe.cpp index 7c46cc26..0b7f408c 100644 --- a/src/io/pipe.cpp +++ b/src/io/pipe.cpp @@ -14,9 +14,9 @@ namespace boost::async::io { -readable_pipe::readable_pipe() : pipe_(this_thread::get_executor()) {} -readable_pipe::readable_pipe(native_handle_type native_handle) - : pipe_(this_thread::get_executor(), native_handle) {} +readable_pipe::readable_pipe(const async::executor & exec) : pipe_(exec) {} +readable_pipe::readable_pipe(native_handle_type native_handle, const async::executor & exec) + : pipe_(exec, native_handle) {} system::result readable_pipe::close() { @@ -73,19 +73,19 @@ auto readable_pipe::release() -> system::result return h; } -system::result readable_pipe::duplicate() +system::result readable_pipe::duplicate(const async::executor & exec) { auto res = detail::io::duplicate_handle(pipe_.native_handle()); if (!res) return res.error(); - return readable_pipe(*res); + return readable_pipe(*res, std::move(exec)); } -writable_pipe::writable_pipe() : pipe_(this_thread::get_executor()) {} -writable_pipe::writable_pipe(native_handle_type native_handle) - : pipe_(this_thread::get_executor(), native_handle) {} +writable_pipe::writable_pipe(const async::executor & exec) : pipe_(std::move(exec)) {} +writable_pipe::writable_pipe(native_handle_type native_handle, const async::executor & exec) + : pipe_(std::move(exec), native_handle) {} system::result writable_pipe::close() { @@ -142,19 +142,19 @@ auto writable_pipe::release() -> system::result return h; } -system::result writable_pipe::duplicate() +system::result writable_pipe::duplicate(const async::executor & exec) { auto res = detail::io::duplicate_handle(pipe_.native_handle()); if (!res) return res.error(); - return writable_pipe(*res); + return writable_pipe(*res, std::move(exec)); } -system::result> make_pipe() +system::result> make_pipe(const async::executor & exec) { - readable_pipe rp{}; - writable_pipe wp{}; + readable_pipe rp{exec}; + writable_pipe wp{exec}; system::error_code ec; asio::connect_pipe(rp.pipe_, wp.pipe_, ec); diff --git a/src/io/popen.cpp b/src/io/popen.cpp index 46c2f952..1c222d45 100644 --- a/src/io/popen.cpp +++ b/src/io/popen.cpp @@ -11,25 +11,27 @@ namespace boost::async::io { popen::popen(boost::process::v2::filesystem::path executable, - std::initializer_list args, - process_initializer initializer) - : popen_(this_thread::get_executor(), - executable, - args, - initializer.stdio, - initializer.start_dir, - initializer.env) {} + std::initializer_list args, + process_initializer initializer, + const async::executor & exec) + : popen_(exec, + executable, + args, + initializer.stdio, + initializer.start_dir, + initializer.env) {} popen::popen(boost::process::v2::filesystem::path executable, - std::span args, - process_initializer initializer) - : popen_(this_thread::get_executor(), - executable, - args, - initializer.stdio, - initializer.start_dir, - initializer.env) {} + std::span args, + process_initializer initializer, + const async::executor & exec) + : popen_(exec, + executable, + args, + initializer.stdio, + initializer.start_dir, + initializer.env) {} pid_type popen::id() const {return popen_.id();} diff --git a/src/io/process.cpp b/src/io/process.cpp index 20e1ad45..e7b2049a 100644 --- a/src/io/process.cpp +++ b/src/io/process.cpp @@ -12,8 +12,9 @@ namespace boost::async::io process::process(boost::process::v2::filesystem::path executable, std::initializer_list args, - process_initializer initializer) - : process_(this_thread::get_executor(), + process_initializer initializer, + const async::executor & exec) + : process_(exec, executable, args, initializer.stdio, @@ -23,8 +24,9 @@ process::process(boost::process::v2::filesystem::path executable, process::process(boost::process::v2::filesystem::path executable, std::span args, - process_initializer initializer) - : process_(this_thread::get_executor(), + process_initializer initializer, + const async::executor & exec) + : process_(exec, executable, args, initializer.stdio, @@ -32,9 +34,9 @@ process::process(boost::process::v2::filesystem::path executable, initializer.env) {} -process::process(pid_type pid) : process_(this_thread::get_executor(), pid) {} -process::process(pid_type pid, native_handle_type native_handle) - : process_(this_thread::get_executor(), pid, native_handle) {} +process::process(pid_type pid, const async::executor & exec) : process_(exec, pid) {} +process::process(pid_type pid, native_handle_type native_handle, const async::executor & exec) + : process_(exec, pid, native_handle) {} void process::wait_op_::initiate(completion_handler handler) { diff --git a/src/io/resolver.cpp b/src/io/resolver.cpp index 1190bdd0..c46716f6 100644 --- a/src/io/resolver.cpp +++ b/src/io/resolver.cpp @@ -14,20 +14,38 @@ namespace boost::async::io { -resolver::resolver() : resolver_(this_thread::get_executor()) {} +resolver::resolver(const async::executor & exec) : resolver_(exec) {} void resolver::cancel() { resolver_.cancel(); } -void resolver::resolve_op_::initiate(completion_handler h) + +void do_initiate(asio::ip::basic_resolver & resolver_, + core::string_view host, core::string_view service, + completion_handler h) { using results_type = typename asio::ip::basic_resolver_results; resolver_.async_resolve( - async::io::ip, host_, service_, + async::io::ip, host, service, asio::deferred([](system::error_code ec, results_type res) - { - container::pmr::vector r{this_thread::get_allocator()}; - r.assign(res.begin(), res.end()); - return asio::deferred.values(ec, std::move(r)); - }))(std::move(h)); + { + container::pmr::vector r{this_thread::get_allocator()}; + r.assign(res.begin(), res.end()); + return asio::deferred.values(ec, std::move(r)); + }))(std::move(h)); +} + + +void resolver::resolve_op_::initiate( + completion_handler h) +{ + do_initiate(resolver_, host_, service_, std::move(h)); +} + +BOOST_ASYNC_DECL +void lookup::initiate( + completion_handler handler) +{ + auto & res = resolver_.emplace(handler.get_executor()); + do_initiate(res, host_, service_, std::move(handler)); } } \ No newline at end of file diff --git a/src/io/sleep.cpp b/src/io/sleep.cpp new file mode 100644 index 00000000..2fb0c10b --- /dev/null +++ b/src/io/sleep.cpp @@ -0,0 +1,34 @@ +// Copyright (c) 2023 Klemens D. Morgenstern +// +// 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) + +#include + +namespace boost::async::detail::io +{ + +void steady_sleep::ready(async::handler h) +{ + if (time_ < std::chrono::steady_clock::now()) + h({}); +} +void steady_sleep::initiate(async::completion_handler complete) +{ + auto & timer = timer_.emplace(complete.get_executor(), time_); + timer.async_wait(std::move(complete)); +} + +void system_sleep::ready(async::handler h) +{ + if (time_ < std::chrono::system_clock::now()) + h({}); +} +void system_sleep::initiate(async::completion_handler complete) +{ + auto &timer = timer_.emplace(complete.get_executor(), time_); + timer.async_wait(std::move(complete)); +} + + +} \ No newline at end of file diff --git a/src/io/ssl.cpp b/src/io/ssl.cpp index 043f3866..b2cb9435 100644 --- a/src/io/ssl.cpp +++ b/src/io/ssl.cpp @@ -29,8 +29,8 @@ static asio::ssl::context & get_ssl_context() } -ssl_stream::ssl_stream() - : ssl_stream_base(this_thread::get_executor(), get_ssl_context()), socket(ssl_stream_.next_layer()) +ssl_stream::ssl_stream(const async::executor & exec) + : ssl_stream_base(exec, get_ssl_context()), socket(ssl_stream_.next_layer()) { } @@ -42,8 +42,8 @@ ssl_stream::ssl_stream(ssl_stream && lhs) ssl_stream::ssl_stream(stream_socket && socket_) : ssl_stream_base(std::move(socket_.stream_socket_), get_ssl_context()), socket(ssl_stream_.next_layer()) {} -ssl_stream::ssl_stream(asio::ssl::context & ctx) - : ssl_stream_base(this_thread::get_executor(), ctx), socket(ssl_stream_.next_layer()) {} +ssl_stream::ssl_stream(asio::ssl::context & ctx, const async::executor & exec) + : ssl_stream_base(exec, ctx), socket(ssl_stream_.next_layer()) {} ssl_stream::ssl_stream(asio::ssl::context & ctx, stream_socket && socket_) : ssl_stream_base(std::move(socket_.stream_socket_), ctx), socket(ssl_stream_.next_layer()) {} diff --git a/src/io/steady_timer.cpp b/src/io/steady_timer.cpp index 846c7edd..8a8c6ab4 100644 --- a/src/io/steady_timer.cpp +++ b/src/io/steady_timer.cpp @@ -12,9 +12,12 @@ namespace boost::async::io { -steady_timer::steady_timer() : timer_(this_thread::get_executor()) {} -steady_timer::steady_timer(const time_point &expiry_time) : timer_(this_thread::get_executor(), expiry_time) {} -steady_timer::steady_timer(const duration &expiry_time) : timer_(this_thread::get_executor(), expiry_time) {} +steady_timer::steady_timer(const async::executor & exec) + : timer_(exec) {} +steady_timer::steady_timer(const time_point &expiry_time, const async::executor & exec) + : timer_(exec, expiry_time) {} +steady_timer::steady_timer(const duration &expiry_time, const async::executor & exec) + : timer_(exec, expiry_time) {} void steady_timer::cancel() { diff --git a/src/io/stream_file.cpp b/src/io/stream_file.cpp index 2bb1c6e4..b4ac8832 100644 --- a/src/io/stream_file.cpp +++ b/src/io/stream_file.cpp @@ -13,24 +13,24 @@ namespace boost::async::io { -system::result stream_file::duplicate() +system::result stream_file::duplicate(const async::executor & exec) { auto res = detail::io::duplicate_handle(stream_file_.native_handle()); if (!res) return res.error(); - return {system::in_place_value, stream_file(*res)}; + return {system::in_place_value, stream_file(*res, exec)}; } -stream_file::stream_file() - : file(stream_file_), stream_file_(this_thread::get_executor()) +stream_file::stream_file(const async::executor & exec) + : file(stream_file_), stream_file_(exec) { } -stream_file::stream_file(native_handle_type h) - : file(stream_file_), stream_file_(this_thread::get_executor()) +stream_file::stream_file(native_handle_type h, const async::executor & exec) + : file(stream_file_), stream_file_(exec) { } @@ -39,8 +39,8 @@ stream_file::stream_file(stream_file && lhs) { } -stream_file::stream_file(core::string_view file_, flags open_flags) - : file(stream_file_), stream_file_(this_thread::get_executor(), std::string(file_), open_flags) +stream_file::stream_file(core::string_view file_, flags open_flags, const async::executor & exec) + : file(stream_file_), stream_file_(exec, std::string(file_), open_flags) { } diff --git a/src/io/stream_socket.cpp b/src/io/stream_socket.cpp index 7d96b8bf..65b3cfe7 100644 --- a/src/io/stream_socket.cpp +++ b/src/io/stream_socket.cpp @@ -11,24 +11,24 @@ namespace boost::async::io { -system::result stream_socket::duplicate() +system::result stream_socket::duplicate(const async::executor & exec) { auto res = detail::io::duplicate_handle(stream_socket_.native_handle()); if (!res) return res.error(); - return {system::in_place_value, stream_socket(*res)}; + return {system::in_place_value, stream_socket(*res, local_endpoint()->protocol(), exec)}; } -stream_socket::stream_socket() - : socket(stream_socket_), stream_socket_(this_thread::get_executor()) +stream_socket::stream_socket(const async::executor & exec) + : socket(stream_socket_), stream_socket_(exec) { } -stream_socket::stream_socket(native_handle_type h, protocol_type protocol) - : socket(stream_socket_), stream_socket_(this_thread::get_executor(), protocol, h) +stream_socket::stream_socket(native_handle_type h, protocol_type protocol, const async::executor & exec) + : socket(stream_socket_), stream_socket_(exec, protocol, h) { } @@ -36,8 +36,8 @@ stream_socket::stream_socket(stream_socket && lhs) : socket(stream_socket_), stream_socket_(std::move(lhs.stream_socket_)) { } -stream_socket::stream_socket(endpoint ep) - : socket(stream_socket_), stream_socket_(this_thread::get_executor(), ep) +stream_socket::stream_socket(endpoint ep, const async::executor & exec) + : socket(stream_socket_), stream_socket_(exec, ep) { } diff --git a/src/io/system_timer.cpp b/src/io/system_timer.cpp index b27b1572..685a050b 100644 --- a/src/io/system_timer.cpp +++ b/src/io/system_timer.cpp @@ -12,9 +12,12 @@ namespace boost::async::io { -system_timer::system_timer() : timer_(this_thread::get_executor()) {} -system_timer::system_timer(const time_point &expiry_time) : timer_(this_thread::get_executor(), expiry_time) {} -system_timer::system_timer(const duration &expiry_time) : timer_(this_thread::get_executor(), expiry_time) {} +system_timer::system_timer(const async::executor & exec) + : timer_(exec) {} +system_timer::system_timer(const time_point &expiry_time, const async::executor & exec) + : timer_(exec, expiry_time) {} +system_timer::system_timer(const duration &expiry_time, const async::executor & exec) + : timer_(exec, expiry_time) {} void system_timer::cancel() { From 9d565961b5e11028155676af7d0a4e6fdec4e156 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Wed, 9 Aug 2023 21:07:07 +0800 Subject: [PATCH 43/43] rebase fixes. --- CMakeLists.txt | 2 -- doc/reference/io/resolver.adoc | 2 +- include/boost/async/io/buffers/register.hpp | 2 +- include/boost/async/io/resolver.hpp | 2 +- include/boost/async/io/result.hpp | 4 ++-- include/boost/async/io/transfer_result.hpp | 2 +- include/boost/async/io/write_at.hpp | 4 ++-- src/io/resolver.cpp | 2 +- 8 files changed, 9 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 95fe8de6..c9d7b71b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,8 +29,6 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html add_custom_target(boost_async_doc DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html) -add_compile_definitions(BOOST_ASIO_HAS_IO_URING=1) - if(BOOST_ASYNC_IS_ROOT) #include(CTest) endif() diff --git a/doc/reference/io/resolver.adoc b/doc/reference/io/resolver.adoc index 38f63de2..f2c2260f 100644 --- a/doc/reference/io/resolver.adoc +++ b/doc/reference/io/resolver.adoc @@ -62,7 +62,7 @@ To make it type-safe, the library provides a `static_protocol` template: struct resolver { - using resolve_result = system::result>; + using resolve_result = system::result>; resolver(); resolver(resolver && ) = delete; diff --git a/include/boost/async/io/buffers/register.hpp b/include/boost/async/io/buffers/register.hpp index 56596326..d682173f 100644 --- a/include/boost/async/io/buffers/register.hpp +++ b/include/boost/async/io/buffers/register.hpp @@ -17,7 +17,7 @@ namespace boost::async::io::buffers { using buffer_registration = asio::buffer_registration>; + pmr::polymorphic_allocator>; BOOST_ASYNC_DECL buffer_registration register_(buffers::mutable_buffer mutable_buffer); BOOST_ASYNC_DECL buffer_registration register_(buffers::mutable_buffer_span mutable_buffers); diff --git a/include/boost/async/io/resolver.hpp b/include/boost/async/io/resolver.hpp index 0f2ee03f..0be9c3fc 100644 --- a/include/boost/async/io/resolver.hpp +++ b/include/boost/async/io/resolver.hpp @@ -23,7 +23,7 @@ namespace boost::async::io struct resolver { - using resolve_result = system::result>; + using resolve_result = system::result>; BOOST_ASYNC_DECL resolver(const async::executor & executor = this_thread::get_executor()); BOOST_ASYNC_DECL resolver(resolver && ) = delete; diff --git a/include/boost/async/io/result.hpp b/include/boost/async/io/result.hpp index 4ec7c604..bf6d568d 100644 --- a/include/boost/async/io/result.hpp +++ b/include/boost/async/io/result.hpp @@ -96,7 +96,7 @@ struct result_op std::exception_ptr error; std::optional> result; char buffer[2048]; - std::optional resource; + std::optional resource; detail::completed_immediately_t completed_immediately = detail::completed_immediately_t::no; }; @@ -180,7 +180,7 @@ struct result_op std::exception_ptr error; std::optional> result; char buffer[2048]; - std::optional resource; + std::optional resource; detail::completed_immediately_t completed_immediately = detail::completed_immediately_t::no; }; diff --git a/include/boost/async/io/transfer_result.hpp b/include/boost/async/io/transfer_result.hpp index f9c458e7..79b25206 100644 --- a/include/boost/async/io/transfer_result.hpp +++ b/include/boost/async/io/transfer_result.hpp @@ -133,7 +133,7 @@ struct transfer_op std::exception_ptr error; std::optional> result; char buffer[2048]; - std::optional resource; + std::optional resource; detail::completed_immediately_t completed_immediately = detail::completed_immediately_t::no; }; diff --git a/include/boost/async/io/write_at.hpp b/include/boost/async/io/write_at.hpp index 55d7b1ed..3a68f3f0 100644 --- a/include/boost/async/io/write_at.hpp +++ b/include/boost/async/io/write_at.hpp @@ -25,8 +25,8 @@ template promise write(random_access_device & source, std::uint64_t offset, MutableBufferSequence && buffer) { buffers::const_buffer buf[32]; - container::pmr::monotonic_buffer_resource res{buf, sizeof(buf), this_thread::get_default_resource()}; - container::pmr::vector buf_span{buffer.begin(), buffer.end(), &res}; + pmr::monotonic_buffer_resource res{buf, sizeof(buf), this_thread::get_default_resource()}; + pmr::vector buf_span{buffer.begin(), buffer.end(), &res}; co_return co_await write_at(source, offset, buffers::const_buffer_span{buf_span}); } diff --git a/src/io/resolver.cpp b/src/io/resolver.cpp index c46716f6..dea2a37d 100644 --- a/src/io/resolver.cpp +++ b/src/io/resolver.cpp @@ -27,7 +27,7 @@ void do_initiate(asio::ip::basic_resolver & resolver_, async::io::ip, host, service, asio::deferred([](system::error_code ec, results_type res) { - container::pmr::vector r{this_thread::get_allocator()}; + pmr::vector r{this_thread::get_allocator()}; r.assign(res.begin(), res.end()); return asio::deferred.values(ec, std::move(r)); }))(std::move(h));