Initial commit of Networking TS implementation
authorJonathan Wakely <jwakely@redhat.com>
Fri, 12 Oct 2018 10:50:15 +0000 (11:50 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 12 Oct 2018 10:50:15 +0000 (11:50 +0100)
* 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

30 files changed:
libstdc++-v3/ChangeLog
libstdc++-v3/include/Makefile.am
libstdc++-v3/include/Makefile.in
libstdc++-v3/include/experimental/bits/net.h [new file with mode: 0644]
libstdc++-v3/include/experimental/buffer [new file with mode: 0644]
libstdc++-v3/include/experimental/executor [new file with mode: 0644]
libstdc++-v3/include/experimental/internet [new file with mode: 0644]
libstdc++-v3/include/experimental/io_context [new file with mode: 0644]
libstdc++-v3/include/experimental/net [new file with mode: 0644]
libstdc++-v3/include/experimental/netfwd [new file with mode: 0644]
libstdc++-v3/include/experimental/socket [new file with mode: 0644]
libstdc++-v3/include/experimental/timer [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/buffer/arithmetic.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/buffer/const.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/buffer/creation.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/buffer/mutable.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/buffer/size.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/buffer/traits.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/execution_context/use_service.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/headers.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/internet/address/v4/comparisons.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/internet/address/v4/cons.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/internet/address/v4/creation.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/internet/address/v4/members.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/internet/resolver/base.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/internet/resolver/ops/lookup.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/internet/resolver/ops/reverse.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/timer/waitable/cons.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/timer/waitable/dest.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/net/timer/waitable/ops.cc [new file with mode: 0644]

index 35be45e4e461d747370836e48f33ce9fefa89cf4..871d6ab4a09e3243982e3b7bd6e2544ea785088a 100644 (file)
@@ -1,5 +1,43 @@
 2018-10-12  Jonathan Wakely  <jwakely@redhat.com>
 
+       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
index 271695806ffaee4a867a41b24aeabd235499e046..d45d937d3a7a102d40632de52eaee240d216509a 100644 (file)
@@ -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}
index 97f738a96a62bbe1741aef4cb9deb2e57eb0dc20..f872d928d716f288076bef229f0400fa4c958124 100644 (file)
@@ -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 (file)
index 0000000..17bd300
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+/** @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 <type_traits>
+#include <system_error>
+#include <experimental/netfwd>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+namespace experimental
+{
+namespace net
+{
+inline namespace v1
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  /**
+   * @ingroup networking
+   * @{
+   */
+
+  template<typename _CompletionToken, typename _Signature, typename>
+    class async_result;
+
+  // A type denoted by DEDUCED in the TS.
+  template<typename _CompletionToken, typename _Signature>
+    using __deduced_t = typename
+      async_result<decay_t<_CompletionToken>, _Signature, void>::return_type;
+
+  // Trait to check for construction from const/non-const lvalue/rvalue.
+  template<typename _Tp>
+    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<typename _Tp>
+    struct __sockopt_base
+    {
+      __sockopt_base() = default;
+
+      explicit __sockopt_base(int __val) : _M_value(__val) { }
+
+      int value() const noexcept { return _M_value; }
+
+      template<typename _Protocol>
+       void*
+       data(const _Protocol&) noexcept
+       { return std::addressof(_M_value); }
+
+      template<typename _Protocol>
+       const void*
+       data(const _Protocol&) const noexcept
+       { return std::addressof(_M_value); }
+
+      template<typename _Protocol>
+       size_t
+       size(const _Protocol&) const noexcept
+       { return sizeof(_M_value); }
+
+      template<typename _Protocol>
+       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<bool> : __sockopt_base<int>
+    {
+      __sockopt_base() = default;
+
+      explicit __sockopt_base(bool __val) : __sockopt_base<int>(__val) { }
+
+      bool value() const noexcept { return __sockopt_base<int>::_M_value; }
+      explicit operator bool() const noexcept { return value(); }
+      bool operator!() const noexcept { return !value(); }
+    };
+
+  template<typename _Derived, typename _Tp = int>
+    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<typename _Protocol>
+       int
+       level(const _Protocol&) const noexcept
+       { return _Derived::_S_level; }
+
+      template<typename _Protocol>
+       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 (file)
index 0000000..5541823
--- /dev/null
@@ -0,0 +1,897 @@
+// <experimental/buffer> -*- 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
+// <http://www.gnu.org/licenses/>.
+
+/** @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 <array>
+#include <string>
+#include <system_error>
+#include <vector>
+#include <cstring>
+#include <experimental/string_view>
+#include <experimental/bits/net.h>
+
+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<int>(__e), stream_category()); }
+
+  inline error_condition
+  make_error_condition(stream_errc __e) noexcept
+  { return error_condition(static_cast<int>(__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<typename _Cont>
+    auto
+    buffer_sequence_begin(_Cont& __c) -> decltype(__c.begin())
+    { return __c.begin(); }
+
+  template<typename _Cont>
+    auto
+    buffer_sequence_begin(const _Cont& __c) -> decltype(__c.begin())
+    { return __c.begin(); }
+
+  template<typename _Cont>
+    auto
+    buffer_sequence_end(_Cont& __c) -> decltype(__c.end())
+    { return __c.end(); }
+
+  template<typename _Cont>
+    auto
+    buffer_sequence_end(const _Cont& __c) -> decltype(__c.end())
+    { return __c.end(); }
+
+  // @}
+
+
+  /** @brief buffer type traits
+   *
+   * @{
+   */
+
+  template<typename _Tp, typename _Buffer,
+          typename _Begin
+           = decltype(net::buffer_sequence_begin(std::declval<_Tp&>())),
+          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<typename iterator_traits<_Begin>::value_type, _Buffer>
+      >::value>;
+
+  template<typename _Tp, typename _Buffer, typename = void>
+    struct __is_buffer_sequence : false_type
+    { };
+
+  template<typename _Tp, typename _Buffer>
+    struct __is_buffer_sequence<_Tp, _Buffer, __buffer_sequence<_Tp, _Buffer>>
+    : true_type
+    { };
+
+  template<typename _Tp>
+    struct is_mutable_buffer_sequence
+    : __is_buffer_sequence<_Tp, mutable_buffer>::type
+    { };
+
+  template<typename _Tp>
+    struct is_const_buffer_sequence
+    : __is_buffer_sequence<_Tp, const_buffer>::type
+    { };
+
+  template<typename _Tp>
+    constexpr bool is_mutable_buffer_sequence_v
+      = is_mutable_buffer_sequence<_Tp>::value;
+
+  template<typename _Tp>
+    constexpr bool is_const_buffer_sequence_v
+      = is_const_buffer_sequence<_Tp>::value;
+
+  template<typename _Tp, typename = void>
+    struct __is_dynamic_buffer_impl : false_type
+    { };
+
+  // Check DynamicBuffer requirements.
+  template<typename _Tp, typename _Up = remove_const_t<_Tp>>
+    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<typename _Tp::const_buffers_type>,
+      is_mutable_buffer_sequence<typename _Tp::mutable_buffers_type>,
+      is_same<decltype(__x1->size()), size_t>,
+      is_same<decltype(__x1->max_size()), size_t>,
+      is_same<decltype(__x1->capacity()), size_t>,
+      is_same<decltype(__x1->data()), typename _Tp::const_buffers_type>,
+      is_same<decltype(__x->prepare(__n)), typename _Tp::mutable_buffers_type>,
+      is_void<decltype(__x->commit(__n), __x->consume(__n), void())>
+    >::value>;
+
+  template<typename _Tp>
+    struct __is_dynamic_buffer_impl<_Tp,
+                                   decltype(__dynamic_buffer_reqs<_Tp>())>
+    : true_type
+    { };
+
+  template<typename _Tp>
+    struct is_dynamic_buffer : __is_dynamic_buffer_impl<_Tp>::type
+    { };
+
+  template<typename _Tp>
+    constexpr bool is_dynamic_buffer_v = is_dynamic_buffer<_Tp>::value;
+
+  // @}
+
+  /// buffer size
+  template<typename _ConstBufferSequence>
+    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<typename _ConstBufferSequence>
+    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<typename _MutableBufferSequence, typename _ConstBufferSequence>
+    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<typename _MutableBufferSequence, typename _ConstBufferSequence>
+    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<char*>(__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<const char*>(__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<typename _Tp>
+    inline mutable_buffer
+    __to_mbuf(_Tp* __data, size_t __n)
+    { return { __n ? __data : nullptr, __n * sizeof(_Tp) }; }
+
+  template<typename _Tp>
+    inline const_buffer
+    __to_cbuf(const _Tp* __data, size_t __n)
+    { return { __n ? __data : nullptr, __n * sizeof(_Tp) }; }
+
+  template<typename _Tp, size_t _Nm>
+    inline mutable_buffer
+    buffer(_Tp (&__data)[_Nm]) noexcept
+    { return net::__to_mbuf(__data, _Nm); }
+
+  template<typename _Tp, size_t _Nm>
+    inline const_buffer
+    buffer(const _Tp (&__data)[_Nm]) noexcept
+    { return net::__to_cbuf(__data, _Nm); }
+
+  template<typename _Tp, size_t _Nm>
+    inline mutable_buffer
+    buffer(array<_Tp, _Nm>& __data) noexcept
+    { return net::__to_mbuf(__data.data(), _Nm); }
+
+  template<typename _Tp, size_t _Nm>
+    inline const_buffer
+    buffer(array<const _Tp, _Nm>& __data) noexcept
+    { return net::__to_cbuf(__data.data(), __data.size()); }
+
+  template<typename _Tp, size_t _Nm>
+    inline const_buffer
+    buffer(const array<_Tp, _Nm>& __data) noexcept
+    { return net::__to_cbuf(__data.data(), __data.size()); }
+
+  template<typename _Tp, typename _Allocator>
+    inline mutable_buffer
+    buffer(vector<_Tp, _Allocator>& __data) noexcept
+    { return net::__to_mbuf(__data.data(), __data.size()); }
+
+  template<typename _Tp, typename _Allocator>
+    inline const_buffer
+    buffer(const vector<_Tp, _Allocator>& __data) noexcept
+    { return net::__to_cbuf(__data.data(), __data.size()); }
+
+  template<typename _CharT, typename _Traits, typename _Allocator>
+    inline mutable_buffer
+    buffer(basic_string<_CharT, _Traits, _Allocator>& __data) noexcept
+    { return net::__to_mbuf(&__data.front(), __data.size()); }
+
+  template<typename _CharT, typename _Traits, typename _Allocator>
+    inline const_buffer
+    buffer(const basic_string<_CharT, _Traits, _Allocator>& __data) noexcept
+    { return net::__to_cbuf(&__data.front(), __data.size()); }
+
+  template<typename _CharT, typename _Traits>
+    inline const_buffer
+    buffer(basic_string_view<_CharT, _Traits> __data) noexcept
+    { return net::__to_cbuf(__data.data(), __data.size()); }
+
+  template<typename _Tp, size_t _Nm>
+    inline mutable_buffer
+    buffer(_Tp (&__data)[_Nm], size_t __n) noexcept
+    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
+
+  template<typename _Tp, size_t _Nm>
+    inline const_buffer
+    buffer(const _Tp (&__data)[_Nm], size_t __n) noexcept
+    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
+
+  template<typename _Tp, size_t _Nm>
+    inline mutable_buffer
+    buffer(array<_Tp, _Nm>& __data, size_t __n) noexcept
+    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
+
+  template<typename _Tp, size_t _Nm>
+    inline const_buffer
+    buffer(array<const _Tp, _Nm>& __data, size_t __n) noexcept
+    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
+
+  template<typename _Tp, size_t _Nm>
+    inline const_buffer
+    buffer(const array<_Tp, _Nm>& __data, size_t __n) noexcept
+    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
+
+  template<typename _Tp, typename _Allocator>
+    inline mutable_buffer
+    buffer(vector<_Tp, _Allocator>& __data, size_t __n) noexcept
+    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
+
+  template<typename _Tp, typename _Allocator>
+    inline const_buffer
+    buffer(const vector<_Tp, _Allocator>& __data, size_t __n) noexcept
+    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
+
+  template<typename _CharT, typename _Traits, typename _Allocator>
+    inline mutable_buffer
+    buffer(basic_string<_CharT, _Traits, _Allocator>& __data,
+          size_t __n) noexcept
+    { return buffer(net::buffer(__data), __n * sizeof(_CharT)); }
+
+  template<typename _CharT, typename _Traits, typename _Allocator>
+    inline const_buffer
+    buffer(const basic_string<_CharT, _Traits, _Allocator>& __data,
+          size_t __n) noexcept
+    { return buffer(net::buffer(__data), __n * sizeof(_CharT)); }
+
+  template<typename _CharT, typename _Traits>
+    inline const_buffer
+    buffer(basic_string_view<_CharT, _Traits> __data, size_t __n) noexcept
+    { return buffer(net::buffer(__data), __n * sizeof(_CharT)); }
+
+
+  template<typename _Sequence>
+    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<typename _Tp, typename _Allocator>
+    class dynamic_vector_buffer
+    : public __dynamic_buffer_base<vector<_Tp, _Allocator>>
+    {
+    public:
+      using __dynamic_buffer_base<vector<_Tp, _Allocator>>::__dynamic_buffer_base;
+    };
+
+  template<typename _CharT, typename _Traits, typename _Allocator>
+    class dynamic_string_buffer
+    : public __dynamic_buffer_base<basic_string<_CharT, _Traits, _Allocator>>
+    {
+    public:
+      using __dynamic_buffer_base<basic_string<_CharT, _Traits, _Allocator>>::
+       __dynamic_buffer_base;
+    };
+
+  // dynamic buffer creation:
+
+  template<typename _Tp, typename _Allocator>
+    inline dynamic_vector_buffer<_Tp, _Allocator>
+    dynamic_buffer(vector<_Tp, _Allocator>& __vec) noexcept
+    { return dynamic_vector_buffer<_Tp, _Allocator>{__vec}; }
+
+  template<typename _Tp, typename _Allocator>
+    inline dynamic_vector_buffer<_Tp, _Allocator>
+    dynamic_buffer(vector<_Tp, _Allocator>& __vec, size_t __n) noexcept
+    { return {__vec, __n}; }
+
+  template<typename _CharT, typename _Traits, typename _Allocator>
+    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<typename _CharT, typename _Traits, typename _Allocator>
+    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<typename _SyncReadStream, typename _MutableBufferSequence,
+          typename _CompletionCondition>
+    enable_if_t<is_mutable_buffer_sequence<_MutableBufferSequence>::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<typename _SyncReadStream, typename _MutableBufferSequence>
+    inline
+    enable_if_t<is_mutable_buffer_sequence<_MutableBufferSequence>::value,
+               size_t>
+    read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers)
+    {
+      error_code __ec;
+      return net::read(__stream, __buffers, transfer_all{}, __ec);
+    }
+
+  template<typename _SyncReadStream, typename _MutableBufferSequence>
+    inline
+    enable_if_t<is_mutable_buffer_sequence<_MutableBufferSequence>::value,
+               size_t>
+    read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers,
+        error_code& __ec)
+    { return net::read(__stream, __buffers, transfer_all{}, __ec); }
+
+  template<typename _SyncReadStream, typename _MutableBufferSequence,
+          typename _CompletionCondition>
+    inline
+    enable_if_t<is_mutable_buffer_sequence<_MutableBufferSequence>::value,
+               size_t>
+    read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers,
+        _CompletionCondition __completion_condition)
+    {
+      error_code __ec;
+      return net::read(__stream, __buffers, __completion_condition, __ec);
+    }
+
+
+  template<typename _SyncReadStream, typename _DynamicBuffer,
+          typename _CompletionCondition>
+    enable_if_t<is_dynamic_buffer<decay_t<_DynamicBuffer>>::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<typename _SyncReadStream, typename _DynamicBuffer>
+    inline enable_if_t<is_dynamic_buffer<_DynamicBuffer>::value, size_t>
+    read(_SyncReadStream& __stream, _DynamicBuffer&& __b)
+    {
+      error_code __ec;
+      return net::read(__stream, __b, transfer_all{}, __ec);
+    }
+
+  template<typename _SyncReadStream, typename _DynamicBuffer>
+    inline enable_if_t<is_dynamic_buffer<_DynamicBuffer>::value, size_t>
+    read(_SyncReadStream& __stream, _DynamicBuffer&& __b, error_code& __ec)
+    {
+      return net::read(__stream, __b, transfer_all{}, __ec);
+    }
+
+  template<typename _SyncReadStream, typename _DynamicBuffer,
+          typename _CompletionCondition>
+    inline enable_if_t<is_dynamic_buffer<_DynamicBuffer>::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<typename _AsyncReadStream, typename _MutableBufferSequence,
+          typename _CompletionCondition, typename _CompletionToken>
+    __deduced_t<_CompletionToken, void(error_code, size_t)>
+    async_read(_AsyncReadStream& __stream,
+              const _MutableBufferSequence& __buffers,
+              _CompletionCondition __completion_condition,
+              _CompletionToken&& __token)
+    {
+      error_code __ec;
+    }
+
+  template<typename _AsyncReadStream, typename _MutableBufferSequence,
+          typename _CompletionToken>
+    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<typename _AsyncReadStream, typename _DynamicBuffer,
+          typename _CompletionCondition, typename _CompletionToken>
+    __deduced_t<_CompletionToken, void(error_code, size_t)>
+    async_read(_AsyncReadStream& __stream, _DynamicBuffer&& __b,
+              _CompletionCondition __completion_condition,
+              _CompletionToken&& __token)
+    {
+      error_code __ec;
+    }
+
+  template<typename _AsyncReadStream, typename _DynamicBuffer,
+          typename _CompletionToken>
+    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<typename _SyncWriteStream, typename _ConstBufferSequence>
+    size_t write(_SyncWriteStream& __stream,
+                 const _ConstBufferSequence& __buffers);
+  template<typename _SyncWriteStream, typename _ConstBufferSequence>
+    size_t write(_SyncWriteStream& __stream,
+                 const _ConstBufferSequence& __buffers, error_code& __ec);
+  template<typename _SyncWriteStream, typename _ConstBufferSequence,
+    typename _CompletionCondition>
+      size_t write(_SyncWriteStream& __stream,
+                   const _ConstBufferSequence& __buffers,
+                   _CompletionCondition __completion_condition);
+  template<typename _SyncWriteStream, typename _ConstBufferSequence,
+    typename _CompletionCondition>
+      size_t write(_SyncWriteStream& __stream,
+                   const _ConstBufferSequence& __buffers,
+                   _CompletionCondition __completion_condition,
+                   error_code& __ec);
+
+  template<typename _SyncWriteStream, typename _DynamicBuffer>
+    size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b);
+  template<typename _SyncWriteStream, typename _DynamicBuffer>
+    size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b, error_code& __ec);
+  template<typename _SyncWriteStream, typename _DynamicBuffer, typename _CompletionCondition>
+    size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b,
+                 _CompletionCondition __completion_condition);
+  template<typename _SyncWriteStream, typename _DynamicBuffer, typename _CompletionCondition>
+    size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b,
+                 _CompletionCondition __completion_condition, error_code& __ec);
+
+  // @}
+
+  /** @brief asynchronous write operations
+   * @{
+   */
+
+  template<typename _AsyncWriteStream, typename _ConstBufferSequence,
+    typename _CompletionToken>
+      DEDUCED async_write(_AsyncWriteStream& __stream,
+                       const _ConstBufferSequence& __buffers,
+                       _CompletionToken&& __token);
+  template<typename _AsyncWriteStream, typename _ConstBufferSequence,
+    typename _CompletionCondition, typename _CompletionToken>
+      DEDUCED async_write(_AsyncWriteStream& __stream,
+                       const _ConstBufferSequence& __buffers,
+                       _CompletionCondition __completion_condition,
+                       _CompletionToken&& __token);
+
+  template<typename _AsyncWriteStream, typename _DynamicBuffer, typename _CompletionToken>
+    DEDUCED async_write(_AsyncWriteStream& __stream,
+                     _DynamicBuffer&& __b, _CompletionToken&& __token);
+  template<typename _AsyncWriteStream, typename _DynamicBuffer,
+    typename _CompletionCondition, typename _CompletionToken>
+      DEDUCED async_write(_AsyncWriteStream& __stream,
+                       _DynamicBuffer&& __b,
+                       _CompletionCondition __completion_condition,
+                       _CompletionToken&& __token);
+
+  // @}
+
+  /** @brief synchronous delimited read operations
+   * @{
+   */
+
+  template<typename _SyncReadStream, typename _DynamicBuffer>
+    size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b, char __delim);
+  template<typename _SyncReadStream, typename _DynamicBuffer>
+    size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b,
+                      char __delim, error_code& __ec);
+  template<typename _SyncReadStream, typename _DynamicBuffer>
+    size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b, string_view __delim);
+  template<typename _SyncReadStream, typename _DynamicBuffer>
+    size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b,
+                      string_view __delim, error_code& __ec);
+
+  // @}
+
+  /** @brief asynchronous delimited read operations
+   * @{
+   */
+
+  template<typename _AsyncReadStream, typename _DynamicBuffer, typename _CompletionToken>
+    DEDUCED async_read_until(_AsyncReadStream& __s,
+                          _DynamicBuffer&& __b, char __delim,
+                          _CompletionToken&& __token);
+  template<typename _AsyncReadStream, typename _DynamicBuffer, typename _CompletionToken>
+    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<experimental::net::v1::stream_errc>
+    : 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 (file)
index 0000000..cd4adb5
--- /dev/null
@@ -0,0 +1,1887 @@
+// <experimental/executor> -*- 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
+// <http://www.gnu.org/licenses/>.
+
+/** @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 <algorithm>
+#include <functional>
+#include <future>
+#include <list>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <tuple>
+#include <unordered_map>
+#include <utility>
+#include <experimental/netfwd>
+#include <bits/unique_ptr.h>
+#include <experimental/bits/net.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+namespace experimental
+{
+namespace net
+{
+inline namespace v1
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  /**
+   * @ingroup networking
+   * @{
+   */
+
+  /// Customization point for asynchronous operations.
+  template<typename _CompletionToken, typename _Signature, typename = void>
+    class async_result;
+
+  /// Convenience utility to help implement asynchronous operations.
+  template<typename _CompletionToken, typename _Signature>
+    class async_completion;
+
+  template<typename _Tp, typename _ProtoAlloc, typename = __void_t<>>
+    struct __associated_allocator_impl
+    {
+      using type = _ProtoAlloc;
+
+      static type
+      _S_get(const _Tp&, const _ProtoAlloc& __a) noexcept { return __a; }
+    };
+
+  template<typename _Tp, typename _ProtoAlloc>
+    struct __associated_allocator_impl<_Tp, _ProtoAlloc,
+                                      __void_t<typename _Tp::allocator_type>>
+    {
+      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<typename _Tp, typename _ProtoAllocator = allocator<void>>
+    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<typename _Tp, typename _ProtoAllocator = allocator<void>>
+    using associated_allocator_t
+      = typename associated_allocator<_Tp, _ProtoAllocator>::type;
+
+  // get_associated_allocator:
+
+  template<typename _Tp>
+    inline associated_allocator_t<_Tp>
+    get_associated_allocator(const _Tp& __t) noexcept
+    { return associated_allocator<_Tp>::get(__t); }
+
+  template<typename _Tp, typename _ProtoAllocator>
+    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<typename _Tp> 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<typename _Tp, typename _Executor> struct uses_executor;
+
+  template<typename _Tp, typename _Executor, typename = __void_t<>>
+    struct __associated_executor_impl
+    {
+      using type = _Executor;
+
+      static type
+      _S_get(const _Tp&, const _Executor& __e) noexcept { return __e; }
+    };
+
+  template<typename _Tp, typename _Executor>
+    struct __associated_executor_impl<_Tp, _Executor,
+                                      __void_t<typename _Tp::executor_type>>
+    {
+      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<typename _Tp, typename _Executor = system_executor>
+    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<typename _Tp, typename _Executor = system_executor>
+    using associated_executor_t
+      = typename associated_executor<_Tp, _Executor>::type;
+
+  template<typename _ExecutionContext>
+    using __is_exec_context
+      = is_convertible<_ExecutionContext&, execution_context&>;
+
+  template<typename _Tp>
+    using __executor_t = typename _Tp::executor_type;
+
+  // get_associated_executor:
+
+  template<typename _Tp>
+    inline associated_executor_t<_Tp>
+    get_associated_executor(const _Tp& __t) noexcept
+    { return associated_executor<_Tp>::get(__t); }
+
+  template<typename _Tp, typename _Executor>
+    inline
+    enable_if_t<is_executor<_Executor>::value,
+               associated_executor_t<_Tp, _Executor>>
+    get_associated_executor(const _Tp& __t, const _Executor& __ex)
+    { return associated_executor<_Tp, _Executor>::get(__t, __ex); }
+
+  template<typename _Tp, typename _ExecutionContext>
+    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<typename _Tp, typename _Executor>
+    class executor_binder;
+
+  template<typename _Tp, typename _Executor, typename _Signature>
+    class async_result<executor_binder<_Tp, _Executor>, _Signature>;
+
+  template<typename _Tp, typename _Executor, typename _ProtoAllocator>
+    struct associated_allocator<executor_binder<_Tp, _Executor>,
+                               _ProtoAllocator>;
+
+  template<typename _Tp, typename _Executor, typename _Executor1>
+    struct associated_executor<executor_binder<_Tp, _Executor>, _Executor1>;
+
+  // bind_executor:
+
+  template<typename _Executor, typename _Tp>
+    inline
+    enable_if_t<is_executor<_Executor>::value,
+               executor_binder<decay_t<_Tp>, _Executor>>
+    bind_executor(const _Executor& __ex, _Tp&& __t)
+    { return { std::forward<_Tp>(__t), __ex }; }
+
+  template<typename _ExecutionContext, typename _Tp>
+    inline
+    enable_if_t<__is_exec_context<_ExecutionContext>::value,
+               executor_binder<decay_t<_Tp>, __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<typename _Executor>
+    class executor_work_guard;
+
+  // make_work_guard:
+
+  template<typename _Executor>
+    inline
+    enable_if_t<is_executor<_Executor>::value, executor_work_guard<_Executor>>
+    make_work_guard(const _Executor& __ex)
+    { return executor_work_guard<_Executor>(__ex); }
+
+  template<typename _ExecutionContext>
+    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<typename _Tp>
+    inline
+    enable_if_t<__not_<__or_<is_executor<_Tp>, __is_exec_context<_Tp>>>::value,
+               executor_work_guard<associated_executor_t<_Tp>>>
+    make_work_guard(const _Tp& __t)
+    { return net::get_associated_executor(__t); }
+
+  template<typename _Tp, typename _Up>
+    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<typename _CompletionToken>
+    __deduced_t<_CompletionToken, void()>
+    dispatch(_CompletionToken&& __token);
+
+  template<typename _Executor, typename _CompletionToken>
+    __deduced_t<_CompletionToken, void()>
+    dispatch(const _Executor& __ex, _CompletionToken&& __token);
+
+  template<typename _ExecutionContext, typename _CompletionToken>
+    __deduced_t<_CompletionToken, void()>
+    dispatch(_ExecutionContext& __ctx, _CompletionToken&& __token);
+
+  // post:
+
+  template<typename _CompletionToken>
+    __deduced_t<_CompletionToken, void()>
+    post(_CompletionToken&& __token);
+  template<typename _Executor, typename _CompletionToken>
+    enable_if_t<is_executor<_Executor>::value,
+               __deduced_t<_CompletionToken, void()>>
+    post(const _Executor& __ex, _CompletionToken&& __token);
+  template<typename _ExecutionContext, typename _CompletionToken>
+    enable_if_t<__is_exec_context<_ExecutionContext>::value,
+               __deduced_t<_CompletionToken, void()>>
+    post(_ExecutionContext& __ctx, _CompletionToken&& __token);
+
+  // defer:
+
+  template<typename _CompletionToken>
+    __deduced_t<_CompletionToken, void()>
+    defer(_CompletionToken&& __token);
+  template<typename _Executor, typename _CompletionToken>
+    __deduced_t<_CompletionToken, void()>
+    defer(const _Executor& __ex, _CompletionToken&& __token);
+  template<typename _ExecutionContext, typename _CompletionToken>
+    __deduced_t<_CompletionToken, void()>
+    defer(_ExecutionContext& __ctx, _CompletionToken&& __token);
+
+  template<typename _Executor>
+    class strand;
+
+  template<typename _Executor>
+    bool
+    operator==(const strand<_Executor>& __a, const strand<_Executor>& __b);
+
+  template<typename _Executor>
+    bool
+    operator!=(const strand<_Executor>& __a, const strand<_Executor>& __b)
+    { return !(__a == __b); }
+
+  template<typename _CompletionToken, typename _Signature, typename>
+    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<typename _CompletionToken, typename _Signature>
+    class async_completion
+    {
+      using __result_type
+       = async_result<decay_t<_CompletionToken>, _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<typename _Service>
+      static void
+      _S_deleter(service* __svc) { delete static_cast<_Service*>(__svc); }
+
+    struct _ServicePtr
+    {
+      template<typename _Service>
+       explicit
+       _ServicePtr(_Service* __svc)
+       : _M_ptr(__svc, &_S_deleter<_Service>), _M_active(true) { }
+
+      std::unique_ptr<service, void(*)(service*)> _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<typename _Service, typename... _Args>
+      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<typename _Key>
+      static __key_type
+      _S_key() { return reinterpret_cast<__key_type>(&_S_key<_Key>); }
+
+    std::unordered_map<__key_type, service*> _M_keys;
+
+    template<typename _Service>
+      friend typename _Service::key_type&
+      use_service(execution_context&);
+
+    template<typename _Service, typename... _Args>
+      friend _Service&
+      make_service(execution_context&, _Args&&...);
+
+    template<typename _Service>
+      friend bool
+      has_service(const execution_context&) noexcept;
+  };
+
+  // service access:
+
+  template<typename _Service>
+    typename _Service::key_type&
+    use_service(execution_context& __ctx)
+    {
+      using _Key = typename _Service::key_type;
+      static_assert(is_base_of<execution_context::service, _Key>::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<std::mutex> __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<typename _Service, typename... _Args>
+    _Service&
+    make_service(execution_context& __ctx, _Args&&... __args)
+    {
+      using _Key = typename _Service::key_type;
+      static_assert(is_base_of<execution_context::service, _Key>::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<std::mutex> __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<typename _Service>
+    inline bool
+    has_service(const execution_context& __ctx) noexcept
+    {
+      using _Key = typename _Service::key_type;
+      static_assert(is_base_of<execution_context::service, _Key>::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<std::mutex> __lock(__ctx._M_mutex);
+      return __ctx._M_keys.count(execution_context::_S_key<_Key>());
+    }
+
+  template<typename _Tp, typename = __void_t<>>
+    struct __is_executor_impl : false_type
+    { };
+
+  // Check Executor requirements.
+  template<typename _Tp, typename _Up = remove_const_t<_Tp>>
+    auto
+    __executor_reqs(_Up* __x = 0, const _Up* __cx = 0, void(*__f)() = 0,
+                   const allocator<int>& __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<typename _Tp>
+    struct __is_executor_impl<_Tp, decltype(__executor_reqs<_Tp>())>
+    : true_type
+    { };
+
+  template<typename _Tp>
+    struct is_executor : __is_executor_impl<_Tp>
+    { };
+
+  template<typename _Tp>
+    constexpr bool is_executor_v = is_executor<_Tp>::value;
+
+  template<typename _Tp, typename _Executor, typename = __void_t<>>
+    struct __uses_executor_impl : false_type
+    { };
+
+  template<typename _Tp, typename _Executor>
+    struct __uses_executor_impl<_Tp, _Executor,
+                               __void_t<typename _Tp::executor_type>>
+    : is_convertible<_Executor, typename _Tp::executor_type>
+    { };
+
+  template<typename _Tp, typename _Executor>
+    struct uses_executor : __uses_executor_impl<_Tp, _Executor>::type
+    { };
+
+  template<typename _Tp, typename _Executor>
+    constexpr bool uses_executor_v = uses_executor<_Tp, _Executor>::value;
+
+  template<typename _Tp, typename _Executor>
+    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<typename _Up, typename _OtherExecutor>
+       executor_binder(const executor_binder<_Up, _OtherExecutor>& __other)
+       : executor_binder(__use_exec{}, __other.get(), __other.get_executor())
+       { }
+
+      template<typename _Up, typename _OtherExecutor>
+       executor_binder(executor_binder<_Up, _OtherExecutor>&& __other)
+       : executor_binder(__use_exec{}, std::move(__other.get()),
+                         __other.get_executor())
+       { }
+
+      template<typename _Up, typename _OtherExecutor>
+       executor_binder(executor_arg_t, const _Executor& __ex,
+                       const executor_binder<_Up, _OtherExecutor>& __other)
+       : executor_binder(__use_exec{}, __other.get(), __ex)
+       { }
+
+      template<typename _Up, typename _OtherExecutor>
+       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<class... _Args>
+       result_of_t<_Tp&(_Args&&...)>
+       operator()(_Args&&... __args)
+       { return std::__invoke(get(), std::forward<_Args>(__args)...); }
+
+      template<class... _Args>
+       result_of_t<const _Tp&(_Args&&...)>
+       operator()(_Args&&... __args) const
+       { return std::__invoke(get(), std::forward<_Args>(__args)...); }
+
+    private:
+      template<typename _Up>
+       using __use_exec_cond
+         = __and_<uses_executor<_Tp, _Executor>,
+                  is_constructible<_Tp, executor_arg_t, _Executor, _Up>>;
+
+      template<typename _Up, typename _Exec, typename =
+              enable_if_t<__use_exec_cond<_Up>::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<typename _Up, typename _Exec, typename =
+              enable_if_t<!__use_exec_cond<_Up>::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<typename _Tp, typename _Executor, typename _Signature>
+    class async_result<executor_binder<_Tp, _Executor>, _Signature>
+    {
+      using __inner = async_result<_Tp, _Signature>;
+
+    public:
+      using completion_handler_type =
+       executor_binder<typename __inner::completion_handler_type, _Executor>;
+
+      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<typename _Tp, typename _Executor, typename _ProtoAlloc>
+    struct associated_allocator<executor_binder<_Tp, _Executor>, _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<typename _Tp, typename _Executor, typename _Executor1>
+    struct associated_executor<executor_binder<_Tp, _Executor>, _Executor1>
+    {
+      typedef _Executor type;
+
+      static type
+      get(const executor_binder<_Tp, _Executor>& __b,
+         const _Executor1& = _Executor1()) noexcept
+      { return __b.get_executor(); }
+    };
+
+  template<typename _Executor>
+    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<mutex> __lock(_M_mtx);
+      _M_stopped = true;
+      _M_cv.notify_all();
+    }
+
+    bool stopped() const noexcept
+    {
+      lock_guard<mutex> __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<function<void()>>    _M_tasks;
+    bool                       _M_stopped = false;
+
+    void
+    _M_run()
+    {
+      while (true)
+       {
+         function<void()> __f;
+         {
+           unique_lock<mutex> __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<void()> __f)
+    {
+      lock_guard<mutex> __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<typename _Func, typename _ProtoAlloc>
+      void
+      dispatch(_Func&& __f, const _ProtoAlloc& __a) const
+      { decay_t<_Func>{std::forward<_Func>(__f)}(); }
+
+    template<typename _Func, typename _ProtoAlloc>
+      void
+      post(_Func&& __f, const _ProtoAlloc&) const // XXX allocator not used
+      {
+       system_context::_S_get()._M_post(std::forward<_Func>(__f));
+      }
+
+    template<typename _Func, typename _ProtoAlloc>
+      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<typename _Executor>
+      executor(_Executor __e)
+      : _M_target(_M_create(std::move(__e)))
+      { }
+
+    template<typename _Executor, typename _ProtoAlloc>
+      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<typename _Executor>
+      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<typename _Executor, typename _Alloc>
+      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<typename _Func, typename _Alloc>
+      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<typename _Func, typename _Alloc>
+      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<typename _Func, typename _Alloc>
+      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<bool>(_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<typename _Executor>
+      _Executor*
+      target() noexcept
+      {
+       if (_M_target)
+         if (const auto* __p = _M_target->target(typeid(_Executor)))
+           return const_cast<_Executor*>(static_cast<const _Executor>(__p));
+       return nullptr;
+      }
+
+    template<typename _Executor>
+      const _Executor*
+      target() const noexcept
+      {
+       if (_M_target)
+         if (const auto* __p = _M_target->target(typeid(_Executor)))
+           return static_cast<const _Executor*>(__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<void()>) const = 0;
+      virtual void post(std::function<void()>) const = 0;
+      virtual void defer(std::function<void()>) 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<typename _Ex, typename _Alloc>
+      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<void()> __f) const
+       { _M_ex().dispatch(std::move(__f), _M_alloc()); }
+       void
+       post(std::function<void()> __f) const
+       { _M_ex().post(std::move(__f), _M_alloc()); }
+       void
+       defer(std::function<void()> __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<const _Ex*>(__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<typename _Ex, typename _Alloc = std::allocator<void>>
+      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<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<typename _CompletionHandler>
+    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<typename _CompletionHandler>
+    inline __dispatcher<_CompletionHandler>
+    __make_dispatcher(_CompletionHandler& __h)
+    { return __dispatcher<_CompletionHandler>{__h}; }
+
+
+
+  // dispatch:
+
+  template<typename _CompletionToken>
+    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<typename _Executor, typename _CompletionToken>
+    inline
+    enable_if_t<is_executor<_Executor>::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<typename _ExecutionContext, typename _CompletionToken>
+    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<typename _CompletionToken>
+    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<typename _Executor, typename _CompletionToken>
+    inline
+    enable_if_t<is_executor<_Executor>::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<typename _ExecutionContext, typename _CompletionToken>
+    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<typename _CompletionToken>
+    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<typename _Executor, typename _CompletionToken>
+    inline
+    enable_if_t<is_executor<_Executor>::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<typename _ExecutionContext, typename _CompletionToken>
+    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<typename _Executor>
+    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<typename _Alloc>
+       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<typename _OtherExecutor>
+       strand(const strand<_OtherExecutor>& __other) noexcept
+       : _M_state(__other._M_state), _M_inner_ex(__other._M_inner_ex) { }
+
+      template<typename _OtherExecutor>
+       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<typename _OtherExecutor>
+       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<typename _OtherExecutor>
+       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<typename _Func, typename _Alloc>
+       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<typename _Func, typename _Alloc>
+       void
+       post(_Func&& __f, const _Alloc& __a) const; // TODO
+
+      template<typename _Func, typename _Alloc>
+       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<typename _Func, typename _Alloc>
+    struct __use_future_ct
+    {
+      std::tuple<_Func, _Alloc> _M_t;
+    };
+
+  template<typename _ProtoAllocator = allocator<void>>
+    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<class _OtherAllocator>
+       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<typename _Func>
+       auto
+       operator()(_Func&& __f) const
+       {
+         using _Token = __use_future_ct<decay_t<_Func>, _ProtoAllocator>;
+         return _Token{ {std::forward<_Func>(__f), _M_alloc} };
+       }
+
+    private:
+      _ProtoAllocator _M_alloc;
+    };
+
+  constexpr use_future_t<> use_future = use_future_t<>();
+
+  template<typename _Func, typename _Alloc, typename _Res, typename... _Args>
+    class async_result<__use_future_ct<_Func, _Alloc>, _Res(_Args...)>;
+
+  template<typename _Result, typename _Executor>
+    struct __use_future_ex;
+
+  // Completion handler for asynchronous operations initiated with use_future.
+  template<typename _Func, typename... _Args>
+    struct __use_future_ch
+    {
+      template<typename _Alloc>
+       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<typename _Result, typename _Executor>
+       friend struct __use_future_ex;
+
+      _Func _M_f;
+      mutable promise<__result> _M_promise;
+    };
+
+  // Specialization of async_result for operations initiated with use_future.
+  template<typename _Func, typename _Alloc, typename _Res, typename... _Args>
+    class async_result<__use_future_ct<_Func, _Alloc>, _Res(_Args...)>
+    {
+    public:
+      using completion_handler_type = __use_future_ch<_Func, _Args...>;
+      using return_type = future<typename completion_handler_type::__result>;
+
+      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<typename _Result, typename _Executor>
+    struct __use_future_ex
+    {
+      template<typename _Handler>
+      __use_future_ex(const _Handler& __h, _Executor __ex)
+      : _M_t(__h._M_promise, __ex)
+      { }
+
+      template<typename _Fn, typename _Alloc>
+       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<typename _Fn, typename _Alloc>
+       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<typename _Fn, typename _Alloc>
+       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<promise<_Result>&, _Executor> _M_t;
+    };
+
+  template<typename _Func, typename... _Args, typename _Executor>
+    struct associated_executor<__use_future_ch<_Func, _Args...>, _Executor>
+    {
+    private:
+      using __handler = __use_future_ch<_Func, _Args...>;
+
+      using type = __use_future_ex<typename __handler::__result, _Executor>;
+
+      static type
+      get(const __handler& __h, const _Executor& __ex)
+      { return { __h, __ex }; }
+    };
+
+#if 0
+
+  // [async.use.future.traits]
+  template<typename _Allocator, typename _Ret, typename... _Args>
+    class handler_type<use_future_t<_Allocator>, _Ret(_Args...)> // TODO uglify name
+    {
+      template<typename... _Args>
+       struct __is_error_result : false_type { };
+
+      template<typename... _Args>
+       struct __is_error_result<error_code, _Args...> : true_type { };
+
+      template<typename... _Args>
+       struct __is_error_result<exception_ptr, _Args...> : 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<bool _IsError, typename... _UArgs>
+       struct _Type;
+
+      // N == 0
+      template<bool _IsError>
+       struct _Type<_IsError>
+       {
+         std::promise<void> _M_promise;
+
+         void
+         operator()()
+         {
+           _M_promise.set_value();
+         }
+       };
+
+      // N == 1, U0 is error_code or exception_ptr
+      template<typename _UArg0>
+       struct _Type<true, _UArg0>
+       {
+         std::promise<void> _M_promise;
+
+         template<typename _Arg0>
+           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<typename _UArg0>
+       struct _Type<false, _UArg0>
+       {
+         std::promise<_UArg0> _M_promise;
+
+         template<typename _Arg0>
+           void
+           operator()(_Arg0&& __a0)
+           {
+             _M_promise.set_value(std::forward<_Arg0>(__a0));
+           }
+       };
+
+      // N == 2, U0 is error_code or exception_ptr
+      template<typename _UArg0, typename _UArg1>
+       struct _Type<true, _UArg0, _UArg1>
+       {
+         std::promise<_UArg1> _M_promise;
+
+         template<typename _Arg0, typename _Arg1>
+           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<typename... _UArgs>
+       struct _Type<false, _UArgs...>
+       {
+         static_assert(sizeof...(_UArgs) > 1, "wrong partial specialization");
+
+         std::promise<tuple<_UArgs...>> _M_promise;
+
+         template<typename... _Args>
+           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<typename _UArg0, typename... _UArgs>
+       struct _Type<true, _UArg0, _UArgs...>
+       {
+         static_assert(sizeof...(_UArgs) > 1, "wrong partial specialization");
+
+         std::promise<tuple<_UArgs...>> _M_promise;
+
+         template<typename _Arg0, typename... _Args>
+           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<typename _Alloc, typename _Ret, typename... _Args>
+    struct async_result<use_future_t<_Alloc>, _Ret(_Args...)>
+    {
+      using completion_handler_type
+       = typename handler_type<use_future_t<_Alloc>, _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<use_future_t<A>, 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<typename _Ret, typename... _Args, typename _Signature>
+    class async_result<packaged_task<_Ret(_Args...)>, _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<typename _Alloc>
+    struct uses_allocator<experimental::net::executor, _Alloc>
+    : 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 (file)
index 0000000..07fe614
--- /dev/null
@@ -0,0 +1,2397 @@
+// <experimental/internet> -*- 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
+// <http://www.gnu.org/licenses/>.
+
+/** @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 <experimental/netfwd>
+#include <array>
+#include <forward_list>
+#include <sstream>
+#include <typeinfo>
+#include <cstring>
+#include <cstdint>
+#include <experimental/io_context>
+#include <experimental/bits/net.h>
+#include <experimental/string_view>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+
+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<int>(__e), resolver_category()); }
+
+  error_condition make_error_condition(resolver_errc __e) noexcept
+  { return error_condition(static_cast<int>(__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<typename _Alloc>
+    using __string_with
+      = enable_if_t<std::is_same<typename _Alloc::value_type, char>::value,
+                   std::basic_string<char, std::char_traits<char>, _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<unsigned char, 4>
+    {
+      template<typename... _Tp>
+       explicit constexpr
+       bytes_type(_Tp... __tp)
+       : array<unsigned char, 4>{{static_cast<unsigned char>(__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<typename _Allocator = allocator<char>>
+      __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<typename _InternetProtocol>
+      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<unsigned char, 16>
+    {
+      template<typename... _Tp> explicit constexpr bytes_type(_Tp... __t)
+       : array<unsigned char, 16>{{static_cast<unsigned char>(__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<typename _Allocator = allocator<char>>
+      __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<typename _InternetProtocol>
+      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<typename _Allocator = allocator<char>>
+      __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<typename _InternetProtocol>
+      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<scope_id_type>::max())
+         {
+           return { __b, static_cast<scope_id_type>(__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<typename _CharT, typename _Traits>
+    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<typename _CharT, typename _Traits>
+    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<typename _CharT, typename _Traits>
+    inline basic_ostream<_CharT, _Traits>&
+    operator<<(basic_ostream<_CharT, _Traits>& __os, const address_v6& __a)
+    { return __os << __a.to_string(); }
+
+  template<typename> class basic_address_iterator; // not defined
+
+  template<> class basic_address_iterator<address_v4>
+  {
+  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> address_v4_iterator;
+
+  template<> class basic_address_iterator<address_v6>
+  {
+  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> address_v6_iterator;
+
+  template<typename> class basic_address_range; // not defined
+
+  /** An IPv6 address range.
+   * @{
+   */
+
+  template<> class basic_address_range<address_v4>
+  {
+  public:
+    // types:
+
+    typedef basic_address_iterator<address_v4> 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> address_v4_range;
+
+  // @}
+
+  /** An IPv6 address range.
+   * @{
+   */
+
+  template<> class basic_address_range<address_v6>
+  {
+  public:
+    // types:
+
+    typedef basic_address_iterator<address_v6> 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> 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<typename _Allocator = allocator<char>>
+      __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<typename _Allocator = allocator<char>>
+      __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<typename _CharT, typename _Traits>
+    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<typename _CharT, typename _Traits>
+    inline basic_ostream<_CharT, _Traits>&
+    operator<<(basic_ostream<_CharT, _Traits>& __os, const network_v6& __net)
+    { return __os << __net.to_string(); }
+
+  /// An IP endpoint.
+  template<typename _InternetProtocol>
+    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<typename _InternetProtocol>
+    inline bool
+    operator==(const basic_endpoint<_InternetProtocol>& __a,
+              const basic_endpoint<_InternetProtocol>& __b)
+    { return __a.address() == __b.address() && __a.port() == __b.port(); }
+
+  template<typename _InternetProtocol>
+    inline bool
+    operator!=(const basic_endpoint<_InternetProtocol>& __a,
+              const basic_endpoint<_InternetProtocol>& __b)
+    { return !(__a == __b); }
+
+  template<typename _InternetProtocol>
+    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<typename _InternetProtocol>
+    inline bool
+    operator> (const basic_endpoint<_InternetProtocol>& __a,
+              const basic_endpoint<_InternetProtocol>& __b)
+    { return __b < __a; }
+
+  template<typename _InternetProtocol>
+    inline bool
+    operator<=(const basic_endpoint<_InternetProtocol>& __a,
+              const basic_endpoint<_InternetProtocol>& __b)
+    { return !(__b < __a); }
+
+  template<typename _InternetProtocol>
+    inline bool
+    operator>=(const basic_endpoint<_InternetProtocol>& __a,
+              const basic_endpoint<_InternetProtocol>& __b)
+    { return !(__a < __b); }
+
+  // @}
+
+  /// basic_endpoint I/O
+  template<typename _CharT, typename _Traits, typename _InternetProtocol>
+    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<typename _InternetProtocol>
+    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<typename _Allocator = allocator<char>>
+       __string_with<_Allocator>
+       host_name(const _Allocator& __a = _Allocator()) const
+       { return { _M_host, __a }; }
+
+      template<typename _Allocator = allocator<char>>
+       __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<typename _InternetProtocol>
+    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<typename _InternetProtocol>
+    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<typename _InternetProtocol>
+    class basic_resolver_results
+    {
+    public:
+      // types:
+      typedef _InternetProtocol protocol_type;
+      typedef typename protocol_type::endpoint endpoint_type;
+      typedef basic_resolver_entry<protocol_type> value_type;
+      typedef const value_type& const_reference;
+      typedef value_type& reference;
+      typedef typename forward_list<value_type>::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<protocol_type>;
+
+      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<value_type> _M_results;
+      size_t _M_size = 0;
+    };
+
+  template<typename _InternetProtocol>
+    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<typename _InternetProtocol>
+    inline bool
+    operator!=(const basic_resolver_results<_InternetProtocol>& __a,
+              const basic_resolver_results<_InternetProtocol>& __b)
+    { return !(__a == __b); }
+
+  // @}
+
+  /// Perform name/address resolution.
+  template<typename _InternetProtocol>
+    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<typename _CompletionToken>
+       __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<typename _CompletionToken>
+       __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<typename _CompletionToken>
+       __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<typename _CompletionToken>
+       __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<typename _CompletionToken> // 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<typename _InternetProtocol>
+    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<int>(__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<typename _InternetProtocol>
+    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<const sockaddr*>(__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<typename _Allocator>
+    __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<typename _Allocator>
+    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<char>{}, __ec); }
+
+  inline string
+  host_name()
+  { return host_name(std::allocator<char>{}, __throw_on_error{"host_name"}); }
+
+  // @}
+
+  /// The TCP byte-stream protocol.
+  class tcp
+  {
+  public:
+    // types:
+    typedef basic_endpoint<tcp> endpoint;       ///< A TCP endpoint.
+    typedef basic_resolver<tcp> resolver;       ///< A TCP resolver.
+    typedef basic_stream_socket<tcp> socket;    ///< A TCP socket.
+    typedef basic_socket_acceptor<tcp> acceptor; ///< A TCP acceptor.
+    typedef basic_socket_iostream<tcp> iostream; /// A TCP iostream.
+
+    /// Disable coalescing of small segments (i.e. the Nagle algorithm).
+    struct no_delay : __sockopt_crtp<no_delay, bool>
+    {
+      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<udp> endpoint;
+    typedef basic_resolver<udp> resolver;
+    typedef basic_datagram_socket<udp> 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<v6_only, bool>
+  {
+    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<hops>
+    {
+      using __sockopt_crtp::__sockopt_crtp;
+
+      template<typename _Protocol>
+       int
+       level(const _Protocol& __p) const noexcept
+       { return __p.family() == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP; }
+
+      template<typename _Protocol>
+       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<typename _Protocol>
+       int
+       level(const _Protocol& __p) const noexcept
+       { return __p.family() == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP; }
+
+      template<typename _Protocol>
+       int
+       name(const _Protocol& __p) const noexcept
+       {
+         return __p.family() == AF_INET6
+           ? IPV6_JOIN_GROUP : IP_ADD_MEMBERSHIP;
+       }
+      template<typename _Protocol>
+       void*
+       data(const _Protocol&) noexcept
+       { return std::addressof(_M_value); }
+
+      template<typename _Protocol>
+       const void*
+       data(const _Protocol&) const noexcept
+       { return std::addressof(_M_value); }
+
+      template<typename _Protocol>
+       size_t
+       size(const _Protocol& __p) const noexcept
+       {
+         return __p.family() == AF_INET6
+           ? sizeof(_M_value._M_v6) : sizeof(_M_value._M_v4);
+       }
+
+      template<typename _Protocol>
+       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<typename _Protocol>
+       int
+       level(const _Protocol& __p) const noexcept
+       { return __p.family() == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP; }
+
+      template<typename _Protocol>
+       int
+       name(const _Protocol& __p) const noexcept
+       {
+         return __p.family() == AF_INET6
+           ? IPV6_LEAVE_GROUP : IP_DROP_MEMBERSHIP;
+       }
+      template<typename _Protocol>
+       void*
+       data(const _Protocol&) noexcept
+       { return std::addressof(_M_value); }
+
+      template<typename _Protocol>
+       const void*
+       data(const _Protocol&) const noexcept
+       { return std::addressof(_M_value); }
+
+      template<typename _Protocol>
+       size_t
+       size(const _Protocol& __p) const noexcept
+       {
+         return __p.family() == AF_INET6
+           ? sizeof(_M_value._M_v6) : sizeof(_M_value._M_v4);
+       }
+
+      template<typename _Protocol>
+       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<typename _Protocol>
+       int
+       level(const _Protocol& __p) const noexcept
+       { return __p.family() == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP; }
+
+      template<typename _Protocol>
+       int
+       name(const _Protocol& __p) const noexcept
+       {
+         return __p.family() == AF_INET6
+           ? IPV6_MULTICAST_IF : IP_MULTICAST_IF;
+       }
+
+      template<typename _Protocol>
+       const void*
+       data(const _Protocol&) const noexcept
+       { return std::addressof(_M_value); }
+
+      template<typename _Protocol>
+       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<hops>
+    {
+      using __sockopt_crtp::__sockopt_crtp;
+
+      template<typename _Protocol>
+       int
+       level(const _Protocol& __p) const noexcept
+       { return __p.family() == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP; }
+
+      template<typename _Protocol>
+       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<enable_loopback>
+    {
+      using __sockopt_crtp::__sockopt_crtp;
+
+      template<typename _Protocol>
+       int
+       level(const _Protocol& __p) const noexcept
+       { return __p.family() == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP; }
+
+      template<typename _Protocol>
+       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<experimental::net::v1::ip::resolver_errc>
+    : public true_type {};
+
+  // hash support
+  template<typename _Tp> struct hash;
+  template<>
+    struct hash<experimental::net::v1::ip::address>
+    : __hash_base<size_t, experimental::net::v1::ip::address>
+    {
+      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<experimental::net::v1::ip::address_v4>
+    : __hash_base<size_t, experimental::net::v1::ip::address_v4>
+    {
+      size_t
+      operator()(const argument_type& __a) const
+      { return _Hash_impl::hash(__a.to_bytes()); }
+    };
+
+  template<> struct hash<experimental::net::v1::ip::address_v6>
+    : __hash_base<size_t, experimental::net::v1::ip::address_v6>
+    {
+      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 (file)
index 0000000..7b42442
--- /dev/null
@@ -0,0 +1,864 @@
+// <experimental/io_service> -*- 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
+// <http://www.gnu.org/licenses/>.
+
+/** @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 <atomic>
+#include <chrono>
+#include <forward_list>
+#include <functional>
+#include <system_error>
+#include <thread>
+#include <experimental/netfwd>
+#include <experimental/executor>
+#include <unistd.h>
+#include <poll.h>
+#include <fcntl.h>
+
+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<mutex> __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<typename _Func, typename _ProtoAllocator>
+       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<typename _Func, typename _ProtoAllocator>
+       void
+       post(_Func&& __f, const _ProtoAllocator& __a) const
+       {
+         lock_guard<mutex> __lock(_M_ctx->_M_mtx);
+         // TODO (re-use functionality in system_context)
+         _M_ctx->_M_reactor._M_notify();
+       }
+
+      template<typename _Func, typename _ProtoAllocator>
+       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<count_type>::max())
+         ++__n;
+      return __n;
+    }
+
+    template<typename _Rep, typename _Period>
+      count_type
+      run_for(const chrono::duration<_Rep, _Period>& __rel_time)
+      { return run_until(chrono::steady_clock::now() + __rel_time); }
+
+    template<typename _Clock, typename _Duration>
+      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<count_type>::max())
+           ++__n;
+       return __n;
+      }
+
+    count_type
+    run_one()
+    { return _M_do_one(chrono::milliseconds{-1}); }
+
+    template<typename _Rep, typename _Period>
+      count_type
+      run_one_for(const chrono::duration<_Rep, _Period>& __rel_time)
+      { return run_one_until(chrono::steady_clock::now() + __rel_time); }
+
+    template<typename _Clock, typename _Duration>
+      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<milliseconds>(__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<count_type>::max())
+         ++__n;
+      return __n;
+    }
+
+    count_type
+    poll_one()
+    { return _M_do_one(chrono::milliseconds{0}); }
+
+    void stop()
+    {
+      lock_guard<mutex> __lock(_M_mtx);
+      _M_stopped = true;
+      _M_reactor._M_notify();
+    }
+
+    bool stopped() const noexcept
+    {
+      lock_guard<mutex> __lock(_M_mtx);
+      return _M_stopped;
+    }
+
+    void restart()
+    {
+      _M_stopped = false;
+    }
+
+  private:
+
+    template<typename _Clock, typename _WaitTraits>
+      friend class basic_waitable_timer;
+
+    friend __socket_impl;
+
+    template<typename _Protocol>
+      friend class __basic_socket_impl;
+
+    template<typename _Protocol>
+      friend class basic_socket;
+
+    template<typename _Protocol>
+      friend class basic_datagram_socket;
+
+    template<typename _Protocol>
+      friend class basic_stream_socket;
+
+    template<typename _Protocol>
+      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<io_context&>(__ctx);
+       lock_guard<mutex> __lock(__ioc._M_mtx);
+       __ioc._M_timers.push_back(this);
+      }
+
+      mutable mutex    _M_qmtx;
+    };
+
+    template<typename _Timer, typename _Key = typename _Timer::_Key>
+      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<io_context&>(service::context()); }
+
+       // Start an asynchronous wait.
+       void
+       push(const _Timer& __t, function<void(error_code)> __h)
+       {
+         context().get_executor().on_work_started();
+         lock_guard<mutex> __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<mutex> __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<mutex> __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<mutex> __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<chrono::milliseconds>(__dur);
+       }
+
+      private:
+
+       bool run_one() override
+       {
+         auto __now = _Timer::clock_type::now();
+         function<void(error_code)> __h;
+         error_code __ec;
+         {
+           lock_guard<mutex> __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<void(error_code)> __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<void(error_code)> _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<typename _Timer, typename _CompletionHandler>
+      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<typename _Timer>
+      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<typename _Timer>
+      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<typename _Op>
+      void
+      async_wait(int __fd, int __w, _Op&& __op)
+      {
+       lock_guard<mutex> __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<mutex> __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<typename _Op>
+      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<count_type>         _M_work_count;
+    mutable mutex              _M_mtx;
+    queue<function<void()>>    _M_op;
+    bool                       _M_stopped = false;
+
+    struct __monitor
+    {
+      __monitor(io_context& __c) : _M_ctx(__c)
+      {
+       lock_guard<mutex> __lock(_M_ctx._M_mtx);
+       _M_ctx._M_call_stack.push_back(this_thread::get_id());
+      }
+
+      ~__monitor()
+      {
+       lock_guard<mutex> __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<mutex> __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<int>::max())
+                 __ms = chrono::milliseconds{numeric_limits<int>::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<mutex> __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<unique_ptr<__async_operation>>        _M_ops;
+
+    vector<thread::id> _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<io_context::executor_type> : 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 (file)
index 0000000..3d97546
--- /dev/null
@@ -0,0 +1,45 @@
+// <experimental/net> -*- 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
+// <http://www.gnu.org/licenses/>.
+
+/** @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 <experimental/executor>
+#include <experimental/io_context>
+#include <experimental/timer>
+#include <experimental/buffer>
+#include <experimental/socket>
+#include <experimental/internet>
+
+#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 (file)
index 0000000..a0311a9
--- /dev/null
@@ -0,0 +1,135 @@
+// <experimental/netfwd> -*- 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
+// <http://www.gnu.org/licenses/>.
+
+/** @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 <chrono>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+namespace experimental
+{
+namespace net
+{
+inline namespace v1
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  /**
+   * @ingroup networking
+   * @{
+   */
+
+  class execution_context;
+  template<typename _Tp, typename _Executor>
+    class executor_binder;
+  template<typename _Executor>
+    class executor_work_guard;
+  class system_executor;
+  class executor;
+  template<typename _Executor>
+    class strand;
+
+  class io_service;
+
+  template<typename _Clock> struct wait_traits;
+  template<typename _Clock, typename _WaitTraits = wait_traits<_Clock>>
+    class basic_waitable_timer;
+  typedef basic_waitable_timer<chrono::system_clock> system_timer;
+  typedef basic_waitable_timer<chrono::steady_clock> steady_timer;
+  typedef basic_waitable_timer<chrono::high_resolution_clock>
+    high_resolution_timer;
+
+  template<typename _Protocol>
+    class basic_socket;
+  template<typename _Protocol>
+    class basic_datagram_socket;
+  template<typename _Protocol>
+    class basic_stream_socket;
+  template<typename _Protocol>
+    class basic_socket_acceptor;
+  template<typename _Protocol, typename _Clock = chrono::steady_clock,
+          typename _WaitTraits = wait_traits<_Clock>>
+    class basic_socket_streambuf;
+  template<typename _Protocol, typename _Clock = chrono::steady_clock,
+          typename _WaitTraits = wait_traits<_Clock>>
+    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<typename _InternetProtocol>
+      class basic_endpoint;
+    template<typename _InternetProtocol>
+      class basic_resolver_entry;
+    template<typename _InternetProtocol>
+      class basic_resolver_results;
+    template<typename _InternetProtocol>
+      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 (file)
index 0000000..7adb42e
--- /dev/null
@@ -0,0 +1,2474 @@
+// <experimental/socket> -*- 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
+// <http://www.gnu.org/licenses/>.
+
+/** @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 <experimental/netfwd>
+#include <experimental/buffer>
+#include <experimental/io_context>
+#include <experimental/bits/net.h>
+#include <streambuf>
+#include <istream>
+#include <bits/unique_ptr.h>
+#if _GLIBCXX_HAVE_UNISTD_H
+# include <unistd.h>
+# include <sys/socket.h>
+# include <sys/ioctl.h>
+# include <sys/fcntl.h>
+# include <sys/uio.h>
+# include <poll.h>
+#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<int>(__e), socket_category()); }
+
+  inline error_condition
+  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
+  // TODO IntegerSocketOption reqs
+  // TODO _IoControlCommand reqs
+  // TODO _ConnectCondition reqs
+
+  /** @brief Sockets
+   * @{
+   */
+
+  class socket_base
+  {
+  public:
+    struct broadcast : __sockopt_crtp<broadcast, bool>
+    {
+      using __sockopt_crtp::__sockopt_crtp;
+
+      static const int _S_level = SOL_SOCKET;
+      static const int _S_name = SO_BROADCAST;
+    };
+
+    struct debug : __sockopt_crtp<debug, bool>
+    {
+      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<do_not_route, bool>
+    {
+      using __sockopt_crtp::__sockopt_crtp;
+
+      static const int _S_level = SOL_SOCKET;
+      static const int _S_name = SO_DONTROUTE;
+    };
+
+    struct keep_alive : __sockopt_crtp<keep_alive, bool>
+    {
+      using __sockopt_crtp::__sockopt_crtp;
+
+      static const int _S_level = SOL_SOCKET;
+      static const int _S_name = SO_KEEPALIVE;
+    };
+
+    struct linger : __sockopt_crtp<linger, ::linger>
+    {
+      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<out_of_band_inline, bool>
+    {
+      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<receive_buffer_size>
+    {
+      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<receive_low_watermark>
+    {
+      using __sockopt_crtp::__sockopt_crtp;
+
+      static const int _S_level = SOL_SOCKET;
+      static const int _S_name = SO_RCVLOWAT;
+    };
+
+    struct reuse_address : __sockopt_crtp<reuse_address, bool>
+    {
+      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<send_buffer_size>
+    {
+      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<send_low_watermark>
+    {
+      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<typename _BufferSequence>
+       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<typename _BufferSequence, typename _Endpoint>
+       __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<typename _Protocol>
+    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<typename _OtherProtocol>
+       __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<typename _SettableSocketOption>
+       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<typename _GettableSocketOption>
+       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<typename _IoControlCommand>
+       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<typename _Protocol>
+    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<typename _SettableSocketOption>
+       void
+       set_option(const _SettableSocketOption& __option)
+       { set_option(__option, __throw_on_error{"basic_socket::set_option"}); }
+
+      template<typename _SettableSocketOption>
+       void
+       set_option(const _SettableSocketOption& __option, error_code& __ec)
+       { __base::set_option(__option, __ec); }
+
+      template<typename _GettableSocketOption>
+       void
+       get_option(_GettableSocketOption& __option) const
+       { get_option(__option, __throw_on_error{"basic_socket::get_option"}); }
+
+      template<typename _GettableSocketOption>
+       void
+       get_option(_GettableSocketOption& __option, error_code& __ec) const
+       { __base::get_option(__option, __ec); }
+
+      template<typename _IoControlCommand>
+       void
+       io_control(_IoControlCommand& __command)
+       {
+         io_control(__command, __throw_on_error{"basic_socket::io_control"});
+       }
+
+      template<typename _IoControlCommand>
+       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<int>(__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<typename _CompletionToken>
+       __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<void>());
+                  __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<int>(__w);
+       int __res = ::poll(&__fd, 1, -1);
+       if (__res == -1)
+         __ec.assign(errno, generic_category());
+       else
+         __ec.clear();
+      }
+
+      template<typename _CompletionToken>
+       __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<int>(__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<typename _OtherProtocol, typename _Requires
+              = _Require<is_convertible<_OtherProtocol, _Protocol>>>
+       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<typename _OtherProtocol>
+       enable_if_t<is_convertible<_OtherProtocol, _Protocol>::value,
+                   basic_socket&>
+       operator=(basic_socket<_OtherProtocol>&& __rhs)
+        { return *this = basic_socket{std::move(__rhs)}; }
+    };
+
+  template<typename _Protocol>
+    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<typename _OtherProtocol, typename _Requires
+              = _Require<is_convertible<_OtherProtocol, _Protocol>>>
+       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<typename _OtherProtocol>
+       enable_if_t<is_convertible<_OtherProtocol, _Protocol>::value,
+                   basic_datagram_socket&>
+       operator=(basic_datagram_socket<_OtherProtocol>&& __rhs)
+       {
+         __base::operator=(std::move(__rhs));
+         return *this;
+       }
+
+      // basic_datagram_socket operations:
+
+      template<typename _MutableBufferSequence>
+       size_t
+       receive(const _MutableBufferSequence& __buffers)
+       {
+         return receive(__buffers, socket_base::message_flags(),
+                        __throw_on_error{"basic_datagram_socket::receive"});
+       }
+
+      template<typename _MutableBufferSequence>
+       size_t
+       receive(const _MutableBufferSequence& __buffers, error_code& __ec)
+        { return receive(__buffers, socket_base::message_flags(), __ec); }
+
+      template<typename _MutableBufferSequence>
+       size_t
+       receive(const _MutableBufferSequence& __buffers,
+                      socket_base::message_flags __flags)
+       {
+         return receive(__buffers, __flags,
+                        __throw_on_error{"basic_datagram_socket::receive"});
+       }
+
+      template<typename _MutableBufferSequence>
+       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<int>(__flags));
+         if (__result == -1)
+            {
+              __ec.assign(errno, generic_category());
+              return 0;
+            }
+          __ec.clear();
+          return __result;
+       }
+
+      template<typename _MutableBufferSequence, typename _CompletionToken>
+       __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<typename _MutableBufferSequence, typename _CompletionToken>
+       __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<int>(__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<typename _MutableBufferSequence>
+       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<typename _MutableBufferSequence>
+       size_t
+       receive_from(const _MutableBufferSequence& __buffers,
+                    endpoint_type& __sender, error_code& __ec)
+       {
+         return receive_from(__buffers, __sender,
+                             socket_base::message_flags(), __ec);
+       }
+
+      template<typename _MutableBufferSequence>
+       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<typename _MutableBufferSequence>
+       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<int>(__flags));
+         if (__result == -1)
+            {
+              __ec.assign(errno, generic_category());
+              return 0;
+            }
+          __ec.clear();
+          __sender.resize(__msg.msg_namelen);
+          return __result;
+       }
+
+      template<typename _MutableBufferSequence, typename _CompletionToken>
+       __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<typename _MutableBufferSequence, typename _CompletionToken>
+       __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<int>(__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<typename _ConstBufferSequence>
+       size_t
+       send(const _ConstBufferSequence& __buffers)
+       {
+         return send(__buffers, socket_base::message_flags(),
+                     __throw_on_error{"basic_datagram_socket::send"});
+       }
+
+      template<typename _ConstBufferSequence>
+       size_t
+       send(const _ConstBufferSequence& __buffers, error_code& __ec)
+       { return send(__buffers, socket_base::message_flags(), __ec); }
+
+      template<typename _ConstBufferSequence>
+       size_t
+       send(const _ConstBufferSequence& __buffers,
+            socket_base::message_flags __flags)
+       {
+         return send(__buffers, __flags,
+                     __throw_on_error{"basic_datagram_socket::send"});
+       }
+
+      template<typename _ConstBufferSequence>
+       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<int>(__flags));
+         if (__result == -1)
+            {
+              __ec.assign(errno, generic_category());
+              return 0;
+            }
+          __ec.clear();
+          return __result;
+       }
+
+      template<typename _ConstBufferSequence, typename _CompletionToken>
+       __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<typename _ConstBufferSequence, typename _CompletionToken>
+       __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<int>(__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<typename _ConstBufferSequence>
+       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<typename _ConstBufferSequence>
+       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<typename _ConstBufferSequence>
+       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<typename _ConstBufferSequence>
+       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<int>(__flags));
+         if (__result == -1)
+            {
+              __ec.assign(errno, generic_category());
+              return 0;
+            }
+          __ec.clear();
+          __recipient.resize(__msg.msg_namelen);
+          return __result;
+       }
+
+      template<typename _ConstBufferSequence, typename _CompletionToken>
+       __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<typename _ConstBufferSequence, typename _CompletionToken>
+       __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<int>(__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<typename _Protocol>
+    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<typename _OtherProtocol, typename _Requires
+              = _Require<is_convertible<_OtherProtocol, _Protocol>>>
+       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<class _OtherProtocol>
+       enable_if_t<is_convertible<_OtherProtocol, _Protocol>::value,
+                   basic_stream_socket&>
+       operator=(basic_stream_socket<_OtherProtocol>&& __rhs)
+       {
+         __base::operator=(std::move(__rhs));
+         return *this;
+       }
+
+      // basic_stream_socket operations:
+
+      template<class _MutableBufferSequence>
+       size_t
+       receive(const _MutableBufferSequence& __buffers)
+       {
+         return receive(__buffers, socket_base::message_flags(),
+                        __throw_on_error{"basic_stream_socket::receive"});
+       }
+
+      template<class _MutableBufferSequence>
+       size_t
+       receive(const _MutableBufferSequence& __buffers, error_code& __ec)
+        { return receive(__buffers, socket_base::message_flags(), __ec); }
+
+      template<class _MutableBufferSequence>
+       size_t
+       receive(const _MutableBufferSequence& __buffers,
+               socket_base::message_flags __flags)
+       {
+         return receive(__buffers, __flags,
+                        __throw_on_error{"basic_stream_socket::receive"});
+       }
+
+      template<class _MutableBufferSequence>
+       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<int>(__flags));
+         if (__result >= 0)
+           {
+             __ec.clear();
+             return __result;
+           }
+         __ec.assign(errno, generic_category());
+         return 0;
+       }
+
+      template<class _MutableBufferSequence, class _CompletionToken>
+       __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<class _MutableBufferSequence, class _CompletionToken>
+       __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<void>());
+              __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<int>(__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<class _ConstBufferSequence>
+       size_t
+       send(const _ConstBufferSequence& __buffers)
+       {
+         return send(__buffers, socket_base::message_flags(),
+                     __throw_on_error{"basic_stream_socket::send"});
+       }
+
+      template<class _ConstBufferSequence>
+       size_t
+       send(const _ConstBufferSequence& __buffers, error_code& __ec)
+       { return send(__buffers, socket_base::message_flags(), __ec); }
+
+      template<class _ConstBufferSequence>
+       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<class _ConstBufferSequence>
+       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<int>(__flags));
+         if (__result >= 0)
+           {
+             __ec.clear();
+             return __result;
+           }
+         __ec.assign(errno, generic_category());
+         return 0;
+       }
+
+      template<class _ConstBufferSequence, class _CompletionToken>
+       __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<class _ConstBufferSequence, class _CompletionToken>
+       __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<void>());
+              __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<int>(__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<class _MutableBufferSequence>
+       size_t
+       read_some(const _MutableBufferSequence& __buffers)
+       {
+         return receive(__buffers,
+                        __throw_on_error{"basic_stream_socket::read_some"});
+       }
+
+      template<class _MutableBufferSequence>
+       size_t
+       read_some(const _MutableBufferSequence& __buffers, error_code& __ec)
+       { return receive(__buffers, __ec); }
+
+      template<class _MutableBufferSequence, class _CompletionToken>
+       __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<class _ConstBufferSequence>
+       size_t
+       write_some(const _ConstBufferSequence& __buffers)
+       {
+         return send(__buffers,
+                     __throw_on_error{"basic_stream_socket:write_some"});
+       }
+
+      template<class _ConstBufferSequence>
+       size_t
+       write_some(const _ConstBufferSequence& __buffers, error_code& __ec)
+       {  return send(__buffers, __ec); }
+
+      template<class _ConstBufferSequence, class _CompletionToken>
+       __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<typename _AcceptableProtocol>
+    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<typename _OtherProtocol, typename _Requires
+              = _Require<is_convertible<_OtherProtocol, protocol_type>>>
+       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<class _OtherProtocol>
+       enable_if_t<is_convertible<_OtherProtocol, protocol_type>::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<typename _SettableSocketOption>
+       void
+       set_option(const _SettableSocketOption& __option)
+       {
+         set_option(__option,
+                    __throw_on_error{"basic_socket_acceptor::set_option"});
+       }
+
+      template<typename _SettableSocketOption>
+       void
+       set_option(const _SettableSocketOption& __option, error_code& __ec)
+       { __base::set_option(__option, __ec); }
+
+      template<typename _GettableSocketOption>
+       void
+       get_option(_GettableSocketOption& __option) const
+       {
+         get_option(__option,
+                    __throw_on_error{"basic_socket_acceptor::get_option"});
+       }
+
+      template<typename _GettableSocketOption>
+       void
+       get_option(_GettableSocketOption& __option, error_code& __ec) const
+       { __base::get_option(__option, __ec); }
+
+      template<typename _IoControlCommand>
+       void
+       io_control(_IoControlCommand& __command)
+       {
+         io_control(__command,
+                    __throw_on_error{"basic_socket_acceptor::io_control"});
+       }
+
+      template<typename _IoControlCommand>
+       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<class _CompletionToken>
+       __deduced_t<_CompletionToken, void(error_code, socket_type)>
+       async_accept(_CompletionToken&& __token)
+       {
+         return async_accept(get_executor().context(),
+                             std::forward<_CompletionToken>(__token));
+       }
+
+      template<class _CompletionToken>
+       __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<class _CompletionToken>
+       __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<class _CompletionToken>
+       __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<class _CompletionToken>
+       __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<int>(__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<typename _Protocol, typename _Clock, typename _WaitTraits>
+    class basic_socket_streambuf : public basic_streambuf<char>
+    {
+    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<protocol_type> __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<typename... _Args>
+       basic_socket_streambuf* connect(_Args&&... ); // TODO
+
+      basic_socket_streambuf* close(); // TODO
+
+      basic_socket<protocol_type>& 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<protocol_type> _M_socket;
+      error_code _M_ec;
+      time_point _M_expiry{ time_point::max() };
+    };
+
+  template<typename _Protocol, class _Clock, typename _WaitTraits>
+    class basic_socket_iostream : public basic_iostream<char>
+    {
+      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<protocol_type> __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<typename... _Args>
+       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<typename... _Args>
+       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<protocol_type, clock_type, wait_traits_type>*
+      rdbuf() const
+      { return const_cast<__streambuf_type*>(std::addressof(_M_sb)); }
+
+      basic_socket<protocol_type>& 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<typename _Protocol, typename _EndpointSequence,
+          typename _ConnectCondition>
+    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<typename _Protocol, typename _InputIterator,
+          typename _ConnectCondition>
+    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<typename _Protocol, typename _EndpointSequence,
+          typename _ConnectCondition>
+    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<typename _Protocol, typename _InputIterator,
+          typename _ConnectCondition>
+    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<typename _Protocol, typename _EndpointSequence>
+    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<typename _Protocol, typename _EndpointSequence>
+    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<typename _Protocol, typename _InputIterator>
+    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<typename _Protocol, typename _InputIterator>
+    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<typename _Protocol, typename _EndpointSequence,
+          typename _ConnectCondition, typename _CompletionToken>
+    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<typename _Protocol, typename _EndpointSequence,
+          typename _CompletionToken>
+    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<typename _Protocol, typename _InputIterator,
+          typename _ConnectCondition, typename _CompletionToken>
+    inline
+    __deduced_t<_CompletionToken, void(error_code, _InputIterator)>
+    async_connect(basic_socket<_Protocol>& __s,
+                 _InputIterator __first, _InputIterator __last,
+                 _ConnectCondition __c, _CompletionToken&& __token); // TODO
+
+  template<typename _Protocol, typename _InputIterator,
+          typename _CompletionToken>
+    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<experimental::net::v1::socket_errc>
+    : 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 (file)
index 0000000..3ec3659
--- /dev/null
@@ -0,0 +1,208 @@
+// <experimental/timer> -*- 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
+// <http://www.gnu.org/licenses/>.
+
+/** @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 <chrono>
+#include <system_error>
+#include <thread>
+#include <experimental/netfwd>
+#include <experimental/io_context>
+#include <experimental/bits/net.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+namespace experimental
+{
+namespace net
+{
+inline namespace v1
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  /**
+   * @ingroup networking
+   * @{
+   */
+
+  template<typename _Clock>
+    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<typename _Clock, typename _WaitTraits>
+    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<typename _CompletionToken>
+       __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<chrono::system_clock> system_timer;
+  typedef basic_waitable_timer<chrono::steady_clock> steady_timer;
+  typedef basic_waitable_timer<chrono::high_resolution_clock>
+    high_resolution_timer;
+
+  template<typename _Clock, typename _WaitTraits>
+    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<void>{});
+    }
+
+  template<typename _Clock, typename _WaitTraits>
+    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<void>{});
+    }
+
+  /// @}
+
+_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 (file)
index 0000000..7a894a9
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/buffer>
+#include <testsuite_hooks.h>
+
+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 (file)
index 0000000..d61f05d
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/buffer>
+#include <testsuite_hooks.h>
+
+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<B>::value,
+      "const_mutable is nothrow default constructible" );
+  static_assert( std::is_copy_assignable<B>::value,
+      "const_mutable is copy assignable" );
+  static_assert( std::is_nothrow_constructible<B, const void*, size_t>::value,
+      "const_mutable is nothrow constructible from pointer and length" );
+  static_assert( std::is_nothrow_constructible<B, mutable_buffer>::value,
+      "const_mutable is nothrow constructible from mutable_buffer" );
+  static_assert( std::is_same<decltype(b.data()), const void*>::value,
+      "data() return const void*" );
+  static_assert( noexcept(b.data()),
+      "data() is nothrow" );
+  static_assert( std::is_same<decltype(b.size()), size_t>::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 (file)
index 0000000..c89d79d
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/buffer>
+#include <testsuite_hooks.h>
+
+namespace net = std::experimental::net;
+
+template<typename T>
+bool is_mutable(const T&)
+{ return std::is_same<T, net::mutable_buffer>::value; }
+
+template<typename T>
+bool is_const(const T&)
+{ return std::is_same<T, net::const_buffer>::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<short, 9> 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<long long, 10> 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<const int, 11> 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<short> 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<long long> 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 (file)
index 0000000..cbcae6f
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/buffer>
+#include <testsuite_hooks.h>
+
+using std::experimental::net::mutable_buffer;
+
+void
+test01()
+{
+  using B = mutable_buffer;
+  const B b;
+
+  static_assert( std::is_nothrow_default_constructible<B>::value,
+      "const_mutable is nothrow default constructible" );
+  static_assert( std::is_copy_assignable<B>::value,
+      "const_mutable is copy assignable" );
+  static_assert( std::is_nothrow_constructible<B, void*, size_t>::value,
+      "const_mutable is nothrow default constructible" );
+  static_assert( std::is_same<decltype(b.data()), void*>::value,
+      "data() return const void*" );
+  static_assert( noexcept(b.data()),
+      "data() is nothrow" );
+  static_assert( std::is_same<decltype(b.size()), size_t>::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 (file)
index 0000000..74fc49e
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/buffer>
+#include <testsuite_hooks.h>
+
+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<mutable_buffer> mv{ {c, 0}, {c, 32}, {c, 16}, {c, 3}, {c, 0} };
+  VERIFY( buffer_size(mv) == (0 + 32 + 16 + 3 + 0) );
+
+  std::vector<const_buffer> 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 (file)
index 0000000..fb19337
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+// { dg-do compile }
+
+#include <experimental/buffer>
+
+using namespace std::experimental::net;
+using std::vector;
+using std::string;
+using std::char_traits;
+using std::allocator;
+
+template<typename T>
+struct Seq {
+  struct Buf {
+    operator T() const { return {}; }
+  };
+
+  Buf* begin() const { return nullptr; }
+  Buf* end() const { return nullptr; }
+};
+
+static_assert( is_mutable_buffer_sequence<mutable_buffer>::value,
+    "mutable_buffer is a mutable buffer sequence" );
+static_assert( is_mutable_buffer_sequence<const mutable_buffer>::value,
+    "const mutable_buffer is a mutable buffer sequence" );
+static_assert( is_mutable_buffer_sequence<vector<mutable_buffer>>::value,
+    "vector<mutable_buffer> is a mutable buffer sequence" );
+static_assert( is_mutable_buffer_sequence<const vector<mutable_buffer>>::value,
+    "const vector<mutable_buffer> is a mutable buffer sequence" );
+static_assert( is_mutable_buffer_sequence<Seq<mutable_buffer>>::value,
+    "Seq<mutable_buffer> is a mutable buffer sequence" );
+static_assert( is_mutable_buffer_sequence<const Seq<mutable_buffer>>::value,
+    "const Seq<mutable_buffer> is a mutable buffer sequence" );
+static_assert( is_mutable_buffer_sequence<Seq<const mutable_buffer>>::value,
+    "Seq<const mutable_buffer> is a mutable buffer sequence" );
+static_assert( ! is_mutable_buffer_sequence<const_buffer>::value,
+    "const_buffer is not a mutable buffer sequence" );
+static_assert( ! is_mutable_buffer_sequence<vector<const_buffer>>::value,
+    "vector<const_buffer> is not a mutable buffer sequence" );
+static_assert( ! is_mutable_buffer_sequence<Seq<const_buffer>>::value,
+    "Seq<const_buffer> is not a mutable buffer sequence" );
+
+static_assert( is_const_buffer_sequence<const_buffer>::value,
+    "const_buffer is a const buffer sequence" );
+static_assert( is_const_buffer_sequence<const const_buffer>::value,
+    "const const_buffer is a const buffer sequence" );
+static_assert( is_const_buffer_sequence<vector<const_buffer>>::value,
+    "vector<const_buffer> is a const buffer sequence" );
+static_assert( is_const_buffer_sequence<const vector<const_buffer>>::value,
+    "const vector<const_buffer> is a const buffer sequence" );
+static_assert( is_const_buffer_sequence<Seq<const_buffer>>::value,
+    "Seq<const_buffer> is a const buffer sequence" );
+static_assert( is_const_buffer_sequence<const Seq<const_buffer>>::value,
+    "const Seq<const_buffer> is a const buffer sequence" );
+static_assert( is_const_buffer_sequence<Seq<const const_buffer>>::value,
+    "Seq<const const_buffer> is a const buffer sequence" );
+static_assert( is_const_buffer_sequence<mutable_buffer>::value,
+    "mutable_buffer is a const buffer sequence" );
+static_assert( is_const_buffer_sequence<const mutable_buffer>::value,
+    "const mutable_buffer is a const buffer sequence" );
+static_assert( is_const_buffer_sequence<vector<mutable_buffer>>::value,
+    "vector<mutable_buffer> is a const buffer sequence" );
+static_assert( is_const_buffer_sequence<const vector<mutable_buffer>>::value,
+    "const vector<mutable_buffer> is a const buffer sequence" );
+
+// Buf -> mutable_buffer -> const_buffer needs two user-defined conversions:
+static_assert( ! is_const_buffer_sequence<Seq<mutable_buffer>>::value,
+    "Seq<mutable_buffer> is not a const buffer sequence" );
+
+static_assert( is_dynamic_buffer<
+    dynamic_vector_buffer<int, allocator<int>>
+    >::value, "dynamic_vector_buffer is a dynamic buffer" );
+static_assert( is_dynamic_buffer<
+    dynamic_string_buffer<char, char_traits<char>, allocator<int>>
+    >::value, "dynamic_string_buffer is a dynamic buffer" );
+static_assert( ! is_dynamic_buffer<vector<int>>::value,
+    "vector is not a dynamic buffer" );
+static_assert( ! is_dynamic_buffer<string>::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 (file)
index 0000000..d8fb640
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/executor>
+#include <testsuite_hooks.h>
+
+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<service1>(ctx);
+  service1& svc1a = use_service<service1>(ctx);
+  VERIFY( &svc1a == &svc1 );
+
+  key2& svc2 = use_service<service2>(ctx);
+  key2& svc2a = use_service<service2>(ctx);
+  VERIFY( &svc2a == &svc2 );
+
+  service1& svc3 = use_service<service3>(ctx);
+  VERIFY( &svc3 == &svc1 );
+
+  key2& svc4 = use_service<service4>(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 (file)
index 0000000..58ba13f
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+// { dg-do compile }
+
+#include <experimental/net>
+
+// Re-include:
+#include <experimental/buffer>
+#include <experimental/executor>
+#include <experimental/internet>
+#include <experimental/io_context>
+#include <experimental/netfwd>
+#include <experimental/socket>
+#include <experimental/timer>
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 (file)
index 0000000..d82e1e4
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/internet>
+#include <testsuite_hooks.h>
+
+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 (file)
index 0000000..ed09b9c
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/internet>
+#include <testsuite_hooks.h>
+
+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 (file)
index 0000000..a168de6
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/internet>
+#include <testsuite_hooks.h>
+
+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 (file)
index 0000000..b854d8f
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/internet>
+#include <testsuite_hooks.h>
+
+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 (file)
index 0000000..c07de7a
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/internet>
+#include <testsuite_hooks.h>
+
+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 (file)
index 0000000..ca1018d
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/internet>
+#include <testsuite_hooks.h>
+
+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 (file)
index 0000000..f503507
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/internet>
+#include <testsuite_hooks.h>
+
+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 (file)
index 0000000..3bce057
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/timer>
+#include <testsuite_hooks.h>
+
+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 (file)
index 0000000..743f28a
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/timer>
+#include <testsuite_hooks.h>
+
+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 (file)
index 0000000..c4e0b1b
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/timer>
+#include <testsuite_hooks.h>
+
+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();
+}