[gcc(refs/users/aoliva/heads/testme)] libstdc++: Better requirements checking in Networking TS

Alexandre Oliva aoliva@gcc.gnu.org
Tue May 26 04:37:02 GMT 2020


https://gcc.gnu.org/g:b780db2ea327f51050d64237e71456b0eacf60e8

commit b780db2ea327f51050d64237e71456b0eacf60e8
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu May 21 00:59:55 2020 +0100

    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 <experimental/socket>.
            (__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:
---
 libstdc++-v3/ChangeLog                       |  10 ++
 libstdc++-v3/include/experimental/bits/net.h | 152 +++++++++++++++++++++++++++
 libstdc++-v3/include/experimental/socket     |  34 ++----
 3 files changed, 169 insertions(+), 27 deletions(-)

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  <jwakely@redhat.com>
 
+	* include/experimental/bits/net.h (__endpoint, __protocol)
+	(__acceptable_protocol, __inet_protocol): New concepts.
+	(__detail::__is_endpoint): Move trait from <experimental/socket>.
+	(__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 <system_error>
 #include <experimental/netfwd>
 
+#if __cplusplus > 201703L
+# include <concepts>
+#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<typename _Tp>
+    concept __protocol_like
+      = copyable<_Tp> && requires { typename _Tp::endpoint; };
+
+  // Endpoint requirements for non-extensible implementations.
+  template<typename _Tp>
+    concept __endpoint_base = semiregular<_Tp>
+      && requires  { typename _Tp::protocol_type; }
+      && __protocol_like<typename _Tp::protocol_type>
+      && requires(const _Tp __a) {
+	{ __a.protocol() } -> same_as<typename _Tp::protocol_type>;
+      };
+
+  // Endpoint requirements for extensible implementations.
+  template<typename _Tp>
+    concept __endpoint = __endpoint_base<_Tp>
+      && requires (const _Tp& __a, _Tp& __b, size_t __s)
+      {
+	{ __a.data() } -> same_as<const void*>;
+	{ __b.data() } -> same_as<void*>;
+	{ __b.size() } -> same_as<size_t>;
+	__b.resize(__s);
+	{ __a.capacity() } -> same_as<size_t>;
+      };
+
+  // Protocol requirements for non-extensible implementations.
+  template<typename _Tp>
+    concept __protocol_base = __protocol_like<_Tp>
+      && __endpoint_base<typename _Tp::endpoint>
+      && same_as<typename _Tp::endpoint::protocol_type, _Tp>;
+
+  // Protocol requirements for extensible implementations.
+  template<typename _Tp>
+    concept __protocol =  __protocol_base<_Tp>
+      && __endpoint<typename _Tp::endpoint>
+      && requires (const _Tp __a) {
+	{ __a.family() } -> same_as<int>;
+	{ __a.type() } -> same_as<int>;
+	{ __a.protocol() } -> same_as<int>;
+      };
+
+  template<typename _Tp>
+    concept __acceptable_protocol = __protocol<_Tp>
+      && requires { typename _Tp::socket; }
+      && move_constructible<typename _Tp::socket>
+      && derived_from<typename _Tp::socket, basic_socket<_Tp>>;
+
+  template<typename _Tp>
+    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<typename _Tp::resolver, ip::basic_resolver<_Tp>>;
+
+#else
+  // Check Endpoint requirements for extensible implementations
+  template<typename _Tp, typename = void>
+    struct __is_endpoint : false_type
+    { };
+
+  template<typename _Tp>
+    auto
+    __endpoint_reqs(const _Tp* __a = nullptr, _Tp* __b = nullptr)
+    -> enable_if_t<__and_<
+      is_default_constructible<_Tp>, __is_value_constructible<_Tp>,
+      is_same<decltype(__a->protocol()), typename _Tp::protocol_type>,
+      is_same<decltype(__a->data()), const void*>,
+      is_same<decltype(__b->data()), void*>,
+      is_same<decltype(__a->size()), size_t>,
+      is_same<decltype(__a->capacity()), size_t>
+      >::value,
+    __void_t< typename _Tp::protocol_type::endpoint,
+	      decltype(__b->resize(std::declval<size_t>())) >>;
+
+  template<typename _Tp>
+    struct __is_endpoint<_Tp, decltype(__detail::__endpoint_reqs<_Tp>())>
+    : true_type
+    { };
+
+  // Check Protocol requirements for extensible implementations.
+  template<typename _Tp, typename = void>
+    struct __is_protocol
+    : false_type { };
+
+  template<typename _Tp>
+    auto
+    __protocol_reqs(const _Tp* __a = nullptr)
+    -> enable_if_t<__and_<
+      is_copy_constructible<_Tp>, is_copy_assignable<_Tp>,
+      __is_endpoint<typename _Tp::endpoint>,
+      is_same<decltype(__a->family()), int>,
+      is_same<decltype(__a->type()), int>,
+      is_same<decltype(__a->protocol()), int>
+      >::value>;
+
+  template<typename _Tp>
+    struct __is_protocol<_Tp, decltype(__detail::__protocol_reqs<_Tp>())>
+    : true_type
+    { };
+
+  // Check AcceptableProtocol requirements
+  template<typename _Tp, typename = void>
+    struct __is_acceptable_protocol
+    : false_type { };
+
+  template<typename _Tp>
+    struct __is_acceptable_protocol<_Tp, __void_t<typename _Tp::socket>>
+    : __and_<__is_protocol<_Tp>, is_move_constructible<typename _Tp::socket>,
+	     is_convertible<typename _Tp::socket*, basic_socket<_Tp>*>>::type
+    { };
+
+  // Check InternetProtocol requirements
+  template<typename _Tp, typename = void>
+    struct __is_inet_protocol
+    : false_type { };
+
+  template<typename _Tp>
+    auto
+    __inet_proto_reqs(const _Tp* __a = nullptr)
+    -> enable_if_t<__and_<
+      __is_acceptable_protocol<_Tp>,
+      is_same<typename _Tp::resolver, ip::basic_resolver<_Tp>>,
+      is_same<decltype(_Tp::v4()), _Tp>,
+      is_same<decltype(_Tp::v6()), _Tp>,
+      is_convertible<decltype(*__a == *__a), bool>,
+      is_convertible<decltype(*__a != *__a), bool>
+      >::value>;
+
+  template<typename _Tp>
+    struct __is_inet_protocol<_Tp, decltype(__inet_proto_reqs<_Tp>())>
+    : true_type { };
+
+  // Variable templates for requirements (with same names as concepts above).
+
+  template<typename _Tp>
+    constexpr bool __endpoint = __is_endpoint<_Tp>::value;
+  template<typename _Tp>
+    constexpr bool __protocol = __is_protocol<_Tp>::value;
+  template<typename _Tp>
+    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<int>(__e), socket_category()); }
 
-  template<typename _Tp, typename = __void_t<>>
-    struct __is_endpoint_impl : false_type
-    { };
-
-  // Check Endpoint requirements.
-  template<typename _Tp>
-    auto
-    __endpoint_reqs(const _Tp* __a = 0)
-    -> enable_if_t<__and_<
-      is_default_constructible<_Tp>,
-      __is_value_constructible<_Tp>,
-      is_same<decltype(__a->__protocol()), typename _Tp::protocol_type>
-      >::value,
-    __void_t< typename _Tp::protocol_type::endpoint >>;
-
-  template<typename _Tp>
-    struct __is_endpoint_impl<_Tp, decltype(__endpoint_reqs<_Tp>())>
-    : true_type
-    { };
-
-  template<typename _Tp>
-    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>,
+		    "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>,
+		    "protocol_type meets the AcceptableProtocol requirements");
+
       // construct / copy / destroy:
 
       explicit


More information about the Libstdc++-cvs mailing list