181418a27Smrg// <experimental/buffer> -*- C++ -*-
281418a27Smrg
3*f0fbc68bSmrg// Copyright (C) 2015-2022 Free Software Foundation, Inc.
481418a27Smrg//
581418a27Smrg// This file is part of the GNU ISO C++ Library.  This library is free
681418a27Smrg// software; you can redistribute it and/or modify it under the
781418a27Smrg// terms of the GNU General Public License as published by the
881418a27Smrg// Free Software Foundation; either version 3, or (at your option)
981418a27Smrg// any later version.
1081418a27Smrg
1181418a27Smrg// This library is distributed in the hope that it will be useful,
1281418a27Smrg// but WITHOUT ANY WARRANTY; without even the implied warranty of
1381418a27Smrg// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1481418a27Smrg// GNU General Public License for more details.
1581418a27Smrg
1681418a27Smrg// Under Section 7 of GPL version 3, you are granted additional
1781418a27Smrg// permissions described in the GCC Runtime Library Exception, version
1881418a27Smrg// 3.1, as published by the Free Software Foundation.
1981418a27Smrg
2081418a27Smrg// You should have received a copy of the GNU General Public License and
2181418a27Smrg// a copy of the GCC Runtime Library Exception along with this program;
2281418a27Smrg// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2381418a27Smrg// <http://www.gnu.org/licenses/>.
2481418a27Smrg
2581418a27Smrg/** @file experimental/buffer
2681418a27Smrg *  This is a TS C++ Library header.
278d286336Smrg *  @ingroup networking-ts
2881418a27Smrg */
2981418a27Smrg
3081418a27Smrg#ifndef _GLIBCXX_EXPERIMENTAL_BUFFER
3181418a27Smrg#define _GLIBCXX_EXPERIMENTAL_BUFFER 1
3281418a27Smrg
3381418a27Smrg#pragma GCC system_header
3481418a27Smrg
3581418a27Smrg#if __cplusplus >= 201402L
3681418a27Smrg
3781418a27Smrg#include <array>
3881418a27Smrg#include <string>
3981418a27Smrg#include <system_error>
4081418a27Smrg#include <vector>
4181418a27Smrg#include <cstring>
4281418a27Smrg#include <experimental/string_view>
4381418a27Smrg#include <experimental/bits/net.h>
4481418a27Smrg
4581418a27Smrgnamespace std _GLIBCXX_VISIBILITY(default)
4681418a27Smrg{
4781418a27Smrg_GLIBCXX_BEGIN_NAMESPACE_VERSION
4881418a27Smrgnamespace experimental
4981418a27Smrg{
5081418a27Smrgnamespace net
5181418a27Smrg{
5281418a27Smrginline namespace v1
5381418a27Smrg{
5481418a27Smrg
558d286336Smrg  /** @addtogroup networking-ts
5681418a27Smrg   *  @{
5781418a27Smrg   */
5881418a27Smrg
5981418a27Smrg  enum class stream_errc {    // TODO decide values
6081418a27Smrg    eof = 1,
6181418a27Smrg    not_found = 2
6281418a27Smrg  };
6381418a27Smrg
6481418a27Smrg  const error_category& stream_category() noexcept // TODO not inline
6581418a27Smrg  {
6681418a27Smrg    struct __cat : error_category
6781418a27Smrg    {
6881418a27Smrg      const char* name() const noexcept { return "stream"; }
6981418a27Smrg
7081418a27Smrg      std::string message(int __e) const
7181418a27Smrg      {
7281418a27Smrg	if (__e == (int)stream_errc::eof)
7381418a27Smrg	  return "EOF";
7481418a27Smrg	else if (__e == (int)stream_errc::not_found)
7581418a27Smrg	  return "not found";
7681418a27Smrg	return "stream";
7781418a27Smrg      }
7881418a27Smrg
7981418a27Smrg      virtual void __message(int) { } // TODO dual ABI XXX
8081418a27Smrg    };
8181418a27Smrg    static __cat __c;
8281418a27Smrg    return __c;
8381418a27Smrg  }
8481418a27Smrg
8581418a27Smrg  inline error_code
8681418a27Smrg  make_error_code(stream_errc __e) noexcept
8781418a27Smrg  { return error_code(static_cast<int>(__e), stream_category()); }
8881418a27Smrg
8981418a27Smrg  inline error_condition
9081418a27Smrg  make_error_condition(stream_errc __e) noexcept
9181418a27Smrg  { return error_condition(static_cast<int>(__e), stream_category()); }
9281418a27Smrg
9381418a27Smrg  class mutable_buffer
9481418a27Smrg  {
9581418a27Smrg  public:
9681418a27Smrg    // constructors:
9781418a27Smrg    mutable_buffer() noexcept : _M_data(), _M_size() { }
9881418a27Smrg
9981418a27Smrg    mutable_buffer(void* __p, size_t __n) noexcept
10081418a27Smrg    : _M_data(__p), _M_size(__n) { }
10181418a27Smrg
10281418a27Smrg    // members:
10381418a27Smrg    void* data() const noexcept { return _M_data; }
10481418a27Smrg    size_t size() const noexcept { return _M_size; }
10581418a27Smrg
10681418a27Smrg  private:
10781418a27Smrg    void*	_M_data;
10881418a27Smrg    size_t	_M_size;
10981418a27Smrg  };
11081418a27Smrg
11181418a27Smrg  class const_buffer
11281418a27Smrg  {
11381418a27Smrg  public:
11481418a27Smrg    // constructors:
11581418a27Smrg    const_buffer() noexcept : _M_data(), _M_size() { }
11681418a27Smrg
11781418a27Smrg    const_buffer(const void* __p, size_t __n) noexcept
11881418a27Smrg    : _M_data(__p), _M_size(__n) { }
11981418a27Smrg
12081418a27Smrg    const_buffer(const mutable_buffer& __b) noexcept
12181418a27Smrg    : _M_data(__b.data()), _M_size(__b.size()) { }
12281418a27Smrg
12381418a27Smrg    // members:
12481418a27Smrg    const void* data() const noexcept { return _M_data; }
12581418a27Smrg    size_t size() const noexcept { return _M_size; }
12681418a27Smrg
12781418a27Smrg  private:
12881418a27Smrg    const void*	_M_data;
12981418a27Smrg    size_t	_M_size;
13081418a27Smrg  };
13181418a27Smrg
13281418a27Smrg
13381418a27Smrg  /** @brief buffer sequence access
13481418a27Smrg   *
13581418a27Smrg   * Uniform access to types that meet the BufferSequence requirements.
13681418a27Smrg   * @{
13781418a27Smrg   */
13881418a27Smrg
13981418a27Smrg  inline const mutable_buffer*
14081418a27Smrg  buffer_sequence_begin(const mutable_buffer& __b)
14181418a27Smrg  { return std::addressof(__b); }
14281418a27Smrg
14381418a27Smrg  inline const const_buffer*
14481418a27Smrg  buffer_sequence_begin(const const_buffer& __b)
14581418a27Smrg  { return std::addressof(__b); }
14681418a27Smrg
14781418a27Smrg  inline const mutable_buffer*
14881418a27Smrg  buffer_sequence_end(const mutable_buffer& __b)
14981418a27Smrg  { return std::addressof(__b) + 1; }
15081418a27Smrg
15181418a27Smrg  inline const const_buffer*
15281418a27Smrg  buffer_sequence_end(const const_buffer& __b)
15381418a27Smrg  { return std::addressof(__b) + 1; }
15481418a27Smrg
15581418a27Smrg  template<typename _Cont>
15681418a27Smrg    auto
15781418a27Smrg    buffer_sequence_begin(_Cont& __c) -> decltype(__c.begin())
15881418a27Smrg    { return __c.begin(); }
15981418a27Smrg
16081418a27Smrg  template<typename _Cont>
16181418a27Smrg    auto
16281418a27Smrg    buffer_sequence_begin(const _Cont& __c) -> decltype(__c.begin())
16381418a27Smrg    { return __c.begin(); }
16481418a27Smrg
16581418a27Smrg  template<typename _Cont>
16681418a27Smrg    auto
16781418a27Smrg    buffer_sequence_end(_Cont& __c) -> decltype(__c.end())
16881418a27Smrg    { return __c.end(); }
16981418a27Smrg
17081418a27Smrg  template<typename _Cont>
17181418a27Smrg    auto
17281418a27Smrg    buffer_sequence_end(const _Cont& __c) -> decltype(__c.end())
17381418a27Smrg    { return __c.end(); }
17481418a27Smrg
1757327edafSmrg  /// @}
17681418a27Smrg
17781418a27Smrg
17881418a27Smrg  /** @brief buffer type traits
17981418a27Smrg   *
18081418a27Smrg   * @{
18181418a27Smrg   */
18281418a27Smrg
18381418a27Smrg  template<typename _Tp, typename _Buffer,
18481418a27Smrg	   typename _Begin
18581418a27Smrg	    = decltype(net::buffer_sequence_begin(std::declval<_Tp&>())),
18681418a27Smrg	   typename _End
18781418a27Smrg	    = decltype(net::buffer_sequence_end(std::declval<_Tp&>()))>
18881418a27Smrg    using __buffer_sequence = enable_if_t<__and_<
18981418a27Smrg      __is_value_constructible<_Tp>, is_same<_Begin, _End>,
19081418a27Smrg      is_convertible<typename iterator_traits<_Begin>::value_type, _Buffer>
19181418a27Smrg      >::value>;
19281418a27Smrg
19381418a27Smrg  template<typename _Tp, typename _Buffer, typename = void>
19481418a27Smrg    struct __is_buffer_sequence : false_type
19581418a27Smrg    { };
19681418a27Smrg
19781418a27Smrg  template<typename _Tp, typename _Buffer>
19881418a27Smrg    struct __is_buffer_sequence<_Tp, _Buffer, __buffer_sequence<_Tp, _Buffer>>
19981418a27Smrg    : true_type
20081418a27Smrg    { };
20181418a27Smrg
20281418a27Smrg  template<typename _Tp>
20381418a27Smrg    struct is_mutable_buffer_sequence
20481418a27Smrg    : __is_buffer_sequence<_Tp, mutable_buffer>::type
20581418a27Smrg    { };
20681418a27Smrg
20781418a27Smrg  template<typename _Tp>
20881418a27Smrg    struct is_const_buffer_sequence
20981418a27Smrg    : __is_buffer_sequence<_Tp, const_buffer>::type
21081418a27Smrg    { };
21181418a27Smrg
21281418a27Smrg  template<typename _Tp>
21381418a27Smrg    constexpr bool is_mutable_buffer_sequence_v
21481418a27Smrg      = is_mutable_buffer_sequence<_Tp>::value;
21581418a27Smrg
21681418a27Smrg  template<typename _Tp>
21781418a27Smrg    constexpr bool is_const_buffer_sequence_v
21881418a27Smrg      = is_const_buffer_sequence<_Tp>::value;
21981418a27Smrg
22081418a27Smrg  template<typename _Tp, typename = void>
22181418a27Smrg    struct __is_dynamic_buffer_impl : false_type
22281418a27Smrg    { };
22381418a27Smrg
22481418a27Smrg  // Check DynamicBuffer requirements.
22581418a27Smrg  template<typename _Tp, typename _Up = remove_const_t<_Tp>>
22681418a27Smrg    auto
22781418a27Smrg    __dynamic_buffer_reqs(_Up* __x = 0, const _Up* __x1 = 0, size_t __n = 0)
22881418a27Smrg    -> enable_if_t<__and_<
22981418a27Smrg      is_move_constructible<_Up>,
23081418a27Smrg      is_const_buffer_sequence<typename _Tp::const_buffers_type>,
23181418a27Smrg      is_mutable_buffer_sequence<typename _Tp::mutable_buffers_type>,
23281418a27Smrg      is_same<decltype(__x1->size()), size_t>,
23381418a27Smrg      is_same<decltype(__x1->max_size()), size_t>,
23481418a27Smrg      is_same<decltype(__x1->capacity()), size_t>,
23581418a27Smrg      is_same<decltype(__x1->data()), typename _Tp::const_buffers_type>,
23681418a27Smrg      is_same<decltype(__x->prepare(__n)), typename _Tp::mutable_buffers_type>,
23781418a27Smrg      is_void<decltype(__x->commit(__n), __x->consume(__n), void())>
23881418a27Smrg    >::value>;
23981418a27Smrg
24081418a27Smrg  template<typename _Tp>
24181418a27Smrg    struct __is_dynamic_buffer_impl<_Tp,
24281418a27Smrg				    decltype(__dynamic_buffer_reqs<_Tp>())>
24381418a27Smrg    : true_type
24481418a27Smrg    { };
24581418a27Smrg
24681418a27Smrg  template<typename _Tp>
24781418a27Smrg    struct is_dynamic_buffer : __is_dynamic_buffer_impl<_Tp>::type
24881418a27Smrg    { };
24981418a27Smrg
25081418a27Smrg  template<typename _Tp>
25181418a27Smrg    constexpr bool is_dynamic_buffer_v = is_dynamic_buffer<_Tp>::value;
25281418a27Smrg
2537327edafSmrg  /// @}
25481418a27Smrg
25581418a27Smrg  /// buffer size
25681418a27Smrg  template<typename _ConstBufferSequence>
25781418a27Smrg    size_t
25881418a27Smrg    buffer_size(const _ConstBufferSequence& __buffers) noexcept
25981418a27Smrg    {
26081418a27Smrg      size_t __total_size = 0;
26181418a27Smrg      auto __i = net::buffer_sequence_begin(__buffers);
26281418a27Smrg      const auto __end = net::buffer_sequence_end(__buffers);
26381418a27Smrg      for (; __i != __end; ++__i)
26481418a27Smrg	__total_size += const_buffer(*__i).size();
26581418a27Smrg      return __total_size;
26681418a27Smrg    }
26781418a27Smrg
26881418a27Smrg  template<typename _ConstBufferSequence>
26981418a27Smrg    bool
27081418a27Smrg    __buffer_empty(const _ConstBufferSequence& __buffers) noexcept
27181418a27Smrg    {
27281418a27Smrg      auto __i = net::buffer_sequence_begin(__buffers);
27381418a27Smrg      const auto __end = net::buffer_sequence_end(__buffers);
27481418a27Smrg      for (; __i != __end; ++__i)
27581418a27Smrg	if (const_buffer(*__i).size() != 0)
27681418a27Smrg	  return false;
27781418a27Smrg      return true;
27881418a27Smrg    }
27981418a27Smrg
28081418a27Smrg  // buffer copy:
28181418a27Smrg
28281418a27Smrg  template<typename _MutableBufferSequence, typename _ConstBufferSequence>
28381418a27Smrg    size_t
28481418a27Smrg    buffer_copy(const _MutableBufferSequence& __dest,
28581418a27Smrg		const _ConstBufferSequence& __source,
28681418a27Smrg		size_t __max_size) noexcept
28781418a27Smrg    {
28881418a27Smrg      size_t __total_size = 0;
28981418a27Smrg      auto __to_i = net::buffer_sequence_begin(__dest);
29081418a27Smrg      const auto __to_end = net::buffer_sequence_end(__dest);
29181418a27Smrg      auto __from_i = net::buffer_sequence_begin(__source);
29281418a27Smrg      const auto __from_end = net::buffer_sequence_end(__source);
29381418a27Smrg      mutable_buffer __to;
29481418a27Smrg      const_buffer __from;
29581418a27Smrg      while (((__from_i != __from_end && __to_i != __to_end)
29681418a27Smrg	    || (__from.size() && __to.size()))
29781418a27Smrg	  && __total_size < __max_size)
29881418a27Smrg	{
29981418a27Smrg	  if (__from.size() == 0)
30081418a27Smrg	    __from = const_buffer{*__from_i++};
30181418a27Smrg	  if (__to.size() == 0)
30281418a27Smrg	    __to = mutable_buffer{*__to_i++};
30381418a27Smrg
30481418a27Smrg	  size_t __n = std::min(__from.size(), __to.size());
30581418a27Smrg	  __n = std::min(__n, __max_size - __total_size);
30681418a27Smrg	  std::memcpy(__to.data(), __from.data(), __n);
30781418a27Smrg	  __from = { (const char*)__from.data() + __n, __from.size() - __n };
30881418a27Smrg	  __to = { (char*)__to.data() + __n, __to.size() - __n };
30981418a27Smrg	  __total_size += __n;
31081418a27Smrg	}
31181418a27Smrg      return __total_size;
31281418a27Smrg    }
31381418a27Smrg
31481418a27Smrg  template<typename _MutableBufferSequence, typename _ConstBufferSequence>
31581418a27Smrg    inline size_t
31681418a27Smrg    buffer_copy(const _MutableBufferSequence& __dest,
31781418a27Smrg		const _ConstBufferSequence& __source) noexcept
318*f0fbc68bSmrg    { return net::buffer_copy(__dest, __source, size_t(-1)); }
31981418a27Smrg
32081418a27Smrg
32181418a27Smrg  // buffer arithmetic:
32281418a27Smrg
32381418a27Smrg  inline mutable_buffer
32481418a27Smrg  operator+(const mutable_buffer& __b, size_t __n) noexcept
32581418a27Smrg  {
32681418a27Smrg    if (__n > __b.size())
32781418a27Smrg      __n = __b.size();
32881418a27Smrg    return { static_cast<char*>(__b.data()) + __n, __b.size() - __n };
32981418a27Smrg  }
33081418a27Smrg
33181418a27Smrg  inline mutable_buffer
33281418a27Smrg  operator+(size_t __n, const mutable_buffer& __b) noexcept
33381418a27Smrg  { return __b + __n; }
33481418a27Smrg
33581418a27Smrg  inline const_buffer
33681418a27Smrg  operator+(const const_buffer& __b, size_t __n) noexcept
33781418a27Smrg  {
33881418a27Smrg    if (__n > __b.size())
33981418a27Smrg      __n = __b.size();
34081418a27Smrg    return { static_cast<const char*>(__b.data()) + __n, __b.size() - __n };
34181418a27Smrg  }
34281418a27Smrg
34381418a27Smrg  inline const_buffer
34481418a27Smrg  operator+(size_t __n, const const_buffer& __b) noexcept
34581418a27Smrg  { return __b + __n; }
34681418a27Smrg
34781418a27Smrg  // buffer creation:
34881418a27Smrg
34981418a27Smrg  inline mutable_buffer
35081418a27Smrg  buffer(void* __p, size_t __n) noexcept
35181418a27Smrg  { return { __p, __n }; }
35281418a27Smrg
35381418a27Smrg  inline const_buffer
35481418a27Smrg  buffer(const void* __p, size_t __n) noexcept
35581418a27Smrg  { return { __p, __n }; }
35681418a27Smrg
35781418a27Smrg  inline mutable_buffer
35881418a27Smrg  buffer(const mutable_buffer& __b) noexcept
35981418a27Smrg  { return __b; }
36081418a27Smrg
36181418a27Smrg  inline mutable_buffer
36281418a27Smrg  buffer(const mutable_buffer& __b, size_t __n) noexcept
36381418a27Smrg  { return { __b.data(), std::min(__b.size(), __n) }; }
36481418a27Smrg
36581418a27Smrg  inline const_buffer
36681418a27Smrg  buffer(const const_buffer& __b) noexcept
36781418a27Smrg  { return __b; }
36881418a27Smrg
36981418a27Smrg  inline const_buffer
37081418a27Smrg  buffer(const const_buffer& __b, size_t __n) noexcept
37181418a27Smrg  { return { __b.data(), std::min(__b.size(), __n) }; }
37281418a27Smrg
37381418a27Smrg  template<typename _Tp>
37481418a27Smrg    inline mutable_buffer
37581418a27Smrg    __to_mbuf(_Tp* __data, size_t __n)
37681418a27Smrg    { return { __n ? __data : nullptr, __n * sizeof(_Tp) }; }
37781418a27Smrg
37881418a27Smrg  template<typename _Tp>
37981418a27Smrg    inline const_buffer
38081418a27Smrg    __to_cbuf(const _Tp* __data, size_t __n)
38181418a27Smrg    { return { __n ? __data : nullptr, __n * sizeof(_Tp) }; }
38281418a27Smrg
38381418a27Smrg  template<typename _Tp, size_t _Nm>
38481418a27Smrg    inline mutable_buffer
38581418a27Smrg    buffer(_Tp (&__data)[_Nm]) noexcept
38681418a27Smrg    { return net::__to_mbuf(__data, _Nm); }
38781418a27Smrg
38881418a27Smrg  template<typename _Tp, size_t _Nm>
38981418a27Smrg    inline const_buffer
39081418a27Smrg    buffer(const _Tp (&__data)[_Nm]) noexcept
39181418a27Smrg    { return net::__to_cbuf(__data, _Nm); }
39281418a27Smrg
39381418a27Smrg  template<typename _Tp, size_t _Nm>
39481418a27Smrg    inline mutable_buffer
39581418a27Smrg    buffer(array<_Tp, _Nm>& __data) noexcept
39681418a27Smrg    { return net::__to_mbuf(__data.data(), _Nm); }
39781418a27Smrg
39881418a27Smrg  template<typename _Tp, size_t _Nm>
39981418a27Smrg    inline const_buffer
40081418a27Smrg    buffer(array<const _Tp, _Nm>& __data) noexcept
40181418a27Smrg    { return net::__to_cbuf(__data.data(), __data.size()); }
40281418a27Smrg
40381418a27Smrg  template<typename _Tp, size_t _Nm>
40481418a27Smrg    inline const_buffer
40581418a27Smrg    buffer(const array<_Tp, _Nm>& __data) noexcept
40681418a27Smrg    { return net::__to_cbuf(__data.data(), __data.size()); }
40781418a27Smrg
40881418a27Smrg  template<typename _Tp, typename _Allocator>
40981418a27Smrg    inline mutable_buffer
41081418a27Smrg    buffer(vector<_Tp, _Allocator>& __data) noexcept
41181418a27Smrg    { return net::__to_mbuf(__data.data(), __data.size()); }
41281418a27Smrg
41381418a27Smrg  template<typename _Tp, typename _Allocator>
41481418a27Smrg    inline const_buffer
41581418a27Smrg    buffer(const vector<_Tp, _Allocator>& __data) noexcept
41681418a27Smrg    { return net::__to_cbuf(__data.data(), __data.size()); }
41781418a27Smrg
41881418a27Smrg  template<typename _CharT, typename _Traits, typename _Allocator>
41981418a27Smrg    inline mutable_buffer
42081418a27Smrg    buffer(basic_string<_CharT, _Traits, _Allocator>& __data) noexcept
42181418a27Smrg    { return net::__to_mbuf(&__data.front(), __data.size()); }
42281418a27Smrg
42381418a27Smrg  template<typename _CharT, typename _Traits, typename _Allocator>
42481418a27Smrg    inline const_buffer
42581418a27Smrg    buffer(const basic_string<_CharT, _Traits, _Allocator>& __data) noexcept
42681418a27Smrg    { return net::__to_cbuf(&__data.front(), __data.size()); }
42781418a27Smrg
42881418a27Smrg  template<typename _CharT, typename _Traits>
42981418a27Smrg    inline const_buffer
43081418a27Smrg    buffer(basic_string_view<_CharT, _Traits> __data) noexcept
43181418a27Smrg    { return net::__to_cbuf(__data.data(), __data.size()); }
43281418a27Smrg
43381418a27Smrg  template<typename _Tp, size_t _Nm>
43481418a27Smrg    inline mutable_buffer
43581418a27Smrg    buffer(_Tp (&__data)[_Nm], size_t __n) noexcept
43681418a27Smrg    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
43781418a27Smrg
43881418a27Smrg  template<typename _Tp, size_t _Nm>
43981418a27Smrg    inline const_buffer
44081418a27Smrg    buffer(const _Tp (&__data)[_Nm], size_t __n) noexcept
44181418a27Smrg    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
44281418a27Smrg
44381418a27Smrg  template<typename _Tp, size_t _Nm>
44481418a27Smrg    inline mutable_buffer
44581418a27Smrg    buffer(array<_Tp, _Nm>& __data, size_t __n) noexcept
44681418a27Smrg    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
44781418a27Smrg
44881418a27Smrg  template<typename _Tp, size_t _Nm>
44981418a27Smrg    inline const_buffer
45081418a27Smrg    buffer(array<const _Tp, _Nm>& __data, size_t __n) noexcept
45181418a27Smrg    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
45281418a27Smrg
45381418a27Smrg  template<typename _Tp, size_t _Nm>
45481418a27Smrg    inline const_buffer
45581418a27Smrg    buffer(const array<_Tp, _Nm>& __data, size_t __n) noexcept
45681418a27Smrg    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
45781418a27Smrg
45881418a27Smrg  template<typename _Tp, typename _Allocator>
45981418a27Smrg    inline mutable_buffer
46081418a27Smrg    buffer(vector<_Tp, _Allocator>& __data, size_t __n) noexcept
46181418a27Smrg    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
46281418a27Smrg
46381418a27Smrg  template<typename _Tp, typename _Allocator>
46481418a27Smrg    inline const_buffer
46581418a27Smrg    buffer(const vector<_Tp, _Allocator>& __data, size_t __n) noexcept
46681418a27Smrg    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
46781418a27Smrg
46881418a27Smrg  template<typename _CharT, typename _Traits, typename _Allocator>
46981418a27Smrg    inline mutable_buffer
47081418a27Smrg    buffer(basic_string<_CharT, _Traits, _Allocator>& __data,
47181418a27Smrg	   size_t __n) noexcept
47281418a27Smrg    { return buffer(net::buffer(__data), __n * sizeof(_CharT)); }
47381418a27Smrg
47481418a27Smrg  template<typename _CharT, typename _Traits, typename _Allocator>
47581418a27Smrg    inline const_buffer
47681418a27Smrg    buffer(const basic_string<_CharT, _Traits, _Allocator>& __data,
47781418a27Smrg	   size_t __n) noexcept
47881418a27Smrg    { return buffer(net::buffer(__data), __n * sizeof(_CharT)); }
47981418a27Smrg
48081418a27Smrg  template<typename _CharT, typename _Traits>
48181418a27Smrg    inline const_buffer
48281418a27Smrg    buffer(basic_string_view<_CharT, _Traits> __data, size_t __n) noexcept
48381418a27Smrg    { return buffer(net::buffer(__data), __n * sizeof(_CharT)); }
48481418a27Smrg
48581418a27Smrg
48681418a27Smrg  template<typename _Sequence>
48781418a27Smrg    class __dynamic_buffer_base
48881418a27Smrg    {
48981418a27Smrg    public:
49081418a27Smrg      // types:
491*f0fbc68bSmrg      using const_buffers_type = const_buffer;
492*f0fbc68bSmrg      using mutable_buffers_type = mutable_buffer;
49381418a27Smrg
49481418a27Smrg      // constructors:
49581418a27Smrg      explicit
49681418a27Smrg      __dynamic_buffer_base(_Sequence& __seq) noexcept
49781418a27Smrg      : _M_seq(__seq), _M_size(__seq.size()), _M_max_size(__seq.max_size())
49881418a27Smrg      { }
49981418a27Smrg
50081418a27Smrg      __dynamic_buffer_base(_Sequence& __seq, size_t __maximum_size) noexcept
50181418a27Smrg      : _M_seq(__seq), _M_size(__seq.size()), _M_max_size(__maximum_size)
50281418a27Smrg      { __glibcxx_assert(__seq.size() <= __maximum_size); }
50381418a27Smrg
50481418a27Smrg      __dynamic_buffer_base(__dynamic_buffer_base&&) = default;
50581418a27Smrg
50681418a27Smrg      // members:
50781418a27Smrg      size_t size() const noexcept { return _M_size; }
50881418a27Smrg      size_t max_size() const noexcept { return _M_max_size; }
50981418a27Smrg      size_t capacity() const noexcept { return _M_seq.capacity(); }
51081418a27Smrg
51181418a27Smrg      const_buffers_type
51281418a27Smrg      data() const noexcept
51381418a27Smrg      { return net::buffer(_M_seq, _M_size); }
51481418a27Smrg
51581418a27Smrg      mutable_buffers_type
51681418a27Smrg      prepare(size_t __n)
51781418a27Smrg      {
51881418a27Smrg	if ((_M_size + __n) > _M_max_size)
51981418a27Smrg	  __throw_length_error("dynamic_vector_buffer::prepare");
52081418a27Smrg
52181418a27Smrg	_M_seq.resize(_M_size + __n);
52281418a27Smrg	return buffer(net::buffer(_M_seq) + _M_size, __n);
52381418a27Smrg      }
52481418a27Smrg
52581418a27Smrg      void
52681418a27Smrg      commit(size_t __n)
52781418a27Smrg      {
52881418a27Smrg	_M_size += std::min(__n, _M_seq.size() - _M_size);
52981418a27Smrg	_M_seq.resize(_M_size);
53081418a27Smrg      }
53181418a27Smrg
53281418a27Smrg      void
53381418a27Smrg      consume(size_t __n)
53481418a27Smrg      {
53581418a27Smrg	size_t __m = std::min(__n, _M_size);
53681418a27Smrg	_M_seq.erase(_M_seq.begin(), _M_seq.begin() + __m);
53781418a27Smrg	_M_size -= __m;
53881418a27Smrg      }
53981418a27Smrg
54081418a27Smrg    private:
54181418a27Smrg      _Sequence&	_M_seq;
54281418a27Smrg      size_t		_M_size;
54381418a27Smrg      const size_t	_M_max_size;
54481418a27Smrg    };
54581418a27Smrg
54681418a27Smrg  template<typename _Tp, typename _Allocator>
54781418a27Smrg    class dynamic_vector_buffer
54881418a27Smrg    : public __dynamic_buffer_base<vector<_Tp, _Allocator>>
54981418a27Smrg    {
55081418a27Smrg    public:
55181418a27Smrg      using __dynamic_buffer_base<vector<_Tp, _Allocator>>::__dynamic_buffer_base;
55281418a27Smrg    };
55381418a27Smrg
55481418a27Smrg  template<typename _CharT, typename _Traits, typename _Allocator>
55581418a27Smrg    class dynamic_string_buffer
55681418a27Smrg    : public __dynamic_buffer_base<basic_string<_CharT, _Traits, _Allocator>>
55781418a27Smrg    {
55881418a27Smrg    public:
55981418a27Smrg      using __dynamic_buffer_base<basic_string<_CharT, _Traits, _Allocator>>::
56081418a27Smrg	__dynamic_buffer_base;
56181418a27Smrg    };
56281418a27Smrg
56381418a27Smrg  // dynamic buffer creation:
56481418a27Smrg
56581418a27Smrg  template<typename _Tp, typename _Allocator>
56681418a27Smrg    inline dynamic_vector_buffer<_Tp, _Allocator>
56781418a27Smrg    dynamic_buffer(vector<_Tp, _Allocator>& __vec) noexcept
56881418a27Smrg    { return dynamic_vector_buffer<_Tp, _Allocator>{__vec}; }
56981418a27Smrg
57081418a27Smrg  template<typename _Tp, typename _Allocator>
57181418a27Smrg    inline dynamic_vector_buffer<_Tp, _Allocator>
57281418a27Smrg    dynamic_buffer(vector<_Tp, _Allocator>& __vec, size_t __n) noexcept
57381418a27Smrg    { return {__vec, __n}; }
57481418a27Smrg
57581418a27Smrg  template<typename _CharT, typename _Traits, typename _Allocator>
57681418a27Smrg    inline dynamic_string_buffer<_CharT, _Traits, _Allocator>
57781418a27Smrg    dynamic_buffer(basic_string<_CharT, _Traits, _Allocator>& __str) noexcept
57881418a27Smrg    { return dynamic_string_buffer<_CharT, _Traits, _Allocator>{__str}; }
57981418a27Smrg
58081418a27Smrg  template<typename _CharT, typename _Traits, typename _Allocator>
58181418a27Smrg    inline dynamic_string_buffer<_CharT, _Traits, _Allocator>
58281418a27Smrg    dynamic_buffer(basic_string<_CharT, _Traits, _Allocator>& __str,
58381418a27Smrg		   size_t __n) noexcept
58481418a27Smrg    { return {__str, __n}; }
58581418a27Smrg
58681418a27Smrg  class transfer_all
58781418a27Smrg  {
58881418a27Smrg  public:
58981418a27Smrg    size_t operator()(const error_code& __ec, size_t) const
59081418a27Smrg    { return !__ec ? 1500 : 0; }
59181418a27Smrg  };
59281418a27Smrg
59381418a27Smrg  class transfer_at_least
59481418a27Smrg  {
59581418a27Smrg  public:
59681418a27Smrg    explicit transfer_at_least(size_t __m) : _M_minimum(__m) { }
59781418a27Smrg
59881418a27Smrg    size_t operator()(const error_code& __ec, size_t __n) const
59981418a27Smrg    { return !__ec  && __n < _M_minimum ? _M_minimum - __n : 0; }
60081418a27Smrg
60181418a27Smrg  private:
60281418a27Smrg    size_t _M_minimum;
60381418a27Smrg  };
60481418a27Smrg
60581418a27Smrg  class transfer_exactly
60681418a27Smrg  {
60781418a27Smrg  public:
60881418a27Smrg    explicit transfer_exactly(size_t __e) : _M_exact(__e) { }
60981418a27Smrg
61081418a27Smrg    size_t operator()(const error_code& __ec, size_t __n) const
61181418a27Smrg    {
61281418a27Smrg      size_t _Nm = -1;
61381418a27Smrg      return !__ec  && __n < _M_exact ? std::min(_M_exact - __n, _Nm) : 0;
61481418a27Smrg    }
61581418a27Smrg
61681418a27Smrg  private:
61781418a27Smrg    size_t _M_exact;
61881418a27Smrg  };
61981418a27Smrg
62081418a27Smrg  /** @brief synchronous read operations
62181418a27Smrg   * @{
62281418a27Smrg   */
62381418a27Smrg
62481418a27Smrg  template<typename _SyncReadStream, typename _MutableBufferSequence,
62581418a27Smrg	   typename _CompletionCondition>
62681418a27Smrg    enable_if_t<is_mutable_buffer_sequence<_MutableBufferSequence>::value,
62781418a27Smrg		size_t>
62881418a27Smrg    read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers,
62981418a27Smrg	 _CompletionCondition __completion_condition, error_code& __ec)
63081418a27Smrg    {
63181418a27Smrg      __ec.clear();
63281418a27Smrg      auto __i = net::buffer_sequence_begin(__buffers);
63381418a27Smrg      auto __end = net::buffer_sequence_end(__buffers);
63481418a27Smrg      mutable_buffer __to;
63581418a27Smrg      size_t __total = 0;
63681418a27Smrg      size_t __n;
63781418a27Smrg      while ((__n = __completion_condition(__ec, __total))
63881418a27Smrg	  && (__i != __end || __to.size()))
63981418a27Smrg	{
64081418a27Smrg	  if (__to.size() == 0)
64181418a27Smrg	    __to = mutable_buffer(*__i++);
64281418a27Smrg	  __n = __stream.read_some(buffer(__to, __n), __ec);
64381418a27Smrg	  __to = __to + __n;
64481418a27Smrg	  __total += __n;
64581418a27Smrg	}
64681418a27Smrg      return __total;
64781418a27Smrg    }
64881418a27Smrg
64981418a27Smrg  template<typename _SyncReadStream, typename _MutableBufferSequence>
65081418a27Smrg    inline
65181418a27Smrg    enable_if_t<is_mutable_buffer_sequence<_MutableBufferSequence>::value,
65281418a27Smrg		size_t>
65381418a27Smrg    read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers)
65481418a27Smrg    {
65581418a27Smrg      error_code __ec;
65681418a27Smrg      return net::read(__stream, __buffers, transfer_all{}, __ec);
65781418a27Smrg    }
65881418a27Smrg
65981418a27Smrg  template<typename _SyncReadStream, typename _MutableBufferSequence>
66081418a27Smrg    inline
66181418a27Smrg    enable_if_t<is_mutable_buffer_sequence<_MutableBufferSequence>::value,
66281418a27Smrg		size_t>
66381418a27Smrg    read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers,
66481418a27Smrg	 error_code& __ec)
66581418a27Smrg    { return net::read(__stream, __buffers, transfer_all{}, __ec); }
66681418a27Smrg
66781418a27Smrg  template<typename _SyncReadStream, typename _MutableBufferSequence,
66881418a27Smrg	   typename _CompletionCondition>
66981418a27Smrg    inline
67081418a27Smrg    enable_if_t<is_mutable_buffer_sequence<_MutableBufferSequence>::value,
67181418a27Smrg		size_t>
67281418a27Smrg    read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers,
67381418a27Smrg	 _CompletionCondition __completion_condition)
67481418a27Smrg    {
67581418a27Smrg      error_code __ec;
67681418a27Smrg      return net::read(__stream, __buffers, __completion_condition, __ec);
67781418a27Smrg    }
67881418a27Smrg
67981418a27Smrg
68081418a27Smrg  template<typename _SyncReadStream, typename _DynamicBuffer,
68181418a27Smrg	   typename _CompletionCondition>
68281418a27Smrg    enable_if_t<is_dynamic_buffer<decay_t<_DynamicBuffer>>::value, size_t>
68381418a27Smrg    read(_SyncReadStream& __stream, _DynamicBuffer&& __b,
68481418a27Smrg	 _CompletionCondition __completion_condition, error_code& __ec)
68581418a27Smrg    {
68681418a27Smrg      const size_t __limit = 64;
68781418a27Smrg      __ec.clear();
68881418a27Smrg      size_t __cap = std::max(__b.capacity() - __b.size(), __limit);
68981418a27Smrg      size_t __total = 0;
69081418a27Smrg      size_t __n;
69181418a27Smrg      while ((__n = __completion_condition(__ec, __total))
69281418a27Smrg	  && __b.size() != __b.max_size())
69381418a27Smrg	{
69481418a27Smrg	  __n =  std::min(__n, __b.max_size() - __b.size());
69581418a27Smrg	  size_t __cap = std::max(__b.capacity() - __b.size(), __limit);
69681418a27Smrg	  mutable_buffer __to = __b.prepare(std::min(__cap, __n));
69781418a27Smrg	  __n = __stream.read_some(__to, __ec);
69881418a27Smrg	  __to = __to + __n;
69981418a27Smrg	  __total += __n;
70081418a27Smrg	  __b.commit(__n);
70181418a27Smrg	}
70281418a27Smrg      return __total;
70381418a27Smrg    }
70481418a27Smrg
70581418a27Smrg  template<typename _SyncReadStream, typename _DynamicBuffer>
70681418a27Smrg    inline enable_if_t<is_dynamic_buffer<_DynamicBuffer>::value, size_t>
70781418a27Smrg    read(_SyncReadStream& __stream, _DynamicBuffer&& __b)
70881418a27Smrg    {
70981418a27Smrg      error_code __ec;
71081418a27Smrg      return net::read(__stream, __b, transfer_all{}, __ec);
71181418a27Smrg    }
71281418a27Smrg
71381418a27Smrg  template<typename _SyncReadStream, typename _DynamicBuffer>
71481418a27Smrg    inline enable_if_t<is_dynamic_buffer<_DynamicBuffer>::value, size_t>
71581418a27Smrg    read(_SyncReadStream& __stream, _DynamicBuffer&& __b, error_code& __ec)
71681418a27Smrg    {
71781418a27Smrg      return net::read(__stream, __b, transfer_all{}, __ec);
71881418a27Smrg    }
71981418a27Smrg
72081418a27Smrg  template<typename _SyncReadStream, typename _DynamicBuffer,
72181418a27Smrg	   typename _CompletionCondition>
72281418a27Smrg    inline enable_if_t<is_dynamic_buffer<_DynamicBuffer>::value, size_t>
72381418a27Smrg    read(_SyncReadStream& __stream, _DynamicBuffer&& __b,
72481418a27Smrg	 _CompletionCondition __completion_condition)
72581418a27Smrg    {
72681418a27Smrg      error_code __ec;
72781418a27Smrg      return net::read(__stream, __b, __completion_condition, __ec);
72881418a27Smrg    }
72981418a27Smrg
7307327edafSmrg  /// @}
73181418a27Smrg
73281418a27Smrg  /** @brief asynchronous read operations
73381418a27Smrg   * @{
73481418a27Smrg   */
73581418a27Smrg
73681418a27Smrg  template<typename _AsyncReadStream, typename _MutableBufferSequence,
73781418a27Smrg	   typename _CompletionCondition, typename _CompletionToken>
73881418a27Smrg    __deduced_t<_CompletionToken, void(error_code, size_t)>
73981418a27Smrg    async_read(_AsyncReadStream& __stream,
74081418a27Smrg	       const _MutableBufferSequence& __buffers,
74181418a27Smrg	       _CompletionCondition __completion_condition,
74281418a27Smrg	       _CompletionToken&& __token)
74381418a27Smrg    {
74481418a27Smrg      error_code __ec;
74581418a27Smrg    }
74681418a27Smrg
74781418a27Smrg  template<typename _AsyncReadStream, typename _MutableBufferSequence,
74881418a27Smrg	   typename _CompletionToken>
74981418a27Smrg    inline __deduced_t<_CompletionToken, void(error_code, size_t)>
75081418a27Smrg    async_read(_AsyncReadStream& __stream,
75181418a27Smrg	       const _MutableBufferSequence& __buffers,
75281418a27Smrg	       _CompletionToken&& __token)
75381418a27Smrg    {
75481418a27Smrg      return net::async_read(__stream, __buffers, transfer_all{},
75581418a27Smrg			     std::forward<_CompletionToken>(__token));
75681418a27Smrg    }
75781418a27Smrg
75881418a27Smrg  template<typename _AsyncReadStream, typename _DynamicBuffer,
75981418a27Smrg	   typename _CompletionCondition, typename _CompletionToken>
76081418a27Smrg    __deduced_t<_CompletionToken, void(error_code, size_t)>
76181418a27Smrg    async_read(_AsyncReadStream& __stream, _DynamicBuffer&& __b,
76281418a27Smrg	       _CompletionCondition __completion_condition,
76381418a27Smrg	       _CompletionToken&& __token)
76481418a27Smrg    {
76581418a27Smrg      error_code __ec;
76681418a27Smrg    }
76781418a27Smrg
76881418a27Smrg  template<typename _AsyncReadStream, typename _DynamicBuffer,
76981418a27Smrg	   typename _CompletionToken>
77081418a27Smrg    inline __deduced_t<_CompletionToken, void(error_code, size_t)>
77181418a27Smrg    async_read(_AsyncReadStream& __stream, _DynamicBuffer&& __b,
77281418a27Smrg	       _CompletionToken&& __token)
77381418a27Smrg    {
77481418a27Smrg      return net::async_read(__stream, __b, transfer_all{},
77581418a27Smrg			     std::forward<_CompletionToken>(__token));
77681418a27Smrg    }
77781418a27Smrg
7787327edafSmrg  /// @}
77981418a27Smrg
78081418a27Smrg#if 0
78181418a27Smrg  /** @brief synchronous write operations:
78281418a27Smrg   * @{
78381418a27Smrg   */
78481418a27Smrg
78581418a27Smrg  template<typename _SyncWriteStream, typename _ConstBufferSequence>
78681418a27Smrg    size_t write(_SyncWriteStream& __stream,
78781418a27Smrg                 const _ConstBufferSequence& __buffers);
78881418a27Smrg  template<typename _SyncWriteStream, typename _ConstBufferSequence>
78981418a27Smrg    size_t write(_SyncWriteStream& __stream,
79081418a27Smrg                 const _ConstBufferSequence& __buffers, error_code& __ec);
79181418a27Smrg  template<typename _SyncWriteStream, typename _ConstBufferSequence,
79281418a27Smrg    typename _CompletionCondition>
79381418a27Smrg      size_t write(_SyncWriteStream& __stream,
79481418a27Smrg                   const _ConstBufferSequence& __buffers,
79581418a27Smrg                   _CompletionCondition __completion_condition);
79681418a27Smrg  template<typename _SyncWriteStream, typename _ConstBufferSequence,
79781418a27Smrg    typename _CompletionCondition>
79881418a27Smrg      size_t write(_SyncWriteStream& __stream,
79981418a27Smrg                   const _ConstBufferSequence& __buffers,
80081418a27Smrg                   _CompletionCondition __completion_condition,
80181418a27Smrg                   error_code& __ec);
80281418a27Smrg
80381418a27Smrg  template<typename _SyncWriteStream, typename _DynamicBuffer>
80481418a27Smrg    size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b);
80581418a27Smrg  template<typename _SyncWriteStream, typename _DynamicBuffer>
80681418a27Smrg    size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b, error_code& __ec);
80781418a27Smrg  template<typename _SyncWriteStream, typename _DynamicBuffer, typename _CompletionCondition>
80881418a27Smrg    size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b,
80981418a27Smrg                 _CompletionCondition __completion_condition);
81081418a27Smrg  template<typename _SyncWriteStream, typename _DynamicBuffer, typename _CompletionCondition>
81181418a27Smrg    size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b,
81281418a27Smrg                 _CompletionCondition __completion_condition, error_code& __ec);
81381418a27Smrg
8147327edafSmrg  /// @}
81581418a27Smrg
81681418a27Smrg  /** @brief asynchronous write operations
81781418a27Smrg   * @{
81881418a27Smrg   */
81981418a27Smrg
82081418a27Smrg  template<typename _AsyncWriteStream, typename _ConstBufferSequence,
82181418a27Smrg    typename _CompletionToken>
82281418a27Smrg      DEDUCED async_write(_AsyncWriteStream& __stream,
82381418a27Smrg                       const _ConstBufferSequence& __buffers,
82481418a27Smrg                       _CompletionToken&& __token);
82581418a27Smrg  template<typename _AsyncWriteStream, typename _ConstBufferSequence,
82681418a27Smrg    typename _CompletionCondition, typename _CompletionToken>
82781418a27Smrg      DEDUCED async_write(_AsyncWriteStream& __stream,
82881418a27Smrg                       const _ConstBufferSequence& __buffers,
82981418a27Smrg                       _CompletionCondition __completion_condition,
83081418a27Smrg                       _CompletionToken&& __token);
83181418a27Smrg
83281418a27Smrg  template<typename _AsyncWriteStream, typename _DynamicBuffer, typename _CompletionToken>
83381418a27Smrg    DEDUCED async_write(_AsyncWriteStream& __stream,
83481418a27Smrg                     _DynamicBuffer&& __b, _CompletionToken&& __token);
83581418a27Smrg  template<typename _AsyncWriteStream, typename _DynamicBuffer,
83681418a27Smrg    typename _CompletionCondition, typename _CompletionToken>
83781418a27Smrg      DEDUCED async_write(_AsyncWriteStream& __stream,
83881418a27Smrg                       _DynamicBuffer&& __b,
83981418a27Smrg                       _CompletionCondition __completion_condition,
84081418a27Smrg                       _CompletionToken&& __token);
84181418a27Smrg
8427327edafSmrg  /// @}
84381418a27Smrg
84481418a27Smrg  /** @brief synchronous delimited read operations
84581418a27Smrg   * @{
84681418a27Smrg   */
84781418a27Smrg
84881418a27Smrg  template<typename _SyncReadStream, typename _DynamicBuffer>
84981418a27Smrg    size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b, char __delim);
85081418a27Smrg  template<typename _SyncReadStream, typename _DynamicBuffer>
85181418a27Smrg    size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b,
85281418a27Smrg                      char __delim, error_code& __ec);
85381418a27Smrg  template<typename _SyncReadStream, typename _DynamicBuffer>
85481418a27Smrg    size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b, string_view __delim);
85581418a27Smrg  template<typename _SyncReadStream, typename _DynamicBuffer>
85681418a27Smrg    size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b,
85781418a27Smrg                      string_view __delim, error_code& __ec);
85881418a27Smrg
8597327edafSmrg  /// @}
86081418a27Smrg
86181418a27Smrg  /** @brief asynchronous delimited read operations
86281418a27Smrg   * @{
86381418a27Smrg   */
86481418a27Smrg
86581418a27Smrg  template<typename _AsyncReadStream, typename _DynamicBuffer, typename _CompletionToken>
86681418a27Smrg    DEDUCED async_read_until(_AsyncReadStream& __s,
86781418a27Smrg                          _DynamicBuffer&& __b, char __delim,
86881418a27Smrg                          _CompletionToken&& __token);
86981418a27Smrg  template<typename _AsyncReadStream, typename _DynamicBuffer, typename _CompletionToken>
87081418a27Smrg    DEDUCED async_read_until(_AsyncReadStream& __s,
87181418a27Smrg                          _DynamicBuffer&& __b, string_view __delim,
87281418a27Smrg                          _CompletionToken&& __token);
87381418a27Smrg
8747327edafSmrg  /// @}
87581418a27Smrg
87681418a27Smrg#endif
87781418a27Smrg  /// @}
87881418a27Smrg
87981418a27Smrg} // namespace v1
88081418a27Smrg} // namespace net
88181418a27Smrg} // namespace experimental
88281418a27Smrg
88381418a27Smrg  template<>
88481418a27Smrg    struct is_error_code_enum<experimental::net::v1::stream_errc>
88581418a27Smrg    : public true_type {};
88681418a27Smrg
88781418a27Smrg_GLIBCXX_END_NAMESPACE_VERSION
88881418a27Smrg} // namespace std
88981418a27Smrg
89081418a27Smrg#endif // C++14
89181418a27Smrg
89281418a27Smrg#endif // _GLIBCXX_EXPERIMENTAL_BUFFER
893