From: Jonathan Wakely Date: Wed, 20 May 2020 23:59:55 +0000 (+0100) Subject: libstdc++: Better requirements checking in Networking TS X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b780db2ea327f51050d64237e71456b0eacf60e8;p=gcc.git libstdc++: Better requirements checking in Networking TS Define concepts and traits for checking type requirements. * include/experimental/bits/net.h (__endpoint, __protocol) (__acceptable_protocol, __inet_protocol): New concepts. (__detail::__is_endpoint): Move trait from . (__is_protocol, __is_acceptable_protocol, __is_inet_protocol): New traits. (__endpoint, __protocol, __acceptable_protocol): New variable templates. * include/experimental/socket (__is_endpoint): Move to net.h header. (basic_socket, basic_socket_acceptor): Check requirements. --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index dec84f03da6..975de44434b 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,15 @@ 2020-05-21 Jonathan Wakely + * include/experimental/bits/net.h (__endpoint, __protocol) + (__acceptable_protocol, __inet_protocol): New concepts. + (__detail::__is_endpoint): Move trait from . + (__is_protocol, __is_acceptable_protocol, __is_inet_protocol): New + traits. + (__endpoint, __protocol, __acceptable_protocol): New variable + templates. + * include/experimental/socket (__is_endpoint): Move to net.h header. + (basic_socket, basic_socket_acceptor): Check requirements. + * include/experimental/executor (use_future_t::use_future_t()): Fix incorrect noexcept-specifier. * include/experimental/internet (basic_resolver_results): Adjust diff --git a/libstdc++-v3/include/experimental/bits/net.h b/libstdc++-v3/include/experimental/bits/net.h index f69ef91c31e..cf7914d0acb 100644 --- a/libstdc++-v3/include/experimental/bits/net.h +++ b/libstdc++-v3/include/experimental/bits/net.h @@ -38,6 +38,10 @@ #include #include +#if __cplusplus > 201703L +# include +#endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -164,6 +168,154 @@ inline namespace v1 { return _Derived::_S_name; } }; +namespace __detail +{ +#if __cpp_lib_concepts + template + concept __protocol_like + = copyable<_Tp> && requires { typename _Tp::endpoint; }; + + // Endpoint requirements for non-extensible implementations. + template + concept __endpoint_base = semiregular<_Tp> + && requires { typename _Tp::protocol_type; } + && __protocol_like + && requires(const _Tp __a) { + { __a.protocol() } -> same_as; + }; + + // Endpoint requirements for extensible implementations. + template + concept __endpoint = __endpoint_base<_Tp> + && requires (const _Tp& __a, _Tp& __b, size_t __s) + { + { __a.data() } -> same_as; + { __b.data() } -> same_as; + { __b.size() } -> same_as; + __b.resize(__s); + { __a.capacity() } -> same_as; + }; + + // Protocol requirements for non-extensible implementations. + template + concept __protocol_base = __protocol_like<_Tp> + && __endpoint_base + && same_as; + + // Protocol requirements for extensible implementations. + template + concept __protocol = __protocol_base<_Tp> + && __endpoint + && requires (const _Tp __a) { + { __a.family() } -> same_as; + { __a.type() } -> same_as; + { __a.protocol() } -> same_as; + }; + + template + concept __acceptable_protocol = __protocol<_Tp> + && requires { typename _Tp::socket; } + && move_constructible + && derived_from>; + + template + concept __inet_protocol = __acceptable_protocol<_Tp> + && equality_comparable<_Tp> && requires { + { _Tp::v4() } -> same_as<_Tp>; + { _Tp::v6() } -> same_as<_Tp>; + typename _Tp::resolver; + } + && same_as>; + +#else + // Check Endpoint requirements for extensible implementations + template + struct __is_endpoint : false_type + { }; + + template + auto + __endpoint_reqs(const _Tp* __a = nullptr, _Tp* __b = nullptr) + -> enable_if_t<__and_< + is_default_constructible<_Tp>, __is_value_constructible<_Tp>, + is_sameprotocol()), typename _Tp::protocol_type>, + is_samedata()), const void*>, + is_samedata()), void*>, + is_samesize()), size_t>, + is_samecapacity()), size_t> + >::value, + __void_t< typename _Tp::protocol_type::endpoint, + decltype(__b->resize(std::declval())) >>; + + template + struct __is_endpoint<_Tp, decltype(__detail::__endpoint_reqs<_Tp>())> + : true_type + { }; + + // Check Protocol requirements for extensible implementations. + template + struct __is_protocol + : false_type { }; + + template + auto + __protocol_reqs(const _Tp* __a = nullptr) + -> enable_if_t<__and_< + is_copy_constructible<_Tp>, is_copy_assignable<_Tp>, + __is_endpoint, + is_samefamily()), int>, + is_sametype()), int>, + is_sameprotocol()), int> + >::value>; + + template + struct __is_protocol<_Tp, decltype(__detail::__protocol_reqs<_Tp>())> + : true_type + { }; + + // Check AcceptableProtocol requirements + template + struct __is_acceptable_protocol + : false_type { }; + + template + struct __is_acceptable_protocol<_Tp, __void_t> + : __and_<__is_protocol<_Tp>, is_move_constructible, + is_convertible*>>::type + { }; + + // Check InternetProtocol requirements + template + struct __is_inet_protocol + : false_type { }; + + template + auto + __inet_proto_reqs(const _Tp* __a = nullptr) + -> enable_if_t<__and_< + __is_acceptable_protocol<_Tp>, + is_same>, + is_same, + is_same, + is_convertible, + is_convertible + >::value>; + + template + struct __is_inet_protocol<_Tp, decltype(__inet_proto_reqs<_Tp>())> + : true_type { }; + + // Variable templates for requirements (with same names as concepts above). + + template + constexpr bool __endpoint = __is_endpoint<_Tp>::value; + template + constexpr bool __protocol = __is_protocol<_Tp>::value; + template + constexpr bool __acceptable_protocol = __is_acceptable_protocol<_Tp>::value; +#endif +} // namespace __detail + /// @} } // namespace v1 diff --git a/libstdc++-v3/include/experimental/socket b/libstdc++-v3/include/experimental/socket index 80fb21da95c..84d23ebe37c 100644 --- a/libstdc++-v3/include/experimental/socket +++ b/libstdc++-v3/include/experimental/socket @@ -122,33 +122,7 @@ inline namespace v1 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 @@ -713,6 +687,9 @@ inline namespace v1 using protocol_type = _Protocol; using endpoint_type = typename protocol_type::endpoint; + static_assert(__detail::__protocol, + "protocol_type meets the Protocol requirements"); + // basic_socket operations: executor_type get_executor() noexcept { return __base::get_executor(); } @@ -1853,6 +1830,9 @@ inline namespace v1 using endpoint_type = typename protocol_type::endpoint; using socket_type = typename protocol_type::socket; + static_assert(__detail::__acceptable_protocol, + "protocol_type meets the AcceptableProtocol requirements"); + // construct / copy / destroy: explicit