libstdc++: Better requirements checking in Networking TS
authorJonathan Wakely <jwakely@redhat.com>
Wed, 20 May 2020 23:59:55 +0000 (00:59 +0100)
committerJonathan Wakely <jwakely@redhat.com>
Wed, 20 May 2020 23:59:55 +0000 (00:59 +0100)
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.

libstdc++-v3/ChangeLog
libstdc++-v3/include/experimental/bits/net.h
libstdc++-v3/include/experimental/socket

index dec84f03da63ab156e13b938ca253f59a37c86e8..975de44434bd4d3977ecceb4f506454f77bcb3bc 100644 (file)
@@ -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
index f69ef91c31ecdb862c242240b7e918f912846b3b..cf7914d0acb7c6a33fbc9afeb82b7bf90234e71c 100644 (file)
 #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
index 80fb21da95c026f12ea26b8a3f3023bbba0697e4..84d23ebe37c16376a1d08daaaf2fdd417a728de4 100644 (file)
@@ -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