From: Jonathan Wakely Date: Fri, 12 Oct 2018 10:50:15 +0000 (+0100) Subject: Initial commit of Networking TS implementation X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e5989e71ffdee9f030f0b8ac38aef5a4ff7bd444;p=gcc.git Initial commit of Networking TS implementation * include/Makefile.am: Add new headers. * include/Makefile.in: Regenerate. * include/experimental/bits/net.h: New header for common implementation details of Networking TS. * include/experimental/buffer: New header. * include/experimental/executor: New header. * include/experimental/internet: New header. * include/experimental/io_context: New header. * include/experimental/net: New header. * include/experimental/netfwd: New header. * include/experimental/socket: New header. * include/experimental/timer: New header. * testsuite/experimental/net/buffer/arithmetic.cc: New test. * testsuite/experimental/net/buffer/const.cc: New test. * testsuite/experimental/net/buffer/creation.cc: New test. * testsuite/experimental/net/buffer/mutable.cc: New test. * testsuite/experimental/net/buffer/size.cc: New test. * testsuite/experimental/net/buffer/traits.cc: New test. * testsuite/experimental/net/execution_context/use_service.cc: New test. * testsuite/experimental/net/headers.cc: New test. * testsuite/experimental/net/internet/address/v4/comparisons.cc: New test. * testsuite/experimental/net/internet/address/v4/cons.cc: New test. * testsuite/experimental/net/internet/address/v4/creation.cc: New test. * testsuite/experimental/net/internet/address/v4/members.cc: New test. * testsuite/experimental/net/internet/resolver/base.cc: New test. * testsuite/experimental/net/internet/resolver/ops/lookup.cc: New test. * testsuite/experimental/net/internet/resolver/ops/reverse.cc: New test. * testsuite/experimental/net/timer/waitable/cons.cc: New test. * testsuite/experimental/net/timer/waitable/dest.cc: New test. * testsuite/experimental/net/timer/waitable/ops.cc: New test. From-SVN: r265080 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 35be45e4e46..871d6ab4a09 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,43 @@ 2018-10-12 Jonathan Wakely + Initial commit of Networking TS implementation. + * include/Makefile.am: Add new headers. + * include/Makefile.in: Regenerate. + * include/experimental/bits/net.h: New header for common + implementation details of Networking TS. + * include/experimental/buffer: New header. + * include/experimental/executor: New header. + * include/experimental/internet: New header. + * include/experimental/io_context: New header. + * include/experimental/net: New header. + * include/experimental/netfwd: New header. + * include/experimental/socket: New header. + * include/experimental/timer: New header. + * testsuite/experimental/net/buffer/arithmetic.cc: New test. + * testsuite/experimental/net/buffer/const.cc: New test. + * testsuite/experimental/net/buffer/creation.cc: New test. + * testsuite/experimental/net/buffer/mutable.cc: New test. + * testsuite/experimental/net/buffer/size.cc: New test. + * testsuite/experimental/net/buffer/traits.cc: New test. + * testsuite/experimental/net/execution_context/use_service.cc: New + test. + * testsuite/experimental/net/headers.cc: New test. + * testsuite/experimental/net/internet/address/v4/comparisons.cc: New + test. + * testsuite/experimental/net/internet/address/v4/cons.cc: New test. + * testsuite/experimental/net/internet/address/v4/creation.cc: New + test. + * testsuite/experimental/net/internet/address/v4/members.cc: New + test. + * testsuite/experimental/net/internet/resolver/base.cc: New test. + * testsuite/experimental/net/internet/resolver/ops/lookup.cc: New + test. + * testsuite/experimental/net/internet/resolver/ops/reverse.cc: New + test. + * testsuite/experimental/net/timer/waitable/cons.cc: New test. + * testsuite/experimental/net/timer/waitable/dest.cc: New test. + * testsuite/experimental/net/timer/waitable/ops.cc: New test. + PR libstdc++/77691 * include/experimental/memory_resource (__resource_adaptor_imp): Do not allocate sizes smaller than alignment when relying on guaranteed diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 271695806ff..d45d937d3a7 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -671,15 +671,21 @@ experimental_headers = \ ${experimental_srcdir}/algorithm \ ${experimental_srcdir}/any \ ${experimental_srcdir}/array \ + ${experimental_srcdir}/buffer \ ${experimental_srcdir}/chrono \ ${experimental_srcdir}/deque \ + ${experimental_srcdir}/executor \ ${experimental_srcdir}/forward_list \ ${experimental_srcdir}/functional \ + ${experimental_srcdir}/internet \ + ${experimental_srcdir}/io_context \ ${experimental_srcdir}/iterator \ ${experimental_srcdir}/list \ ${experimental_srcdir}/map \ ${experimental_srcdir}/memory \ ${experimental_srcdir}/memory_resource \ + ${experimental_srcdir}/net \ + ${experimental_srcdir}/netfwd \ ${experimental_srcdir}/numeric \ ${experimental_srcdir}/optional \ ${experimental_srcdir}/propagate_const \ @@ -687,10 +693,12 @@ experimental_headers = \ ${experimental_srcdir}/ratio \ ${experimental_srcdir}/regex \ ${experimental_srcdir}/set \ + ${experimental_srcdir}/socket \ ${experimental_srcdir}/source_location \ ${experimental_srcdir}/string \ ${experimental_srcdir}/string_view \ ${experimental_srcdir}/system_error \ + ${experimental_srcdir}/timer \ ${experimental_srcdir}/tuple \ ${experimental_srcdir}/type_traits \ ${experimental_srcdir}/unordered_map \ @@ -704,6 +712,7 @@ experimental_bits_builddir = ./experimental/bits experimental_bits_headers = \ ${experimental_bits_srcdir}/erase_if.h \ ${experimental_bits_srcdir}/lfts_config.h \ + ${experimental_bits_srcdir}/net.h \ ${experimental_bits_srcdir}/shared_ptr.h \ ${experimental_bits_srcdir}/string_view.tcc \ ${experimental_bits_filesystem_headers} diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index 97f738a96a6..f872d928d71 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -963,15 +963,21 @@ experimental_headers = \ ${experimental_srcdir}/algorithm \ ${experimental_srcdir}/any \ ${experimental_srcdir}/array \ + ${experimental_srcdir}/buffer \ ${experimental_srcdir}/chrono \ ${experimental_srcdir}/deque \ + ${experimental_srcdir}/executor \ ${experimental_srcdir}/forward_list \ ${experimental_srcdir}/functional \ + ${experimental_srcdir}/internet \ + ${experimental_srcdir}/io_context \ ${experimental_srcdir}/iterator \ ${experimental_srcdir}/list \ ${experimental_srcdir}/map \ ${experimental_srcdir}/memory \ ${experimental_srcdir}/memory_resource \ + ${experimental_srcdir}/net \ + ${experimental_srcdir}/netfwd \ ${experimental_srcdir}/numeric \ ${experimental_srcdir}/optional \ ${experimental_srcdir}/propagate_const \ @@ -979,10 +985,12 @@ experimental_headers = \ ${experimental_srcdir}/ratio \ ${experimental_srcdir}/regex \ ${experimental_srcdir}/set \ + ${experimental_srcdir}/socket \ ${experimental_srcdir}/source_location \ ${experimental_srcdir}/string \ ${experimental_srcdir}/string_view \ ${experimental_srcdir}/system_error \ + ${experimental_srcdir}/timer \ ${experimental_srcdir}/tuple \ ${experimental_srcdir}/type_traits \ ${experimental_srcdir}/unordered_map \ @@ -996,6 +1004,7 @@ experimental_bits_builddir = ./experimental/bits experimental_bits_headers = \ ${experimental_bits_srcdir}/erase_if.h \ ${experimental_bits_srcdir}/lfts_config.h \ + ${experimental_bits_srcdir}/net.h \ ${experimental_bits_srcdir}/shared_ptr.h \ ${experimental_bits_srcdir}/string_view.tcc \ ${experimental_bits_filesystem_headers} diff --git a/libstdc++-v3/include/experimental/bits/net.h b/libstdc++-v3/include/experimental/bits/net.h new file mode 100644 index 00000000000..17bd300ccf2 --- /dev/null +++ b/libstdc++-v3/include/experimental/bits/net.h @@ -0,0 +1,174 @@ +// Networking implementation details -*- C++ -*- + +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file experimental/bits/net.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{experimental/networking} + */ + +#ifndef _GLIBCXX_EXPERIMENTAL_NET_H +#define _GLIBCXX_EXPERIMENTAL_NET_H 1 + +#pragma GCC system_header + +#if __cplusplus >= 201402L + +#include +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +namespace experimental +{ +namespace net +{ +inline namespace v1 +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @ingroup networking + * @{ + */ + + template + class async_result; + + // A type denoted by DEDUCED in the TS. + template + using __deduced_t = typename + async_result, _Signature, void>::return_type; + + // Trait to check for construction from const/non-const lvalue/rvalue. + template + using __is_value_constructible = typename __and_< + is_copy_constructible<_Tp>, is_move_constructible<_Tp>, + is_constructible<_Tp, _Tp&>, is_constructible<_Tp, const _Tp&&> + >::type; + + struct __throw_on_error + { + explicit + __throw_on_error(const char* __msg) : _M_msg(__msg) { } + + ~__throw_on_error() noexcept(false) + { + if (_M_ec) + _GLIBCXX_THROW_OR_ABORT(system_error(_M_ec, _M_msg)); + } + + __throw_on_error(const __throw_on_error&) = delete; + __throw_on_error& operator=(const __throw_on_error&) = delete; + + operator error_code&() noexcept { return _M_ec; } + + const char* _M_msg; + error_code _M_ec; + }; + + // Base class for types meeting IntegerSocketOption requirements. + template + struct __sockopt_base + { + __sockopt_base() = default; + + explicit __sockopt_base(int __val) : _M_value(__val) { } + + int value() const noexcept { return _M_value; } + + template + void* + data(const _Protocol&) noexcept + { return std::addressof(_M_value); } + + template + const void* + data(const _Protocol&) const noexcept + { return std::addressof(_M_value); } + + template + size_t + size(const _Protocol&) const noexcept + { return sizeof(_M_value); } + + template + void + resize(const _Protocol&, size_t __s) + { + if (__s != sizeof(_M_value)) + __throw_length_error("invalid value for socket option resize"); + } + + protected: + _Tp _M_value { }; + }; + + // Base class for types meeting BooleanSocketOption requirements. + template<> + struct __sockopt_base : __sockopt_base + { + __sockopt_base() = default; + + explicit __sockopt_base(bool __val) : __sockopt_base(__val) { } + + bool value() const noexcept { return __sockopt_base::_M_value; } + explicit operator bool() const noexcept { return value(); } + bool operator!() const noexcept { return !value(); } + }; + + template + struct __sockopt_crtp : __sockopt_base<_Tp> + { + using __sockopt_base<_Tp>::__sockopt_base; + + _Derived& + operator=(_Tp __value) + { + __sockopt_base<_Tp>::_M_value = __value; + return static_cast<_Derived&>(*this); + } + + template + int + level(const _Protocol&) const noexcept + { return _Derived::_S_level; } + + template + int + name(const _Protocol&) const noexcept + { return _Derived::_S_name; } + }; + + /// @} + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace v1 +} // namespace net +} // namespace experimental +} // namespace std + +#endif // C++14 + +#endif // _GLIBCXX_EXPERIMENTAL_NET_H diff --git a/libstdc++-v3/include/experimental/buffer b/libstdc++-v3/include/experimental/buffer new file mode 100644 index 00000000000..5541823165b --- /dev/null +++ b/libstdc++-v3/include/experimental/buffer @@ -0,0 +1,897 @@ +// -*- C++ -*- + +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file experimental/buffer + * This is a TS C++ Library header. + */ + +#ifndef _GLIBCXX_EXPERIMENTAL_BUFFER +#define _GLIBCXX_EXPERIMENTAL_BUFFER 1 + +#pragma GCC system_header + +#if __cplusplus >= 201402L + +#include +#include +#include +#include +#include +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +namespace experimental +{ +namespace net +{ +inline namespace v1 +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @ingroup networking + * @{ + */ + + enum class stream_errc { // TODO decide values + eof = 1, + not_found = 2 + }; + + const error_category& stream_category() noexcept // TODO not inline + { + struct __cat : error_category + { + const char* name() const noexcept { return "stream"; } + + std::string message(int __e) const + { + if (__e == (int)stream_errc::eof) + return "EOF"; + else if (__e == (int)stream_errc::not_found) + return "not found"; + return "stream"; + } + + virtual void __message(int) { } // TODO dual ABI XXX + }; + static __cat __c; + return __c; + } + + inline error_code + make_error_code(stream_errc __e) noexcept + { return error_code(static_cast(__e), stream_category()); } + + inline error_condition + make_error_condition(stream_errc __e) noexcept + { return error_condition(static_cast(__e), stream_category()); } + + class mutable_buffer + { + public: + // constructors: + mutable_buffer() noexcept : _M_data(), _M_size() { } + + mutable_buffer(void* __p, size_t __n) noexcept + : _M_data(__p), _M_size(__n) { } + + // members: + void* data() const noexcept { return _M_data; } + size_t size() const noexcept { return _M_size; } + + private: + void* _M_data; + size_t _M_size; + }; + + class const_buffer + { + public: + // constructors: + const_buffer() noexcept : _M_data(), _M_size() { } + + const_buffer(const void* __p, size_t __n) noexcept + : _M_data(__p), _M_size(__n) { } + + const_buffer(const mutable_buffer& __b) noexcept + : _M_data(__b.data()), _M_size(__b.size()) { } + + // members: + const void* data() const noexcept { return _M_data; } + size_t size() const noexcept { return _M_size; } + + private: + const void* _M_data; + size_t _M_size; + }; + + + /** @brief buffer sequence access + * + * Uniform access to types that meet the BufferSequence requirements. + * @{ + */ + + inline const mutable_buffer* + buffer_sequence_begin(const mutable_buffer& __b) + { return std::addressof(__b); } + + inline const const_buffer* + buffer_sequence_begin(const const_buffer& __b) + { return std::addressof(__b); } + + inline const mutable_buffer* + buffer_sequence_end(const mutable_buffer& __b) + { return std::addressof(__b) + 1; } + + inline const const_buffer* + buffer_sequence_end(const const_buffer& __b) + { return std::addressof(__b) + 1; } + + template + auto + buffer_sequence_begin(_Cont& __c) -> decltype(__c.begin()) + { return __c.begin(); } + + template + auto + buffer_sequence_begin(const _Cont& __c) -> decltype(__c.begin()) + { return __c.begin(); } + + template + auto + buffer_sequence_end(_Cont& __c) -> decltype(__c.end()) + { return __c.end(); } + + template + auto + buffer_sequence_end(const _Cont& __c) -> decltype(__c.end()) + { return __c.end(); } + + // @} + + + /** @brief buffer type traits + * + * @{ + */ + + template())), + typename _End + = decltype(net::buffer_sequence_end(std::declval<_Tp&>()))> + using __buffer_sequence = enable_if_t<__and_< + __is_value_constructible<_Tp>, is_same<_Begin, _End>, + is_convertible::value_type, _Buffer> + >::value>; + + template + struct __is_buffer_sequence : false_type + { }; + + template + struct __is_buffer_sequence<_Tp, _Buffer, __buffer_sequence<_Tp, _Buffer>> + : true_type + { }; + + template + struct is_mutable_buffer_sequence + : __is_buffer_sequence<_Tp, mutable_buffer>::type + { }; + + template + struct is_const_buffer_sequence + : __is_buffer_sequence<_Tp, const_buffer>::type + { }; + + template + constexpr bool is_mutable_buffer_sequence_v + = is_mutable_buffer_sequence<_Tp>::value; + + template + constexpr bool is_const_buffer_sequence_v + = is_const_buffer_sequence<_Tp>::value; + + template + struct __is_dynamic_buffer_impl : false_type + { }; + + // Check DynamicBuffer requirements. + template> + auto + __dynamic_buffer_reqs(_Up* __x = 0, const _Up* __x1 = 0, size_t __n = 0) + -> enable_if_t<__and_< + is_move_constructible<_Up>, + is_const_buffer_sequence, + is_mutable_buffer_sequence, + is_samesize()), size_t>, + is_samemax_size()), size_t>, + is_samecapacity()), size_t>, + is_samedata()), typename _Tp::const_buffers_type>, + is_sameprepare(__n)), typename _Tp::mutable_buffers_type>, + is_voidcommit(__n), __x->consume(__n), void())> + >::value>; + + template + struct __is_dynamic_buffer_impl<_Tp, + decltype(__dynamic_buffer_reqs<_Tp>())> + : true_type + { }; + + template + struct is_dynamic_buffer : __is_dynamic_buffer_impl<_Tp>::type + { }; + + template + constexpr bool is_dynamic_buffer_v = is_dynamic_buffer<_Tp>::value; + + // @} + + /// buffer size + template + size_t + buffer_size(const _ConstBufferSequence& __buffers) noexcept + { + size_t __total_size = 0; + auto __i = net::buffer_sequence_begin(__buffers); + const auto __end = net::buffer_sequence_end(__buffers); + for (; __i != __end; ++__i) + __total_size += const_buffer(*__i).size(); + return __total_size; + } + + template + bool + __buffer_empty(const _ConstBufferSequence& __buffers) noexcept + { + auto __i = net::buffer_sequence_begin(__buffers); + const auto __end = net::buffer_sequence_end(__buffers); + for (; __i != __end; ++__i) + if (const_buffer(*__i).size() != 0) + return false; + return true; + } + + // buffer copy: + + template + size_t + buffer_copy(const _MutableBufferSequence& __dest, + const _ConstBufferSequence& __source, + size_t __max_size) noexcept + { + size_t __total_size = 0; + auto __to_i = net::buffer_sequence_begin(__dest); + const auto __to_end = net::buffer_sequence_end(__dest); + auto __from_i = net::buffer_sequence_begin(__source); + const auto __from_end = net::buffer_sequence_end(__source); + mutable_buffer __to; + const_buffer __from; + while (((__from_i != __from_end && __to_i != __to_end) + || (__from.size() && __to.size())) + && __total_size < __max_size) + { + if (__from.size() == 0) + __from = const_buffer{*__from_i++}; + if (__to.size() == 0) + __to = mutable_buffer{*__to_i++}; + + size_t __n = std::min(__from.size(), __to.size()); + __n = std::min(__n, __max_size - __total_size); + std::memcpy(__to.data(), __from.data(), __n); + __from = { (const char*)__from.data() + __n, __from.size() - __n }; + __to = { (char*)__to.data() + __n, __to.size() - __n }; + __total_size += __n; + } + return __total_size; + } + + template + inline size_t + buffer_copy(const _MutableBufferSequence& __dest, + const _ConstBufferSequence& __source) noexcept + { return net::buffer_copy(__dest, __source, size_t{-1}); } + + + // buffer arithmetic: + + inline mutable_buffer + operator+(const mutable_buffer& __b, size_t __n) noexcept + { + if (__n > __b.size()) + __n = __b.size(); + return { static_cast(__b.data()) + __n, __b.size() - __n }; + } + + inline mutable_buffer + operator+(size_t __n, const mutable_buffer& __b) noexcept + { return __b + __n; } + + inline const_buffer + operator+(const const_buffer& __b, size_t __n) noexcept + { + if (__n > __b.size()) + __n = __b.size(); + return { static_cast(__b.data()) + __n, __b.size() - __n }; + } + + inline const_buffer + operator+(size_t __n, const const_buffer& __b) noexcept + { return __b + __n; } + + // buffer creation: + + inline mutable_buffer + buffer(void* __p, size_t __n) noexcept + { return { __p, __n }; } + + inline const_buffer + buffer(const void* __p, size_t __n) noexcept + { return { __p, __n }; } + + inline mutable_buffer + buffer(const mutable_buffer& __b) noexcept + { return __b; } + + inline mutable_buffer + buffer(const mutable_buffer& __b, size_t __n) noexcept + { return { __b.data(), std::min(__b.size(), __n) }; } + + inline const_buffer + buffer(const const_buffer& __b) noexcept + { return __b; } + + inline const_buffer + buffer(const const_buffer& __b, size_t __n) noexcept + { return { __b.data(), std::min(__b.size(), __n) }; } + + template + inline mutable_buffer + __to_mbuf(_Tp* __data, size_t __n) + { return { __n ? __data : nullptr, __n * sizeof(_Tp) }; } + + template + inline const_buffer + __to_cbuf(const _Tp* __data, size_t __n) + { return { __n ? __data : nullptr, __n * sizeof(_Tp) }; } + + template + inline mutable_buffer + buffer(_Tp (&__data)[_Nm]) noexcept + { return net::__to_mbuf(__data, _Nm); } + + template + inline const_buffer + buffer(const _Tp (&__data)[_Nm]) noexcept + { return net::__to_cbuf(__data, _Nm); } + + template + inline mutable_buffer + buffer(array<_Tp, _Nm>& __data) noexcept + { return net::__to_mbuf(__data.data(), _Nm); } + + template + inline const_buffer + buffer(array& __data) noexcept + { return net::__to_cbuf(__data.data(), __data.size()); } + + template + inline const_buffer + buffer(const array<_Tp, _Nm>& __data) noexcept + { return net::__to_cbuf(__data.data(), __data.size()); } + + template + inline mutable_buffer + buffer(vector<_Tp, _Allocator>& __data) noexcept + { return net::__to_mbuf(__data.data(), __data.size()); } + + template + inline const_buffer + buffer(const vector<_Tp, _Allocator>& __data) noexcept + { return net::__to_cbuf(__data.data(), __data.size()); } + + template + inline mutable_buffer + buffer(basic_string<_CharT, _Traits, _Allocator>& __data) noexcept + { return net::__to_mbuf(&__data.front(), __data.size()); } + + template + inline const_buffer + buffer(const basic_string<_CharT, _Traits, _Allocator>& __data) noexcept + { return net::__to_cbuf(&__data.front(), __data.size()); } + + template + inline const_buffer + buffer(basic_string_view<_CharT, _Traits> __data) noexcept + { return net::__to_cbuf(__data.data(), __data.size()); } + + template + inline mutable_buffer + buffer(_Tp (&__data)[_Nm], size_t __n) noexcept + { return buffer(net::buffer(__data), __n * sizeof(_Tp)); } + + template + inline const_buffer + buffer(const _Tp (&__data)[_Nm], size_t __n) noexcept + { return buffer(net::buffer(__data), __n * sizeof(_Tp)); } + + template + inline mutable_buffer + buffer(array<_Tp, _Nm>& __data, size_t __n) noexcept + { return buffer(net::buffer(__data), __n * sizeof(_Tp)); } + + template + inline const_buffer + buffer(array& __data, size_t __n) noexcept + { return buffer(net::buffer(__data), __n * sizeof(_Tp)); } + + template + inline const_buffer + buffer(const array<_Tp, _Nm>& __data, size_t __n) noexcept + { return buffer(net::buffer(__data), __n * sizeof(_Tp)); } + + template + inline mutable_buffer + buffer(vector<_Tp, _Allocator>& __data, size_t __n) noexcept + { return buffer(net::buffer(__data), __n * sizeof(_Tp)); } + + template + inline const_buffer + buffer(const vector<_Tp, _Allocator>& __data, size_t __n) noexcept + { return buffer(net::buffer(__data), __n * sizeof(_Tp)); } + + template + inline mutable_buffer + buffer(basic_string<_CharT, _Traits, _Allocator>& __data, + size_t __n) noexcept + { return buffer(net::buffer(__data), __n * sizeof(_CharT)); } + + template + inline const_buffer + buffer(const basic_string<_CharT, _Traits, _Allocator>& __data, + size_t __n) noexcept + { return buffer(net::buffer(__data), __n * sizeof(_CharT)); } + + template + inline const_buffer + buffer(basic_string_view<_CharT, _Traits> __data, size_t __n) noexcept + { return buffer(net::buffer(__data), __n * sizeof(_CharT)); } + + + template + class __dynamic_buffer_base + { + public: + // types: + typedef const_buffer const_buffers_type; + typedef mutable_buffer mutable_buffers_type; + + // constructors: + explicit + __dynamic_buffer_base(_Sequence& __seq) noexcept + : _M_seq(__seq), _M_size(__seq.size()), _M_max_size(__seq.max_size()) + { } + + __dynamic_buffer_base(_Sequence& __seq, size_t __maximum_size) noexcept + : _M_seq(__seq), _M_size(__seq.size()), _M_max_size(__maximum_size) + { __glibcxx_assert(__seq.size() <= __maximum_size); } + + __dynamic_buffer_base(__dynamic_buffer_base&&) = default; + + // members: + size_t size() const noexcept { return _M_size; } + size_t max_size() const noexcept { return _M_max_size; } + size_t capacity() const noexcept { return _M_seq.capacity(); } + + const_buffers_type + data() const noexcept + { return net::buffer(_M_seq, _M_size); } + + mutable_buffers_type + prepare(size_t __n) + { + if ((_M_size + __n) > _M_max_size) + __throw_length_error("dynamic_vector_buffer::prepare"); + + _M_seq.resize(_M_size + __n); + return buffer(net::buffer(_M_seq) + _M_size, __n); + } + + void + commit(size_t __n) + { + _M_size += std::min(__n, _M_seq.size() - _M_size); + _M_seq.resize(_M_size); + } + + void + consume(size_t __n) + { + size_t __m = std::min(__n, _M_size); + _M_seq.erase(_M_seq.begin(), _M_seq.begin() + __m); + _M_size -= __m; + } + + private: + _Sequence& _M_seq; + size_t _M_size; + const size_t _M_max_size; + }; + + template + class dynamic_vector_buffer + : public __dynamic_buffer_base> + { + public: + using __dynamic_buffer_base>::__dynamic_buffer_base; + }; + + template + class dynamic_string_buffer + : public __dynamic_buffer_base> + { + public: + using __dynamic_buffer_base>:: + __dynamic_buffer_base; + }; + + // dynamic buffer creation: + + template + inline dynamic_vector_buffer<_Tp, _Allocator> + dynamic_buffer(vector<_Tp, _Allocator>& __vec) noexcept + { return dynamic_vector_buffer<_Tp, _Allocator>{__vec}; } + + template + inline dynamic_vector_buffer<_Tp, _Allocator> + dynamic_buffer(vector<_Tp, _Allocator>& __vec, size_t __n) noexcept + { return {__vec, __n}; } + + template + inline dynamic_string_buffer<_CharT, _Traits, _Allocator> + dynamic_buffer(basic_string<_CharT, _Traits, _Allocator>& __str) noexcept + { return dynamic_string_buffer<_CharT, _Traits, _Allocator>{__str}; } + + template + inline dynamic_string_buffer<_CharT, _Traits, _Allocator> + dynamic_buffer(basic_string<_CharT, _Traits, _Allocator>& __str, + size_t __n) noexcept + { return {__str, __n}; } + + class transfer_all + { + public: + size_t operator()(const error_code& __ec, size_t) const + { return !__ec ? 1500 : 0; } + }; + + class transfer_at_least + { + public: + explicit transfer_at_least(size_t __m) : _M_minimum(__m) { } + + size_t operator()(const error_code& __ec, size_t __n) const + { return !__ec && __n < _M_minimum ? _M_minimum - __n : 0; } + + private: + size_t _M_minimum; + }; + + class transfer_exactly + { + public: + explicit transfer_exactly(size_t __e) : _M_exact(__e) { } + + size_t operator()(const error_code& __ec, size_t __n) const + { + size_t _Nm = -1; + return !__ec && __n < _M_exact ? std::min(_M_exact - __n, _Nm) : 0; + } + + private: + size_t _M_exact; + }; + + /** @brief synchronous read operations + * @{ + */ + + template + enable_if_t::value, + size_t> + read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers, + _CompletionCondition __completion_condition, error_code& __ec) + { + __ec.clear(); + auto __i = net::buffer_sequence_begin(__buffers); + auto __end = net::buffer_sequence_end(__buffers); + mutable_buffer __to; + size_t __total = 0; + size_t __n; + while ((__n = __completion_condition(__ec, __total)) + && (__i != __end || __to.size())) + { + if (__to.size() == 0) + __to = mutable_buffer(*__i++); + __n = __stream.read_some(buffer(__to, __n), __ec); + __to = __to + __n; + __total += __n; + } + return __total; + } + + template + inline + enable_if_t::value, + size_t> + read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers) + { + error_code __ec; + return net::read(__stream, __buffers, transfer_all{}, __ec); + } + + template + inline + enable_if_t::value, + size_t> + read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers, + error_code& __ec) + { return net::read(__stream, __buffers, transfer_all{}, __ec); } + + template + inline + enable_if_t::value, + size_t> + read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers, + _CompletionCondition __completion_condition) + { + error_code __ec; + return net::read(__stream, __buffers, __completion_condition, __ec); + } + + + template + enable_if_t>::value, size_t> + read(_SyncReadStream& __stream, _DynamicBuffer&& __b, + _CompletionCondition __completion_condition, error_code& __ec) + { + const size_t __limit = 64; + __ec.clear(); + size_t __cap = std::max(__b.capacity() - __b.size(), __limit); + size_t __total = 0; + size_t __n; + while ((__n = __completion_condition(__ec, __total)) + && __b.size() != __b.max_size()) + { + __n = std::min(__n, __b.max_size() - __b.size()); + size_t __cap = std::max(__b.capacity() - __b.size(), __limit); + mutable_buffer __to = __b.prepare(std::min(__cap, __n)); + __n = __stream.read_some(__to, __ec); + __to = __to + __n; + __total += __n; + __b.commit(__n); + } + return __total; + } + + template + inline enable_if_t::value, size_t> + read(_SyncReadStream& __stream, _DynamicBuffer&& __b) + { + error_code __ec; + return net::read(__stream, __b, transfer_all{}, __ec); + } + + template + inline enable_if_t::value, size_t> + read(_SyncReadStream& __stream, _DynamicBuffer&& __b, error_code& __ec) + { + return net::read(__stream, __b, transfer_all{}, __ec); + } + + template + inline enable_if_t::value, size_t> + read(_SyncReadStream& __stream, _DynamicBuffer&& __b, + _CompletionCondition __completion_condition) + { + error_code __ec; + return net::read(__stream, __b, __completion_condition, __ec); + } + + // @} + + /** @brief asynchronous read operations + * @{ + */ + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_read(_AsyncReadStream& __stream, + const _MutableBufferSequence& __buffers, + _CompletionCondition __completion_condition, + _CompletionToken&& __token) + { + error_code __ec; + } + + template + inline __deduced_t<_CompletionToken, void(error_code, size_t)> + async_read(_AsyncReadStream& __stream, + const _MutableBufferSequence& __buffers, + _CompletionToken&& __token) + { + return net::async_read(__stream, __buffers, transfer_all{}, + std::forward<_CompletionToken>(__token)); + } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_read(_AsyncReadStream& __stream, _DynamicBuffer&& __b, + _CompletionCondition __completion_condition, + _CompletionToken&& __token) + { + error_code __ec; + } + + template + inline __deduced_t<_CompletionToken, void(error_code, size_t)> + async_read(_AsyncReadStream& __stream, _DynamicBuffer&& __b, + _CompletionToken&& __token) + { + return net::async_read(__stream, __b, transfer_all{}, + std::forward<_CompletionToken>(__token)); + } + + // @} + +#if 0 + /** @brief synchronous write operations: + * @{ + */ + + template + size_t write(_SyncWriteStream& __stream, + const _ConstBufferSequence& __buffers); + template + size_t write(_SyncWriteStream& __stream, + const _ConstBufferSequence& __buffers, error_code& __ec); + template + size_t write(_SyncWriteStream& __stream, + const _ConstBufferSequence& __buffers, + _CompletionCondition __completion_condition); + template + size_t write(_SyncWriteStream& __stream, + const _ConstBufferSequence& __buffers, + _CompletionCondition __completion_condition, + error_code& __ec); + + template + size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b); + template + size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b, error_code& __ec); + template + size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b, + _CompletionCondition __completion_condition); + template + size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b, + _CompletionCondition __completion_condition, error_code& __ec); + + // @} + + /** @brief asynchronous write operations + * @{ + */ + + template + DEDUCED async_write(_AsyncWriteStream& __stream, + const _ConstBufferSequence& __buffers, + _CompletionToken&& __token); + template + DEDUCED async_write(_AsyncWriteStream& __stream, + const _ConstBufferSequence& __buffers, + _CompletionCondition __completion_condition, + _CompletionToken&& __token); + + template + DEDUCED async_write(_AsyncWriteStream& __stream, + _DynamicBuffer&& __b, _CompletionToken&& __token); + template + DEDUCED async_write(_AsyncWriteStream& __stream, + _DynamicBuffer&& __b, + _CompletionCondition __completion_condition, + _CompletionToken&& __token); + + // @} + + /** @brief synchronous delimited read operations + * @{ + */ + + template + size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b, char __delim); + template + size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b, + char __delim, error_code& __ec); + template + size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b, string_view __delim); + template + size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b, + string_view __delim, error_code& __ec); + + // @} + + /** @brief asynchronous delimited read operations + * @{ + */ + + template + DEDUCED async_read_until(_AsyncReadStream& __s, + _DynamicBuffer&& __b, char __delim, + _CompletionToken&& __token); + template + DEDUCED async_read_until(_AsyncReadStream& __s, + _DynamicBuffer&& __b, string_view __delim, + _CompletionToken&& __token); + + // @} + +#endif + /// @} + +_GLIBCXX_END_NAMESPACE_VERSION + +} // namespace v1 +} // namespace net +} // namespace experimental + +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + template<> + struct is_error_code_enum + : public true_type {}; + +_GLIBCXX_END_NAMESPACE_VERSION + +} // namespace std + +#endif // C++14 + +#endif // _GLIBCXX_EXPERIMENTAL_BUFFER diff --git a/libstdc++-v3/include/experimental/executor b/libstdc++-v3/include/experimental/executor new file mode 100644 index 00000000000..cd4adb58b0d --- /dev/null +++ b/libstdc++-v3/include/experimental/executor @@ -0,0 +1,1887 @@ +// -*- C++ -*- + +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file experimental/executor + * This is a TS C++ Library header. + */ + +#ifndef _GLIBCXX_EXPERIMENTAL_EXECUTOR +#define _GLIBCXX_EXPERIMENTAL_EXECUTOR 1 + +#pragma GCC system_header + +#if __cplusplus >= 201402L + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +namespace experimental +{ +namespace net +{ +inline namespace v1 +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @ingroup networking + * @{ + */ + + /// Customization point for asynchronous operations. + template + class async_result; + + /// Convenience utility to help implement asynchronous operations. + template + class async_completion; + + template> + struct __associated_allocator_impl + { + using type = _ProtoAlloc; + + static type + _S_get(const _Tp&, const _ProtoAlloc& __a) noexcept { return __a; } + }; + + template + struct __associated_allocator_impl<_Tp, _ProtoAlloc, + __void_t> + { + using type = typename _Tp::allocator_type; + + static type + _S_get(const _Tp& __t, const _ProtoAlloc&) noexcept + { return __t.get_allocator(); } + }; + + /// Helper to associate an allocator with a type. + template> + struct associated_allocator + : __associated_allocator_impl<_Tp, _ProtoAllocator> + { + static auto + get(const _Tp& __t, + const _ProtoAllocator& __a = _ProtoAllocator()) noexcept + { + using _Impl = __associated_allocator_impl<_Tp, _ProtoAllocator>; + return _Impl::_S_get(__t, __a); + } + }; + + /// Alias template for associated_allocator. + template> + using associated_allocator_t + = typename associated_allocator<_Tp, _ProtoAllocator>::type; + + // get_associated_allocator: + + template + inline associated_allocator_t<_Tp> + get_associated_allocator(const _Tp& __t) noexcept + { return associated_allocator<_Tp>::get(__t); } + + template + inline associated_allocator_t<_Tp, _ProtoAllocator> + get_associated_allocator(const _Tp& __t, + const _ProtoAllocator& __a) noexcept + { return associated_allocator<_Tp, _ProtoAllocator>::get(__t, __a); } + + enum class fork_event { prepare, parent, child }; + + /// An extensible, type-safe, polymorphic set of services. + class execution_context; + + class service_already_exists : public logic_error { }; + + template struct is_executor; + + struct executor_arg_t { }; + + constexpr executor_arg_t executor_arg = executor_arg_t(); + + /// Trait for determining whether to construct an object with an executor. + template struct uses_executor; + + template> + struct __associated_executor_impl + { + using type = _Executor; + + static type + _S_get(const _Tp&, const _Executor& __e) noexcept { return __e; } + }; + + template + struct __associated_executor_impl<_Tp, _Executor, + __void_t> + { + using type = typename _Tp::executor_type; + + static type + _S_get(const _Tp& __t, const _Executor&) noexcept + { return __t.get_executor(); } + }; + + /// Helper to associate an executor with a type. + template + struct associated_executor + : __associated_executor_impl<_Tp, _Executor> + { + static auto + get(const _Tp& __t, const _Executor& __e = _Executor()) noexcept + { return __associated_executor_impl<_Tp, _Executor>::_S_get(__t, __e); } + }; + + + template + using associated_executor_t + = typename associated_executor<_Tp, _Executor>::type; + + template + using __is_exec_context + = is_convertible<_ExecutionContext&, execution_context&>; + + template + using __executor_t = typename _Tp::executor_type; + + // get_associated_executor: + + template + inline associated_executor_t<_Tp> + get_associated_executor(const _Tp& __t) noexcept + { return associated_executor<_Tp>::get(__t); } + + template + inline + enable_if_t::value, + associated_executor_t<_Tp, _Executor>> + get_associated_executor(const _Tp& __t, const _Executor& __ex) + { return associated_executor<_Tp, _Executor>::get(__t, __ex); } + + template + inline + enable_if_t<__is_exec_context<_ExecutionContext>::value, + associated_executor_t<_Tp, __executor_t<_ExecutionContext>>> + get_associated_executor(const _Tp& __t, _ExecutionContext& __ctx) noexcept + { return net::get_associated_executor(__t, __ctx.get_executor()); } + + + /// Helper to bind an executor to an object or function. + template + class executor_binder; + + template + class async_result, _Signature>; + + template + struct associated_allocator, + _ProtoAllocator>; + + template + struct associated_executor, _Executor1>; + + // bind_executor: + + template + inline + enable_if_t::value, + executor_binder, _Executor>> + bind_executor(const _Executor& __ex, _Tp&& __t) + { return { std::forward<_Tp>(__t), __ex }; } + + template + inline + enable_if_t<__is_exec_context<_ExecutionContext>::value, + executor_binder, __executor_t<_ExecutionContext>>> + bind_executor(_ExecutionContext& __ctx, _Tp&& __t) + { return { __ctx.get_executor(), forward<_Tp>(__t) }; } + + + /// A scope-guard type to record when work is started and finished. + template + class executor_work_guard; + + // make_work_guard: + + template + inline + enable_if_t::value, executor_work_guard<_Executor>> + make_work_guard(const _Executor& __ex) + { return executor_work_guard<_Executor>(__ex); } + + template + inline + enable_if_t<__is_exec_context<_ExecutionContext>::value, + executor_work_guard<__executor_t<_ExecutionContext>>> + make_work_guard(_ExecutionContext& __ctx) + { return net::make_work_guard(__ctx.get_executor()); } + + template + inline + enable_if_t<__not_<__or_, __is_exec_context<_Tp>>>::value, + executor_work_guard>> + make_work_guard(const _Tp& __t) + { return net::get_associated_executor(__t); } + + template + auto + make_work_guard(const _Tp& __t, _Up&& __u) + -> decltype(net::make_work_guard( + net::get_associated_executor(__t, forward<_Up>(__u)))) + { + return net::make_work_guard( + net::get_associated_executor(__t, forward<_Up>(__u))); + } + + /// Allows function objects to execute on any thread. + class system_executor; + + /// The execution context associated with system_executor objects. + class system_context; + + inline bool + operator==(const system_executor&, const system_executor&) { return true; } + + inline bool + operator!=(const system_executor&, const system_executor&) { return false; } + + /// Exception thrown by empty executors. + class bad_executor; + + /// Polymorphic wrapper for types satisfying the Executor requirements. + class executor; + + bool + operator==(const executor& __a, const executor& __b) noexcept; + + bool + operator==(const executor& __e, nullptr_t) noexcept; + + inline bool + operator==(nullptr_t, const executor& __e) noexcept + { return __e == nullptr; } + + inline bool + operator!=(const executor& __a, const executor& __b) noexcept + { return !(__a == __b); } + + inline bool + operator!=(const executor& __e, nullptr_t) noexcept + { return !(__e == nullptr); } + + inline bool + operator!=(nullptr_t, const executor& __e) noexcept + { return !(__e == nullptr); } + + void swap(executor&, executor&) noexcept; + + // dispatch: + + template + __deduced_t<_CompletionToken, void()> + dispatch(_CompletionToken&& __token); + + template + __deduced_t<_CompletionToken, void()> + dispatch(const _Executor& __ex, _CompletionToken&& __token); + + template + __deduced_t<_CompletionToken, void()> + dispatch(_ExecutionContext& __ctx, _CompletionToken&& __token); + + // post: + + template + __deduced_t<_CompletionToken, void()> + post(_CompletionToken&& __token); + template + enable_if_t::value, + __deduced_t<_CompletionToken, void()>> + post(const _Executor& __ex, _CompletionToken&& __token); + template + enable_if_t<__is_exec_context<_ExecutionContext>::value, + __deduced_t<_CompletionToken, void()>> + post(_ExecutionContext& __ctx, _CompletionToken&& __token); + + // defer: + + template + __deduced_t<_CompletionToken, void()> + defer(_CompletionToken&& __token); + template + __deduced_t<_CompletionToken, void()> + defer(const _Executor& __ex, _CompletionToken&& __token); + template + __deduced_t<_CompletionToken, void()> + defer(_ExecutionContext& __ctx, _CompletionToken&& __token); + + template + class strand; + + template + bool + operator==(const strand<_Executor>& __a, const strand<_Executor>& __b); + + template + bool + operator!=(const strand<_Executor>& __a, const strand<_Executor>& __b) + { return !(__a == __b); } + + template + class async_result + { + public: + typedef _CompletionToken completion_handler_type; + typedef void return_type; + + explicit async_result(completion_handler_type&) {} + async_result(const async_result&) = delete; + async_result& operator=(const async_result&) = delete; + + return_type get() {} + }; + + template + class async_completion + { + using __result_type + = async_result, _Signature>; + + public: + using completion_handler_type + = typename __result_type::completion_handler_type; + + private: + using __handler_type = conditional_t< + is_same<_CompletionToken, completion_handler_type>::value, + completion_handler_type&, + completion_handler_type>; + + public: + explicit + async_completion(_CompletionToken& __t) + : completion_handler(std::forward<__handler_type>(__t)), + result(completion_handler) + { } + + async_completion(const async_completion&) = delete; + async_completion& operator=(const async_completion&) = delete; + + __handler_type completion_handler; + __result_type result; + }; + + + class execution_context + { + public: + class service + { + protected: + // construct / copy / destroy: + + explicit + service(execution_context& __owner) : _M_context(__owner) { } + + service(const service&) = delete; + service& operator=(const service&) = delete; + + virtual ~service() { } // TODO should not be inline + + // service observers: + + execution_context& context() const noexcept { return _M_context; } + + private: + // service operations: + + virtual void shutdown() noexcept = 0; + virtual void notify_fork(fork_event) { } + + friend class execution_context; + execution_context& _M_context; + }; + + // construct / copy / destroy: + + execution_context() { } + + execution_context(const execution_context&) = delete; + execution_context& operator=(const execution_context&) = delete; + + virtual ~execution_context() + { + shutdown(); + destroy(); + } + + // execution context operations: + + void + notify_fork(fork_event __e) + { + auto __l = [=](auto& __svc) { __svc._M_ptr->notify_fork(__e); }; + if (__e == fork_event::prepare) + std::for_each(_M_services.rbegin(), _M_services.rend(), __l); + else + std::for_each(_M_services.begin(), _M_services.end(), __l); + } + + protected: + // execution context protected operations: + + void + shutdown() + { + std::for_each(_M_services.rbegin(), _M_services.rend(), + [=](auto& __svc) { + if (__svc._M_active) + { + __svc._M_ptr->shutdown(); + __svc._M_active = false; + } + }); + } + + void + destroy() + { + while (_M_services.size()) + _M_services.pop_back(); + _M_keys.clear(); + } + + protected: + + template + static void + _S_deleter(service* __svc) { delete static_cast<_Service*>(__svc); } + + struct _ServicePtr + { + template + explicit + _ServicePtr(_Service* __svc) + : _M_ptr(__svc, &_S_deleter<_Service>), _M_active(true) { } + + std::unique_ptr _M_ptr; + bool _M_active; + }; + + mutable std::mutex _M_mutex; + + // Sorted in order of beginning of service object lifetime. + std::list<_ServicePtr> _M_services; + + template + service* + _M_add_svc(_Args&&... __args) + { + _M_services.push_back( + _ServicePtr{new _Service{*this, std::forward<_Args>(__args)...}} ); + return _M_services.back()._M_ptr.get(); + } + + using __key_type = void(*)(); + + template + static __key_type + _S_key() { return reinterpret_cast<__key_type>(&_S_key<_Key>); } + + std::unordered_map<__key_type, service*> _M_keys; + + template + friend typename _Service::key_type& + use_service(execution_context&); + + template + friend _Service& + make_service(execution_context&, _Args&&...); + + template + friend bool + has_service(const execution_context&) noexcept; + }; + + // service access: + + template + typename _Service::key_type& + use_service(execution_context& __ctx) + { + using _Key = typename _Service::key_type; + static_assert(is_base_of::value, + "a service type must derive from execution_context::service"); + static_assert(is_base_of<_Key, _Service>::value, + "a service type must match or derive from its key_type"); + auto __key = execution_context::_S_key<_Key>(); + std::lock_guard __lock(__ctx._M_mutex); + auto& __svc = __ctx._M_keys[__key]; + if (__svc == nullptr) + { + __try { + __svc = __ctx._M_add_svc<_Service>(); + } __catch(...) { + __ctx._M_keys.erase(__key); + __throw_exception_again; + } + } + return static_cast<_Key&>(*__svc); + } + + template + _Service& + make_service(execution_context& __ctx, _Args&&... __args) + { + using _Key = typename _Service::key_type; + static_assert(is_base_of::value, + "a service type must derive from execution_context::service"); + static_assert(is_base_of<_Key, _Service>::value, + "a service type must match or derive from its key_type"); + auto __key = execution_context::_S_key<_Key>(); + std::lock_guard __lock(__ctx._M_mutex); + auto& __svc = __ctx._M_keys[__key]; + if (__svc != nullptr) + throw service_already_exists(); + __try { + __svc = __ctx._M_add_svc<_Service>(std::forward<_Args>(__args)...); + } __catch(...) { + __ctx._M_keys.erase(__key); + __throw_exception_again; + } + return static_cast<_Service&>(*__svc); + } + + template + inline bool + has_service(const execution_context& __ctx) noexcept + { + using _Key = typename _Service::key_type; + static_assert(is_base_of::value, + "a service type must derive from execution_context::service"); + static_assert(is_base_of<_Key, _Service>::value, + "a service type must match or derive from its key_type"); + std::lock_guard __lock(__ctx._M_mutex); + return __ctx._M_keys.count(execution_context::_S_key<_Key>()); + } + + template> + struct __is_executor_impl : false_type + { }; + + // Check Executor requirements. + template> + auto + __executor_reqs(_Up* __x = 0, const _Up* __cx = 0, void(*__f)() = 0, + const allocator& __a = {}) + -> enable_if_t<__is_value_constructible<_Tp>::value, __void_t< + decltype(*__cx == *__cx), + decltype(*__cx != *__cx), + decltype(__x->context()), + decltype(__x->on_work_started()), + decltype(__x->on_work_finished()), + decltype(__x->dispatch(std::move(__f), __a)), + decltype(__x->post(std::move(__f), __a)), + decltype(__x->defer(std::move(__f), __a)) + >>; + + template + struct __is_executor_impl<_Tp, decltype(__executor_reqs<_Tp>())> + : true_type + { }; + + template + struct is_executor : __is_executor_impl<_Tp> + { }; + + template + constexpr bool is_executor_v = is_executor<_Tp>::value; + + template> + struct __uses_executor_impl : false_type + { }; + + template + struct __uses_executor_impl<_Tp, _Executor, + __void_t> + : is_convertible<_Executor, typename _Tp::executor_type> + { }; + + template + struct uses_executor : __uses_executor_impl<_Tp, _Executor>::type + { }; + + template + constexpr bool uses_executor_v = uses_executor<_Tp, _Executor>::value; + + template + class executor_binder + { + struct __use_exec { }; + + public: + // types: + + typedef _Tp target_type; + typedef _Executor executor_type; + + // construct / copy / destroy: + + executor_binder(_Tp __t, const _Executor& __ex) + : executor_binder(__use_exec{}, std::move(__t), __ex) + { } + + executor_binder(const executor_binder&) = default; + executor_binder(executor_binder&&) = default; + + template + executor_binder(const executor_binder<_Up, _OtherExecutor>& __other) + : executor_binder(__use_exec{}, __other.get(), __other.get_executor()) + { } + + template + executor_binder(executor_binder<_Up, _OtherExecutor>&& __other) + : executor_binder(__use_exec{}, std::move(__other.get()), + __other.get_executor()) + { } + + template + executor_binder(executor_arg_t, const _Executor& __ex, + const executor_binder<_Up, _OtherExecutor>& __other) + : executor_binder(__use_exec{}, __other.get(), __ex) + { } + + template + executor_binder(executor_arg_t, const _Executor& __ex, + executor_binder<_Up, _OtherExecutor>&& __other) + : executor_binder(__use_exec{}, std::move(__other.get()), __ex) + { } + + ~executor_binder(); + + // executor binder access: + + _Tp& get() noexcept { return _M_target; } + const _Tp& get() const noexcept { return _M_target; } + executor_type get_executor() const noexcept { return _M_ex; } + + // executor binder invocation: + + template + result_of_t<_Tp&(_Args&&...)> + operator()(_Args&&... __args) + { return std::__invoke(get(), std::forward<_Args>(__args)...); } + + template + result_of_t + operator()(_Args&&... __args) const + { return std::__invoke(get(), std::forward<_Args>(__args)...); } + + private: + template + using __use_exec_cond + = __and_, + is_constructible<_Tp, executor_arg_t, _Executor, _Up>>; + + template::value>> + executor_binder(__use_exec, _Up&& __u, _Exec&& __ex) + : _M_ex(std::forward<_Exec>(__ex)), + _M_target(executor_arg, _M_ex, std::forward<_Up>(__u)) + { } + + template::value>> + executor_binder(__use_exec, _Up&& __u, const _Exec& __ex) + : _M_ex(std::forward<_Exec>(__ex)), + _M_target(std::forward<_Up>(__u)) + { } + + _Executor _M_ex; + _Tp _M_target; + }; + + template + class async_result, _Signature> + { + using __inner = async_result<_Tp, _Signature>; + + public: + using completion_handler_type = + executor_binder; + + using return_type = typename __inner::return_type; + + explicit + async_result(completion_handler_type& __h) + : _M_target(__h.get()) { } + + async_result(const async_result&) = delete; + async_result& operator=(const async_result&) = delete; + + return_type get() { return _M_target.get(); } + + private: + __inner _M_target; + }; + + template + struct associated_allocator, _ProtoAlloc> + { + typedef associated_allocator_t<_Tp, _ProtoAlloc> type; + + static type + get(const executor_binder<_Tp, _Executor>& __b, + const _ProtoAlloc& __a = _ProtoAlloc()) noexcept + { return associated_allocator<_Tp, _ProtoAlloc>::get(__b.get(), __a); } + }; + + template + struct associated_executor, _Executor1> + { + typedef _Executor type; + + static type + get(const executor_binder<_Tp, _Executor>& __b, + const _Executor1& = _Executor1()) noexcept + { return __b.get_executor(); } + }; + + template + class executor_work_guard + { + public: + // types: + + typedef _Executor executor_type; + + // construct / copy / destroy: + + explicit + executor_work_guard(const executor_type& __ex) noexcept + : _M_ex(__ex), _M_owns(true) + { _M_ex.on_work_started(); } + + executor_work_guard(const executor_work_guard& __other) noexcept + : _M_ex(__other._M_ex), _M_owns(__other._M_owns) + { + if (_M_owns) + _M_ex.on_work_started(); + } + + executor_work_guard(executor_work_guard&& __other) noexcept + : _M_ex(__other._M_ex), _M_owns(__other._M_owns) + { __other._M_owns = false; } + + executor_work_guard& operator=(const executor_work_guard&) = delete; + + ~executor_work_guard() + { + if (_M_owns) + _M_ex.on_work_finished(); + } + + // executor work guard observers: + + executor_type get_executor() const noexcept { return _M_ex; } + + bool owns_work() const noexcept { return _M_owns; } + + // executor work guard modifiers: + + void reset() noexcept + { + if (_M_owns) + _M_ex.on_work_finished(); + _M_owns = false; + } + + private: + _Executor _M_ex; + bool _M_owns; + }; + + + class system_context : public execution_context + { + public: + // types: + + typedef system_executor executor_type; + + // construct / copy / destroy: + + system_context() = default; + system_context(const system_context&) = delete; + system_context& operator=(const system_context&) = delete; + + ~system_context() + { + stop(); + join(); + } + + // system_context operations: + + executor_type get_executor() noexcept; + + void stop() + { + lock_guard __lock(_M_mtx); + _M_stopped = true; + _M_cv.notify_all(); + } + + bool stopped() const noexcept + { + lock_guard __lock(_M_mtx); + return _M_stopped; + } + + void join() + { + _M_thread.join(); + } + + private: + friend system_executor; + + struct __tag { }; + system_context(__tag) { } + + thread _M_thread; + mutable mutex _M_mtx; + condition_variable _M_cv; + queue> _M_tasks; + bool _M_stopped = false; + + void + _M_run() + { + while (true) + { + function __f; + { + unique_lock __lock(_M_mtx); + _M_cv.wait(__lock, + [this]{ return !_M_stopped && !_M_tasks.empty(); }); + if (_M_stopped) + return; + __f = std::move(_M_tasks.front()); + _M_tasks.pop(); + } + __f(); + } + } + + void + _M_post(std::function __f) + { + lock_guard __lock(_M_mtx); + if (_M_stopped) + return; + if (!_M_thread.joinable()) + _M_thread = std::thread(&system_context::_M_run, this); + _M_tasks.push(std::move(__f)); // XXX allocator not used + _M_cv.notify_one(); + } + + static system_context& + _S_get() noexcept + { + static system_context __sc(__tag{}); + return __sc; + } + }; + + class system_executor + { + public: + // executor operations: + + system_executor() { } + + system_context& + context() const noexcept { return system_context::_S_get(); } + + void on_work_started() const noexcept { } + void on_work_finished() const noexcept { } + + template + void + dispatch(_Func&& __f, const _ProtoAlloc& __a) const + { decay_t<_Func>{std::forward<_Func>(__f)}(); } + + template + void + post(_Func&& __f, const _ProtoAlloc&) const // XXX allocator not used + { + system_context::_S_get()._M_post(std::forward<_Func>(__f)); + } + + template + void + defer(_Func&& __f, const _ProtoAlloc& __a) const + { post(std::forward<_Func>(__f), __a); } + }; + + inline system_executor + system_context::get_executor() noexcept + { return {}; } + + class bad_executor : public std::exception + { + virtual const char* what() const noexcept { return "bad executor"; } + }; + + inline void __throw_bad_executor() // TODO make non-inline + { +#if __cpp_exceptions + throw bad_executor(); +#else + __builtin_abort(); +#endif + } + + class executor + { + public: + // construct / copy / destroy: + + executor() noexcept = default; + + executor(nullptr_t) noexcept { } + executor(const executor&) noexcept = default; + executor(executor&&) noexcept = default; + + template + executor(_Executor __e) + : _M_target(_M_create(std::move(__e))) + { } + + template + executor(allocator_arg_t, const _ProtoAlloc& __a, _Executor __e) + : _M_target(_M_create(std::move(__e), __a)) + { } + + executor& operator=(const executor&) noexcept = default; + executor& operator=(executor&&) noexcept = default; + + executor& + operator=(nullptr_t) noexcept + { + _M_target = nullptr; + return *this; + } + + template + executor& + operator=(_Executor __e) + { + executor(std::move(__e)).swap(*this); + return *this; + } + + ~executor() = default; + + // executor modifiers: + + void + swap(executor& __other) noexcept + { _M_target.swap(__other._M_target); } + + template + void + assign(_Executor __e, const _Alloc& __a) + { executor(allocator_arg, __a, std::move(__e)).swap(*this); } + + // executor operations: + + execution_context& + context() const noexcept + { + __glibcxx_assert( _M_target ); + return _M_target->context(); + } + + void + on_work_started() const noexcept + { + __glibcxx_assert( _M_target ); + return _M_target->on_work_started(); + } + + void + on_work_finished() const noexcept + { + __glibcxx_assert( _M_target ); + return _M_target->on_work_finished(); + } + + template + void + dispatch(_Func&& __f, const _Alloc& __a) const + { + if (!_M_target) + __throw_bad_executor(); + // _M_target->dispatch({allocator_arg, __a, std::forward<_Func>(__f)}); + _M_target->dispatch(std::forward<_Func>(__f)); + } + + template + void + post(_Func&& __f, const _Alloc& __a) const + { + if (!_M_target) + __throw_bad_executor(); + // _M_target->post({allocator_arg, __a, std::forward<_Func>(__f)}); + _M_target->post(std::forward<_Func>(__f)); + } + + template + void + defer(_Func&& __f, const _Alloc& __a) const + { + if (!_M_target) + __throw_bad_executor(); + // _M_target->defer({allocator_arg, __a, std::forward<_Func>(__f)}); + _M_target->defer(std::forward<_Func>(__f)); + } + + // executor capacity: + + explicit operator bool() const noexcept + { return static_cast(_M_target); } + + // executor target access: + +#if __cpp_rtti + const type_info& + target_type() const noexcept + { return _M_target ? _M_target->target_type() : typeid(void); } + + template + _Executor* + target() noexcept + { + if (_M_target) + if (const auto* __p = _M_target->target(typeid(_Executor))) + return const_cast<_Executor*>(static_cast(__p)); + return nullptr; + } + + template + const _Executor* + target() const noexcept + { + if (_M_target) + if (const auto* __p = _M_target->target(typeid(_Executor))) + return static_cast(__p); + return nullptr; + } +#endif + + private: + struct _Tgt + { + virtual void on_work_started() const noexcept = 0; + virtual void on_work_finished() const noexcept = 0; + virtual execution_context& context() const noexcept = 0; + virtual void dispatch(std::function) const = 0; + virtual void post(std::function) const = 0; + virtual void defer(std::function) const = 0; +#if __cpp_rtti + virtual const type_info& target_type() const = 0; + virtual void* target(const std::type_info&) const = 0; + virtual bool _M_equals(_Tgt*) const noexcept = 0; + virtual const void* _M_get_executor() const noexcept = 0; +#endif + }; + + template + struct _TgtImpl : _Tgt + { + explicit + _TgtImpl(_Ex&& __ex, const _Alloc& __a) + : _M_impl(std::move(__ex), __a) { } + + void on_work_started() const noexcept { _M_ex().on_work_started(); } + void on_work_finished() const noexcept { _M_ex().on_work_finished(); } + execution_context& context() const noexcept { return _M_ex().context(); } + void + dispatch(std::function __f) const + { _M_ex().dispatch(std::move(__f), _M_alloc()); } + void + post(std::function __f) const + { _M_ex().post(std::move(__f), _M_alloc()); } + void + defer(std::function __f) const + { _M_ex().defer(std::move(__f), _M_alloc()); } + +#if __cpp_rtti + virtual const type_info& + target_type() const + { return typeid(_Ex); } + + virtual const void* + target(const std::type_info& __ti) const + { + if (__ti == typeid(_Ex)) + return std::addressof(_M_ex()); + return nullptr; + } + + virtual bool + _M_equals(const _Tgt* __tgt) const noexcept + { + if (__tgt->target_type() == typeid(_Ex)) + *static_cast(__tgt->_M_get_executor()) == _M_ex(); + return false; + } + + virtual const void* + _M_get_executor() const noexcept + { return std::addressof(_M_ex()); } +#endif + + _Ex& _M_ex() { return std::get<0>(_M_impl); } + _Alloc& _M_alloc() { return std::get<1>(_M_impl); } + std::tuple<_Ex, _Alloc> _M_impl; + }; + + template> + shared_ptr<_Tgt> + _M_create(_Ex&& __ex, const _Alloc& __a = _Alloc()) + { + return allocate_shared<_TgtImpl<_Ex, _Alloc>>(__a, std::move(__ex), + __a); + } + + friend bool + operator==(const executor& __a, const executor& __b) noexcept + { + if (__a._M_target == __b._M_target) + return true; + if (!__a._M_target || !__b._M_target) + return false; +#if __cpp_rtti + return __a._M_target->_M_equals(__b._M_target.get()); +#else + return false; // XXX can we do better? +#endif + } + + shared_ptr<_Tgt> _M_target; + }; + + template<> struct is_executor : true_type { }; + + /// executor comparisons + inline bool + operator==(const executor& __e, nullptr_t) noexcept + { return !__e; } + + /// Swap two executor objects. + inline void swap(executor& __a, executor& __b) noexcept { __a.swap(__b); } + + + template + struct __dispatcher + { + explicit + __dispatcher(_CompletionHandler& __h) + : _M_h(std::move(__h)), _M_w(net::make_work_guard(_M_h)) + { } + + void operator()() + { + auto __alloc = net::get_associated_allocator(_M_h); + _M_w.get_executor().dispatch(std::move(_M_h), __alloc); + _M_w.reset(); + } + + _CompletionHandler _M_h; + decltype(net::make_work_guard(_M_h)) _M_w; + }; + + template + inline __dispatcher<_CompletionHandler> + __make_dispatcher(_CompletionHandler& __h) + { return __dispatcher<_CompletionHandler>{__h}; } + + + + // dispatch: + + template + inline __deduced_t<_CompletionToken, void()> + dispatch(_CompletionToken&& __token) + { + async_completion<_CompletionToken, void()> __cmpl{__token}; + auto __ex = net::get_associated_executor(__cmpl.completion_handler); + auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); + __ex.dispatch(std::move(__cmpl.completion_handler), __alloc); + return __cmpl.result.get(); + } + + template + inline + enable_if_t::value, + __deduced_t<_CompletionToken, void()>> + dispatch(const _Executor& __ex, _CompletionToken&& __token) + { + async_completion<_CompletionToken, void()> __cmpl{__token}; + auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); + __ex.dispatch(net::__make_dispatcher(__cmpl.completion_handler), + __alloc); + return __cmpl.result.get(); + } + + template + inline + enable_if_t<__is_exec_context<_ExecutionContext>::value, + __deduced_t<_CompletionToken, void()>> + dispatch(_ExecutionContext& __ctx, _CompletionToken&& __token) + { + return net::dispatch(__ctx.get_executor(), + forward<_CompletionToken>(__token)); + } + + // post: + + template + inline __deduced_t<_CompletionToken, void()> + post(_CompletionToken&& __token) + { + async_completion<_CompletionToken, void()> __cmpl{__token}; + auto __ex = net::get_associated_executor(__cmpl.completion_handler); + auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); + __ex.post(std::move(__cmpl.completion_handler), __alloc); + return __cmpl.result.get(); + } + + template + inline + enable_if_t::value, + __deduced_t<_CompletionToken, void()>> + post(const _Executor& __ex, _CompletionToken&& __token) + { + async_completion<_CompletionToken, void()> __cmpl{__token}; + auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); + __ex.post(net::__make_dispatcher(__cmpl.completion_handler), __alloc); + return __cmpl.result.get(); + } + + template + inline + enable_if_t<__is_exec_context<_ExecutionContext>::value, + __deduced_t<_CompletionToken, void()>> + post(_ExecutionContext& __ctx, _CompletionToken&& __token) + { + return net::post(__ctx.get_executor(), + forward<_CompletionToken>(__token)); + } + + // defer: + + template + inline __deduced_t<_CompletionToken, void()> + defer(_CompletionToken&& __token) + { + async_completion<_CompletionToken, void()> __cmpl{__token}; + auto __ex = net::get_associated_executor(__cmpl.completion_handler); + auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); + __ex.defer(std::move(__cmpl.completion_handler), __alloc); + return __cmpl.result.get(); + } + + template + inline + enable_if_t::value, + __deduced_t<_CompletionToken, void()>> + defer(const _Executor& __ex, _CompletionToken&& __token) + { + async_completion<_CompletionToken, void()> __cmpl{__token}; + auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); + __ex.defer(net::__make_dispatcher(__cmpl.completion_handler), __alloc); + return __cmpl.result.get(); + } + + template + inline + enable_if_t<__is_exec_context<_ExecutionContext>::value, + __deduced_t<_CompletionToken, void()>> + defer(_ExecutionContext& __ctx, _CompletionToken&& __token) + { + return net::defer(__ctx.get_executor(), + forward<_CompletionToken>(__token)); + } + + + template + class strand + { + public: + // types: + + typedef _Executor inner_executor_type; + + // construct / copy / destroy: + + strand(); // TODO make state + + explicit strand(_Executor __ex) : _M_inner_ex(__ex) { } // TODO make state + + template + strand(allocator_arg_t, const _Alloc& __a, _Executor __ex) + : _M_inner_ex(__ex) { } // TODO make state + + strand(const strand& __other) noexcept + : _M_state(__other._M_state), _M_inner_ex(__other._M_inner_ex) { } + + strand(strand&& __other) noexcept + : _M_state(std::move(__other._M_state)), + _M_inner_ex(std::move(__other._M_inner_ex)) { } + + template + strand(const strand<_OtherExecutor>& __other) noexcept + : _M_state(__other._M_state), _M_inner_ex(__other._M_inner_ex) { } + + template + strand(strand<_OtherExecutor>&& __other) noexcept + : _M_state(std::move(__other._M_state)), + _M_inner_ex(std::move(__other._M_inner_ex)) { } + + strand& + operator=(const strand& __other) noexcept + { + static_assert(is_copy_assignable<_Executor>::value, + "inner executor type must be CopyAssignable"); + + // TODO lock __other + // TODO copy state + _M_inner_ex = __other._M_inner_ex; + return *this; + } + + strand& + operator=(strand&& __other) noexcept + { + static_assert(is_move_assignable<_Executor>::value, + "inner executor type must be MoveAssignable"); + + // TODO move state + _M_inner_ex = std::move(__other._M_inner_ex); + return *this; + } + + template + strand& + operator=(const strand<_OtherExecutor>& __other) noexcept + { + static_assert(is_convertible<_OtherExecutor, _Executor>::value, + "inner executor type must be compatible"); + + // TODO lock __other + // TODO copy state + _M_inner_ex = __other._M_inner_ex; + return *this; + } + + template + strand& + operator=(strand<_OtherExecutor>&& __other) noexcept + { + static_assert(is_convertible<_OtherExecutor, _Executor>::value, + "inner executor type must be compatible"); + + // TODO move state + _M_inner_ex = std::move(__other._M_inner_ex); + return *this; + } + + ~strand() + { + // the task queue outlives this object if non-empty + // TODO create circular ref in queue? + } + + // strand operations: + + inner_executor_type + get_inner_executor() const noexcept + { return _M_inner_ex; } + + bool + running_in_this_thread() const noexcept + { return std::this_thread::get_id() == _M_state->_M_running_on; } + + execution_context& + context() const noexcept + { return _M_inner_ex.context(); } + + void on_work_started() const noexcept { _M_inner_ex.on_work_started(); } + void on_work_finished() const noexcept { _M_inner_ex.on_work_finished(); } + + template + void + dispatch(_Func&& __f, const _Alloc& __a) const + { + if (running_in_this_thread()) + decay_t<_Func>{std::forward<_Func>(__f)}(); + else + post(std::forward<_Func>(__f), __a); + } + + template + void + post(_Func&& __f, const _Alloc& __a) const; // TODO + + template + void + defer(_Func&& __f, const _Alloc& __a) const + { post(std::forward<_Func>(__f), __a); } + + private: + friend bool + operator==(const strand& __a, const strand& __b) + { return __a._M_state == __b._M_state; } + + // TODO add synchronised queue + struct _State + { + std::thread::id _M_running_on; + }; + shared_ptr<_State> _M_state; + _Executor _M_inner_ex; + }; + +#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) + + // Completion token for asynchronous operations initiated with use_future. + template + struct __use_future_ct + { + std::tuple<_Func, _Alloc> _M_t; + }; + + template> + class use_future_t + { + public: + // use_future_t types: + typedef _ProtoAllocator allocator_type; + + // use_future_t members: + constexpr use_future_t() noexcept : _M_alloc() { } + + explicit + use_future_t(const _ProtoAllocator& __a) noexcept : _M_alloc(__a) { } + + template + use_future_t<_OtherAllocator> + rebind(const _OtherAllocator& __a) const noexcept + { return use_future_t<_OtherAllocator>(__a); } + + allocator_type get_allocator() const noexcept { return _M_alloc; } + + template + auto + operator()(_Func&& __f) const + { + using _Token = __use_future_ct, _ProtoAllocator>; + return _Token{ {std::forward<_Func>(__f), _M_alloc} }; + } + + private: + _ProtoAllocator _M_alloc; + }; + + constexpr use_future_t<> use_future = use_future_t<>(); + + template + class async_result<__use_future_ct<_Func, _Alloc>, _Res(_Args...)>; + + template + struct __use_future_ex; + + // Completion handler for asynchronous operations initiated with use_future. + template + struct __use_future_ch + { + template + explicit + __use_future_ch(__use_future_ct<_Func, _Alloc>&& __token) + : _M_f{ std::move(std::get<0>(__token._M_t)) }, + _M_promise{ std::get<1>(__token._M_t) } + { } + + void + operator()(_Args&&... __args) + { + __try + { + _M_promise.set_value(_M_f(std::forward<_Args>(__args)...)); + } + __catch(__cxxabiv1::__forced_unwind&) + { + __throw_exception_again; + } + __catch(...) + { + _M_promise.set_exception(std::current_exception()); + } + } + + using __result = result_of_t<_Func(decay_t<_Args>...)>; + + future<__result> get_future() { return _M_promise.get_future(); } + + private: + template + friend struct __use_future_ex; + + _Func _M_f; + mutable promise<__result> _M_promise; + }; + + // Specialization of async_result for operations initiated with use_future. + template + class async_result<__use_future_ct<_Func, _Alloc>, _Res(_Args...)> + { + public: + using completion_handler_type = __use_future_ch<_Func, _Args...>; + using return_type = future; + + explicit + async_result(completion_handler_type& __h) + : _M_future(__h.get_future()) + { } + + async_result(const async_result&) = delete; + async_result& operator=(const async_result&) = delete; + + return_type get() { return std::move(_M_future); } + + private: + return_type _M_future; + }; + + template + struct __use_future_ex + { + template + __use_future_ex(const _Handler& __h, _Executor __ex) + : _M_t(__h._M_promise, __ex) + { } + + template + void + dispatch(_Fn&& __fn) + { + __try + { + std::get<1>(_M_t).dispatch(std::forward<_Fn>(__fn)); + } + __catch(__cxxabiv1::__forced_unwind&) + { + __throw_exception_again; + } + __catch(...) + { + std::get<0>(_M_t).set_exception(std::current_exception()); + } + } + + template + void + post(_Fn&& __fn) + { + __try + { + std::get<1>(_M_t).post(std::forward<_Fn>(__fn)); + } + __catch(__cxxabiv1::__forced_unwind&) + { + __throw_exception_again; + } + __catch(...) + { + std::get<0>(_M_t).set_exception(std::current_exception()); + } + } + + template + void + defer(_Fn&& __fn) + { + __try + { + std::get<1>(_M_t).defer(std::forward<_Fn>(__fn)); + } + __catch(__cxxabiv1::__forced_unwind&) + { + __throw_exception_again; + } + __catch(...) + { + std::get<0>(_M_t).set_exception(std::current_exception()); + } + } + + private: + tuple&, _Executor> _M_t; + }; + + template + struct associated_executor<__use_future_ch<_Func, _Args...>, _Executor> + { + private: + using __handler = __use_future_ch<_Func, _Args...>; + + using type = __use_future_ex; + + static type + get(const __handler& __h, const _Executor& __ex) + { return { __h, __ex }; } + }; + +#if 0 + + // [async.use.future.traits] + template + class handler_type, _Ret(_Args...)> // TODO uglify name + { + template + struct __is_error_result : false_type { }; + + template + struct __is_error_result : true_type { }; + + template + struct __is_error_result : true_type { }; + + static exception_ptr + _S_exptr(exception_ptr& __ex) + { return std::move(__ex); } + + static exception_ptr + _S_exptr(const error_code& __ec) + { return make_exception_ptr(system_error(__ec)); } + + template + struct _Type; + + // N == 0 + template + struct _Type<_IsError> + { + std::promise _M_promise; + + void + operator()() + { + _M_promise.set_value(); + } + }; + + // N == 1, U0 is error_code or exception_ptr + template + struct _Type + { + std::promise _M_promise; + + template + void + operator()(_Arg0&& __a0) + { + if (__a0) + _M_promise.set_exception(_S_exptr(__a0)); + else + _M_promise.set_value(); + } + }; + + // N == 1, U0 is not error_code or exception_ptr + template + struct _Type + { + std::promise<_UArg0> _M_promise; + + template + void + operator()(_Arg0&& __a0) + { + _M_promise.set_value(std::forward<_Arg0>(__a0)); + } + }; + + // N == 2, U0 is error_code or exception_ptr + template + struct _Type + { + std::promise<_UArg1> _M_promise; + + template + void + operator()(_Arg0&& __a0, _Arg1&& __a1) + { + if (__a0) + _M_promise.set_exception(_S_exptr(__a0)); + else + _M_promise.set_value(std::forward<_Arg1>(__a1)); + } + }; + + // N >= 2, U0 is not error_code or exception_ptr + template + struct _Type + { + static_assert(sizeof...(_UArgs) > 1, "wrong partial specialization"); + + std::promise> _M_promise; + + template + void + operator()(_Args&&... __args) + { + _M_promise.set_value( + std::forward_as_tuple(std::forward<_Args>(__args)...)); + } + }; + + // N > 2, U0 is error_code or exception_ptr + template + struct _Type + { + static_assert(sizeof...(_UArgs) > 1, "wrong partial specialization"); + + std::promise> _M_promise; + + template + void + operator()(_Arg0&& __a0, _Args&&... __args) + { + if (__a0) + _M_promise.set_exception(_S_exptr(__a0)); + else + _M_promise.set_value( + std::forward_as_tuple(std::forward<_Args>(__args)...)); + } + }; + + public: + using type = + _Type<__is_error_result<_Args...>::value, decay_t<_Args>...>; + }; + + + template + struct async_result, _Ret(_Args...)> + { + using completion_handler_type + = typename handler_type, _Ret(_Args...)>::type; + + using return_type = void; // XXX TODO ???; + + explicit + async_result(completion_handler_type& __h) : _M_handler(__h) { } + + auto get() { return _M_handler._M_provider.get_future(); } + + async_result(const async_result&) = delete; + async_result& operator=(const async_result&) = delete; + + return_type get() { return _M_handler._M_promise.get_future(); } + + private: + completion_handler_type& _M_handler; + }; + + // TODO specialize associated_executor for + // async_result, Sig>::completion_handler_type + // to use a __use_future_ex + // (probably need to move _Type outside of handler_type so we don't have + // a non-deduced context) + + +#endif + + // [async.packaged.task.specializations] + template + class async_result, _Signature> + { + public: + using completion_handler_type = packaged_task<_Ret(_Args...)>; + using return_type = future<_Ret>; + + explicit + async_result(completion_handler_type& __h) + : _M_future(__h.get_future()) { } + + async_result(const async_result&) = delete; + async_result& operator=(const async_result&) = delete; + + return_type get() { return std::move(_M_future); } + + private: + return_type _M_future; + }; + +#endif + + /// @} + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace v1 +} // namespace net +} // namespace experimental + +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + template + struct uses_allocator + : true_type {}; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++14 + +#endif // _GLIBCXX_EXPERIMENTAL_EXECUTOR diff --git a/libstdc++-v3/include/experimental/internet b/libstdc++-v3/include/experimental/internet new file mode 100644 index 00000000000..07fe6140f30 --- /dev/null +++ b/libstdc++-v3/include/experimental/internet @@ -0,0 +1,2397 @@ +// -*- C++ -*- + +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file experimental/internet + * This is a TS C++ Library header. + */ + +#ifndef _GLIBCXX_EXPERIMENTAL_INTERNET +#define _GLIBCXX_EXPERIMENTAL_INTERNET + +#pragma GCC system_header + +#if __cplusplus >= 201402L + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +namespace experimental +{ +namespace net +{ +inline namespace v1 +{ +namespace ip +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @ingroup networking + * @{ + */ + + /** Error codes for resolver errors. + * @{ + */ + + enum class resolver_errc : int { + host_not_found = EAI_NONAME, + host_not_found_try_again = EAI_AGAIN, + service_not_found = EAI_SERVICE + }; + + /// Error category for resolver errors. + inline const error_category& resolver_category() noexcept // TODO non-inline + { + struct __cat : error_category + { + const char* name() const noexcept { return "resolver"; } + std::string message(int __e) const { return ::gai_strerror(__e); } + virtual void __message(int) { } // TODO dual ABI XXX + }; + static __cat __c; + return __c; + } + + error_code make_error_code(resolver_errc __e) noexcept + { return error_code(static_cast(__e), resolver_category()); } + + error_condition make_error_condition(resolver_errc __e) noexcept + { return error_condition(static_cast(__e), resolver_category()); } + + /// @} + + typedef uint_least16_t port_type; ///< Type used for port numbers. + typedef uint_least32_t scope_id_type; ///< Type used for IPv6 scope IDs. + + /// Convenience alias for constraining allocators for strings. + template + using __string_with + = enable_if_t::value, + std::basic_string, _Alloc>>; + + /** Tag indicating conversion between IPv4 and IPv4-mapped IPv6 addresses. + * @{ + */ + + struct v4_mapped_t {}; + constexpr v4_mapped_t v4_mapped; + + // @} + + /// An IPv4 address. + class address_v4 + { + public: + // types: + typedef uint_least32_t uint_type; + + struct bytes_type : array + { + template + explicit constexpr + bytes_type(_Tp... __tp) + : array{{static_cast(__tp)...}} + { +#if UCHAR_MAX > 0xFF + for (auto __b : *this) + if (__b > 0xFF) + __throw_out_of_range("invalid address_v4::bytes_type value"); +#endif + } + }; + + // constructors: + constexpr address_v4() noexcept : _M_addr(0) { } + + constexpr address_v4(const address_v4& a) noexcept = default; + + constexpr + address_v4(const bytes_type& __b) + : _M_addr((__b[0] << 24) | (__b[1] << 16) | (__b[2] << 8) | __b[3]) + { } + + explicit constexpr + address_v4(uint_type __val) : _M_addr(_S_hton(__val)) + { +#if UINT_LEAST32_MAX > 0xFFFFFFFF + if (__val > 0xFFFFFFFF) + __throw_out_of_range("invalid address_v4::uint_type value"); +#endif + } + + // assignment: + address_v4& operator=(const address_v4& a) noexcept = default; + + // members: + constexpr bool is_unspecified() const noexcept { return to_uint() == 0; } + + constexpr bool + is_loopback() const noexcept + { return (to_uint() & 0xFF000000) == 0x7F000000; } + + constexpr bool + is_multicast() const noexcept + { return (to_uint() & 0xF0000000) == 0xE0000000; } + + constexpr bytes_type + to_bytes() const noexcept + { + return bytes_type{ + (_M_addr >> 24) & 0xFF, + (_M_addr >> 16) & 0xFF, + (_M_addr >> 8) & 0xFF, + _M_addr & 0xFF + }; + } + + constexpr uint_type to_uint() const noexcept { return _S_ntoh(_M_addr); } + + template> + __string_with<_Allocator> + to_string(const _Allocator& __a = _Allocator()) const + { + __string_with<_Allocator> __str(__a); + __str.resize(INET6_ADDRSTRLEN); + if (inet_ntop(AF_INET, &_M_addr, &__str.front(), __str.size())) + __str.erase(__str.find('\0')); + else + __str.resize(0); + return __str; + } + + // static members: + static constexpr address_v4 any() noexcept { return address_v4{}; } + + static constexpr + address_v4 loopback() noexcept { return address_v4{0x7F000001}; } + + static constexpr + address_v4 broadcast() noexcept { return address_v4{0xFFFFFFFF}; } + + private: + template + friend class basic_endpoint; + + friend address_v4 make_address_v4(const char*, error_code&) noexcept; + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + static constexpr uint16_t _S_hton(uint16_t __h) { return __h; } + static constexpr uint16_t _S_ntoh(uint16_t __n) { return __n; } + static constexpr uint32_t _S_hton(uint32_t __h) { return __h; } + static constexpr uint32_t _S_ntoh(uint32_t __n) { return __n; } +#else + static constexpr uint16_t + _S_hton(uint16_t __h) { return __builtin_bswap16(__h); } + + static constexpr uint16_t + _S_ntoh(uint16_t __n) { return __builtin_bswap16(__n); } + + static constexpr uint32_t + _S_hton(uint32_t __h) { return __builtin_bswap32(__h); } + + static constexpr uint32_t + _S_ntoh(uint32_t __n) { return __builtin_bswap32(__n); } +#endif + + in_addr_t _M_addr; // network byte order + }; + + /// An IPv6 address. + class address_v6 + { + public: + // types: + struct bytes_type : array + { + template explicit constexpr bytes_type(_Tp... __t) + : array{{static_cast(__t)...}} { } + }; + + // constructors: + constexpr address_v6() noexcept : _M_bytes(), _M_scope_id() { } + + constexpr address_v6(const address_v6& __a) noexcept = default; + + constexpr + address_v6(const bytes_type& __bytes, scope_id_type __scope = 0) + : _M_bytes(__bytes), _M_scope_id(__scope) + { } + + // assignment: + address_v6& operator=(const address_v6& __a) noexcept = default; + + // members: + void scope_id(scope_id_type __id) noexcept { _M_scope_id = __id; } + + constexpr scope_id_type scope_id() const noexcept { return _M_scope_id; } + + constexpr bool + is_unspecified() const noexcept + { + for (int __i = 0; __i < 16; ++__i) + if (_M_bytes[__i] != 0x00) + return false; + return _M_scope_id == 0; + } + + constexpr bool + is_loopback() const noexcept + { + for (int __i = 0; __i < 15; ++__i) + if (_M_bytes[__i] != 0x00) + return false; + return _M_bytes[15] == 0x01 && _M_scope_id == 0; + } + + constexpr bool + is_multicast() const noexcept { return _M_bytes[0] == 0xFF; } + + constexpr bool + is_link_local() const noexcept + { return _M_bytes[0] == 0xFE && (_M_bytes[1] & 0xC0) == 0x80; } + + constexpr bool + is_site_local() const noexcept + { return _M_bytes[0] == 0xFE && (_M_bytes[1] & 0xC0) == 0xC0; } + + constexpr bool + is_v4_mapped() const noexcept + { + const bytes_type& __b = _M_bytes; + return __b[0] == 0 && __b[1] == 0 && __b[ 2] == 0 && __b[ 3] == 0 + && __b[4] == 0 && __b[5] == 0 && __b[ 6] == 0 && __b[ 7] == 0 + && __b[8] == 0 && __b[9] == 0 && __b[10] == 0xFF && __b[11] == 0xFF; + } + + constexpr bool + is_multicast_node_local() const noexcept + { return is_multicast() && (_M_bytes[1] & 0x0F) == 0x01; } + + constexpr bool + is_multicast_link_local() const noexcept + { return is_multicast() && (_M_bytes[1] & 0x0F) == 0x02; } + + constexpr bool + is_multicast_site_local() const noexcept + { return is_multicast() && (_M_bytes[1] & 0x0F) == 0x05; } + + constexpr bool + is_multicast_org_local() const noexcept + { return is_multicast() && (_M_bytes[1] & 0x0F) == 0x08; } + + constexpr bool + is_multicast_global() const noexcept + { return is_multicast() && (_M_bytes[1] & 0x0F) == 0x0b; } + + constexpr bytes_type to_bytes() const noexcept { return _M_bytes; } + + template> + __string_with<_Allocator> + to_string(const _Allocator& __a = _Allocator()) const + { + __string_with<_Allocator> __str(__a); + __str.resize(INET6_ADDRSTRLEN); + if (inet_ntop(AF_INET6, &_M_bytes, &__str.front(), __str.size())) + __str.erase(__str.find('\0')); + else + __str.resize(0); + return __str; + } + + // static members: + static constexpr address_v6 + any() noexcept + { + address_v6 __addr; + std::memcpy(&__addr._M_bytes, in6addr_any.s6_addr, 16); + return __addr; + } + + static constexpr address_v6 + loopback() noexcept + { + address_v6 __addr; + std::memcpy(&__addr._M_bytes, in6addr_loopback.s6_addr, 16); + return __addr; + } + + private: + template + friend class basic_endpoint; + + friend constexpr bool + operator==(const address_v6&, const address_v6&) noexcept; + + friend constexpr bool + operator< (const address_v6&, const address_v6&) noexcept; + + bytes_type _M_bytes; + scope_id_type _M_scope_id; + }; + + /// Exception type thrown on misuse of IPv4 addresses as IPv6 or vice versa. + class bad_address_cast : public bad_cast + { + public: + bad_address_cast() { } + + const char* what() const noexcept { return "bad address cast"; } + }; + + /// An IPv4 or IPv6 address. + class address + { + public: + // constructors: + constexpr address() noexcept : _M_v4(), _M_is_v4(true) { } + + constexpr + address(const address& __a) noexcept : _M_uninit(), _M_is_v4(__a._M_is_v4) + { + if (_M_is_v4) + ::new (std::addressof(_M_v4)) address_v4(__a.to_v4()); + else + ::new (std::addressof(_M_v6)) address_v6(__a.to_v6()); + } + + constexpr + address(const address_v4& __a) noexcept : _M_v4(__a), _M_is_v4(true) { } + + constexpr + address(const address_v6& __a) noexcept : _M_v6(__a), _M_is_v4(false) { } + + // assignment: + address& + operator=(const address& __a) noexcept + { + if (__a._M_is_v4) + *this = __a.to_v4(); + else + *this = __a.to_v6(); + return *this; + } + + address& + operator=(const address_v4& __a) noexcept + { + ::new (std::addressof(_M_v4)) address_v4(__a); + _M_is_v4 = true; + return *this; + } + + address& + operator=(const address_v6& __a) noexcept + { + ::new (std::addressof(_M_v6)) address_v6(__a); + _M_is_v4 = false; + return *this; + } + + // members: + + constexpr bool is_v4() const noexcept { return _M_is_v4; } + constexpr bool is_v6() const noexcept { return !_M_is_v4; } + + constexpr address_v4 + to_v4() const + { + if (!is_v4()) + _GLIBCXX_THROW_OR_ABORT(bad_address_cast()); + return _M_v4; + } + + constexpr address_v6 + to_v6() const + { + if (!is_v6()) + _GLIBCXX_THROW_OR_ABORT(bad_address_cast()); + return _M_v6; + } + + constexpr bool + is_unspecified() const noexcept + { return _M_is_v4 ? _M_v4.is_unspecified() : _M_v6.is_unspecified(); } + + constexpr bool + is_loopback() const noexcept + { return _M_is_v4 ? _M_v4.is_loopback() : _M_v6.is_loopback(); } + + constexpr bool + is_multicast() const noexcept + { return _M_is_v4 ? _M_v4.is_multicast() : _M_v6.is_multicast(); } + + template> + __string_with<_Allocator> + to_string(const _Allocator& __a = _Allocator()) const + { + if (_M_is_v4) + return to_v4().to_string(__a); + return to_v6().to_string(__a); + } + + private: + template + friend class basic_endpoint; + + friend constexpr bool + operator==(const address&, const address&) noexcept; + + friend constexpr bool + operator<(const address&, const address&) noexcept; + + union { + address_v4 _M_v4; + address_v6 _M_v6; + bool _M_uninit; + }; + bool _M_is_v4; + }; + + /** ip::address_v4 comparisons + * @{ + */ + + constexpr bool + operator==(const address_v4& __a, const address_v4& __b) noexcept + { return __a.to_uint() == __b.to_uint(); } + + constexpr bool + operator!=(const address_v4& __a, const address_v4& __b) noexcept + { return !(__a == __b); } + + constexpr bool + operator< (const address_v4& __a, const address_v4& __b) noexcept + { return __a.to_uint() < __b.to_uint(); } + + constexpr bool + operator> (const address_v4& __a, const address_v4& __b) noexcept + { return __b < __a; } + + constexpr bool + operator<=(const address_v4& __a, const address_v4& __b) noexcept + { return !(__b < __a); } + + constexpr bool + operator>=(const address_v4& __a, const address_v4& __b) noexcept + { return !(__a < __b); } + + // @} + + /** ip::address_v6 comparisons + * @{ + */ + + constexpr bool + operator==(const address_v6& __a, const address_v6& __b) noexcept + { + const auto& __aa = __a._M_bytes; + const auto& __bb = __b._M_bytes; + int __i = 0; + for (; __aa[__i] == __bb[__i] && __i < 16; ++__i) + ; + return __i == 16 ? __a.scope_id() == __b.scope_id() : false; + } + + constexpr bool + operator!=(const address_v6& __a, const address_v6& __b) noexcept + { return !(__a == __b); } + + constexpr bool + operator< (const address_v6& __a, const address_v6& __b) noexcept + { + const auto& __aa = __a._M_bytes; + const auto& __bb = __b._M_bytes; + int __i = 0; + for (; __aa[__i] == __bb[__i] && __i < 16; ++__i) + ; + return __i == 16 ? __a.scope_id() < __b.scope_id() : __aa[__i] < __bb[__i]; + } + + constexpr bool + operator> (const address_v6& __a, const address_v6& __b) noexcept + { return __b < __a; } + + constexpr bool + operator<=(const address_v6& __a, const address_v6& __b) noexcept + { return !(__b < __a); } + + constexpr bool + operator>=(const address_v6& __a, const address_v6& __b) noexcept + { return !(__a < __b); } + + // @} + + /** ip::address comparisons + * @{ + */ + + constexpr bool + operator==(const address& __a, const address& __b) noexcept + { + if (__a.is_v4()) + return __b.is_v4() ? __a._M_v4 == __b._M_v4 : false; + return __b.is_v4() ? false : __a._M_v6 == __b._M_v6; + } + + constexpr bool + operator!=(const address& __a, const address& __b) noexcept + { return !(__a == __b); } + + constexpr bool + operator< (const address& __a, const address& __b) noexcept + { + if (__a.is_v4()) + return __b.is_v4() ? __a._M_v4 < __b._M_v4 : true; + return __b.is_v4() ? false : __a._M_v6 < __b._M_v6; + } + + constexpr bool + operator> (const address& __a, const address& __b) noexcept + { return __b < __a; } + + constexpr bool + operator<=(const address& __a, const address& __b) noexcept + { return !(__b < __a); } + + constexpr bool + operator>=(const address& __a, const address& __b) noexcept + { return !(__a < __b); } + + // @} + + /** ip::address_v4 creation + * @{ + */ + + constexpr address_v4 + make_address_v4(const address_v4::bytes_type& __b) + { return address_v4{__b}; } + + constexpr address_v4 + make_address_v4(address_v4::uint_type __val) + { return address_v4{__val}; } + + constexpr address_v4 + make_address_v4(v4_mapped_t, const address_v6& __a) + { + if (!__a.is_v4_mapped()) + _GLIBCXX_THROW_OR_ABORT(bad_address_cast()); + + const auto __v6b = __a.to_bytes(); + return address_v4::bytes_type(__v6b[12], __v6b[13], __v6b[14], __v6b[15]); + } + + inline address_v4 + make_address_v4(const char* __str, error_code& __ec) noexcept + { + address_v4 __a; + const int __res = ::inet_pton(AF_INET, __str, &__a._M_addr); + if (__res == 1) + { + __ec.clear(); + return __a; + } + if (__res == 0) + __ec = std::make_error_code(std::errc::invalid_argument); + else + __ec.assign(errno, generic_category()); + return {}; + } + + inline address_v4 + make_address_v4(const char* __str) + { return make_address_v4(__str, __throw_on_error{"make_address_v4"}); } + + inline address_v4 + make_address_v4(const string& __str, error_code& __ec) noexcept + { return make_address_v4(__str.c_str(), __ec); } + + inline address_v4 + make_address_v4(const string& __str) + { return make_address_v4(__str.c_str()); } + + inline address_v4 + make_address_v4(string_view __str, error_code& __ec) noexcept + { + char __buf[INET_ADDRSTRLEN]; + auto __len = __str.copy(__buf, sizeof(__buf)); + if (__len == sizeof(__buf)) + { + __ec = std::make_error_code(std::errc::invalid_argument); + return {}; + } + __ec.clear(); + __buf[__len] = '\0'; + return make_address_v4(__buf, __ec); + } + + inline address_v4 + make_address_v4(string_view __str) + { return make_address_v4(__str, __throw_on_error{"make_address_v4"}); } + + // @} + + /** ip::address_v6 creation + * @{ + */ + + constexpr address_v6 + make_address_v6(const address_v6::bytes_type& __b, scope_id_type __scope = 0) + { return address_v6{__b, __scope}; } + + constexpr address_v6 + make_address_v6(v4_mapped_t, const address_v4& __a) noexcept + { + const address_v4::bytes_type __v4b = __a.to_bytes(); + address_v6::bytes_type __v6b(0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0xFF, 0xFF, + __v4b[0], __v4b[1], __v4b[2], __v4b[3]); + return address_v6(__v6b); + } + + inline address_v6 + __make_address_v6(const char* __addr, const char* __scope, error_code& __ec) + { + address_v6::bytes_type __b; + int __res = ::inet_pton(AF_INET6, __addr, __b.data()); + if (__res == 1) + { + __ec.clear(); + if (!__scope) + { + return { __b }; + } + + char* __eptr; + unsigned long __val = std::strtoul(__scope, &__eptr, 10); + if (__eptr != __scope && !*__eptr + && __val <= numeric_limits::max()) + { + return { __b, static_cast(__val) }; + } + __ec = std::make_error_code(std::errc::invalid_argument); + } + else if (__res == 0) + __ec = std::make_error_code(std::errc::invalid_argument); + else + __ec.assign(errno, generic_category()); + return {}; + } + + inline address_v6 + make_address_v6(const char* __str, error_code& __ec) noexcept + { + auto __p = std::strchr(__str, '%'); + if (__p == nullptr) + return __make_address_v6(__str, nullptr, __ec); + char __buf[64]; + char* __out = __buf; + bool __skip_leading_zero = true; + while (__str < __p && __out < std::end(__buf)) + { + if (!__skip_leading_zero || *__str != '0') + { + if (*__str == ':' || *__str == '.') + __skip_leading_zero = true; + else + __skip_leading_zero = false; + *__out = *__str; + } + __str++; + } + if (__out == std::end(__buf)) + __ec = std::make_error_code(std::errc::invalid_argument); + else + { + *__out = '\0'; + return __make_address_v6(__buf, __p + 1, __ec); + } + } + + inline address_v6 + make_address_v6(const char* __str) + { return make_address_v6(__str, __throw_on_error{"make_address_v6"}); } + + inline address_v6 + make_address_v6(const string& __str, error_code& __ec) noexcept + { + auto __pos = __str.find('%'); + if (__pos == string::npos) + return __make_address_v6(__str.c_str(), nullptr, __ec); + char __buf[64]; + char* __out = __buf; + bool __skip_leading_zero = true; + size_t __n = 0; + while (__n < __pos && __out < std::end(__buf)) + { + if (!__skip_leading_zero || __str[__n] != '0') + { + if (__str[__n] == ':' || __str[__n] == '.') + __skip_leading_zero = true; + else + __skip_leading_zero = false; + *__out = __str[__n]; + } + __n++; + } + if (__out == std::end(__buf)) + __ec = std::make_error_code(std::errc::invalid_argument); + else + { + *__out = '\0'; + return __make_address_v6(__buf, __str.c_str() + __pos + 1, __ec); + } + } + + inline address_v6 + make_address_v6(const string& __str) + { return make_address_v6(__str, __throw_on_error{"make_address_v6"}); } + + inline address_v6 + make_address_v6(string_view __str, error_code& __ec) noexcept + { + char __buf[64]; + char* __out = __buf; + char* __scope = nullptr; + bool __skip_leading_zero = true; + size_t __n = 0; + while (__n < __str.length() && __out < std::end(__buf)) + { + if (__str[__n] == '%') + { + if (__scope) + __out = std::end(__buf); + else + { + *__out = '\0'; + __scope = ++__out; + __skip_leading_zero = true; + } + } + else if (!__skip_leading_zero || __str[__n] != '0') + { + if (__str[__n] == ':' || __str[__n] == '.') + __skip_leading_zero = true; + else + __skip_leading_zero = false; + *__out = __str[__n]; + __out++; + } + __n++; + } + if (__out == std::end(__buf)) + __ec = std::make_error_code(std::errc::invalid_argument); + else + { + *__out = '\0'; + return __make_address_v6(__buf, __scope, __ec); + } + } + + inline address_v6 + make_address_v6(string_view __str) + { return make_address_v6(__str, __throw_on_error{"make_address_v6"}); } + + // @} + + /** ip::address creation + * @{ + */ + + inline address + make_address(const char* __str, error_code& __ec) noexcept + { + address __a; + address_v6 __v6a = make_address_v6(__str, __ec); + if (!__ec) + __a = __v6a; + else + { + address_v4 __v4a = make_address_v4(__str, __ec); + if (!__ec) + __a = __v4a; + } + return __a; + } + + inline address + make_address(const char* __str) + { return make_address(__str, __throw_on_error{"make_address"}); } + + inline address + make_address(const string& __str, error_code& __ec) noexcept; // TODO + + inline address + make_address(const string& __str) + { return make_address(__str, __throw_on_error{"make_address"}); } + + inline address + make_address(string_view __str, error_code& __ec) noexcept + { + if (__str.rfind('\0') != string_view::npos) + return make_address(__str.data(), __ec); + return make_address(__str.to_string(), __ec); // TODO don't allocate + } + + inline address + make_address(string_view __str) + { return make_address(__str, __throw_on_error{"make_address"}); } + + // @} + + /// ip::address I/O + template + inline basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, const address& __a) + { return __os << __a.to_string(); } + + /// ip::address_v4 I/O + template + inline basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, const address_v4& __a) + { return __os << __a.to_string(); } + + /// ip::address_v6 I/O + template + inline basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, const address_v6& __a) + { return __os << __a.to_string(); } + + template class basic_address_iterator; // not defined + + template<> class basic_address_iterator + { + public: + // types: + typedef address_v4 value_type; + typedef ptrdiff_t difference_type; + typedef const address_v4* pointer; + typedef const address_v4& reference; + typedef input_iterator_tag iterator_category; + + // constructors: + basic_address_iterator(const address_v4& __a) noexcept + : _M_address(__a) { } + + // members: + reference operator*() const noexcept { return _M_address; } + pointer operator->() const noexcept { return &_M_address; } + + basic_address_iterator& + operator++() noexcept + { + _M_address = value_type(_M_address.to_uint() + 1); + return *this; + } + + basic_address_iterator operator++(int) noexcept + { + auto __tmp = *this; + ++*this; + return __tmp; + } + + basic_address_iterator& operator--() noexcept + { + _M_address = value_type(_M_address.to_uint() - 1); + return *this; + } + + basic_address_iterator + operator--(int) noexcept + { + auto __tmp = *this; + --*this; + return __tmp; + } + + bool + operator==(const basic_address_iterator& __rhs) const noexcept + { return _M_address == __rhs._M_address; } + + bool + operator!=(const basic_address_iterator& __rhs) const noexcept + { return _M_address != __rhs._M_address; } + + private: + address_v4 _M_address; + }; + + typedef basic_address_iterator address_v4_iterator; + + template<> class basic_address_iterator + { + public: + // types: + typedef address_v6 value_type; + typedef ptrdiff_t difference_type; + typedef const address_v6* pointer; + typedef const address_v6& reference; + typedef input_iterator_tag iterator_category; + + // constructors: + basic_address_iterator(const address_v6& __a) noexcept + : _M_address(__a) { } + + // members: + reference operator*() const noexcept { return _M_address; } + pointer operator->() const noexcept { return &_M_address; } + + basic_address_iterator& + operator++() noexcept; // TODO + + basic_address_iterator + operator++(int) noexcept + { + auto __tmp = *this; + ++*this; + return __tmp; + } + + basic_address_iterator& + operator--() noexcept; // TODO + + basic_address_iterator + operator--(int) noexcept + { + auto __tmp = *this; + --*this; + return __tmp; + } + + bool + operator==(const basic_address_iterator& __rhs) const noexcept + { return _M_address == __rhs._M_address; } + + bool + operator!=(const basic_address_iterator& __rhs) const noexcept + { return _M_address != __rhs._M_address; } + + private: + address_v6 _M_address; + }; + + typedef basic_address_iterator address_v6_iterator; + + template class basic_address_range; // not defined + + /** An IPv6 address range. + * @{ + */ + + template<> class basic_address_range + { + public: + // types: + + typedef basic_address_iterator iterator; + + // constructors: + + basic_address_range() noexcept : _M_begin({}), _M_end({}) { } + + basic_address_range(const address_v4& __first, + const address_v4& __last) noexcept + : _M_begin(__first), _M_end(__last) { } + + // members: + + iterator begin() const noexcept { return _M_begin; } + iterator end() const noexcept { return _M_end; } + bool empty() const noexcept { return _M_begin == _M_end; } + + size_t + size() const noexcept { return _M_end->to_uint() - _M_begin->to_uint(); } + + iterator + find(const address_v4& __addr) const noexcept + { + if (*_M_begin <= __addr && __addr < *_M_end) + return iterator{__addr}; + return end(); + } + + private: + iterator _M_begin; + iterator _M_end; + }; + + typedef basic_address_range address_v4_range; + + // @} + + /** An IPv6 address range. + * @{ + */ + + template<> class basic_address_range + { + public: + // types: + + typedef basic_address_iterator iterator; + + // constructors: + + basic_address_range() noexcept : _M_begin({}), _M_end({}) { } + basic_address_range(const address_v6& __first, + const address_v6& __last) noexcept + : _M_begin(__first), _M_end(__last) { } + + // members: + + iterator begin() const noexcept { return _M_begin; } + iterator end() const noexcept { return _M_end; } + bool empty() const noexcept { return _M_begin == _M_end; } + + iterator + find(const address_v6& __addr) const noexcept + { + if (*_M_begin <= __addr && __addr < *_M_end) + return iterator{__addr}; + return end(); + } + + private: + iterator _M_begin; + iterator _M_end; + }; + + typedef basic_address_range address_v6_range; + + bool + operator==(const network_v4& __a, const network_v4& __b) noexcept; + + bool + operator==(const network_v6& __a, const network_v6& __b) noexcept; + + // @} + + /// An IPv4 network address. + class network_v4 + { + public: + // constructors: + constexpr network_v4() noexcept : _M_addr(), _M_prefix_len(0) { } + + constexpr + network_v4(const address_v4& __addr, int __prefix_len) + : _M_addr(__addr), _M_prefix_len(__prefix_len) + { + if (_M_prefix_len < 0 || _M_prefix_len > 32) + __throw_out_of_range("network_v4: invalid prefix length"); + } + + constexpr + network_v4(const address_v4& __addr, const address_v4& __mask) + : _M_addr(__addr), _M_prefix_len(__builtin_popcount(__mask.to_uint())) + { + if (_M_prefix_len != 0) + { + address_v4::uint_type __mask_uint = __mask.to_uint(); + if (__builtin_ctz(__mask_uint) != (32 - _M_prefix_len)) + __throw_invalid_argument("network_v4: invalid mask"); + if ((__mask_uint & 0x80000000) == 0) + __throw_invalid_argument("network_v4: invalid mask"); + } + } + + // members: + + constexpr address_v4 address() const noexcept { return _M_addr; } + constexpr int prefix_length() const noexcept { return _M_prefix_len; } + + constexpr address_v4 + netmask() const noexcept + { + address_v4::uint_type __val = address_v4::broadcast().to_uint(); + __val >>= (32 - _M_prefix_len); + __val <<= (32 - _M_prefix_len); + return address_v4{__val}; + } + + constexpr address_v4 + network() const noexcept + { return address_v4{_M_addr.to_uint() & netmask().to_uint()}; } + + constexpr address_v4 + broadcast() const noexcept + { return address_v4{_M_addr.to_uint() | ~netmask().to_uint()}; } + + address_v4_range + hosts() const noexcept + { + if (is_host()) + return { address(), *++address_v4_iterator(address()) }; + return { network(), broadcast() }; + } + + constexpr network_v4 + canonical() const noexcept + { return network_v4(network(), prefix_length()); } + + constexpr bool is_host() const noexcept { return _M_prefix_len == 32; } + + constexpr bool + is_subnet_of(const network_v4& __other) const noexcept + { + if (__other.prefix_length() < prefix_length()) + { + network_v4 __net(address(), __other.prefix_length()); + return __net.canonical() == __other.canonical(); + } + return false; + } + + template> + __string_with<_Allocator> + to_string(const _Allocator& __a = _Allocator()) const + { + return address().to_string(__a) + '/' + + std::to_string(prefix_length()); + } + + private: + address_v4 _M_addr; + int _M_prefix_len; + }; + + /// An IPv6 network address. + class network_v6 + { + public: + // constructors: + constexpr network_v6() noexcept : _M_addr(), _M_prefix_len(0) { } + + constexpr + network_v6(const address_v6& __addr, int __prefix_len) + : _M_addr(__addr), _M_prefix_len(__prefix_len) + { + if (_M_prefix_len < 0 || _M_prefix_len > 128) + __throw_out_of_range("network_v6: invalid prefix length"); + } + + // members: + constexpr address_v6 address() const noexcept { return _M_addr; } + constexpr int prefix_length() const noexcept { return _M_prefix_len; } + + constexpr address_v6 network() const noexcept; // TODO + + address_v6_range + hosts() const noexcept + { + if (is_host()) + return { address(), *++address_v6_iterator(address()) }; + return {}; // { network(), XXX broadcast() XXX }; // TODO + } + + constexpr network_v6 + canonical() const noexcept + { return network_v6{network(), prefix_length()}; } + + constexpr bool is_host() const noexcept { return _M_prefix_len == 128; } + + constexpr bool + is_subnet_of(const network_v6& __other) const noexcept + { + if (__other.prefix_length() < prefix_length()) + { + network_v6 __net(address(), __other.prefix_length()); + return __net.canonical() == __other.canonical(); + } + return false; + } + + template> + __string_with<_Allocator> + to_string(const _Allocator& __a = _Allocator()) const + { + return address().to_string(__a) + '/' + + std::to_string(prefix_length()); + } + + private: + address_v6 _M_addr; + int _M_prefix_len; + }; + + + /** ip::network_v4 comparisons + * @{ + */ + + inline bool + operator==(const network_v4& __a, const network_v4& __b) noexcept + { + return __a.address() == __b.address() + && __a.prefix_length() == __b.prefix_length(); + } + + inline bool + operator!=(const network_v4& __a, const network_v4& __b) noexcept + { return !(__a == __b); } + + // @} + + /** ip::network_v6 comparisons + * @{ + */ + + inline bool + operator==(const network_v6& __a, const network_v6& __b) noexcept + { + return __a.address() == __b.address() + && __a.prefix_length() == __b.prefix_length(); + } + + inline bool + operator!=(const network_v6& __a, const network_v6& __b) noexcept + { return !(__a == __b); } + + // @} + + /** ip::network_v4 creation + * @{ + */ + + inline network_v4 + make_network_v4(const address_v4& __a, int __prefix_len) + { return network_v4{__a, __prefix_len}; } + + network_v4 + make_network_v4(const address_v4& __a, const address_v4& __mask) + { return network_v4{ __a, __mask }; } + + network_v4 make_network_v4(const char*, error_code&) noexcept; // TODO + + inline network_v4 + make_network_v4(const char* __str) + { return make_network_v4(__str, __throw_on_error{"make_network_v4"}); } + + network_v4 make_network_v4(const string&, error_code&) noexcept; // TODO + + inline network_v4 + make_network_v4(const string& __str) + { return make_network_v4(__str, __throw_on_error{"make_network_v4"}); } + + network_v4 make_network_v4(string_view, error_code&) noexcept; // TODO + + inline network_v4 + make_network_v4(string_view __str) + { return make_network_v4(__str, __throw_on_error{"make_network_v4"}); } + + // @} + + /** ip::network_v6 creation + * @{ + */ + + inline network_v6 + make_network_v6(const address_v6& __a, int __prefix_len) + { return network_v6{__a, __prefix_len}; } + + network_v6 make_network_v6(const char*, error_code&) noexcept; // TODO + + inline network_v6 + make_network_v6(const char* __str) + { return make_network_v6(__str, __throw_on_error{"make_network_v6"}); } + + network_v6 make_network_v6(const string&, error_code&) noexcept; // TODO + + inline network_v6 + make_network_v6(const string& __str) + { return make_network_v6(__str, __throw_on_error{"make_network_v6"}); } + + network_v6 make_network_v6(string_view, error_code&) noexcept; // TODO + + inline network_v6 + make_network_v6(string_view __str) + { return make_network_v6(__str, __throw_on_error{"make_network_v6"}); } + + // @} + + /// ip::network_v4 I/O + template + inline basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, const network_v4& __net) + { return __os << __net.to_string(); } + + /// ip::network_v6 I/O + template + inline basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, const network_v6& __net) + { return __os << __net.to_string(); } + + /// An IP endpoint. + template + class basic_endpoint + { + public: + // types: + typedef _InternetProtocol protocol_type; + + // constructors: + + constexpr + basic_endpoint() noexcept : _M_data() + { _M_data._M_v4.sin_family = protocol_type::v4().family(); } + + constexpr + basic_endpoint(const protocol_type& __proto, + port_type __port_num) noexcept + : _M_data() + { + __glibcxx_assert(__proto == protocol_type::v4() + || __proto == protocol_type::v6()); + + _M_data._M_v4.sin_family = __proto.family(); + _M_data._M_v4.sin_port = address_v4::_S_hton(__port_num); + } + + constexpr + basic_endpoint(const ip::address& __addr, + port_type __port_num) noexcept + : _M_data() + { + if (__addr.is_v4()) + { + _M_data._M_v4.sin_family = protocol_type::v4().family(); + _M_data._M_v4.sin_port = address_v4::_S_hton(__port_num); + _M_data._M_v4.sin_addr.s_addr = __addr._M_v4._M_addr; + } + else + { + _M_data._M_v6 = {}; + _M_data._M_v6.sin6_family = protocol_type::v6().family(); + _M_data._M_v6.sin6_port = address_v4::_S_hton(__port_num); + std::memcpy(_M_data._M_v6.sin6_addr.s6_addr, + __addr._M_v6._M_bytes.data(), 16); + _M_data._M_v6.sin6_scope_id = __addr._M_v6._M_scope_id; + } + } + + // members: + constexpr protocol_type protocol() const noexcept + { + return _M_data._M_v4.sin_family == AF_INET6 + ? protocol_type::v6() : protocol_type::v4(); + } + + constexpr ip::address + address() const noexcept + { + ip::address __addr; + if (protocol().family() == AF_INET6) + { + std::memcpy(&__addr._M_v6._M_bytes, + _M_data._M_v6.sin6_addr.s6_addr, 16); + __addr._M_is_v4 = false; + } + else + { + std::memcpy(&__addr._M_v4._M_addr, + &_M_data._M_v4.sin_addr.s_addr, 4); + } + return __addr; + } + + void + address(const ip::address& __addr) noexcept + { + if (__addr.is_v6()) + { + _M_data._M_v6 = {}; + _M_data._M_v6.sin6_family = protocol_type::v6().family(); + std::memcpy(_M_data._M_v6.sin6_addr.s6_addr, + __addr._M_v6._M_bytes.data(), 16); + _M_data._M_v6.sin6_scope_id = __addr._M_v6._M_scope_id; + } + else + { + _M_data._M_v4.sin_family = protocol_type::v4().family(); + _M_data._M_v4.sin_addr.s_addr = __addr._M_v4._M_addr; + } + } + + constexpr port_type + port() const noexcept + { return address_v4::_S_ntoh(_M_data._M_v4.sin_port); } + + void + port(port_type __port_num) noexcept + { _M_data._M_v4.sin_port = address_v4::_S_hton(__port_num); } + + void* data() noexcept { return &_M_data; } + const void* data() const noexcept { return &_M_data; } + constexpr size_t size() const noexcept + { + return protocol().family() == AF_INET6 + ? sizeof(sockaddr_in6) : sizeof(sockaddr_in); + } + + void + resize(size_t __s) + { + if ((protocol().family() == AF_INET6 && __s != sizeof(sockaddr_in6)) + || (protocol().family() == AF_INET && __s != sizeof(sockaddr_in))) + __throw_length_error("net::ip::basic_endpoint::resize"); + } + + constexpr size_t capacity() const noexcept { return sizeof(_M_data); } + + private: + union + { + sockaddr_in _M_v4; + sockaddr_in6 _M_v6; + } _M_data; + }; + + /** basic_endpoint comparisons + * @{ + */ + + template + inline bool + operator==(const basic_endpoint<_InternetProtocol>& __a, + const basic_endpoint<_InternetProtocol>& __b) + { return __a.address() == __b.address() && __a.port() == __b.port(); } + + template + inline bool + operator!=(const basic_endpoint<_InternetProtocol>& __a, + const basic_endpoint<_InternetProtocol>& __b) + { return !(__a == __b); } + + template + inline bool + operator< (const basic_endpoint<_InternetProtocol>& __a, + const basic_endpoint<_InternetProtocol>& __b) + { + return __a.address() < __b.address() + || (!(__b.address() < __a.address()) && __a.port() < __b.port()); + } + + template + inline bool + operator> (const basic_endpoint<_InternetProtocol>& __a, + const basic_endpoint<_InternetProtocol>& __b) + { return __b < __a; } + + template + inline bool + operator<=(const basic_endpoint<_InternetProtocol>& __a, + const basic_endpoint<_InternetProtocol>& __b) + { return !(__b < __a); } + + template + inline bool + operator>=(const basic_endpoint<_InternetProtocol>& __a, + const basic_endpoint<_InternetProtocol>& __b) + { return !(__a < __b); } + + // @} + + /// basic_endpoint I/O + template + inline basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, + const basic_endpoint<_InternetProtocol>& __ep) + { + basic_ostringstream<_CharT, _Traits> __ss; + if (__ep.protocol() + == basic_endpoint<_InternetProtocol>::protocol_type::v6()) + __ss << '[' << __ep.address() << ']'; + else + __ss << __ep.address(); + __ss << ':' << __ep.port(); + __os << __ss.str(); + return __os; + } + + /** Type representing a single result of name/address resolution. + * @{ + */ + + template + class basic_resolver_entry + { + public: + // types: + typedef _InternetProtocol protocol_type; + typedef typename _InternetProtocol::endpoint endpoint_type; + + // constructors: + basic_resolver_entry() { } + + basic_resolver_entry(const endpoint_type& __ep, + string_view __h, string_view __s) + : _M_ep(__ep), _M_host(__h), _M_svc(__s) { } + + // members: + endpoint_type endpoint() const { return _M_ep; } + operator endpoint_type() const { return _M_ep; } + + template> + __string_with<_Allocator> + host_name(const _Allocator& __a = _Allocator()) const + { return { _M_host, __a }; } + + template> + __string_with<_Allocator> + service_name(const _Allocator& __a = _Allocator()) const + { return { _M_svc, __a }; } + + private: + basic_endpoint<_InternetProtocol> _M_ep; + string _M_host; + string _M_svc; + }; + + template + inline bool + operator==(const basic_resolver_entry<_InternetProtocol>& __a, + const basic_resolver_entry<_InternetProtocol>& __b) + { + return __a.endpoint() == __b.endpoint() + && __a.host_name() == __b.host_name() + && __a.service_name() == __b.service_name(); + } + + template + inline bool + operator!=(const basic_resolver_entry<_InternetProtocol>& __a, + const basic_resolver_entry<_InternetProtocol>& __b) + { return !(__a == __b); } + + // @} + + /** Base class defining flags for name/address resolution. + * @{ + */ + + class resolver_base + { + public: + enum flags : int + { + __flags_passive = AI_PASSIVE, + __flags_canonical_name = AI_CANONNAME, + __flags_numeric_host = AI_NUMERICHOST, + __flags_numeric_service = AI_NUMERICSERV, + __flags_v4_mapped = AI_V4MAPPED, + __flags_all_matching = AI_ALL, + __flags_address_configured = AI_ADDRCONFIG + }; + static constexpr flags passive = __flags_passive; + static constexpr flags canonical_name = __flags_canonical_name; + static constexpr flags numeric_host = __flags_numeric_host; + static constexpr flags numeric_service = __flags_numeric_service; + static constexpr flags v4_mapped = __flags_v4_mapped; + static constexpr flags all_matching = __flags_all_matching; + static constexpr flags address_configured = __flags_address_configured; + + protected: + resolver_base() = default; + ~resolver_base() = default; + }; + + constexpr resolver_base::flags + operator&(resolver_base::flags __f1, resolver_base::flags __f2) + { return resolver_base::flags( int(__f1) & int(__f2) ); } + + constexpr resolver_base::flags + operator|(resolver_base::flags __f1, resolver_base::flags __f2) + { return resolver_base::flags( int(__f1) | int(__f2) ); } + + constexpr resolver_base::flags + operator^(resolver_base::flags __f1, resolver_base::flags __f2) + { return resolver_base::flags( int(__f1) ^ int(__f2) ); } + + constexpr resolver_base::flags + operator~(resolver_base::flags __f) + { return resolver_base::flags( ~int(__f) ); } + + inline resolver_base::flags& + operator&=(resolver_base::flags& __f1, resolver_base::flags __f2) + { return __f1 = (__f1 & __f2); } + + inline resolver_base::flags& + operator|=(resolver_base::flags& __f1, resolver_base::flags __f2) + { return __f1 = (__f1 | __f2); } + + inline resolver_base::flags& + operator^=(resolver_base::flags& __f1, resolver_base::flags __f2) + { return __f1 = (__f1 ^ __f2); } + + // TODO define resolver_base::flags static constants + + // @} + + /** Container for results of name/address resolution. + * @{ + */ + + template + class basic_resolver_results + { + public: + // types: + typedef _InternetProtocol protocol_type; + typedef typename protocol_type::endpoint endpoint_type; + typedef basic_resolver_entry value_type; + typedef const value_type& const_reference; + typedef value_type& reference; + typedef typename forward_list::const_iterator const_iterator; + typedef const_iterator iterator; + typedef ptrdiff_t difference_type; + typedef size_t size_type; + + // construct / copy / destroy: + + basic_resolver_results() = default; + + basic_resolver_results(const basic_resolver_results&) = default; + + basic_resolver_results(basic_resolver_results&&) noexcept = default; + + basic_resolver_results& + operator=(const basic_resolver_results&) = default; + + basic_resolver_results& + operator=(basic_resolver_results&&) = default; + + ~basic_resolver_results() = default; + + // size: + size_type size() const noexcept { return _M_size; } + size_type max_size() const noexcept { return _M_results.max_size(); } + bool empty() const noexcept { return _M_results.empty(); } + + // element access: + const_iterator begin() const { return _M_results.begin(); } + const_iterator end() const { return _M_results.end(); } + const_iterator cbegin() const { return _M_results.begin(); } + const_iterator cend() const { return _M_results.end(); } + + // swap: + void + swap(basic_resolver_results& __that) noexcept + { _M_results.swap(__that._M_results); } + + private: + friend class basic_resolver; + + basic_resolver_results(string_view, string_view, resolver_base::flags, + error_code&, protocol_type* = nullptr); + + basic_resolver_results(const endpoint_type&, error_code&); + + forward_list _M_results; + size_t _M_size = 0; + }; + + template + inline bool + operator==(const basic_resolver_results<_InternetProtocol>& __a, + const basic_resolver_results<_InternetProtocol>& __b) + { + return __a.size() == __b.size() + && std::equal(__a.begin(), __a.end(), __b.begin()); + } + + template + inline bool + operator!=(const basic_resolver_results<_InternetProtocol>& __a, + const basic_resolver_results<_InternetProtocol>& __b) + { return !(__a == __b); } + + // @} + + /// Perform name/address resolution. + template + class basic_resolver : public resolver_base + { + public: + // types: + + typedef io_context::executor_type executor_type; + typedef _InternetProtocol protocol_type; + typedef typename _InternetProtocol::endpoint endpoint_type; + typedef basic_resolver_results<_InternetProtocol> results_type; + + // construct / copy / destroy: + + explicit basic_resolver(io_context& __ctx) : _M_ctx(&__ctx) { } + + basic_resolver(const basic_resolver&) = delete; + + basic_resolver(basic_resolver&& __rhs) noexcept + : _M_ctx(__rhs._M_ctx) + { } // TODO move state/tasks etc. + + ~basic_resolver() { cancel(); } + + basic_resolver& operator=(const basic_resolver&) = delete; + + basic_resolver& operator=(basic_resolver&& __rhs) + { + cancel(); + _M_ctx = __rhs._M_ctx; + // TODO move state/tasks etc. + return *this; + } + + // basic_resolver operations: + + executor_type get_executor() noexcept { return _M_ctx->get_executor(); } + + void cancel() { } // TODO + + results_type + resolve(string_view __host_name, string_view __service_name) + { + return resolve(__host_name, __service_name, resolver_base::flags(), + __throw_on_error{"basic_resolver::resolve"}); + } + + results_type + resolve(string_view __host_name, string_view __service_name, + error_code& __ec) + { + return resolve(__host_name, __service_name, resolver_base::flags(), + __ec); + } + + results_type + resolve(string_view __host_name, string_view __service_name, flags __f) + { + return resolve(__host_name, __service_name, __f, + __throw_on_error{"basic_resolver::resolve"}); + } + + results_type + resolve(string_view __host_name, string_view __service_name, flags __f, + error_code& __ec) + { return {__host_name, __service_name, __f, __ec}; } + + template + __deduced_t<_CompletionToken, void(error_code, results_type)> + async_resolve(string_view __host_name, string_view __service_name, + _CompletionToken&& __token) + { + return async_resolve(__host_name, __service_name, + resolver_base::flags(), + forward<_CompletionToken>(__token)); + } + + template + __deduced_t<_CompletionToken, void(error_code, results_type)> + async_resolve(string_view __host_name, string_view __service_name, + flags __f, _CompletionToken&& __token); // TODO + + results_type + resolve(const protocol_type& __protocol, + string_view __host_name, string_view __service_name) + { + return resolve(__protocol, __host_name, __service_name, + resolver_base::flags(), + __throw_on_error{"basic_resolver::resolve"}); + } + + results_type + resolve(const protocol_type& __protocol, + string_view __host_name, string_view __service_name, + error_code& __ec) + { + return resolve(__protocol, __host_name, __service_name, + resolver_base::flags(), __ec); + } + + results_type + resolve(const protocol_type& __protocol, + string_view __host_name, string_view __service_name, flags __f) + { + return resolve(__protocol, __host_name, __service_name, __f, + __throw_on_error{"basic_resolver::resolve"}); + } + + results_type + resolve(const protocol_type& __protocol, + string_view __host_name, string_view __service_name, + flags __f, error_code& __ec) + { return {__host_name, __service_name, __f, __ec, &__protocol}; } + + template + __deduced_t<_CompletionToken, void(error_code, results_type)> + async_resolve(const protocol_type& __protocol, + string_view __host_name, string_view __service_name, + _CompletionToken&& __token) + { + return async_resolve(__protocol, __host_name, __service_name, + resolver_base::flags(), + forward<_CompletionToken>(__token)); + } + + template + __deduced_t<_CompletionToken, void(error_code, results_type)> + async_resolve(const protocol_type& __protocol, + string_view __host_name, string_view __service_name, + flags __f, _CompletionToken&& __token); // TODO + + results_type + resolve(const endpoint_type& __ep) + { return resolve(__ep, __throw_on_error{"basic_resolver::resolve"}); } + + results_type + resolve(const endpoint_type& __ep, error_code& __ec) + { return { __ep, __ec }; } + + template // TODO + __deduced_t<_CompletionToken, void(error_code, results_type)> + async_resolve(const endpoint_type& __ep, _CompletionToken&& __token); + + private: + io_context* _M_ctx; + }; + + /// Private constructor to synchronously resolve host and service names. + template + basic_resolver_results<_InternetProtocol>:: + basic_resolver_results(string_view __host_name, string_view __service_name, + resolver_base::flags __f, error_code& __ec, + protocol_type* __protocol) + { + string __host; + const char* __h = __host_name.data() + ? (__host = __host_name.to_string()).c_str() + : nullptr; + string __svc; + const char* __s = __service_name.data() + ? (__svc = __service_name.to_string()).c_str() + : nullptr; + + ::addrinfo __hints{ }; + __hints.ai_flags = static_cast(__f); + if (__protocol) + { + __hints.ai_family = __protocol->family(); + __hints.ai_socktype = __protocol->type(); + __hints.ai_protocol = __protocol->protocol(); + } + else + { + auto __p = endpoint_type{}.protocol(); + __hints.ai_family = AF_UNSPEC; + __hints.ai_socktype = __p.type(); + __hints.ai_protocol = __p.protocol(); + } + + struct __scoped_addrinfo + { + ~__scoped_addrinfo() { if (_M_p) ::freeaddrinfo(_M_p); } + ::addrinfo* _M_p = nullptr; + } __sai; + + if (int __err = ::getaddrinfo(__h, __s, &__hints, &__sai._M_p)) + { + __ec.assign(__err, resolver_category()); + return; + } + __ec.clear(); + + endpoint_type __ep; + auto __tail = _M_results.before_begin(); + for (auto __ai = __sai._M_p; __ai != nullptr; __ai = __ai->ai_next) + { + if (__ai->ai_family == AF_INET || __ai->ai_family == AF_INET6) + { + if (__ai->ai_addrlen <= __ep.capacity()) + std::memcpy(__ep.data(), __ai->ai_addr, __ai->ai_addrlen); + __ep.resize(__ai->ai_addrlen); + __tail = _M_results.emplace_after(__tail, __ep, __host, __svc); + _M_size++; + } + } + } + + /// Private constructor to synchronously resolve an endpoint. + template + basic_resolver_results<_InternetProtocol>:: + basic_resolver_results(const endpoint_type& __ep, error_code& __ec) + { + char __host_name[256]; + char __service_name[128]; + int __flags = 0; + if (__ep.protocol().type() == SOCK_DGRAM) + __flags |= NI_DGRAM; + auto __sa = static_cast(__ep.data()); + int __err = ::getnameinfo(__sa, __ep.size(), + __host_name, sizeof(__host_name), + __service_name, sizeof(__service_name), + __flags); + if (__err) + { + __flags |= NI_NUMERICSERV; + __err = ::getnameinfo(__sa, __ep.size(), + __host_name, sizeof(__host_name), + __service_name, sizeof(__service_name), + __flags); + } + if (__err) + __ec.assign(__err, resolver_category()); + else + { + __ec.clear(); + _M_results.emplace_front(__ep, __host_name, __service_name); + _M_size = 1; + } + } + + /** The name of the local host. + * @{ + */ + + template + __string_with<_Allocator> + host_name(const _Allocator& __a, error_code& __ec) + { +#ifdef HOST_NAME_MAX + constexpr size_t __maxlen = HOST_NAME_MAX; +#else + constexpr size_t __maxlen = 256; +#endif + char __buf[__maxlen + 1]; + if (::gethostname(__buf, __maxlen) == -1) + __ec.assign(errno, generic_category()); + __buf[__maxlen] = '\0'; + return { __buf, __a }; + } + + template + inline __string_with<_Allocator> + host_name(const _Allocator& __a) + { return host_name(__a, __throw_on_error{"host_name"}); } + + inline string + host_name(error_code& __ec) + { return host_name(std::allocator{}, __ec); } + + inline string + host_name() + { return host_name(std::allocator{}, __throw_on_error{"host_name"}); } + + // @} + + /// The TCP byte-stream protocol. + class tcp + { + public: + // types: + typedef basic_endpoint endpoint; ///< A TCP endpoint. + typedef basic_resolver resolver; ///< A TCP resolver. + typedef basic_stream_socket socket; ///< A TCP socket. + typedef basic_socket_acceptor acceptor; ///< A TCP acceptor. + typedef basic_socket_iostream iostream; /// A TCP iostream. + + /// Disable coalescing of small segments (i.e. the Nagle algorithm). + struct no_delay : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + static const int _S_level = IPPROTO_TCP; + static const int _S_name = TCP_NODELAY; + }; + + // static members: + + /// A protocol object representing IPv4 TCP. + static constexpr tcp v4() noexcept { return tcp(AF_INET); } + /// A protocol object representing IPv6 TCP. + static constexpr tcp v6() noexcept { return tcp(AF_INET6); } + + tcp() = delete; + + constexpr int family() const noexcept { return _M_family; } + constexpr int type() const noexcept { return SOCK_STREAM; } + constexpr int protocol() const noexcept { return IPPROTO_TCP; } + + private: + constexpr explicit tcp(int __family) : _M_family(__family) { } + + int _M_family; + }; + + /** tcp comparisons + * @{ + */ + + inline bool + operator==(const tcp& __a, const tcp& __b) + { return __a.family() == __b.family(); } + + inline bool + operator!=(const tcp& __a, const tcp& __b) + { return !(__a == __b); } + + // @} + + /// The UDP datagram protocol. + class udp + { + public: + // types: + typedef basic_endpoint endpoint; + typedef basic_resolver resolver; + typedef basic_datagram_socket socket; + + // static members: + static constexpr udp v4() noexcept { return udp(AF_INET); } + static constexpr udp v6() noexcept { return udp(AF_INET6); } + + udp() = delete; + + constexpr int family() const noexcept { return _M_family; } + constexpr int type() const noexcept { return SOCK_DGRAM; } + constexpr int protocol() const noexcept { return IPPROTO_UDP; } + + private: + constexpr explicit udp(int __family) : _M_family(__family) { } + + int _M_family; + }; + + /** udp comparisons + * @{ + */ + + bool + operator==(const udp& __a, const udp& __b) + { return __a.family() == __b.family(); } + + inline bool + operator!=(const udp& __a, const udp& __b) + { return !(__a == __b); } + + // @} + + /// Restrict a socket created for an IPv6 protocol to IPv6 only. + struct v6_only : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + static const int _S_level = IPPROTO_IPV6; + static const int _S_name = IPV6_V6ONLY; + }; + +_GLIBCXX_END_NAMESPACE_VERSION + + namespace unicast { +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /// Set the default number of hops (TTL) for outbound datagrams. + struct hops : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + template + int + level(const _Protocol& __p) const noexcept + { return __p.family() == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP; } + + template + int + name(const _Protocol& __p) const noexcept + { return __p.family() == AF_INET6 ? IPV6_UNICAST_HOPS : IP_TTL; } + }; + +_GLIBCXX_END_NAMESPACE_VERSION + } // namespace unicast + + namespace multicast { +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /// Request that a socket joins a multicast group. + struct join_group + { + explicit + join_group(const address&); + + explicit + join_group(const address_v4&, const address_v4& = address_v4::any()); + + explicit + join_group(const address_v6&, unsigned int = 0); + + template + int + level(const _Protocol& __p) const noexcept + { return __p.family() == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP; } + + template + int + name(const _Protocol& __p) const noexcept + { + return __p.family() == AF_INET6 + ? IPV6_JOIN_GROUP : IP_ADD_MEMBERSHIP; + } + template + void* + data(const _Protocol&) noexcept + { return std::addressof(_M_value); } + + template + const void* + data(const _Protocol&) const noexcept + { return std::addressof(_M_value); } + + template + size_t + size(const _Protocol& __p) const noexcept + { + return __p.family() == AF_INET6 + ? sizeof(_M_value._M_v6) : sizeof(_M_value._M_v4); + } + + template + void + resize(const _Protocol& __p, size_t __s) + { + if (__s != size(__p)) + __throw_length_error("invalid value for socket option resize"); + } + + protected: + union + { + ipv6_mreq _M_v6; + ip_mreq _M_v4; + } _M_value; + }; + + /// Request that a socket leaves a multicast group. + struct leave_group + { + explicit + leave_group(const address&); + + explicit + leave_group(const address_v4&, const address_v4& = address_v4::any()); + + explicit + leave_group(const address_v6&, unsigned int = 0); + + template + int + level(const _Protocol& __p) const noexcept + { return __p.family() == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP; } + + template + int + name(const _Protocol& __p) const noexcept + { + return __p.family() == AF_INET6 + ? IPV6_LEAVE_GROUP : IP_DROP_MEMBERSHIP; + } + template + void* + data(const _Protocol&) noexcept + { return std::addressof(_M_value); } + + template + const void* + data(const _Protocol&) const noexcept + { return std::addressof(_M_value); } + + template + size_t + size(const _Protocol& __p) const noexcept + { + return __p.family() == AF_INET6 + ? sizeof(_M_value._M_v6) : sizeof(_M_value._M_v4); + } + + template + void + resize(const _Protocol& __p, size_t __s) + { + if (__s != size(__p)) + __throw_length_error("invalid value for socket option resize"); + } + + protected: + union + { + ipv6_mreq _M_v6; + ip_mreq _M_v4; + } _M_value; + }; + + /// Specify the network interface for outgoing multicast datagrams. + class outbound_interface + { + explicit + outbound_interface(const address_v4&); + + explicit + outbound_interface(unsigned int); + + template + int + level(const _Protocol& __p) const noexcept + { return __p.family() == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP; } + + template + int + name(const _Protocol& __p) const noexcept + { + return __p.family() == AF_INET6 + ? IPV6_MULTICAST_IF : IP_MULTICAST_IF; + } + + template + const void* + data(const _Protocol&) const noexcept + { return std::addressof(_M_value); } + + template + size_t + size(const _Protocol& __p) const noexcept + { + return __p.family() == AF_INET6 + ? sizeof(_M_value._M_v6) : sizeof(_M_value._M_v4); + } + + protected: + union { + unsigned _M_v6; + in_addr _M_v4; + } _M_value; + }; + + /// Set the default number of hops (TTL) for outbound datagrams. + struct hops : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + template + int + level(const _Protocol& __p) const noexcept + { return __p.family() == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP; } + + template + int + name(const _Protocol& __p) const noexcept + { + return __p.family() == AF_INET6 + ? IPV6_MULTICAST_HOPS : IP_MULTICAST_TTL; + } + }; + + /// Set whether datagrams are delivered back to the local application. + struct enable_loopback : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + template + int + level(const _Protocol& __p) const noexcept + { return __p.family() == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP; } + + template + int + name(const _Protocol& __p) const noexcept + { + return __p.family() == AF_INET6 + ? IPV6_MULTICAST_LOOP : IP_MULTICAST_LOOP; + } + }; + +_GLIBCXX_END_NAMESPACE_VERSION + } // namespace multicast + + // @} + +} // namespace ip +} // namespace v1 +} // namespace net +} // namespace experimental + + template<> + struct is_error_condition_enum + : public true_type {}; + + // hash support + template struct hash; + template<> + struct hash + : __hash_base + { + size_t + operator()(const argument_type& __a) const + { + if (__a.is_v4()) + return _Hash_impl::hash(__a.to_v4()); + else + return _Hash_impl::hash(__a.to_v6()); + } + }; + + template<> + struct hash + : __hash_base + { + size_t + operator()(const argument_type& __a) const + { return _Hash_impl::hash(__a.to_bytes()); } + }; + + template<> struct hash + : __hash_base + { + size_t + operator()(const argument_type& __a) const + { return _Hash_impl::hash(__a.to_bytes()); } + }; + +} // namespace std + +#endif // C++14 + +#endif // _GLIBCXX_EXPERIMENTAL_INTERNET diff --git a/libstdc++-v3/include/experimental/io_context b/libstdc++-v3/include/experimental/io_context new file mode 100644 index 00000000000..7b42442a034 --- /dev/null +++ b/libstdc++-v3/include/experimental/io_context @@ -0,0 +1,864 @@ +// -*- C++ -*- + +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file experimental/io_service + * This is a TS C++ Library header. + */ + +#ifndef _GLIBCXX_EXPERIMENTAL_IO_SERVICE +#define _GLIBCXX_EXPERIMENTAL_IO_SERVICE 1 + +#pragma GCC system_header + +#if __cplusplus >= 201402L + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +namespace experimental +{ +namespace net +{ +inline namespace v1 +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @ingroup networking + * @{ + */ + + class __socket_impl; + + /// An ExecutionContext for I/O operations. + class io_context : public execution_context + { + public: + // types: + + /// An executor for an io_context. + class executor_type + { + public: + // construct / copy / destroy: + + executor_type(const executor_type& __other) noexcept = default; + executor_type(executor_type&& __other) noexcept = default; + + executor_type& operator=(const executor_type& __other) noexcept = default; + executor_type& operator=(executor_type&& __other) noexcept = default; + + // executor operations: + + bool running_in_this_thread() const noexcept + { + lock_guard __lock(_M_ctx->_M_mtx); + auto __end = _M_ctx->_M_call_stack.end(); + return std::find(_M_ctx->_M_call_stack.begin(), __end, + this_thread::get_id()) != __end; + } + + io_context& context() const noexcept { return *_M_ctx; } + + void on_work_started() const noexcept { ++_M_ctx->_M_work_count; } + void on_work_finished() const noexcept { --_M_ctx->_M_work_count; } + + template + void + dispatch(_Func&& __f, const _ProtoAllocator& __a) const + { + if (running_in_this_thread()) + decay_t<_Func>{std::forward<_Func>(__f)}(); + else + post(std::forward<_Func>(__f), __a); + } + + template + void + post(_Func&& __f, const _ProtoAllocator& __a) const + { + lock_guard __lock(_M_ctx->_M_mtx); + // TODO (re-use functionality in system_context) + _M_ctx->_M_reactor._M_notify(); + } + + template + void + defer(_Func&& __f, const _ProtoAllocator& __a) const + { post(std::forward<_Func>(__f), __a); } + + private: + friend io_context; + + explicit + executor_type(io_context& __ctx) : _M_ctx(std::addressof(__ctx)) { } + + io_context* _M_ctx; + }; + + using count_type = size_t; + + // construct / copy / destroy: + + io_context() : _M_work_count(0) { } + + explicit + io_context(int __concurrency_hint) : _M_work_count(0) { } + + io_context(const io_context&) = delete; + io_context& operator=(const io_context&) = delete; + + // io_context operations: + + executor_type get_executor() noexcept { return executor_type(*this); } + + count_type + run() + { + count_type __n = 0; + while (run_one()) + if (__n != numeric_limits::max()) + ++__n; + return __n; + } + + template + count_type + run_for(const chrono::duration<_Rep, _Period>& __rel_time) + { return run_until(chrono::steady_clock::now() + __rel_time); } + + template + count_type + run_until(const chrono::time_point<_Clock, _Duration>& __abs_time) + { + count_type __n = 0; + while (run_one_until(__abs_time)) + if (__n != numeric_limits::max()) + ++__n; + return __n; + } + + count_type + run_one() + { return _M_do_one(chrono::milliseconds{-1}); } + + template + count_type + run_one_for(const chrono::duration<_Rep, _Period>& __rel_time) + { return run_one_until(chrono::steady_clock::now() + __rel_time); } + + template + count_type + run_one_until(const chrono::time_point<_Clock, _Duration>& __abs_time) + { + auto __now = _Clock::now(); + while (__now < __abs_time) + { + using namespace std::chrono; + auto __ms = duration_cast(__abs_time - __now); + if (_M_do_one(__ms)) + return 1; + __now = _Clock::now(); + } + return 0; + } + + count_type + poll() + { + count_type __n = 0; + while (poll_one()) + if (__n != numeric_limits::max()) + ++__n; + return __n; + } + + count_type + poll_one() + { return _M_do_one(chrono::milliseconds{0}); } + + void stop() + { + lock_guard __lock(_M_mtx); + _M_stopped = true; + _M_reactor._M_notify(); + } + + bool stopped() const noexcept + { + lock_guard __lock(_M_mtx); + return _M_stopped; + } + + void restart() + { + _M_stopped = false; + } + + private: + + template + friend class basic_waitable_timer; + + friend __socket_impl; + + template + friend class __basic_socket_impl; + + template + friend class basic_socket; + + template + friend class basic_datagram_socket; + + template + friend class basic_stream_socket; + + template + friend class basic_socket_acceptor; + + count_type + _M_outstanding_work() const + { return _M_work_count + !_M_ops.empty(); } + + struct __timer_queue_base : execution_context::service + { + // return milliseconds until next timer expires, or milliseconds::max() + virtual chrono::milliseconds _M_next() const = 0; + virtual bool run_one() = 0; + + protected: + explicit + __timer_queue_base(execution_context& __ctx) : service(__ctx) + { + auto& __ioc = static_cast(__ctx); + lock_guard __lock(__ioc._M_mtx); + __ioc._M_timers.push_back(this); + } + + mutable mutex _M_qmtx; + }; + + template + struct __timer_queue : __timer_queue_base + { + using key_type = __timer_queue; + + explicit + __timer_queue(execution_context& __ctx) : __timer_queue_base(__ctx) + { } + + void shutdown() noexcept { } + + io_context& context() noexcept + { return static_cast(service::context()); } + + // Start an asynchronous wait. + void + push(const _Timer& __t, function __h) + { + context().get_executor().on_work_started(); + lock_guard __lock(_M_qmtx); + _M_queue.emplace(__t, _M_next_id++, std::move(__h)); + // no need to notify reactor unless this timer went to the front? + } + + // Cancel all outstanding waits for __t + size_t + cancel(const _Timer& __t) + { + lock_guard __lock(_M_qmtx); + size_t __count = 0; + auto __last = _M_queue.end(); + for (auto __it = _M_queue.begin(), __end = __last; __it != __end; + ++__it) + { + if (__it->_M_key == __t._M_key.get()) + { + __it->cancel(); + __last = __it; + ++__count; + } + } + if (__count) + _M_queue._M_sort_to(__last); + return __count; + } + + // Cancel oldest outstanding wait for __t + bool + cancel_one(const _Timer& __t) + { + lock_guard __lock(_M_qmtx); + const auto __end = _M_queue.end(); + auto __oldest = __end; + for (auto __it = _M_queue.begin(); __it != __end; ++__it) + if (__it->_M_key == __t._M_key.get()) + if (__oldest == __end || __it->_M_id < __oldest->_M_id) + __oldest = __it; + if (__oldest == __end) + return false; + __oldest->cancel(); + _M_queue._M_sort_to(__oldest); + return true; + } + + chrono::milliseconds + _M_next() const override + { + typename _Timer::time_point __exp; + { + lock_guard __lock(_M_qmtx); + if (_M_queue.empty()) + return chrono::milliseconds::max(); // no pending timers + if (_M_queue.top()._M_key == nullptr) + return chrono::milliseconds::zero(); // cancelled, run now + __exp = _M_queue.top()._M_expiry; + } + auto __dur = _Timer::traits_type::to_wait_duration(__exp); + if (__dur < __dur.zero()) + __dur = __dur.zero(); + return chrono::duration_cast(__dur); + } + + private: + + bool run_one() override + { + auto __now = _Timer::clock_type::now(); + function __h; + error_code __ec; + { + lock_guard __lock(_M_qmtx); + + if (_M_queue.top()._M_key == nullptr) // cancelled + { + __h = std::move(_M_queue.top()._M_h); + __ec = std::make_error_code(errc::operation_canceled); + _M_queue.pop(); + } + else if (_M_queue.top()._M_expiry <= _Timer::clock_type::now()) + { + __h = std::move(_M_queue.top()._M_h); + _M_queue.pop(); + } + } + if (__h) + { + __h(__ec); + context().get_executor().on_work_finished(); + return true; + } + return false; + } + + using __timer_id_type = uint64_t; + + struct __pending_timer + { + __pending_timer(const _Timer& __t, uint64_t __id, + function __h) + : _M_expiry(__t.expiry()), _M_key(__t._M_key.get()), _M_id(__id), + _M_h(std::move(__h)) + { } + + typename _Timer::time_point _M_expiry; + _Key* _M_key; + __timer_id_type _M_id; + function _M_h; + + void cancel() { _M_expiry = _M_expiry.min(); _M_key = nullptr; } + + bool + operator<(const __pending_timer& __rhs) const + { return _M_expiry < __rhs._M_expiry; } + }; + + struct __queue : priority_queue<__pending_timer> + { + using iterator = + typename priority_queue<__pending_timer>::container_type::iterator; + + // expose begin/end/erase for direct access to underlying container + iterator begin() { return this->c.begin(); } + iterator end() { return this->c.end(); } + iterator erase(iterator __it) { return this->c.erase(__it); } + + void + _M_sort_to(iterator __it) + { std::stable_sort(this->c.begin(), ++__it); } + }; + + __queue _M_queue; + __timer_id_type _M_next_id = 0; + }; + + template + void + async_wait(const _Timer& __timer, _CompletionHandler&& __h) + { + auto& __queue = use_service<__timer_queue<_Timer>>(*this); + __queue.push(__timer, std::move(__h)); + _M_reactor._M_notify(); + } + + // Cancel all wait operations initiated by __timer. + template + size_t + cancel(const _Timer& __timer) + { + if (!has_service<__timer_queue<_Timer>>(*this)) + return 0; + + auto __c = use_service<__timer_queue<_Timer>>(*this).cancel(__timer); + if (__c != 0) + _M_reactor._M_notify(); + return __c; + } + + // Cancel the oldest wait operation initiated by __timer. + template + size_t + cancel_one(const _Timer& __timer) + { + if (!has_service<__timer_queue<_Timer>>(*this)) + return 0; + + if (use_service<__timer_queue<_Timer>>(*this).cancel_one(__timer)) + { + _M_reactor._M_notify(); + return 1; + } + return 0; + } + + template + void + async_wait(int __fd, int __w, _Op&& __op) + { + lock_guard __lock(_M_mtx); + // TODO need push_back, use std::list not std::forward_list + auto __tail = _M_ops.before_begin(), __it = _M_ops.begin(); + while (__it != _M_ops.end()) + { + ++__it; + ++__tail; + } + using __type = __async_operation_impl<_Op>; + _M_ops.emplace_after(__tail, + make_unique<__type>(std::move(__op), __fd, __w)); + _M_reactor._M_fd_interest(__fd, __w); + } + + void _M_add_fd(int __fd) { _M_reactor._M_add_fd(__fd); } + void _M_remove_fd(int __fd) { _M_reactor._M_remove_fd(__fd); } + + void cancel(int __fd, error_code&) + { + lock_guard __lock(_M_mtx); + const auto __end = _M_ops.end(); + auto __it = _M_ops.begin(); + auto __prev = _M_ops.before_begin(); + while (__it != __end && (*__it)->_M_is_cancelled()) + { + ++__it; + ++__prev; + } + auto __cancelled = __prev; + while (__it != __end) + { + if ((*__it)->_M_fd == __fd) + { + (*__it)->cancel(); + ++__it; + _M_ops.splice_after(__cancelled, _M_ops, __prev); + ++__cancelled; + } + else + { + ++__it; + ++__prev; + } + } + _M_reactor._M_not_interested(__fd); + } + + struct __async_operation + { + __async_operation(int __fd, int __ev) : _M_fd(__fd), _M_ev(__ev) { } + + virtual ~__async_operation() = default; + + int _M_fd; + short _M_ev; + + void cancel() { _M_fd = -1; } + bool _M_is_cancelled() const { return _M_fd == -1; } + virtual void run(io_context&) = 0; + }; + + template + struct __async_operation_impl : __async_operation + { + __async_operation_impl(_Op&& __op, int __fd, int __ev) + : __async_operation{__fd, __ev}, _M_op(std::move(__op)) { } + + _Op _M_op; + + void run(io_context& __ctx) + { + if (_M_is_cancelled()) + _M_op(std::make_error_code(errc::operation_canceled)); + else + _M_op(error_code{}); + } + }; + + atomic _M_work_count; + mutable mutex _M_mtx; + queue> _M_op; + bool _M_stopped = false; + + struct __monitor + { + __monitor(io_context& __c) : _M_ctx(__c) + { + lock_guard __lock(_M_ctx._M_mtx); + _M_ctx._M_call_stack.push_back(this_thread::get_id()); + } + + ~__monitor() + { + lock_guard __lock(_M_ctx._M_mtx); + _M_ctx._M_call_stack.pop_back(); + if (_M_ctx._M_outstanding_work() == 0) + { + _M_ctx._M_stopped = true; + _M_ctx._M_reactor._M_notify(); + } + } + + __monitor(__monitor&&) = delete; + + io_context& _M_ctx; + }; + + bool + _M_do_one(chrono::milliseconds __timeout) + { + const bool __block = __timeout != chrono::milliseconds::zero(); + + __reactor::__fdvec __fds; + + __monitor __mon{*this}; + + __timer_queue_base* __timerq = nullptr; + unique_ptr<__async_operation> __async_op; + + while (true) + { + if (__timerq) + { + if (__timerq->run_one()) + return true; + else + __timerq = nullptr; + } + + if (__async_op) + { + __async_op->run(*this); + // TODO need to unregister __async_op + return true; + } + + chrono::milliseconds __ms{0}; + + { + lock_guard __lock(_M_mtx); + + if (_M_stopped) + return false; + + // find first timer with something to do + for (auto __q : _M_timers) + { + auto __next = __q->_M_next(); + if (__next == __next.zero()) // ready to run immediately + { + __timerq = __q; + __ms = __next; + break; + } + else if (__next != __next.max() && __block + && (__next < __ms || __timerq == nullptr)) + { + __timerq = __q; + __ms = __next; + } + } + + if (__timerq && __ms == __ms.zero()) + continue; // restart loop to run a timer immediately + + if (!_M_ops.empty() && _M_ops.front()->_M_is_cancelled()) + { + _M_ops.front().swap(__async_op); + _M_ops.pop_front(); + continue; + } + + // TODO run any posted items + + if (__block) + { + if (__timerq == nullptr) + __ms = __timeout; + else if (__ms.zero() <= __timeout && __timeout < __ms) + __ms = __timeout; + else if (__ms.count() > numeric_limits::max()) + __ms = chrono::milliseconds{numeric_limits::max()}; + } + // else __ms == 0 and poll() will return immediately + + } + + auto __res = _M_reactor.wait(__fds, __ms); + + if (__res == __reactor::_S_retry) + continue; + + if (__res == __reactor::_S_timeout) + if (__timerq == nullptr) + return false; + else + continue; // timed out, so restart loop and process the timer + + __timerq = nullptr; + + if (__fds.empty()) // nothing to do + return false; + + lock_guard __lock(_M_mtx); + for (auto __it = _M_ops.begin(), __end = _M_ops.end(), + __prev = _M_ops.before_begin(); __it != __end; ++__it, ++__prev) + { + auto& __op = **__it; + auto __pos = std::lower_bound(__fds.begin(), __fds.end(), + __op._M_fd, + [](const auto& __p, int __fd) { return __p.fd < __fd; }); + if (__pos != __fds.end() && __pos->fd == __op._M_fd + && __pos->revents & __op._M_ev) + { + __it->swap(__async_op); + _M_ops.erase_after(__prev); + break; // restart loop and run op + } + } + } + } + + struct __reactor + { + __reactor() : _M_fds(1) + { + int __pipe[2]; + if (::pipe(__pipe) == -1) + __throw_system_error(errno); + if (::fcntl(__pipe[0], F_SETFL, O_NONBLOCK) == -1 + || ::fcntl(__pipe[1], F_SETFL, O_NONBLOCK) == -1) + { + int __e = errno; + ::close(__pipe[0]); + ::close(__pipe[1]); + __throw_system_error(__e); + } + _M_fds.back().events = POLLIN; + _M_fds.back().fd = __pipe[0]; + _M_notify_wr = __pipe[1]; + } + + ~__reactor() + { + ::close(_M_fds.back().fd); + ::close(_M_notify_wr); + } + + // write a notification byte to the pipe (ignoring errors) + void _M_notify() + { + int __n; + do { + __n = ::write(_M_notify_wr, "", 1); + } while (__n == -1 && errno == EINTR); + } + + // read all notification bytes from the pipe + void _M_on_notify() + { + // Drain the pipe. + char __buf[64]; + ssize_t __n; + do { + __n = ::read(_M_fds.back().fd, __buf, sizeof(__buf)); + } while (__n != -1 || errno == EINTR); + } + + void + _M_add_fd(int __fd) + { + auto __pos = _M_lower_bound(__fd); + if (__pos->fd == __fd) + __throw_system_error((int)errc::invalid_argument); + _M_fds.insert(__pos, __fdvec::value_type{})->fd = __fd; + _M_notify(); + } + + void + _M_remove_fd(int __fd) + { + auto __pos = _M_lower_bound(__fd); + if (__pos->fd == __fd) + _M_fds.erase(__pos); + // else bug! + _M_notify(); + } + + void + _M_fd_interest(int __fd, int __w) + { + auto __pos = _M_lower_bound(__fd); + if (__pos->fd == __fd) + __pos->events |= __w; + // else bug! + _M_notify(); + } + + void + _M_not_interested(int __fd) + { + auto __pos = _M_lower_bound(__fd); + if (__pos->fd == __fd) + __pos->events = 0; + _M_notify(); + } + + using __fdvec = vector<::pollfd>; + + // Find first element p such that !(p.fd < __fd) + // N.B. always returns a dereferencable iterator. + __fdvec::iterator + _M_lower_bound(int __fd) + { + return std::lower_bound(_M_fds.begin(), _M_fds.end() - 1, + __fd, [](const auto& __p, int __fd) { return __p.fd < __fd; }); + } + + enum __status { _S_retry, _S_timeout, _S_ok, _S_error }; + + __status + wait(__fdvec& __fds, chrono::milliseconds __timeout) + { + // XXX not thread-safe! + __fds = _M_fds; // take snapshot to pass to poll() + + int __res = ::poll(__fds.data(), __fds.size(), __timeout.count()); + + if (__res == -1) + { + __fds.clear(); + if (errno == EINTR) + return _S_retry; + return _S_error; // XXX ??? + } + else if (__res == 0) + { + __fds.clear(); + return _S_timeout; + } + else if (__fds.back().revents != 0) // something changed, restart + { + __fds.clear(); + _M_on_notify(); + return _S_retry; + } + + auto __part = std::stable_partition(__fds.begin(), __fds.end() - 1, + [](const __fdvec::value_type& __p) { return __p.revents != 0; }); + __fds.erase(__part, __fds.end()); + + return _S_ok; + } + + __fdvec _M_fds; // _M_fds.back() is the read end of the self-pipe + int _M_notify_wr; // write end of the self-pipe + }; + + __reactor _M_reactor; + + vector<__timer_queue_base*> _M_timers; + forward_list> _M_ops; + + vector _M_call_stack; + }; + + inline bool + operator==(const io_context::executor_type& __a, + const io_context::executor_type& __b) noexcept + { + // https://github.com/chriskohlhoff/asio-tr2/issues/201 + using executor_type = io_context::executor_type; + return std::addressof(executor_type(__a).context()) + == std::addressof(executor_type(__b).context()); + } + + inline bool + operator!=(const io_context::executor_type& __a, + const io_context::executor_type& __b) noexcept + { return !(__a == __b); } + + template<> struct is_executor : true_type {}; + + /// @} + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace v1 +} // namespace net +} // namespace experimental +} // namespace std + +#endif // C++14 + +#endif // _GLIBCXX_EXPERIMENTAL_IO_SERVICE diff --git a/libstdc++-v3/include/experimental/net b/libstdc++-v3/include/experimental/net new file mode 100644 index 00000000000..3d97546c365 --- /dev/null +++ b/libstdc++-v3/include/experimental/net @@ -0,0 +1,45 @@ +// -*- C++ -*- + +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file experimental/net + * This is a TS C++ Library header. + */ + +#ifndef _GLIBCXX_EXPERIMENTAL_NET +#define _GLIBCXX_EXPERIMENTAL_NET + +#pragma GCC system_header + +#if __cplusplus >= 201402L + +#include +#include +#include +#include +#include +#include + +#endif // C++14 + +#endif // _GLIBCXX_EXPERIMENTAL_NET diff --git a/libstdc++-v3/include/experimental/netfwd b/libstdc++-v3/include/experimental/netfwd new file mode 100644 index 00000000000..a0311a9aa69 --- /dev/null +++ b/libstdc++-v3/include/experimental/netfwd @@ -0,0 +1,135 @@ +// -*- C++ -*- + +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file experimental/netfwd + * This is a TS C++ Library header. + */ + +#ifndef _GLIBCXX_EXPERIMENTAL_NETFWD +#define _GLIBCXX_EXPERIMENTAL_NETFWD 1 + +#pragma GCC system_header + +#if __cplusplus >= 201402L + +// #define __cpp_lib_experimental_net 201803 +// #define __cpp_lib_experimental_net_extensible 201803 + +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +namespace experimental +{ +namespace net +{ +inline namespace v1 +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @ingroup networking + * @{ + */ + + class execution_context; + template + class executor_binder; + template + class executor_work_guard; + class system_executor; + class executor; + template + class strand; + + class io_service; + + template struct wait_traits; + template> + class basic_waitable_timer; + typedef basic_waitable_timer system_timer; + typedef basic_waitable_timer steady_timer; + typedef basic_waitable_timer + high_resolution_timer; + + template + class basic_socket; + template + class basic_datagram_socket; + template + class basic_stream_socket; + template + class basic_socket_acceptor; + template> + class basic_socket_streambuf; + template> + class basic_socket_iostream; + + /// @} + +_GLIBCXX_END_NAMESPACE_VERSION + +namespace ip +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @ingroup networking + * @{ + */ + class address; + class address_v4; + class address_v6; + class address_iterator_v4; + class address_iterator_v6; + class address_range_v4; + class address_range_v6; + class network_v4; + class network_v6; + template + class basic_endpoint; + template + class basic_resolver_entry; + template + class basic_resolver_results; + template + class basic_resolver; + class tcp; + class udp; + /// @} + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace ip + + +} // namespace v1 +} // namespace net +} // namespace experimental +} // namespace std + +#endif // C++14 + +#endif // _GLIBCXX_EXPERIMENTAL_NETFWD diff --git a/libstdc++-v3/include/experimental/socket b/libstdc++-v3/include/experimental/socket new file mode 100644 index 00000000000..7adb42e7e20 --- /dev/null +++ b/libstdc++-v3/include/experimental/socket @@ -0,0 +1,2474 @@ +// -*- C++ -*- + +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file experimental/socket + * This is a TS C++ Library header. + */ + +#ifndef _GLIBCXX_EXPERIMENTAL_SOCKET +#define _GLIBCXX_EXPERIMENTAL_SOCKET + +#pragma GCC system_header + +#if __cplusplus >= 201402L + +#include +#include +#include +#include +#include +#include +#include +#if _GLIBCXX_HAVE_UNISTD_H +# include +# include +# include +# include +# include +# include +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +namespace experimental +{ +namespace net +{ +inline namespace v1 +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @ingroup networking + * @{ + */ + + enum class socket_errc { // TODO decide values + already_open = 3, + not_found = 4 + }; + + const error_category& socket_category() noexcept + { + struct __cat : error_category + { + const char* name() const noexcept { return "socket"; } + + std::string message(int __e) const + { + if (__e == (int)socket_errc::already_open) + return "already open"; + else if (__e == (int)socket_errc::not_found) + return "endpoint not found"; + return "socket error"; + } + + virtual void __message(int) { } // TODO dual ABI XXX + }; + static __cat __c; + return __c; + } + + inline error_code + make_error_code(socket_errc __e) noexcept + { return error_code(static_cast(__e), socket_category()); } + + inline error_condition + make_error_condition(socket_errc __e) noexcept + { return error_condition(static_cast(__e), socket_category()); } + + template> + struct __is_endpoint_impl : false_type + { }; + + // Check Endpoint requirements. + template + auto + __endpoint_reqs(const _Tp* __a = 0) + -> enable_if_t<__and_< + is_default_constructible<_Tp>, + __is_value_constructible<_Tp>, + is_same__protocol()), typename _Tp::protocol_type> + >::value, + __void_t< typename _Tp::protocol_type::endpoint >>; + + template + struct __is_endpoint_impl<_Tp, decltype(__endpoint_reqs<_Tp>())> + : true_type + { }; + + template + struct __is_endpoint : __is_endpoint_impl<_Tp> + { }; + + // TODO Endpoint reqs for extensible implementations + // TODO _Protocol reqs + // TODO AcceptableProtocol reqs + // TODO GettableSocket reqs + // TODO SettableSocket reqs + // TODO BooleanSocketOption reqs + // TODO IntegerSocketOption reqs + // TODO _IoControlCommand reqs + // TODO _ConnectCondition reqs + + /** @brief Sockets + * @{ + */ + + class socket_base + { + public: + struct broadcast : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + static const int _S_level = SOL_SOCKET; + static const int _S_name = SO_BROADCAST; + }; + + struct debug : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + static const int _S_level = SOL_SOCKET; + static const int _S_name = SO_DEBUG; + }; + + struct do_not_route : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + static const int _S_level = SOL_SOCKET; + static const int _S_name = SO_DONTROUTE; + }; + + struct keep_alive : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + static const int _S_level = SOL_SOCKET; + static const int _S_name = SO_KEEPALIVE; + }; + + struct linger : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + linger() noexcept = default; + + linger(bool __e, chrono::seconds __t) noexcept + { + enabled(__e); + timeout(__t); + } + + bool + enabled() const noexcept + { return _M_value.l_onoff != 0; } + + void + enabled(bool __e) noexcept + { _M_value.l_onoff = int(__e); } + + chrono::seconds + timeout() const noexcept + { return chrono::seconds(_M_value.l_linger); } + + void + timeout(chrono::seconds __t) noexcept + { _M_value.l_linger = __t.count(); } + + static const int _S_level = SOL_SOCKET; + static const int _S_name = SO_LINGER; + }; + + struct out_of_band_inline : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + static const int _S_level = SOL_SOCKET; + static const int _S_name = SO_OOBINLINE; + }; + + struct receive_buffer_size : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + static const int _S_level = SOL_SOCKET; + static const int _S_name = SO_RCVBUF; + }; + + struct receive_low_watermark : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + static const int _S_level = SOL_SOCKET; + static const int _S_name = SO_RCVLOWAT; + }; + + struct reuse_address : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + static const int _S_level = SOL_SOCKET; + static const int _S_name = SO_REUSEADDR; + }; + + struct send_buffer_size : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + static const int _S_level = SOL_SOCKET; + static const int _S_name = SO_SNDBUF; + }; + + struct send_low_watermark : __sockopt_crtp + { + using __sockopt_crtp::__sockopt_crtp; + + static const int _S_level = SOL_SOCKET; + static const int _S_name = SO_SNDLOWAT; + }; + + enum shutdown_type : int + { + __shutdown_receive = SHUT_RD, + __shutdown_send = SHUT_WR, + __shutdown_both = SHUT_RDWR + }; + static constexpr shutdown_type shutdown_receive = __shutdown_receive; + static constexpr shutdown_type shutdown_send = __shutdown_send; + static constexpr shutdown_type shutdown_both = __shutdown_both; + + enum wait_type : int + { + __wait_read = POLLIN, + __wait_write = POLLOUT, + __wait_error = POLLERR + }; + static constexpr wait_type wait_read = __wait_read; + static constexpr wait_type wait_write = __wait_write; + static constexpr wait_type wait_error = __wait_error; + + enum message_flags : int + { + __message_peek = MSG_PEEK, + __message_oob = MSG_OOB, + __message_dontroute = MSG_DONTROUTE + }; + static constexpr message_flags message_peek = __message_peek; + static constexpr message_flags message_out_of_band = __message_oob; + static constexpr message_flags message_do_not_route = __message_dontroute; + + static const int max_listen_connections = SOMAXCONN; + + protected: + socket_base() = default; + ~socket_base() = default; + + struct __msg_hdr : ::msghdr + { +#ifdef IOV_MAX + using __iovec_array = array<::iovec, IOV_MAX>; +#elif _GLIBCXX_HAVE_UNISTD_H + struct __iovec_array + { + __iovec_array() : _M_ptr(new ::iovec[size()]) { } + + ::iovec& operator[](size_t __n) noexcept { return _M_ptr[__n]; } + + ::iovec* data() noexcept { return _M_ptr.get(); } + + static size_t size() + { + static const size_t __iov_max = ::sysconf(_SC_IOV_MAX); + return __iov_max; + } + + private: + unique_ptr<::iovec[]> _M_ptr; + }; +#else + using __iovec_array = array<::iovec, 16>; +#endif + + __iovec_array _M_iov; + + template + explicit + __msg_hdr(const _BufferSequence& __buffers) + : msghdr() + { + auto __buf = net::buffer_sequence_begin(__buffers); + const auto __bufend = net::buffer_sequence_end(__buffers); + size_t __len = 0; + while (__buf != __bufend && __len != _M_iov.size()) + { + _M_iov[__len].iov_base = (void*)__buf->data(); + _M_iov[__len].iov_len = __buf->size(); + ++__buf; + ++__len; + } + this->msg_iovlen = __len; + this->msg_iov = _M_iov.data(); + } + + template + __msg_hdr(const _BufferSequence& __buffers, const _Endpoint& __ep) + : __msg_hdr(__buffers) + { + this->msg_name = __ep.data(); + this->msg_namelen = __ep.size(); + } + }; + }; + + constexpr socket_base::message_flags + operator&(socket_base::message_flags __f1, socket_base::message_flags __f2) + { return socket_base::message_flags( int(__f1) & int(__f2) ); } + + constexpr socket_base::message_flags + operator|(socket_base::message_flags __f1, socket_base::message_flags __f2) + { return socket_base::message_flags( int(__f1) | int(__f2) ); } + + constexpr socket_base::message_flags + operator^(socket_base::message_flags __f1, socket_base::message_flags __f2) + { return socket_base::message_flags( int(__f1) ^ int(__f2) ); } + + constexpr socket_base::message_flags + operator~(socket_base::message_flags __f) + { return socket_base::message_flags( ~int(__f) ); } + + inline socket_base::message_flags& + operator&=(socket_base::message_flags& __f1, socket_base::message_flags __f2) + { return __f1 = (__f1 & __f2); } + + inline socket_base::message_flags& + operator|=(socket_base::message_flags& __f1, socket_base::message_flags __f2) + { return __f1 = (__f1 | __f2); } + + inline socket_base::message_flags& + operator^=(socket_base::message_flags& __f1, socket_base::message_flags __f2) + { return __f1 = (__f1 ^ __f2); } + +#if _GLIBCXX_HAVE_UNISTD_H + + class __socket_impl + { + protected: + + using executor_type = io_context::executor_type; + using native_handle_type = int; + + explicit + __socket_impl(io_context& __ctx) : _M_ctx(std::addressof(__ctx)) { } + + __socket_impl(__socket_impl&& __rhs) + : _M_ctx(__rhs._M_ctx), + _M_sockfd(std::exchange(__rhs._M_sockfd, -1)), + _M_bits(std::exchange(__rhs._M_bits, {})) + { } + + __socket_impl& + operator=(__socket_impl&& __rhs) + { + _M_ctx = __rhs._M_ctx; + _M_sockfd = std::exchange(__rhs._M_sockfd, -1); + _M_bits = std::exchange(__rhs._M_bits, {}); + return *this; + } + + ~__socket_impl() = default; + + __socket_impl(const __socket_impl&) = delete; + __socket_impl& operator=(const __socket_impl&) = delete; + + executor_type get_executor() noexcept { return _M_ctx->get_executor(); } + + native_handle_type native_handle() noexcept { return _M_sockfd; } + + bool is_open() const noexcept { return _M_sockfd != -1; } + + void + close(error_code& __ec) + { + if (is_open()) + { + cancel(__ec); + if (!__ec) + { + if (::close(_M_sockfd) == -1) + __ec.assign(errno, generic_category()); + else + { + get_executor().context()._M_remove_fd(_M_sockfd); + _M_sockfd = -1; + } + } + } + } + + void cancel(error_code& __ec) { _M_ctx->cancel(_M_sockfd, __ec); } + + void + non_blocking(bool __mode, error_code&) + { _M_bits.non_blocking = __mode; } + + bool non_blocking() const { return _M_bits.non_blocking; } + + void + native_non_blocking(bool __mode, error_code& __ec) + { + int __flags = ::fcntl(_M_sockfd, F_GETFL, 0); + if (__flags >= 0) + { + if (__mode) + __flags |= O_NONBLOCK; + else + __flags &= ~O_NONBLOCK; + __flags = ::fcntl(_M_sockfd, F_SETFL, __flags); + } + if (__flags == -1) + __ec.assign(errno, generic_category()); + else + { + __ec.clear(); + _M_bits.native_non_blocking = __mode; + } + } + + bool + native_non_blocking() const + { + if (_M_bits.native_non_blocking == -1) + { + const int __flags = ::fcntl(_M_sockfd, F_GETFL, 0); + if (__flags == -1) + return 0; + _M_bits.native_non_blocking = __flags & O_NONBLOCK; + } + return _M_bits.native_non_blocking; + } + + io_context* _M_ctx; + int _M_sockfd{-1}; + struct { + unsigned non_blocking : 1; + mutable signed native_non_blocking : 2; + unsigned enable_connection_aborted : 1; + } _M_bits{}; + }; + + template + class __basic_socket_impl : public __socket_impl + { + using __base = __socket_impl; + + protected: + using protocol_type = _Protocol; + using endpoint_type = typename protocol_type::endpoint; + + explicit + __basic_socket_impl(io_context& __ctx) : __base(__ctx) { } + + __basic_socket_impl(__basic_socket_impl&&) = default; + + template + __basic_socket_impl(__basic_socket_impl<_OtherProtocol>&& __rhs) + : __base(std::move(__rhs)), _M_protocol(std::move(__rhs._M_protocol)) + { } + + __basic_socket_impl& + operator=(__basic_socket_impl&& __rhs) + { + if (this == std::addressof(__rhs)) + return *this; + _M_close(); + __base::operator=(std::move(__rhs)); + return *this; + } + + ~__basic_socket_impl() { _M_close(); } + + __basic_socket_impl(const __basic_socket_impl&) = delete; + __basic_socket_impl& operator=(const __basic_socket_impl&) = delete; + + void + open(const protocol_type& __protocol, error_code& __ec) + { + if (is_open()) + __ec = socket_errc::already_open; + else + { + _M_protocol = __protocol; + _M_sockfd = ::socket(__protocol.family(), __protocol.type(), + __protocol.protocol()); + if (is_open()) + { + get_executor().context()._M_add_fd(_M_sockfd); + __ec.clear(); + } + else + __ec.assign(errno, std::generic_category()); + } + } + + void + assign(const protocol_type& __protocol, + const native_handle_type& __native_socket, + error_code& __ec) + { + if (is_open()) + __ec = socket_errc::already_open; + else + { + _M_protocol = __protocol; + _M_bits.native_non_blocking = -1; + _M_sockfd = __native_socket; + if (is_open()) + { + get_executor().context()._M_add_fd(_M_sockfd); + __ec.clear(); + } + else + __ec.assign(errno, std::generic_category()); + } + } + + template + void + set_option(const _SettableSocketOption& __option, error_code& __ec) + { + int __result = ::setsockopt(_M_sockfd, __option.level(_M_protocol), + __option.name(_M_protocol), + __option.data(_M_protocol), + __option.size(_M_protocol)); + if (__result == -1) + __ec.assign(errno, generic_category()); + else + __ec.clear(); + } + + template + void + get_option(_GettableSocketOption& __option, error_code& __ec) const + { + int __result = ::getsockopt(_M_sockfd, __option.level(_M_protocol), + __option.name(_M_protocol), + __option.data(_M_protocol), + __option.size(_M_protocol)); + if (__result == -1) + __ec.assign(errno, generic_category()); + else + __ec.clear(); + } + + template + void + io_control(_IoControlCommand& __command, error_code& __ec) + { + int __result = ::ioctl(_M_sockfd, __command.name(_M_protocol), + __command.data(_M_protocol)); + if (__result == -1) + __ec.assign(errno, generic_category()); + else + __ec.clear(); + } + + endpoint_type + local_endpoint(error_code& __ec) const + { + endpoint_type __endpoint; + socklen_t __endpoint_len = __endpoint.capacity(); + if (::getsockname(_M_sockfd, (sockaddr*)__endpoint.data(), + &__endpoint_len) == -1) + { + __ec.assign(errno, generic_category()); + return endpoint_type{}; + } + __ec.clear(); + __endpoint.resize(__endpoint_len); + return __endpoint; + } + + void + bind(const endpoint_type& __endpoint, error_code& __ec) + { + if (::bind(_M_sockfd, (sockaddr*)__endpoint.data(), __endpoint.size()) + == -1) + __ec.assign(errno, generic_category()); + else + __ec.clear(); + } + + _Protocol _M_protocol{ endpoint_type{}.protocol() }; + + private: + void + _M_close() + { + if (is_open()) + { + error_code __ec; + cancel(__ec); + set_option(socket_base::linger{false, chrono::seconds{}}, __ec); + ::close(_M_sockfd); + } + } + }; + + template + class basic_socket + : public socket_base, private __basic_socket_impl<_Protocol> + { + using __base = __basic_socket_impl<_Protocol>; + + public: + // types: + + typedef io_context::executor_type executor_type; + typedef int native_handle_type; + typedef _Protocol protocol_type; + typedef typename protocol_type::endpoint endpoint_type; + + // basic_socket operations: + + executor_type get_executor() noexcept { return __base::get_executor(); } + + native_handle_type + native_handle() noexcept { return __base::native_handle(); } + + void + open(const protocol_type& __protocol = protocol_type()) + { open(__protocol, __throw_on_error{"basic_socket::open"}); } + + void + open(const protocol_type& __protocol, error_code& __ec) + { __base::open(__protocol, __ec); } + + void + assign(const protocol_type& __protocol, + const native_handle_type& __native_socket) + { + assign(__protocol, __native_socket, + __throw_on_error{"basic_socket::assign"}); + } + + void + assign(const protocol_type& __protocol, + const native_handle_type& __native_socket, + error_code& __ec) + { __base::assign(__protocol, __native_socket, __ec); } + + bool is_open() const noexcept { return __base::is_open(); } + + void close() { close(__throw_on_error{"basic_socket::close"}); } + + void close(error_code& __ec) { __base::close(); } + + void cancel() { cancel(__throw_on_error{"basic_socket::cancel"}); } + + void cancel(error_code& __ec) { __base::cancel(__ec); } + + template + void + set_option(const _SettableSocketOption& __option) + { set_option(__option, __throw_on_error{"basic_socket::set_option"}); } + + template + void + set_option(const _SettableSocketOption& __option, error_code& __ec) + { __base::set_option(__option, __ec); } + + template + void + get_option(_GettableSocketOption& __option) const + { get_option(__option, __throw_on_error{"basic_socket::get_option"}); } + + template + void + get_option(_GettableSocketOption& __option, error_code& __ec) const + { __base::get_option(__option, __ec); } + + template + void + io_control(_IoControlCommand& __command) + { + io_control(__command, __throw_on_error{"basic_socket::io_control"}); + } + + template + void + io_control(_IoControlCommand& __command, error_code& __ec) + { __base::io_control(__command, __ec); } + + void + non_blocking(bool __mode) + { non_blocking(__mode, __throw_on_error{"basic_socket::non_blocking"}); } + + void + non_blocking(bool __mode, error_code& __ec) + { __base::non_blocking(__mode, __ec); } + + bool non_blocking() const { return __base::non_blocking(); } + + void + native_non_blocking(bool __mode) + { + native_non_blocking(__mode, __throw_on_error{ + "basic_socket::native_non_blocking"}); + } + + void + native_non_blocking(bool __mode, error_code& __ec) + { __base::native_non_blocking(__mode, __ec); } + + bool + native_non_blocking() const + { return __base::native_non_blocking(); } + + bool at_mark() const + { return at_mark(__throw_on_error{"basic_socket::at_mark"}); } + + bool + at_mark(error_code& __ec) const + { + const int __result = ::sockatmark(native_handle()); + if (__result == -1) + __ec.assign(errno, generic_category()); + else + { + __ec.clear(); + return __result; + } + } + + size_t + available() const + { return available(__throw_on_error{"basic_socket::available"}); } + + size_t + available(error_code& __ec) const + { + if (!is_open()) + { + __ec = std::make_error_code(errc::bad_file_descriptor); + return 0; + } +#ifdef FIONREAD + int __avail = 0; + if (::ioctl(this->_M_sockfd, FIONREAD, &__avail) == -1) + { + __ec.assign(errno, generic_category()); + return 0; + } + __ec.clear(); + return __avail; +#else + return 0; +#endif + } + + void + bind(const endpoint_type& __endpoint) + { return bind(__endpoint, __throw_on_error{"basic_socket::bind"}); } + + void + bind(const endpoint_type& __endpoint, error_code& __ec) + { __base::bind(__endpoint, __ec); } + + void shutdown(shutdown_type __what) + { return shutdown(__what, __throw_on_error{"basic_socket::shutdown"}); } + + void + shutdown(shutdown_type __what, error_code& __ec) + { + if (::shutdown(native_handle(), static_cast(__what)) == -1) + __ec.assign(errno, generic_category()); + else + __ec.clear(); + } + + endpoint_type + local_endpoint() const + { + return local_endpoint( + __throw_on_error{"basic_socket::local_endpoint"}); + } + + endpoint_type + local_endpoint(error_code& __ec) const + { return __base::local_endpoint(__ec); } + + endpoint_type + remote_endpoint() const + { + return remote_endpoint( + __throw_on_error{"basic_socket::remote_endpoint"}); + } + + endpoint_type + remote_endpoint(error_code& __ec) const + { + endpoint_type __endpoint; + socklen_t __endpoint_len = __endpoint.capacity(); + if (::getpeername(this->_M_sockfd, (sockaddr*)__endpoint.data(), + &__endpoint_len) + == -1) + { + __ec.assign(errno, generic_category()); + return endpoint_type{}; + } + __ec.clear(); + __endpoint.resize(__endpoint_len); + return __endpoint; + } + + void + connect(const endpoint_type& __endpoint) + { + return connect(__endpoint, __throw_on_error{"basic_socket::connect"}); + } + + void + connect(const endpoint_type& __endpoint, error_code& __ec) + { + if (!is_open()) + { + open(__endpoint.protocol(), __ec); + if (__ec) + return; + } + if (::connect(native_handle(), (const sockaddr*)__endpoint.data(), + __endpoint.size()) == -1) + __ec.assign(errno, generic_category()); + else + __ec.clear(); + } + + template + __deduced_t<_CompletionToken, void(error_code)> + async_connect(const endpoint_type& __endpoint, + _CompletionToken&& __token) + { + async_completion<_CompletionToken, void(error_code)> __init{__token}; + + if (!is_open()) + { + error_code __ec; + open(__endpoint.protocol(), __ec); + if (__ec) + { + auto __ex = net::get_associated_executor( + __init.completion_handler, get_executor()); + auto __a = get_associated_allocator( + __init.completion_handler, std::allocator()); + __ex.post( + [__h=std::move(__init.completion_handler), __ec] + () mutable + { __h(__ec); }, __a); + return __init.result.get(); + } + } + + get_executor().context().async_wait( native_handle(), + socket_base::wait_read, + [__h = std::move(__init.completion_handler), + __ep = std::move(__endpoint), + __fd = native_handle()] + (error_code __ec) mutable { + if (!__ec && ::connect(__fd, (const sockaddr*)__ep.data(), + __ep.size()) == -1) + __ec.assign(errno, generic_category()); + __h(__ec); + }); + return __init.result.get(); + } + + void + wait(wait_type __w) + { return wait(__w, __throw_on_error{"basic_socket::wait"}); } + + void + wait(wait_type __w, error_code& __ec) + { + ::pollfd __fd; + __fd.fd = native_handle(); + __fd.events = static_cast(__w); + int __res = ::poll(&__fd, 1, -1); + if (__res == -1) + __ec.assign(errno, generic_category()); + else + __ec.clear(); + } + + template + __deduced_t<_CompletionToken, void(error_code)> + async_wait(wait_type __w, _CompletionToken&& __token) + { + async_completion<_CompletionToken, void(error_code)> __init{__token}; + get_executor().context().async_wait( native_handle(), + static_cast(__w), + [__h = std::move(__init.completion_handler)] + (error_code __ec) mutable { + __h(__ec); + }); + return __init.result.get(); + } + + protected: + // construct / copy / destroy: + + using __base::__base; + + explicit + basic_socket(io_context& __ctx) : __base(__ctx) { } + + basic_socket(io_context& __ctx, const protocol_type& __protocol) + : __base(__ctx) + { open(__protocol); } + + basic_socket(io_context& __ctx, const endpoint_type& __endpoint) + : basic_socket(std::addressof(__ctx), __endpoint.protocol()) + { bind(__endpoint); } + + basic_socket(io_context& __ctx, const protocol_type& __protocol, + const native_handle_type& __native_socket) + : __base(__ctx) + { assign(__protocol, __native_socket); } + + basic_socket(const basic_socket&) = delete; + + basic_socket(basic_socket&& __rhs) = default; + + template>> + basic_socket(basic_socket<_OtherProtocol>&& __rhs) + : __base(std::move(__rhs)) { } + + ~basic_socket() = default; + + basic_socket& operator=(const basic_socket&) = delete; + + basic_socket& operator=(basic_socket&& __rhs) = default; + + template + enable_if_t::value, + basic_socket&> + operator=(basic_socket<_OtherProtocol>&& __rhs) + { return *this = basic_socket{std::move(__rhs)}; } + }; + + template + class basic_datagram_socket : public basic_socket<_Protocol> + { + using __base = basic_socket<_Protocol>; + + public: + // types: + + typedef int native_handle_type; + typedef _Protocol protocol_type; + typedef typename protocol_type::endpoint endpoint_type; + + // construct / copy / destroy: + + explicit + basic_datagram_socket(io_context& __ctx) : __base(__ctx) { } + + basic_datagram_socket(io_context& __ctx, const protocol_type& __protocol) + : __base(__ctx, __protocol) { } + + basic_datagram_socket(io_context& __ctx, const endpoint_type& __endpoint) + : __base(__ctx, __endpoint) { } + + basic_datagram_socket(io_context& __ctx, const protocol_type& __protocol, + const native_handle_type& __native_socket) + : __base(__ctx, __protocol, __native_socket) { } + + basic_datagram_socket(const basic_datagram_socket&) = delete; + + basic_datagram_socket(basic_datagram_socket&& __rhs) = default; + + template>> + basic_datagram_socket(basic_datagram_socket<_OtherProtocol>&& __rhs) + : __base(std::move(__rhs)) { } + + ~basic_datagram_socket() = default; + + basic_datagram_socket& operator=(const basic_datagram_socket&) = delete; + + basic_datagram_socket& operator=(basic_datagram_socket&& __rhs) = default; + + template + enable_if_t::value, + basic_datagram_socket&> + operator=(basic_datagram_socket<_OtherProtocol>&& __rhs) + { + __base::operator=(std::move(__rhs)); + return *this; + } + + // basic_datagram_socket operations: + + template + size_t + receive(const _MutableBufferSequence& __buffers) + { + return receive(__buffers, socket_base::message_flags(), + __throw_on_error{"basic_datagram_socket::receive"}); + } + + template + size_t + receive(const _MutableBufferSequence& __buffers, error_code& __ec) + { return receive(__buffers, socket_base::message_flags(), __ec); } + + template + size_t + receive(const _MutableBufferSequence& __buffers, + socket_base::message_flags __flags) + { + return receive(__buffers, __flags, + __throw_on_error{"basic_datagram_socket::receive"}); + } + + template + size_t + receive(const _MutableBufferSequence& __buffers, + socket_base::message_flags __flags, error_code& __ec) + { + socket_base::__msg_hdr __msg(__buffers); + ssize_t __result = ::recvmsg(this->native_handle(), &__msg, + static_cast(__flags)); + if (__result == -1) + { + __ec.assign(errno, generic_category()); + return 0; + } + __ec.clear(); + return __result; + } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_receive(const _MutableBufferSequence& __buffers, + _CompletionToken&& __token) + { + return async_receive(__buffers, socket_base::message_flags(), + std::forward<_CompletionToken>(__token)); + } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_receive(const _MutableBufferSequence& __buffers, + socket_base::message_flags __flags, + _CompletionToken&& __token) + { + async_completion<_CompletionToken, void(error_code, size_t)> + __init{__token}; + + this->get_executor().context().async_wait(this->native_handle(), + socket_base::wait_read, + [__h = std::move(__init.completion_handler), + &__buffers, __flags = static_cast(__flags), + __fd = this->native_handle()] + (error_code __ec) mutable { + if (__ec) + { + __h(__ec); + return; + } + socket_base::__msg_hdr __msg(__buffers); + ssize_t __result = ::recvmsg(__fd, &__msg, __flags); + if (__result == -1) + { + __ec.assign(errno, generic_category()); + __result = 0; + } + else + __ec.clear(); + __h(__ec, __result); + }); + return __init.result.get(); + } + + template + size_t + receive_from(const _MutableBufferSequence& __buffers, + endpoint_type& __sender) + { + return receive_from(__buffers, __sender, + socket_base::message_flags(), + __throw_on_error{ + "basic_datagram_socket::receive_from"}); + } + + template + size_t + receive_from(const _MutableBufferSequence& __buffers, + endpoint_type& __sender, error_code& __ec) + { + return receive_from(__buffers, __sender, + socket_base::message_flags(), __ec); + } + + template + size_t + receive_from(const _MutableBufferSequence& __buffers, + endpoint_type& __sender, + socket_base::message_flags __flags) + { + return receive_from(__buffers, __sender, __flags, + __throw_on_error{ + "basic_datagram_socket::receive_from"}); + } + + template + size_t + receive_from(const _MutableBufferSequence& __buffers, + endpoint_type& __sender, + socket_base::message_flags __flags, + error_code& __ec) + { + socket_base::__msg_hdr __msg(__buffers, __sender); + ssize_t __result = ::recvmsg(this->native_handle(), &__msg, + static_cast(__flags)); + if (__result == -1) + { + __ec.assign(errno, generic_category()); + return 0; + } + __ec.clear(); + __sender.resize(__msg.msg_namelen); + return __result; + } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_receive_from(const _MutableBufferSequence& __buffers, + endpoint_type& __sender, + _CompletionToken&& __token) + { + return async_receive_from(__buffers, __sender, + socket_base::message_flags(), + std::forward<_CompletionToken>(__token)); + } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_receive_from(const _MutableBufferSequence& __buffers, + endpoint_type& __sender, + socket_base::message_flags __flags, + _CompletionToken&& __token) + { + async_completion<_CompletionToken, void(error_code, size_t)> + __init{__token}; + + this->get_executor().context().async_wait( this->native_handle(), + socket_base::wait_read, + [__h = std::move(__init.completion_handler), + &__buffers, __flags = static_cast(__flags), + __sender = std::move(__sender), + __fd = this->native_handle()] + (error_code __ec) mutable { + if (__ec) + { + __h(__ec); + return; + } + socket_base::__msg_hdr __msg(__buffers, __sender); + ssize_t __result = ::recvmsg(__fd, &__msg, __flags); + if (__result == -1) + { + __ec.assign(errno, generic_category()); + __result = 0; + } + else + { + __ec.clear(); + __sender.resize(__msg.msg_namelen); + } + __h(__ec, __result); + }); + return __init.result.get(); + } + + template + size_t + send(const _ConstBufferSequence& __buffers) + { + return send(__buffers, socket_base::message_flags(), + __throw_on_error{"basic_datagram_socket::send"}); + } + + template + size_t + send(const _ConstBufferSequence& __buffers, error_code& __ec) + { return send(__buffers, socket_base::message_flags(), __ec); } + + template + size_t + send(const _ConstBufferSequence& __buffers, + socket_base::message_flags __flags) + { + return send(__buffers, __flags, + __throw_on_error{"basic_datagram_socket::send"}); + } + + template + size_t + send(const _ConstBufferSequence& __buffers, + socket_base::message_flags __flags, error_code& __ec) + { + socket_base::__msg_hdr __msg(__buffers); + ssize_t __result = ::sendmsg(this->native_handle(), &__msg, + static_cast(__flags)); + if (__result == -1) + { + __ec.assign(errno, generic_category()); + return 0; + } + __ec.clear(); + return __result; + } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_send(const _ConstBufferSequence& __buffers, + _CompletionToken&& __token) + { + return async_send(__buffers, socket_base::message_flags(), + std::forward<_CompletionToken>(__token)); + } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_send(const _ConstBufferSequence& __buffers, + socket_base::message_flags __flags, + _CompletionToken&& __token) + { + async_completion<_CompletionToken, void(error_code, size_t)> + __init{__token}; + + this->get_executor().context().async_wait( this->native_handle(), + socket_base::wait_write, + [__h = std::move(__init.completion_handler), + &__buffers, __flags = static_cast(__flags), + __fd = this->native_handle()] + (error_code __ec) mutable { + if (__ec) + { + __h(__ec); + return; + } + socket_base::__msg_hdr __msg(__buffers); + ssize_t __result = ::sendmsg(__fd, &__msg, __flags); + if (__result == -1) + { + __ec.assign(errno, generic_category()); + __result = 0; + } + else + __ec.clear(); + __h(__ec, __result); + }); + return __init.result.get(); + } + + template + size_t + send_to(const _ConstBufferSequence& __buffers, + const endpoint_type& __recipient) + { + return send_to(__buffers, __recipient, + socket_base::message_flags(), + __throw_on_error{"basic_datagram_socket::send_to"}); + } + + template + size_t + send_to(const _ConstBufferSequence& __buffers, + const endpoint_type& __recipient, error_code& __ec) + { + return send_to(__buffers, __recipient, + socket_base::message_flags(), __ec); + } + + template + size_t + send_to(const _ConstBufferSequence& __buffers, + const endpoint_type& __recipient, + socket_base::message_flags __flags) + { + return send_to(__buffers, __recipient, __flags, + __throw_on_error{"basic_datagram_socket::send_to"}); + } + + template + size_t + send_to(const _ConstBufferSequence& __buffers, + const endpoint_type& __recipient, + socket_base::message_flags __flags, error_code& __ec) + { + socket_base::__msg_hdr __msg(__buffers, __recipient); + ssize_t __result = ::sendmsg(this->native_handle(), &__msg, + static_cast(__flags)); + if (__result == -1) + { + __ec.assign(errno, generic_category()); + return 0; + } + __ec.clear(); + __recipient.resize(__msg.msg_namelen); + return __result; + } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_send_to(const _ConstBufferSequence& __buffers, + const endpoint_type& __recipient, + _CompletionToken&& __token) + { + return async_send_to(__buffers, __recipient, + socket_base::message_flags(), + std::forward<_CompletionToken>(__token)); + } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_send_to(const _ConstBufferSequence& __buffers, + const endpoint_type& __recipient, + socket_base::message_flags __flags, + _CompletionToken&& __token) + { + async_completion<_CompletionToken, void(error_code, size_t)> + __init{__token}; + + this->get_executor().context().async_wait( this->native_handle(), + socket_base::wait_write, + [__h = std::move(__init.completion_handler), + &__buffers, __flags = static_cast(__flags), + __recipient = std::move(__recipient), + __fd = this->native_handle()] + (error_code __ec) mutable { + if (__ec) + { + __h(__ec); + return; + } + socket_base::__msg_hdr __msg(__buffers, __recipient); + ssize_t __result = ::sendmsg(__fd, &__msg, __flags); + if (__result == -1) + { + __ec.assign(errno, generic_category()); + __result = 0; + } + else + { + __ec.clear(); + __recipient.resize(__msg.msg_namelen); + } + __h(__ec, __result); + }); + return __init.result.get(); + } + }; + + template + class basic_stream_socket : public basic_socket<_Protocol> + { + using __base = basic_socket<_Protocol>; + + public: + // types: + + typedef int native_handle_type; + typedef _Protocol protocol_type; + typedef typename protocol_type::endpoint endpoint_type; + + // construct / copy / destroy: + + explicit + basic_stream_socket(io_context& __ctx) : __base(__ctx) { } + + basic_stream_socket(io_context& __ctx, const protocol_type& __protocol) + : __base(__ctx, __protocol) { } + + basic_stream_socket(io_context& __ctx, const endpoint_type& __endpoint) + : __base(__ctx, __endpoint) { } + + basic_stream_socket(io_context& __ctx, const protocol_type& __protocol, + const native_handle_type& __native_socket) + : __base(__ctx, __protocol, __native_socket) { } + + basic_stream_socket(const basic_stream_socket&) = delete; + + basic_stream_socket(basic_stream_socket&& __rhs) = default; + + template>> + basic_stream_socket(basic_stream_socket<_OtherProtocol>&& __rhs) + : __base(std::move(__rhs)) { } + + ~basic_stream_socket() = default; + + basic_stream_socket& operator=(const basic_stream_socket&) = delete; + + basic_stream_socket& operator=(basic_stream_socket&& __rhs) = default; + + template + enable_if_t::value, + basic_stream_socket&> + operator=(basic_stream_socket<_OtherProtocol>&& __rhs) + { + __base::operator=(std::move(__rhs)); + return *this; + } + + // basic_stream_socket operations: + + template + size_t + receive(const _MutableBufferSequence& __buffers) + { + return receive(__buffers, socket_base::message_flags(), + __throw_on_error{"basic_stream_socket::receive"}); + } + + template + size_t + receive(const _MutableBufferSequence& __buffers, error_code& __ec) + { return receive(__buffers, socket_base::message_flags(), __ec); } + + template + size_t + receive(const _MutableBufferSequence& __buffers, + socket_base::message_flags __flags) + { + return receive(__buffers, __flags, + __throw_on_error{"basic_stream_socket::receive"}); + } + + template + size_t + receive(const _MutableBufferSequence& __buffers, + socket_base::message_flags __flags, error_code& __ec) + { + if (__buffer_empty(__buffers)) + { + __ec.clear(); + return 0; + } + + socket_base::__msg_hdr __msg(__buffers); + ssize_t __result = ::recvmsg(this->native_handle(), &__msg, + static_cast(__flags)); + if (__result >= 0) + { + __ec.clear(); + return __result; + } + __ec.assign(errno, generic_category()); + return 0; + } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_receive(const _MutableBufferSequence& __buffers, + _CompletionToken&& __token) + { + return async_receive(__buffers, socket_base::message_flags(), + std::forward<_CompletionToken>(__token)); + } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_receive(const _MutableBufferSequence& __buffers, + socket_base::message_flags __flags, + _CompletionToken&& __token) + { + async_completion<_CompletionToken, void(error_code, size_t)> + __init{__token}; + + if (__buffer_empty(__buffers)) + { + auto __ex = net::get_associated_executor( + __init.completion_handler, this->get_executor()); + auto __a = get_associated_allocator( + __init.completion_handler, std::allocator()); + __ex.post( + [__h=std::move(__init.completion_handler)] () mutable + { __h(error_code{}, 0); }, __a); + return __init.result.get(); + } + + this->get_executor().context().async_wait(this->native_handle(), + socket_base::wait_read, + [__h = std::move(__init.completion_handler), + &__buffers, __flags = static_cast(__flags), + __fd = this->native_handle()] + (error_code __ec) mutable { + if (__ec) + { + __h(__ec); + return; + } + socket_base::__msg_hdr __msg(__buffers); + ssize_t __result = ::recvmsg(__fd, &__msg, __flags); + if (__result == -1) + { + __ec.assign(errno, generic_category()); + __result = 0; + } + else + __ec.clear(); + __h(__ec, __result); + }); + return __init.result.get(); + } + + template + size_t + send(const _ConstBufferSequence& __buffers) + { + return send(__buffers, socket_base::message_flags(), + __throw_on_error{"basic_stream_socket::send"}); + } + + template + size_t + send(const _ConstBufferSequence& __buffers, error_code& __ec) + { return send(__buffers, socket_base::message_flags(), __ec); } + + template + size_t + send(const _ConstBufferSequence& __buffers, + socket_base::message_flags __flags) + { + return send(__buffers, socket_base::message_flags(), + __throw_on_error{"basic_stream_socket::send"}); + } + + template + size_t + send(const _ConstBufferSequence& __buffers, + socket_base::message_flags __flags, error_code& __ec) + { + if (__buffer_empty(__buffers)) + { + __ec.clear(); + return 0; + } + + socket_base::__msg_hdr __msg(__buffers); + ssize_t __result = ::sendmsg(this->native_handle(), &__msg, + static_cast(__flags)); + if (__result >= 0) + { + __ec.clear(); + return __result; + } + __ec.assign(errno, generic_category()); + return 0; + } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_send(const _ConstBufferSequence& __buffers, + _CompletionToken&& __token) + { + return async_send(__buffers, socket_base::message_flags(), + std::forward<_CompletionToken>(__token)); + } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_send(const _ConstBufferSequence& __buffers, + socket_base::message_flags __flags, + _CompletionToken&& __token) + { + async_completion<_CompletionToken, void(error_code, size_t)> + __init{__token}; + + if (__buffer_empty(__buffers)) + { + auto __ex = net::get_associated_executor( + __init.completion_handler, this->get_executor()); + auto __a = get_associated_allocator( + __init.completion_handler, std::allocator()); + __ex.post( + [__h=std::move(__init.completion_handler)] () mutable + { __h(error_code{}, 0); }, __a); + return __init.result.get(); + } + + this->get_executor().context().async_wait(this->native_handle(), + socket_base::wait_write, + [__h = std::move(__init.completion_handler), + &__buffers, __flags = static_cast(__flags), + __fd = this->native_handle()] + (error_code __ec) mutable { + if (__ec) + { + __h(__ec); + return; + } + socket_base::__msg_hdr __msg(__buffers); + ssize_t __result = ::sendmsg(__fd, &__msg, __flags); + if (__result == -1) + { + __ec.assign(errno, generic_category()); + __result = 0; + } + else + __ec.clear(); + __h(__ec, __result); + }); + return __init.result.get(); + } + + template + size_t + read_some(const _MutableBufferSequence& __buffers) + { + return receive(__buffers, + __throw_on_error{"basic_stream_socket::read_some"}); + } + + template + size_t + read_some(const _MutableBufferSequence& __buffers, error_code& __ec) + { return receive(__buffers, __ec); } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_read_some(const _MutableBufferSequence& __buffers, + _CompletionToken&& __token) + { + return async_receive(__buffers, + std::forward<_CompletionToken>(__token)); + } + + template + size_t + write_some(const _ConstBufferSequence& __buffers) + { + return send(__buffers, + __throw_on_error{"basic_stream_socket:write_some"}); + } + + template + size_t + write_some(const _ConstBufferSequence& __buffers, error_code& __ec) + { return send(__buffers, __ec); } + + template + __deduced_t<_CompletionToken, void(error_code, size_t)> + async_write_some(const _ConstBufferSequence& __buffers, + _CompletionToken&& __token) + { + return async_send(__buffers, + std::forward<_CompletionToken>(__token)); + } + }; + + template + class basic_socket_acceptor + : public socket_base, private __basic_socket_impl<_AcceptableProtocol> + { + using __base = __basic_socket_impl<_AcceptableProtocol>; + + public: + // types: + + typedef io_context::executor_type executor_type; + typedef int native_handle_type; + typedef _AcceptableProtocol protocol_type; + typedef typename protocol_type::endpoint endpoint_type; + typedef typename protocol_type::socket socket_type; + + // construct / copy / destroy: + + explicit + basic_socket_acceptor(io_context& __ctx) + : __base(__ctx), _M_protocol(endpoint_type{}.protocol()) { } + + basic_socket_acceptor(io_context& __ctx, + const protocol_type& __protocol) + : __base(__ctx), _M_protocol(__protocol) + { open(__protocol); } + + basic_socket_acceptor(io_context& __ctx, const endpoint_type& __endpoint, + bool __reuse_addr = true) + : basic_socket_acceptor(__ctx, __endpoint.protocol()) + { + if (__reuse_addr) + set_option(reuse_address(true)); + bind(__endpoint); + listen(); + } + + basic_socket_acceptor(io_context& __ctx, const protocol_type& __protocol, + const native_handle_type& __native_acceptor) + : basic_socket_acceptor(__ctx, __protocol) + { assign(__protocol, __native_acceptor); } + + basic_socket_acceptor(const basic_socket_acceptor&) = delete; + + basic_socket_acceptor(basic_socket_acceptor&&) = default; + + template>> + basic_socket_acceptor(basic_socket_acceptor<_OtherProtocol>&& __rhs) + : __base(std::move(__rhs)) { } + + ~basic_socket_acceptor() = default; + + basic_socket_acceptor& operator=(const basic_socket_acceptor&) = delete; + + basic_socket_acceptor& operator=(basic_socket_acceptor&&) = default; + + template + enable_if_t::value, + basic_socket_acceptor&> + operator=(basic_socket_acceptor<_OtherProtocol>&& __rhs) + { + __base::operator=(std::move(__rhs)); + return *this; + } + + // basic_socket_acceptor operations: + + executor_type get_executor() noexcept { return __base::get_executor(); } + + native_handle_type + native_handle() noexcept { return __base::native_handle(); } + + void + open(const protocol_type& __protocol = protocol_type()) + { open(__protocol, __throw_on_error{"basic_socket_acceptor::open"}); } + + void + open(const protocol_type& __protocol, error_code& __ec) + { __base::open(__protocol, __ec); } + + void + assign(const protocol_type& __protocol, + const native_handle_type& __native_acceptor) + { + assign(__protocol, __native_acceptor, + __throw_on_error{"basic_socket_acceptor::assign"}); + } + + void + assign(const protocol_type& __protocol, + const native_handle_type& __native_acceptor, + error_code& __ec) + { __base::assign(__protocol, __native_acceptor, __ec); } + + bool + is_open() const noexcept { return __base::is_open(); } + + void + close() { close(__throw_on_error{"basic_socket_acceptor::close"}); } + + void + close(error_code& __ec) { __base::_close(__ec); } + + void + cancel() { cancel(__throw_on_error{"basic_socket_acceptor::cancel"}); } + + void + cancel(error_code& __ec) { __base::cancel(__ec); } + + template + void + set_option(const _SettableSocketOption& __option) + { + set_option(__option, + __throw_on_error{"basic_socket_acceptor::set_option"}); + } + + template + void + set_option(const _SettableSocketOption& __option, error_code& __ec) + { __base::set_option(__option, __ec); } + + template + void + get_option(_GettableSocketOption& __option) const + { + get_option(__option, + __throw_on_error{"basic_socket_acceptor::get_option"}); + } + + template + void + get_option(_GettableSocketOption& __option, error_code& __ec) const + { __base::get_option(__option, __ec); } + + template + void + io_control(_IoControlCommand& __command) + { + io_control(__command, + __throw_on_error{"basic_socket_acceptor::io_control"}); + } + + template + void + io_control(_IoControlCommand& __command, error_code& __ec) + { __base::io_control(__command, __ec); } + + void + non_blocking(bool __mode) + { + non_blocking(__mode, + __throw_on_error{"basic_socket_acceptor::non_blocking"}); + } + + void + non_blocking(bool __mode, error_code& __ec) + { __base::non_blocking(__mode, __ec); } + + bool non_blocking() const { return __base::non_blocking(); } + + void + native_non_blocking(bool __mode) + { + native_non_blocking(__mode, __throw_on_error{ + "basic_socket_acceptor::native_non_blocking"}); + } + + void + native_non_blocking(bool __mode, error_code& __ec) + { __base::native_non_blocking(__mode, __ec); } + + bool + native_non_blocking() const + { return __base::native_non_blocking(); } + + void + bind(const endpoint_type& __endpoint) + { + return bind(__endpoint, + __throw_on_error{"basic_socket_acceptor::bind"}); + } + + void + bind(const endpoint_type& __endpoint, error_code& __ec) + { __base::bind(__endpoint, __ec); } + + void + listen(int __backlog = max_listen_connections) + { + return listen(__backlog, + __throw_on_error{"basic_socket_acceptor::listen"}); + } + + void listen(int __backlog, error_code& __ec) + { + if (::listen(native_handle(), __backlog) == -1) + __ec.assign(errno, generic_category()); + else + __ec.clear(); + } + + endpoint_type + local_endpoint() const + { + return local_endpoint( + __throw_on_error{"basic_socket_acceptor::local_endpoint"}); + } + + endpoint_type + local_endpoint(error_code& __ec) const + { return __base::local_endpoint(__ec); } + + void + enable_connection_aborted(bool __mode) + { __base::_M_bits.enable_connection_aborted = __mode; } + + bool + enable_connection_aborted() const + { return __base::_M_bits.enable_connection_aborted; } + + socket_type + accept() + { return accept(__throw_on_error{"basic_socket_acceptor::accept"}); } + + socket_type + accept(error_code& __ec) + { return accept(get_executor().context(), __ec); } + + socket_type accept(io_context& __ctx) + { + return accept(__ctx, + __throw_on_error{"basic_socket_acceptor::accept"}); + } + + socket_type + accept(io_context& __ctx, error_code& __ec) + { + do + { + int __h = ::accept(native_handle(), nullptr, 0); + if (__h != -1) + { + __ec.clear(); + return socket_type{__ctx, _M_protocol, __h}; + } + } while (errno == ECONNABORTED && enable_connection_aborted()); + __ec.assign(errno, generic_category()); + return socket_type{__ctx}; + } + + template + __deduced_t<_CompletionToken, void(error_code, socket_type)> + async_accept(_CompletionToken&& __token) + { + return async_accept(get_executor().context(), + std::forward<_CompletionToken>(__token)); + } + + template + __deduced_t<_CompletionToken, void(error_code, socket_type)> + async_accept(io_context& __ctx, _CompletionToken&& __token) + { + async_completion<_CompletionToken, void(error_code, socket_type)> + __init{__token}; + + __ctx.get_executor().context().async_wait(native_handle(), + socket_base::wait_read, + [__h = std::move(__init.completion_handler), + __connabort = enable_connection_aborted(), + __fd = native_handle(), + __protocol = _M_protocol, + &__ctx + ] + (error_code __ec) mutable { + if (__ec) + { + __h(__ec, socket_type(__ctx)); + return; + } + do + { + int __newfd = ::accept(__fd, nullptr, 0); + if (__newfd != -1) + { + __ec.clear(); + __h(__ec, socket_type{__ctx, __protocol, __newfd}); + return; + } + } while (errno == ECONNABORTED && __connabort); + __ec.assign(errno, generic_category()); + __h(__ec, socket_type(__ctx)); + }); + return __init.result.get(); + } + + socket_type + accept(endpoint_type& __endpoint) + { + return accept(get_executor().context(), __endpoint, + __throw_on_error{"basic_socket_acceptor::accept"}); + } + + socket_type + accept(endpoint_type& __endpoint, error_code& __ec) + { return accept(get_executor().context(), __endpoint, __ec); } + + socket_type + accept(io_context& __ctx, endpoint_type& __endpoint) + { + return accept(__ctx, __endpoint, + __throw_on_error{"basic_socket_acceptor::accept"}); + } + + socket_type + accept(io_context& __ctx, endpoint_type& __endpoint, error_code& __ec) + { + do + { + socklen_t __len = __endpoint.capacity(); + int __h = ::accept(native_handle(), (sockaddr*)__endpoint.data(), + &__len); + if (__h != -1) + { + __endpoint.resize(__len); + return socket_type{__ctx, _M_protocol, __h}; + } + } while (errno == ECONNABORTED && enable_connection_aborted()); + __ec.assign(errno, generic_category()); + return socket_type{__ctx}; + } + + template + __deduced_t<_CompletionToken, void(error_code, socket_type)> + async_accept(endpoint_type& __endpoint, + _CompletionToken&& __token) + { + return async_accept(get_executor().context(), __endpoint, + std::forward<_CompletionToken>(__token)); + } + + template + __deduced_t<_CompletionToken, void(error_code, socket_type)> + async_accept(io_context& __ctx, endpoint_type& __endpoint, + _CompletionToken&& __token) + { + async_completion<_CompletionToken, void(error_code, socket_type)> + __init{__token}; + + __ctx.get_executor().context().async_wait(native_handle(), + socket_base::wait_read, + [__h = std::move(__init.completion_handler), + __ep = std::move(__endpoint), + __connabort = enable_connection_aborted(), + __fd = native_handle(), + &__ctx + ] + (error_code __ec) mutable { + if (__ec) + { + __h(__ec, socket_type(__ctx)); + return; + } + do + { + socklen_t __len = __ep.capacity(); + int __newfd = ::accept(__fd, __ep.data, &__len); + if (__newfd != -1) + { + __ep.resize(__len); + auto __protocol = __ep.protocol(); + __ec.clear(); + __h(__ec, socket_type{__ctx, __protocol, __newfd}); + return; + } + } while (errno == ECONNABORTED && __connabort); + __ec.assign(errno, generic_category()); + __h(__ec, socket_type(__ctx)); + }); + return __init.result.get(); + } + + void + wait(wait_type __w) + { wait(__w, __throw_on_error{"basic_socket_acceptor::wait"}); } + + void + wait(wait_type __w, error_code& __ec) + { + ::pollfd __fds; + __fds.fd = native_handle(); + __fds.events = __w; // __w | POLLIN; + if (::poll(&__fds, 1, -1) == -1) + __ec.assign(errno, generic_category()); + else + __ec.clear(); + } + + template + __deduced_t<_CompletionToken, void(error_code)> + async_wait(wait_type __w, _CompletionToken&& __token) + { + async_completion<_CompletionToken, void(error_code)> __init{__token}; + get_executor().context().async_wait( native_handle(), + static_cast(__w), + [__h = std::move(__init.completion_handler)] + (error_code __ec) mutable { + __h(__ec); + }); + return __init.result.get(); + } + + private: + protocol_type _M_protocol; + }; + + // @} + + /** @brief Socket streams + * @{ + */ + + template + class basic_socket_streambuf : public basic_streambuf + { + public: + // types: + + typedef _Protocol protocol_type; + typedef typename protocol_type::endpoint endpoint_type; + typedef _Clock clock_type; + typedef typename clock_type::time_point time_point; + typedef typename clock_type::duration duration; + typedef _WaitTraits wait_traits_type; + + // construct / copy / destroy: + + basic_socket_streambuf() : _M_socket(_S_ctx()) { } + + explicit + basic_socket_streambuf(basic_stream_socket __s) + : _M_socket(std::move(__s)) { } + + basic_socket_streambuf(const basic_socket_streambuf&) = delete; + + basic_socket_streambuf(basic_socket_streambuf&& __rhs); // TODO + + + virtual ~basic_socket_streambuf(); // TODO + + basic_socket_streambuf& operator=(const basic_socket_streambuf&) = delete; + + basic_socket_streambuf& operator=(basic_socket_streambuf&& __rhs); // TODO + + // members: + + basic_socket_streambuf* connect(const endpoint_type& __e); // TODO + + template + basic_socket_streambuf* connect(_Args&&... ); // TODO + + basic_socket_streambuf* close(); // TODO + + basic_socket& socket() { return _M_socket; } + error_code error() const { return _M_ec; } + + time_point expiry() const { return _M_expiry; } + + void + expires_at(const time_point& __t) + { _M_expiry = __t; } + + void + expires_after(const duration& __d) + { expires_at(clock_type::now() + __d); } + + protected: + // overridden virtual functions: // TODO + virtual int_type underflow() override; + virtual int_type pbackfail(int_type __c = traits_type::eof()) override; + virtual int_type overflow(int_type __c = traits_type::eof()) override; + virtual int sync() override; + virtual streambuf* setbuf(char_type* __s, streamsize __n) override; + + private: + static io_context& + _S_ctx() + { + static io_context __ctx; + return __ctx; + } + + basic_stream_socket _M_socket; + error_code _M_ec; + time_point _M_expiry{ time_point::max() }; + }; + + template + class basic_socket_iostream : public basic_iostream + { + using __streambuf_type + = basic_socket_streambuf<_Protocol, _Clock, _WaitTraits>; + + public: + // types: + + typedef _Protocol protocol_type; + typedef typename protocol_type::endpoint endpoint_type; + typedef _Clock clock_type; + typedef typename clock_type::time_point time_point; + typedef typename clock_type::duration duration; + typedef _WaitTraits wait_traits_type; + + // construct / copy / destroy: + + // TODO base-from-member ? + basic_socket_iostream() : basic_iostream(nullptr), _M_sb() + { + this->init(std::addressof(_M_sb)); + this->setf(std::ios::unitbuf); + } + + explicit + basic_socket_iostream(basic_stream_socket __s) + : basic_iostream(nullptr), _M_sb(std::move(__s)) + { + this->init(std::addressof(_M_sb)); + this->setf(std::ios::unitbuf); + } + + basic_socket_iostream(const basic_socket_iostream&) = delete; + + basic_socket_iostream(basic_socket_iostream&& __rhs) + : basic_iostream(nullptr), _M_sb(std::move(__rhs._M_sb)) + // XXX ??? ^^^^^^^ + { + // XXX ??? this->init(std::addressof(_M_sb)); + this->set_rbduf(std::addressof(_M_sb)); + } + + template + explicit + basic_socket_iostream(_Args&&... __args) + : basic_iostream(nullptr), _M_sb() + { + this->init(std::addressof(_M_sb)); + this->setf(std::ios::unitbuf); + connect(forward<_Args>(__args)...); + } + + basic_socket_iostream& operator=(const basic_socket_iostream&) = delete; + + basic_socket_iostream& operator=(basic_socket_iostream&& __rhs); // TODO + + // members: + + template + void + connect(_Args&&... __args) + { + if (rdbuf()->connect(forward<_Args>(__args)...) == nullptr) + this->setstate(failbit); + } + + void + close() + { + if (rdbuf()->close() == nullptr) + this->setstate(failbit); + } + + basic_socket_streambuf* + rdbuf() const + { return const_cast<__streambuf_type*>(std::addressof(_M_sb)); } + + basic_socket& socket() { return rdbuf()->socket(); } + error_code error() const { return rdbuf()->error(); } + + time_point expiry() const { return rdbuf()->expiry(); } + void expires_at(const time_point& __t) { rdbuf()->expires_at(__t); } + void expires_after(const duration& __d) { rdbuf()->expires_after(__d); } + + private: + __streambuf_type _M_sb; + }; + + // @} + + /** @brief synchronous connect operations + * @{ + */ + + template + inline typename _Protocol::endpoint + connect(basic_socket<_Protocol>& __s, + const _EndpointSequence& __endpoints, + _ConnectCondition __c, error_code& __ec) + { + __ec.clear(); + bool __found = false; + for (auto& __ep : __endpoints) + { + if (__c(__ec, __ep)) + { + __found = true; + __s.close(__ec); + if (!__ec) + __s.open(__ep.protocol(), __ec); + if (!__ec) + __s.connect(__ep, __ec); + if (!__ec) + return __ep; + } + } + if (!__found) + __ec = socket_errc::not_found; + return typename _Protocol::endpoint{}; + } + + template + inline _InputIterator + connect(basic_socket<_Protocol>& __s, + _InputIterator __first, _InputIterator __last, + _ConnectCondition __c, error_code& __ec) + { + __ec.clear(); + bool __found = false; + for (auto __i = __first; __i != __last; ++__i) + { + if (__c(__ec, *__i)) + { + __found = true; + __s.close(__ec); + if (!__ec) + __s.open(typename _Protocol::endpoint(*__i).protocol(), __ec); + if (!__ec) + __s.connect(*__i, __ec); + if (!__ec) + return __i; + } + } + if (!__found) + __ec = socket_errc::not_found; + return __last; + } + + template + inline typename _Protocol::endpoint + connect(basic_socket<_Protocol>& __s, + const _EndpointSequence& __endpoints, + _ConnectCondition __c) + { + return net::connect(__s, __endpoints, __c, __throw_on_error{"connect"}); + } + + template + inline _InputIterator + connect(basic_socket<_Protocol>& __s, + _InputIterator __first, _InputIterator __last, + _ConnectCondition __c) + { + return net::connect(__s, __first, __last, __c, + __throw_on_error{"connect"}); + } + + template + inline typename _Protocol::endpoint + connect(basic_socket<_Protocol>& __s, + const _EndpointSequence& __endpoints) + { + return net::connect(__s, __endpoints, [](auto, auto){ return true; }, + __throw_on_error{"connect"}); + } + + template + inline typename _Protocol::endpoint + connect(basic_socket<_Protocol>& __s, + const _EndpointSequence& __endpoints, + error_code& __ec) + { + return net::connect(__s, __endpoints, [](auto, auto){ return true; }, + __ec); + } + + template + inline _InputIterator + connect(basic_socket<_Protocol>& __s, + _InputIterator __first, _InputIterator __last) + { + return net::connect(__s, __first, __last, [](auto, auto){ return true; }, + __throw_on_error{"connect"}); + } + + template + inline _InputIterator + connect(basic_socket<_Protocol>& __s, + _InputIterator __first, _InputIterator __last, + error_code& __ec) + { + return net::connect(__s, __first, __last, [](auto, auto){ return true; }, + __ec); + } + + // @} + + /** @brief asynchronous connect operations + * @{ + */ + + template + inline + __deduced_t<_CompletionToken, + void(error_code, typename _Protocol::endpoint)> + async_connect(basic_socket<_Protocol>& __s, + const _EndpointSequence& __endpoints, + _ConnectCondition __c, _CompletionToken&& __token); // TODO + + template + inline + __deduced_t<_CompletionToken, + void(error_code, typename _Protocol::endpoint)> + async_connect(basic_socket<_Protocol>& __s, + const _EndpointSequence& __endpoints, + _CompletionToken&& __token) + { + return net::async_connect(__s, __endpoints, + [](auto, auto){ return true; }, + forward<_CompletionToken>(__token)); + } + + template + inline + __deduced_t<_CompletionToken, void(error_code, _InputIterator)> + async_connect(basic_socket<_Protocol>& __s, + _InputIterator __first, _InputIterator __last, + _ConnectCondition __c, _CompletionToken&& __token); // TODO + + template + inline + __deduced_t<_CompletionToken, void(error_code, _InputIterator)> + async_connect(basic_socket<_Protocol>& __s, + _InputIterator __first, _InputIterator __last, + _CompletionToken&& __token) + { + return net::async_connect(__s, __first, __last, + [](auto, auto){ return true; }, + forward<_CompletionToken>(__token)); + } + + // @} + +#endif // _GLIBCXX_HAVE_UNISTD_H + + // @} + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace v1 +} // namespace net +} // namespace experimental + + template<> + struct is_error_code_enum + : public true_type {}; + +} // namespace std + +#endif // C++14 + +#endif // _GLIBCXX_EXPERIMENTAL_SOCKET diff --git a/libstdc++-v3/include/experimental/timer b/libstdc++-v3/include/experimental/timer new file mode 100644 index 00000000000..3ec365944da --- /dev/null +++ b/libstdc++-v3/include/experimental/timer @@ -0,0 +1,208 @@ +// -*- C++ -*- + +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file experimental/timer + * This is a TS C++ Library header. + */ + +#ifndef _GLIBCXX_EXPERIMENTAL_TIMER +#define _GLIBCXX_EXPERIMENTAL_TIMER 1 + +#pragma GCC system_header + +#if __cplusplus >= 201402L + +#include +#include +#include +#include +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +namespace experimental +{ +namespace net +{ +inline namespace v1 +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @ingroup networking + * @{ + */ + + template + struct wait_traits + { + static typename _Clock::duration + to_wait_duration(const typename _Clock::duration& __d) + { return __d; } + + static typename _Clock::duration + to_wait_duration(const typename _Clock::time_point& __t) + { + auto __now = _Clock::now(); + auto __diff = __t - __now; + if (__diff > _Clock::duration::max()) + return _Clock::duration::max(); + if (__diff < _Clock::duration::min()) + return _Clock::duration::min(); + return __diff; + } + }; + + template + class basic_waitable_timer + { + public: + // types: + + typedef io_context::executor_type executor_type; + typedef _Clock clock_type; + typedef typename clock_type::duration duration; + typedef typename clock_type::time_point time_point; + typedef _WaitTraits traits_type; + + // construct / copy / destroy: + + explicit + basic_waitable_timer(io_context& __ctx) + : _M_ex(__ctx.get_executor()), _M_expiry() + { } + + basic_waitable_timer(io_context& __ctx, const time_point& __t) + : _M_ex(__ctx.get_executor()), _M_expiry(__t) + { } + + basic_waitable_timer(io_context& __ctx, const duration& __d) + : _M_ex(__ctx.get_executor()), _M_expiry(_Clock::now() + __d) + { } + + basic_waitable_timer(const basic_waitable_timer&) = delete; + + basic_waitable_timer(basic_waitable_timer&& __rhs) + : _M_ex(std::move(__rhs._M_ex)), _M_expiry(__rhs._M_expiry) + { + _M_key.swap(__rhs._M_key); + __rhs._M_expiry = time_point{}; + } + + ~basic_waitable_timer() { cancel(); } + + basic_waitable_timer& operator=(const basic_waitable_timer&) = delete; + + basic_waitable_timer& + operator=(basic_waitable_timer&& __rhs) + { + if (this == std::addressof(__rhs)) + return *this; + cancel(); + _M_ex = std::move(__rhs._M_ex); + _M_expiry = __rhs._M_expiry; + __rhs._M_expiry = time_point{}; + _M_key.swap(__rhs._M_key); + return *this; + } + + // basic_waitable_timer operations: + + executor_type get_executor() noexcept { return _M_ex; } + + size_t cancel() { return _M_ex.context().cancel(*this); } + size_t cancel_one() { return _M_ex.context().cancel_one(*this); } + + time_point expiry() const { return _M_expiry; } + + size_t expires_at(const time_point& __t) + { + size_t __cancelled = cancel(); + _M_expiry = __t; + return __cancelled; + } + + size_t expires_after(const duration& __d) + { return expires_at(_Clock::now() + __d); } + + void wait(); + void wait(error_code& __ec); + + template + __deduced_t<_CompletionToken, void(error_code)> + async_wait(_CompletionToken&& __token) + { + async_completion<_CompletionToken, void(error_code)> __init(__token); + _M_ex.context().async_wait(*this, + std::move(__init.completion_handler)); + return __init.result.get(); + } + + private: + executor_type _M_ex; + time_point _M_expiry; + + struct _Key { }; // TODO move _M_expiry into here? + unique_ptr<_Key> _M_key{new _Key}; + + friend class io_context; + }; + + typedef basic_waitable_timer system_timer; + typedef basic_waitable_timer steady_timer; + typedef basic_waitable_timer + high_resolution_timer; + + template + void + basic_waitable_timer<_Clock, _WaitTraits>::wait() + { + _M_ex.dispatch([this] { + while (clock_type::now() < _M_expiry) + this_thread::sleep_for(traits_type::to_wait_duration(_M_expiry)); + }, allocator{}); + } + + template + void + basic_waitable_timer<_Clock, _WaitTraits>::wait(error_code&) + { + _M_ex.dispatch([this] { + while (clock_type::now() < _M_expiry) + this_thread::sleep_for(traits_type::to_wait_duration(_M_expiry)); + }, allocator{}); + } + + /// @} + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace v1 +} // namespace net +} // namespace experimental +} // namespace std + +#endif // C++14 + +#endif // _GLIBCXX_EXPERIMENTAL_TIMER diff --git a/libstdc++-v3/testsuite/experimental/net/buffer/arithmetic.cc b/libstdc++-v3/testsuite/experimental/net/buffer/arithmetic.cc new file mode 100644 index 00000000000..7a894a90530 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/buffer/arithmetic.cc @@ -0,0 +1,107 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +using std::experimental::net::mutable_buffer; +using std::experimental::net::const_buffer; + +void +test01() +{ + bool test __attribute__((unused)) = false; + char c[4]; + + mutable_buffer mb; + mb = mb + 0; + VERIFY( mb.data() == nullptr ); + VERIFY( mb.size() == 0 ); + + mb = 0 + mb; + VERIFY( mb.data() == nullptr ); + VERIFY( mb.size() == 0 ); + + mb = mutable_buffer(c, sizeof(c)); + mb = mb + 1; + VERIFY( mb.data() == c+1 ); + VERIFY( mb.size() == 3 ); + + mb = mb + 2; + VERIFY( mb.data() == c+3 ); + VERIFY( mb.size() == 1 ); + + mb = mb + 2; + VERIFY( mb.data() == c+4 ); + VERIFY( mb.size() == 0 ); + + mb = mutable_buffer(c, sizeof(c)); + mb = 3 + mb; + VERIFY( mb.data() == c+3 ); + VERIFY( mb.size() == 1 ); + + mb = 2 + mb; + VERIFY( mb.data() == c+4 ); + VERIFY( mb.size() == 0 ); +} + +void +test02() +{ + bool test __attribute__((unused)) = false; + char c[4]; + + const_buffer cb; + cb = cb + 0; + VERIFY( cb.data() == nullptr ); + VERIFY( cb.size() == 0 ); + + cb = 0 + cb; + VERIFY( cb.data() == nullptr ); + VERIFY( cb.size() == 0 ); + + cb = const_buffer(c, sizeof(c)); + cb = cb + 1; + VERIFY( cb.data() == c+1 ); + VERIFY( cb.size() == 3 ); + + cb = cb + 2; + VERIFY( cb.data() == c+3 ); + VERIFY( cb.size() == 1 ); + + cb = cb + 2; + VERIFY( cb.data() == c+4 ); + VERIFY( cb.size() == 0 ); + + cb = const_buffer(c, sizeof(c)); + cb = 3 + cb; + VERIFY( cb.data() == c+3 ); + VERIFY( cb.size() == 1 ); + + cb = 2 + cb; + VERIFY( cb.data() == c+4 ); + VERIFY( cb.size() == 0 ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/buffer/const.cc b/libstdc++-v3/testsuite/experimental/net/buffer/const.cc new file mode 100644 index 00000000000..d61f05dc897 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/buffer/const.cc @@ -0,0 +1,74 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +using std::experimental::net::const_buffer; +using std::experimental::net::mutable_buffer; + +void +test01() +{ + using B = const_buffer; + const B b; + + static_assert( std::is_nothrow_default_constructible::value, + "const_mutable is nothrow default constructible" ); + static_assert( std::is_copy_assignable::value, + "const_mutable is copy assignable" ); + static_assert( std::is_nothrow_constructible::value, + "const_mutable is nothrow constructible from pointer and length" ); + static_assert( std::is_nothrow_constructible::value, + "const_mutable is nothrow constructible from mutable_buffer" ); + static_assert( std::is_same::value, + "data() return const void*" ); + static_assert( noexcept(b.data()), + "data() is nothrow" ); + static_assert( std::is_same::value, + "size() return size_t" ); + static_assert( noexcept(b.size()), + "size() is nothrow" ); +} + +void +test02() +{ + bool test __attribute__((unused)) = false; + char c[4]; + + const_buffer b; + VERIFY( b.data() == nullptr ); + VERIFY( b.size() == 0 ); + + b = const_buffer(c, sizeof(c)); + VERIFY( b.data() == c ); + VERIFY( b.size() == sizeof(c) ); + + b = const_buffer{}; + VERIFY( b.data() == nullptr ); + VERIFY( b.size() == 0 ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/buffer/creation.cc b/libstdc++-v3/testsuite/experimental/net/buffer/creation.cc new file mode 100644 index 00000000000..c89d79dbde2 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/buffer/creation.cc @@ -0,0 +1,172 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +namespace net = std::experimental::net; + +template +bool is_mutable(const T&) +{ return std::is_same::value; } + +template +bool is_const(const T&) +{ return std::is_same::value; } + +void +test01() +{ + bool test = false; + + auto b1 = net::buffer((void*)&test, sizeof(test)); + VERIFY( is_mutable(b1) ); + VERIFY( b1.data() == &test ); + VERIFY( b1.size() == sizeof(test) ); + + auto b2 = net::buffer((const void*)&test, sizeof(test)); + VERIFY( is_const(b2) ); + VERIFY( b2.data() == &test ); + VERIFY( b1.size() == sizeof(test) ); + + auto b3 = net::buffer(b1); + VERIFY( is_mutable(b3) ); + VERIFY( b3.data() == b1.data() ); + VERIFY( b3.size() == b1.size() ); + + auto b4 = net::buffer(b2); + VERIFY( is_const(b4) ); + VERIFY( b4.data() == b2.data() ); + VERIFY( b4.size() == b2.size() ); + + auto b5 = net::buffer(b1, 0); + VERIFY( is_mutable(b5) ); + VERIFY( b5.data() == b1.data() ); + VERIFY( b5.size() == 0 ); + + auto b6 = net::buffer(b2, 0); + VERIFY( is_const(b6) ); + VERIFY( b6.data() == b2.data() ); + VERIFY( b6.size() == 0 ); + + int a7[7]; + auto b7 = net::buffer(a7); + VERIFY( is_mutable(b7) ); + VERIFY( b7.data() == a7 ); + VERIFY( b7.size() == sizeof(a7) ); + + auto b7x = net::buffer(a7, 2); + VERIFY( is_mutable(b7x) ); + VERIFY( b7x.data() == a7 ); + VERIFY( b7x.size() == sizeof(a7[0]) * 2 ); + + const short a8[8] = { }; + auto b8 = net::buffer(a8); + VERIFY( is_const(b8) ); + VERIFY( b8.data() == a8 ); + VERIFY( b8.size() == sizeof(a8) ); + + auto b8x = net::buffer(a8, 3); + VERIFY( is_const(b8x) ); + VERIFY( b8x.data() == a8 ); + VERIFY( b8x.size() == sizeof(a8[0]) * 3 ); + + std::array a9; + auto b9 = net::buffer(a9); + VERIFY( is_mutable(b9) ); + VERIFY( b9.data() == a9.data() ); + VERIFY( b9.size() == sizeof(a9) ); + + auto b9x = net::buffer(a9, 4); + VERIFY( is_mutable(b9x) ); + VERIFY( b9x.data() == a9.data() ); + VERIFY( b9x.size() == sizeof(a9[0]) * 4 ); + + const std::array a10{}; + auto b10 = net::buffer(a10); + VERIFY( is_const(b10) ); + VERIFY( b10.data() == a10.data() ); + VERIFY( b10.size() == sizeof(a10) ); + + auto b10x = net::buffer(a10, 5); + VERIFY( is_const(b10x) ); + VERIFY( b10x.data() == a10.data() ); + VERIFY( b10x.size() == sizeof(a10[0]) * 5 ); + + std::array a11{}; + auto b11 = net::buffer(a11); + VERIFY( is_const(b11) ); + VERIFY( b11.data() == a11.data() ); + VERIFY( b11.size() == sizeof(a11) ); + + auto b11x = net::buffer(a11, 6); + VERIFY( is_const(b11x) ); + VERIFY( b11x.data() == a11.data() ); + VERIFY( b11x.size() == sizeof(a11[0]) * 6 ); + + std::vector a12(12); + auto b12 = net::buffer(a12); + VERIFY( is_mutable(b12) ); + VERIFY( b12.data() == a12.data() ); + VERIFY( b12.size() == sizeof(a12[0]) * a12.size() ); + + auto b12x = net::buffer(a12, 7); + VERIFY( is_mutable(b12x) ); + VERIFY( b12x.data() == a12.data() ); + VERIFY( b12x.size() == sizeof(a12[0]) * 7 ); + + const std::vector a13(13); + auto b13 = net::buffer(a13); + VERIFY( is_const(b13) ); + VERIFY( b13.data() == a13.data() ); + VERIFY( b13.size() == sizeof(a13[0]) * a13.size() ); + + auto b13x = net::buffer(a13, 7); + VERIFY( is_const(b13x) ); + VERIFY( b13x.data() == a13.data() ); + VERIFY( b13x.size() == sizeof(a13[0]) * 7 ); + + std::u32string a14(14, ' '); + auto b14 = net::buffer(a14); + VERIFY( is_mutable(b14) ); + VERIFY( b14.data() == a14.data() ); + VERIFY( b14.size() == sizeof(a14[0]) * a14.size() ); + + auto b14x = net::buffer(a14, 8); + VERIFY( is_mutable(b14x) ); + VERIFY( b14x.data() == a14.data() ); + VERIFY( b14x.size() == sizeof(a14[0]) * 8 ); + + const std::u16string a15(15, ' '); + auto b15 = net::buffer(std::experimental::u16string_view(a15)); + VERIFY( is_const(b15) ); + VERIFY( b15.data() == a15.data() ); + VERIFY( b15.size() == sizeof(a15[0]) * a15.size() ); + + auto b15x = net::buffer(std::experimental::u16string_view(a15), 9); + VERIFY( is_const(b15x) ); + VERIFY( b15x.data() == a15.data() ); + VERIFY( b15x.size() == sizeof(a15[0]) * 9 ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/buffer/mutable.cc b/libstdc++-v3/testsuite/experimental/net/buffer/mutable.cc new file mode 100644 index 00000000000..cbcae6fc686 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/buffer/mutable.cc @@ -0,0 +1,71 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +using std::experimental::net::mutable_buffer; + +void +test01() +{ + using B = mutable_buffer; + const B b; + + static_assert( std::is_nothrow_default_constructible::value, + "const_mutable is nothrow default constructible" ); + static_assert( std::is_copy_assignable::value, + "const_mutable is copy assignable" ); + static_assert( std::is_nothrow_constructible::value, + "const_mutable is nothrow default constructible" ); + static_assert( std::is_same::value, + "data() return const void*" ); + static_assert( noexcept(b.data()), + "data() is nothrow" ); + static_assert( std::is_same::value, + "size() return size_t" ); + static_assert( noexcept(b.size()), + "size() is nothrow" ); +} + +void +test02() +{ + bool test __attribute__((unused)) = false; + char c[4]; + + mutable_buffer b; + VERIFY( b.data() == nullptr ); + VERIFY( b.size() == 0 ); + + b = mutable_buffer(c, sizeof(c)); + VERIFY( b.data() == c ); + VERIFY( b.size() == sizeof(c) ); + + b = mutable_buffer{}; + VERIFY( b.data() == nullptr ); + VERIFY( b.size() == 0 ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/buffer/size.cc b/libstdc++-v3/testsuite/experimental/net/buffer/size.cc new file mode 100644 index 00000000000..74fc49eca77 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/buffer/size.cc @@ -0,0 +1,62 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +using std::experimental::net::const_buffer; +using std::experimental::net::mutable_buffer; + +void +test01() +{ + bool test __attribute__((unused)) = false; + char c[4]; + + mutable_buffer mb; + VERIFY( buffer_size(mb) == 0 ); + + mb = mutable_buffer(c, sizeof(c)); + VERIFY( buffer_size(mb) == mb.size() ); + + const_buffer cb; + VERIFY( buffer_size(cb) == 0 ); + cb = const_buffer(c, sizeof(c)); + VERIFY( buffer_size(cb) == cb.size() ); +} + +void +test02() +{ + bool test __attribute__((unused)) = false; + char c[32]; + + std::vector mv{ {c, 0}, {c, 32}, {c, 16}, {c, 3}, {c, 0} }; + VERIFY( buffer_size(mv) == (0 + 32 + 16 + 3 + 0) ); + + std::vector cv{ {c, 0}, {c, 32}, {c, 16}, {c, 3}, {c, 0} }; + VERIFY( buffer_size(cv) == (0 + 32 + 16 + 3 + 0) ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/buffer/traits.cc b/libstdc++-v3/testsuite/experimental/net/buffer/traits.cc new file mode 100644 index 00000000000..fb19337f041 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/buffer/traits.cc @@ -0,0 +1,96 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } +// { dg-do compile } + +#include + +using namespace std::experimental::net; +using std::vector; +using std::string; +using std::char_traits; +using std::allocator; + +template +struct Seq { + struct Buf { + operator T() const { return {}; } + }; + + Buf* begin() const { return nullptr; } + Buf* end() const { return nullptr; } +}; + +static_assert( is_mutable_buffer_sequence::value, + "mutable_buffer is a mutable buffer sequence" ); +static_assert( is_mutable_buffer_sequence::value, + "const mutable_buffer is a mutable buffer sequence" ); +static_assert( is_mutable_buffer_sequence>::value, + "vector is a mutable buffer sequence" ); +static_assert( is_mutable_buffer_sequence>::value, + "const vector is a mutable buffer sequence" ); +static_assert( is_mutable_buffer_sequence>::value, + "Seq is a mutable buffer sequence" ); +static_assert( is_mutable_buffer_sequence>::value, + "const Seq is a mutable buffer sequence" ); +static_assert( is_mutable_buffer_sequence>::value, + "Seq is a mutable buffer sequence" ); +static_assert( ! is_mutable_buffer_sequence::value, + "const_buffer is not a mutable buffer sequence" ); +static_assert( ! is_mutable_buffer_sequence>::value, + "vector is not a mutable buffer sequence" ); +static_assert( ! is_mutable_buffer_sequence>::value, + "Seq is not a mutable buffer sequence" ); + +static_assert( is_const_buffer_sequence::value, + "const_buffer is a const buffer sequence" ); +static_assert( is_const_buffer_sequence::value, + "const const_buffer is a const buffer sequence" ); +static_assert( is_const_buffer_sequence>::value, + "vector is a const buffer sequence" ); +static_assert( is_const_buffer_sequence>::value, + "const vector is a const buffer sequence" ); +static_assert( is_const_buffer_sequence>::value, + "Seq is a const buffer sequence" ); +static_assert( is_const_buffer_sequence>::value, + "const Seq is a const buffer sequence" ); +static_assert( is_const_buffer_sequence>::value, + "Seq is a const buffer sequence" ); +static_assert( is_const_buffer_sequence::value, + "mutable_buffer is a const buffer sequence" ); +static_assert( is_const_buffer_sequence::value, + "const mutable_buffer is a const buffer sequence" ); +static_assert( is_const_buffer_sequence>::value, + "vector is a const buffer sequence" ); +static_assert( is_const_buffer_sequence>::value, + "const vector is a const buffer sequence" ); + +// Buf -> mutable_buffer -> const_buffer needs two user-defined conversions: +static_assert( ! is_const_buffer_sequence>::value, + "Seq is not a const buffer sequence" ); + +static_assert( is_dynamic_buffer< + dynamic_vector_buffer> + >::value, "dynamic_vector_buffer is a dynamic buffer" ); +static_assert( is_dynamic_buffer< + dynamic_string_buffer, allocator> + >::value, "dynamic_string_buffer is a dynamic buffer" ); +static_assert( ! is_dynamic_buffer>::value, + "vector is not a dynamic buffer" ); +static_assert( ! is_dynamic_buffer::value, + "string is not a dynamic buffer" ); diff --git a/libstdc++-v3/testsuite/experimental/net/execution_context/use_service.cc b/libstdc++-v3/testsuite/experimental/net/execution_context/use_service.cc new file mode 100644 index 00000000000..d8fb6404b3c --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/execution_context/use_service.cc @@ -0,0 +1,80 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +using std::experimental::net::execution_context; +using std::experimental::net::use_service; + +struct service1 : execution_context::service +{ + using key_type = service1; + service1(execution_context& c) : service(c) { } + void shutdown() noexcept { } +}; + +struct key2 : execution_context::service +{ + key2(execution_context& c) : service(c) { } +}; + +struct service2 : key2 +{ + using key_type = key2; + service2(execution_context& c) : key2(c) { } + void shutdown() noexcept { } +}; + +struct service3 : service1 +{ + using service1::service1; +}; + +struct service4 : service2 +{ + using service2::service2; +}; + +void +test01() +{ + execution_context ctx; + service1& svc1 = use_service(ctx); + service1& svc1a = use_service(ctx); + VERIFY( &svc1a == &svc1 ); + + key2& svc2 = use_service(ctx); + key2& svc2a = use_service(ctx); + VERIFY( &svc2a == &svc2 ); + + service1& svc3 = use_service(ctx); + VERIFY( &svc3 == &svc1 ); + + key2& svc4 = use_service(ctx); + VERIFY( &svc4 == &svc2 ); + + // TODO test02() function that puts derived types in first, then tests base comes out +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/headers.cc b/libstdc++-v3/testsuite/experimental/net/headers.cc new file mode 100644 index 00000000000..58ba13f4744 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/headers.cc @@ -0,0 +1,30 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } +// { dg-do compile } + +#include + +// Re-include: +#include +#include +#include +#include +#include +#include +#include diff --git a/libstdc++-v3/testsuite/experimental/net/internet/address/v4/comparisons.cc b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/comparisons.cc new file mode 100644 index 00000000000..d82e1e4f4fc --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/comparisons.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +using std::experimental::net::ip::address_v4; + +void +test01() +{ + bool test __attribute__((unused)) = false; + + address_v4 addrs[] = { + address_v4::any(), address_v4::loopback(), address_v4::broadcast(), + address_v4{0x11001100}, address_v4{0xEFEFEFEF} + }; + + auto begin = std::begin(addrs); + auto end = std::end(addrs); + for (auto it = begin; it != end; ++it) + { + auto& a = *it; + VERIFY( a == a ); + VERIFY( a <= a ); + VERIFY( a >= a ); + VERIFY( ! (a != a) ); + VERIFY( ! (a < a) ); + VERIFY( ! (a > a) ); + } + + std::sort(begin, end); + + for (auto it = begin + 1; it != end; ++it) + { + auto& a = *it; + auto& b = *begin; + VERIFY( ! (a == b) ); + VERIFY( a != b ); + VERIFY( b < a ); + VERIFY( b <= a ); + VERIFY( a > b ); + VERIFY( a >= b ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/internet/address/v4/cons.cc b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/cons.cc new file mode 100644 index 00000000000..ed09b9cb977 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/cons.cc @@ -0,0 +1,71 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +using std::experimental::net::ip::address_v4; + +void +test01() +{ + bool test __attribute__((unused)) = false; + + address_v4 a0; + VERIFY( a0.to_uint() == 0 ); + VERIFY( a0.to_bytes() == address_v4::bytes_type{} ); +} + +void +test02() +{ + bool test __attribute__((unused)) = false; + + address_v4 a0{ address_v4::bytes_type{} }; + VERIFY( a0.to_uint() == 0 ); + VERIFY( a0.to_bytes() == address_v4::bytes_type{} ); + + address_v4::bytes_type b1{ 1, 2, 3, 4 }; + address_v4 a1{ b1 }; + VERIFY( a1.to_uint() == ntohl((1 << 24) | (2 << 16) | (3 << 8) | 4) ); + VERIFY( a1.to_bytes() == b1 ); +} + +void +test03() +{ + bool test __attribute__((unused)) = false; + + address_v4 a0{ 0u }; + VERIFY( a0.to_uint() == 0 ); + VERIFY( a0.to_bytes() == address_v4::bytes_type{} ); + + address_v4::uint_type u1 = ntohl((5 << 24) | (6 << 16) | (7 << 8) | 8); + address_v4 a1{ u1 }; + VERIFY( a1.to_uint() == u1 ); + VERIFY( a1.to_bytes() == address_v4::bytes_type( 5, 6, 7, 8 ) ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/internet/address/v4/creation.cc b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/creation.cc new file mode 100644 index 00000000000..a168de66f72 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/creation.cc @@ -0,0 +1,91 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +namespace ip = std::experimental::net::ip; +using ip::address_v4; + +void +test01() +{ + bool test __attribute__((unused)) = false; + + auto a0 = make_address_v4( address_v4::bytes_type{} ); + VERIFY( a0.to_uint() == 0 ); + VERIFY( a0.to_bytes() == address_v4::bytes_type{} ); + + address_v4::bytes_type b1{ 1, 2, 3, 4 }; + auto a1 = make_address_v4( b1 ); + VERIFY( a1.to_uint() == ntohl((1 << 24) | (2 << 16) | (3 << 8) | 4) ); + VERIFY( a1.to_bytes() == b1 ); +} + +void +test02() +{ + bool test __attribute__((unused)) = false; + + auto a0 = ip::make_address_v4(0u); + VERIFY( a0.to_uint() == 0 ); + VERIFY( a0.to_bytes() == address_v4::bytes_type{} ); + + address_v4::uint_type u1 = ntohl((5 << 24) | (6 << 16) | (7 << 8) | 8); + auto a1 = ip::make_address_v4( u1 ); + VERIFY( a1.to_uint() == u1 ); + VERIFY( a1.to_bytes() == address_v4::bytes_type( 5, 6, 7, 8 ) ); +} + +void +test03() +{ + bool test __attribute__((unused)) = false; + + auto a1 = ip::make_address_v4("127.0.0.1"); + VERIFY( a1.is_loopback() ); + auto a2 = ip::make_address_v4(std::string{"127.0.0.2"}); + VERIFY( a2.is_loopback() ); + auto a3 = ip::make_address_v4(std::experimental::string_view{"127.0.0.3"}); + VERIFY( a3.is_loopback() ); + + std::error_code ec; + auto a4 = ip::make_address_v4("127...1", ec); + VERIFY( ec == std::errc::invalid_argument ); + + ip::make_address_v4("127.0.0.1", ec); + VERIFY( !ec ); + + a4 = ip::make_address_v4(std::string{"256.0.0.1"}, ec); + VERIFY( ec == std::errc::invalid_argument ); + + ip::make_address_v4(std::string{"127.0.0.1"}, ec); + VERIFY( !ec ); + + a4 = ip::make_address_v4(std::experimental::string_view{""}, ec); + VERIFY( ec == std::errc::invalid_argument ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/internet/address/v4/members.cc b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/members.cc new file mode 100644 index 00000000000..b854d8fcc14 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/members.cc @@ -0,0 +1,118 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +using std::experimental::net::ip::address_v4; + +void +test01() +{ + bool test __attribute__((unused)) = false; + + address_v4 a; + VERIFY( a.is_unspecified() ); + + a = address_v4::any(); + VERIFY( a.is_unspecified() ); + + a = address_v4::loopback(); + VERIFY( !a.is_unspecified() ); + + a = address_v4::broadcast(); + VERIFY( !a.is_unspecified() ); +} + +void +test02() +{ + bool test __attribute__((unused)) = false; + + auto a = address_v4::loopback(); + VERIFY( a.is_loopback() ); + + a = address_v4{0x7F000001}; + VERIFY( a.is_loopback() ); + + a = address_v4{0x7F010203}; + VERIFY( a.is_loopback() ); + + a = address_v4{0x7FFFFFFF}; + VERIFY( a.is_loopback() ); + + a = address_v4::any(); + VERIFY( !a.is_loopback() ); + + a = address_v4::broadcast(); + VERIFY( !a.is_loopback() ); +} + +void +test03() +{ + bool test __attribute__((unused)) = false; + + auto a = address_v4{0xE0000001}; + VERIFY( a.is_multicast() ); + + a = address_v4{0xE0010203}; + VERIFY( a.is_multicast() ); + + a = address_v4{0xE0FFFFFF}; + VERIFY( a.is_multicast() ); + + a = address_v4{0xF0000000}; + VERIFY( !a.is_multicast() ); + + a = address_v4{0xDFFFFFFF}; + VERIFY( !a.is_multicast() ); +} + +void +test04() +{ + bool test __attribute__((unused)) = false; + + VERIFY( address_v4::any().to_string() == "0.0.0.0" ); + VERIFY( address_v4::loopback().to_string() == "127.0.0.1" ); + VERIFY( address_v4::broadcast().to_string() == "255.255.255.255" ); +} + +void +test05() +{ + bool test __attribute__((unused)) = false; + + std::ostringstream ss; + ss << address_v4::any() << ' ' << address_v4::loopback() << ' ' + << address_v4::broadcast(); + VERIFY( ss.str() == "0.0.0.0 127.0.0.1 255.255.255.255" ); +} + + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/internet/resolver/base.cc b/libstdc++-v3/testsuite/experimental/net/internet/resolver/base.cc new file mode 100644 index 00000000000..c07de7aec5a --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/internet/resolver/base.cc @@ -0,0 +1,61 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +void +test01() +{ + bool test __attribute__((unused)) = false; + + using resolver = std::experimental::net::ip::resolver_base; + + resolver::flags f = resolver::passive; + + VERIFY( (f & resolver::numeric_host) == 0); + f &= resolver::numeric_host; + VERIFY( f == 0 ); + + VERIFY( (f | resolver::numeric_host) == resolver::numeric_host); + f |= resolver::numeric_host; + VERIFY( f == resolver::numeric_host ); + + VERIFY( (f ^ resolver::numeric_host) == 0 ); + f ^= resolver::numeric_host; + VERIFY( f == 0 ); + + f = ~resolver::numeric_host; + VERIFY( (f & resolver::numeric_host) == 0); + VERIFY( (f | resolver::numeric_host) == ~resolver::flags{} ); + + (void) resolver::passive; + (void) resolver::canonical_name; + (void) resolver::numeric_host; + (void) resolver::numeric_service; + (void) resolver::v4_mapped; + (void) resolver::all_matching; + (void) resolver::address_configured; +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/internet/resolver/ops/lookup.cc b/libstdc++-v3/testsuite/experimental/net/internet/resolver/ops/lookup.cc new file mode 100644 index 00000000000..ca1018d218c --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/internet/resolver/ops/lookup.cc @@ -0,0 +1,110 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +using namespace std::experimental::net; + +void +test01() +{ + bool test __attribute__((unused)) = false; + + std::error_code ec; + io_context ctx; + ip::tcp::resolver resolv(ctx); + auto addrs = resolv.resolve("localhost", "http", ec); + VERIFY( !ec ); + VERIFY( addrs.size() > 0 ); + VERIFY( addrs.begin() != addrs.end() ); + VERIFY( ! addrs.empty() ); + + auto addrs2 = resolv.resolve("localhost", "http"); + VERIFY( addrs == addrs2 ); +} + +void +test02() +{ + bool test __attribute__((unused)) = false; + + std::error_code ec; + io_context ctx; + ip::tcp::resolver resolv(ctx); + auto flags = ip::resolver_base::numeric_host | ip::tcp::resolver::numeric_service; + auto addrs = resolv.resolve("127.0.0.1", "42", flags, ec); + VERIFY( !ec ); + VERIFY( addrs.size() > 0 ); + VERIFY( addrs.begin() != addrs.end() ); + + auto addrs2 = resolv.resolve("127.0.0.1", "42", flags); + VERIFY( addrs == addrs2 ); + + addrs = resolv.resolve("localhost", "42", flags, ec); + VERIFY( ec ); + VERIFY( addrs.empty() ); + addrs = resolv.resolve("127.0.0.1", "nameserver", flags, ec); + VERIFY( ec ); + VERIFY( addrs.empty() ); + +#if __cpp_exceptions + bool caught = false; + try { + resolv.resolve("localhost", "http", flags); + } catch (const std::system_error& e) { + caught = true; + VERIFY( e.code() == ec ); + } + VERIFY( caught ); +#endif +} + +void +test03() +{ + bool test __attribute__((unused)) = false; + + std::error_code ec; + io_context ctx; + ip::tcp::resolver resolv(ctx); + auto addrs = resolv.resolve("test.invalid", "http", ec); + VERIFY( ec ); + VERIFY( addrs.size() == 0 ); + VERIFY( addrs.begin() == addrs.end() ); + VERIFY( addrs.empty() ); +#if __cpp_exceptions + bool caught = false; + try { + resolv.resolve("test.invalid", "http"); + } catch (const std::system_error& e) { + caught = true; + VERIFY( e.code() == ec ); + } + VERIFY( caught ); +#endif +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/internet/resolver/ops/reverse.cc b/libstdc++-v3/testsuite/experimental/net/internet/resolver/ops/reverse.cc new file mode 100644 index 00000000000..f5035079eb6 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/internet/resolver/ops/reverse.cc @@ -0,0 +1,48 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +using namespace std::experimental::net; + +void +test01() +{ + bool test __attribute__((unused)) = false; + + std::error_code ec; + io_context ctx; + ip::tcp::resolver resolv(ctx); + ip::tcp::endpoint home{ip::address_v4::loopback(), 80}; + auto addrs = resolv.resolve(home, ec); + VERIFY( !ec ); + VERIFY( addrs.size() == 1 ); + VERIFY( addrs.begin() != addrs.end() ); + VERIFY( ! addrs.empty() ); + + auto addrs2 = resolv.resolve(home); + VERIFY( addrs == addrs2 ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/timer/waitable/cons.cc b/libstdc++-v3/testsuite/experimental/net/timer/waitable/cons.cc new file mode 100644 index 00000000000..3bce0576e12 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/timer/waitable/cons.cc @@ -0,0 +1,119 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +using std::experimental::net::system_timer; +using std::experimental::net::io_context; + +void +test01() +{ + bool test __attribute__((unused)) = false; + + io_context ctx1, ctx2; + + system_timer timer1(ctx1); + VERIFY( timer1.get_executor() == ctx1.get_executor() ); + VERIFY( timer1.expiry() == system_timer::time_point() ); + + system_timer timer2(ctx2); + VERIFY( timer2.get_executor() == ctx2.get_executor() ); + VERIFY( timer2.get_executor() != timer1.get_executor() ); + VERIFY( timer2.expiry() == system_timer::time_point() ); + + system_timer timer3(std::move(timer1)); + VERIFY( timer3.get_executor() == ctx1.get_executor() ); + VERIFY( timer3.expiry() == system_timer::time_point() ); + VERIFY( timer1.expiry() == system_timer::time_point() ); + + system_timer timer4(std::move(timer2)); + VERIFY( timer4.get_executor() == ctx2.get_executor() ); + VERIFY( timer4.expiry() == system_timer::time_point() ); + VERIFY( timer2.expiry() == system_timer::time_point() ); +} + +void +test02() +{ + bool test __attribute__((unused)) = false; + + io_context ctx1, ctx2; + auto t1 = system_timer::clock_type::now(); + auto t2 = t1 + system_timer::duration(10); + + system_timer timer1(ctx1, t1); + VERIFY( timer1.get_executor() == ctx1.get_executor() ); + VERIFY( timer1.expiry() == t1 ); + + system_timer timer2(ctx2, t2); + VERIFY( timer2.get_executor() == ctx2.get_executor() ); + VERIFY( timer2.get_executor() != timer1.get_executor() ); + VERIFY( timer2.expiry() == t2 ); + + system_timer timer3(std::move(timer1)); + VERIFY( timer3.get_executor() == ctx1.get_executor() ); + VERIFY( timer3.expiry() == t1 ); + VERIFY( timer1.expiry() == system_timer::time_point() ); + + system_timer timer4(std::move(timer2)); + VERIFY( timer4.get_executor() == ctx2.get_executor() ); + VERIFY( timer4.expiry() == t2 ); + VERIFY( timer2.expiry() == system_timer::time_point() ); +} + +void +test03() +{ + bool test __attribute__((unused)) = false; + + io_context ctx1, ctx2; + auto now = system_timer::clock_type::now(); + auto d1 = system_timer::duration(10); + auto d2 = system_timer::duration(100); + + system_timer timer1(ctx1, d1); + VERIFY( timer1.get_executor() == ctx1.get_executor() ); + VERIFY( timer1.expiry() > now ); + + system_timer timer2(ctx2, d2); + VERIFY( timer2.get_executor() == ctx2.get_executor() ); + VERIFY( timer2.get_executor() != timer1.get_executor() ); + VERIFY( timer2.expiry() > now ); + VERIFY( timer2.expiry() != timer1.expiry() ); + + system_timer timer3(std::move(timer1)); + VERIFY( timer3.get_executor() == ctx1.get_executor() ); + VERIFY( timer3.expiry() > now ); + VERIFY( timer1.expiry() == system_timer::time_point() ); + + system_timer timer4(std::move(timer2)); + VERIFY( timer4.get_executor() == ctx2.get_executor() ); + VERIFY( timer4.expiry() > now ); + VERIFY( timer2.expiry() == system_timer::time_point() ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/timer/waitable/dest.cc b/libstdc++-v3/testsuite/experimental/net/timer/waitable/dest.cc new file mode 100644 index 00000000000..743f28a55e9 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/timer/waitable/dest.cc @@ -0,0 +1,48 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +using std::experimental::net::system_timer; +using std::experimental::net::io_context; + +void +test01() +{ + bool test __attribute__((unused)) = false; + + std::error_code ec; + + io_context ctx; + { + system_timer timer(ctx, system_timer::duration(3600)); + timer.async_wait([&ec](std::error_code e) { ec = e; }); + } + auto n = ctx.run(); + __builtin_printf("ran %lu\n", n); + VERIFY( n == 1 ); + VERIFY( ec == std::errc::operation_canceled ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/experimental/net/timer/waitable/ops.cc b/libstdc++-v3/testsuite/experimental/net/timer/waitable/ops.cc new file mode 100644 index 00000000000..c4e0b1bfe41 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/timer/waitable/ops.cc @@ -0,0 +1,106 @@ +// Copyright (C) 2015-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++14" } + +#include +#include + +using std::experimental::net::system_timer; +using std::experimental::net::io_context; +using std::error_code; + +void +test01() +{ + bool test __attribute__((unused)) = false; + + io_context ctx; + error_code ec; + bool complete = false; + + auto then = system_timer::clock_type::now() + system_timer::duration(100); + + system_timer timer(ctx, then); + VERIFY( timer.cancel_one() == 0 ); + VERIFY( timer.cancel() == 0 ); + + timer.async_wait([&](error_code e) { ec = e; complete = true; }); + VERIFY( timer.cancel_one() == 1 ); + VERIFY( !complete ); + + VERIFY( timer.cancel_one() == 0 ); + VERIFY( timer.cancel() == 0 ); + + VERIFY( ctx.run() == 1 ); + VERIFY( ctx.stopped() ); + VERIFY( complete ); + VERIFY( ec == std::errc::operation_canceled ); +} + +void +test02() +{ + bool test __attribute__((unused)) = false; + + io_context ctx; + error_code ec1, ec2; + + const auto now = system_timer::clock_type::now(); + const auto t1 = now + std::chrono::seconds(100); + const auto t2 = t1 + std::chrono::seconds(100); + + system_timer timer(ctx, t1); + VERIFY( timer.expiry() == t1 ); + + VERIFY( timer.expires_at(t2) == 0 ); + VERIFY( timer.expiry() == t2 ); + + timer.async_wait([&ec1](error_code e) { ec1 = e; }); + timer.async_wait([&ec2](error_code e) { ec2 = e; }); + auto n = timer.expires_at(t1); + VERIFY( n == 2 ); + VERIFY( timer.expiry() == t1 ); + + VERIFY( ctx.run_one() == 1 ); + VERIFY( ! ctx.stopped() ); + VERIFY( ctx.run_one() == 1 ); + VERIFY( ctx.stopped() ); + VERIFY( ec1 == std::errc::operation_canceled ); + VERIFY( ec2 == std::errc::operation_canceled ); + + VERIFY( timer.expires_after(std::chrono::seconds(50)) == 0 ); + VERIFY( timer.expiry() < t1 ); + + ec1.clear(); + ec2.clear(); + ctx.restart(); + timer.async_wait([&ec1](error_code e) { ec1 = e; }); + timer.async_wait([&ec2](error_code e) { ec2 = e; }); + VERIFY( timer.expires_after(std::chrono::seconds(10)) == 2 ); + VERIFY( timer.expiry() < t1 ); + ctx.run(); + VERIFY( ec1 == std::errc::operation_canceled ); + VERIFY( ec2 == std::errc::operation_canceled ); +} + +int +main() +{ + test01(); + test02(); +}