1// <experimental/buffer> -*- C++ -*-
2
3// Copyright (C) 2015-2019 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library.  This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file experimental/buffer
26 *  This is a TS C++ Library header.
27 */
28
29#ifndef _GLIBCXX_EXPERIMENTAL_BUFFER
30#define _GLIBCXX_EXPERIMENTAL_BUFFER 1
31
32#pragma GCC system_header
33
34#if __cplusplus >= 201402L
35
36#include <array>
37#include <string>
38#include <system_error>
39#include <vector>
40#include <cstring>
41#include <experimental/string_view>
42#include <experimental/bits/net.h>
43
44namespace std _GLIBCXX_VISIBILITY(default)
45{
46_GLIBCXX_BEGIN_NAMESPACE_VERSION
47namespace experimental
48{
49namespace net
50{
51inline namespace v1
52{
53
54  /**
55   * @ingroup networking
56   * @{
57   */
58
59  enum class stream_errc {    // TODO decide values
60    eof = 1,
61    not_found = 2
62  };
63
64  const error_category& stream_category() noexcept // TODO not inline
65  {
66    struct __cat : error_category
67    {
68      const char* name() const noexcept { return "stream"; }
69
70      std::string message(int __e) const
71      {
72	if (__e == (int)stream_errc::eof)
73	  return "EOF";
74	else if (__e == (int)stream_errc::not_found)
75	  return "not found";
76	return "stream";
77      }
78
79      virtual void __message(int) { } // TODO dual ABI XXX
80    };
81    static __cat __c;
82    return __c;
83  }
84
85  inline error_code
86  make_error_code(stream_errc __e) noexcept
87  { return error_code(static_cast<int>(__e), stream_category()); }
88
89  inline error_condition
90  make_error_condition(stream_errc __e) noexcept
91  { return error_condition(static_cast<int>(__e), stream_category()); }
92
93  class mutable_buffer
94  {
95  public:
96    // constructors:
97    mutable_buffer() noexcept : _M_data(), _M_size() { }
98
99    mutable_buffer(void* __p, size_t __n) noexcept
100    : _M_data(__p), _M_size(__n) { }
101
102    // members:
103    void* data() const noexcept { return _M_data; }
104    size_t size() const noexcept { return _M_size; }
105
106  private:
107    void*	_M_data;
108    size_t	_M_size;
109  };
110
111  class const_buffer
112  {
113  public:
114    // constructors:
115    const_buffer() noexcept : _M_data(), _M_size() { }
116
117    const_buffer(const void* __p, size_t __n) noexcept
118    : _M_data(__p), _M_size(__n) { }
119
120    const_buffer(const mutable_buffer& __b) noexcept
121    : _M_data(__b.data()), _M_size(__b.size()) { }
122
123    // members:
124    const void* data() const noexcept { return _M_data; }
125    size_t size() const noexcept { return _M_size; }
126
127  private:
128    const void*	_M_data;
129    size_t	_M_size;
130  };
131
132
133  /** @brief buffer sequence access
134   *
135   * Uniform access to types that meet the BufferSequence requirements.
136   * @{
137   */
138
139  inline const mutable_buffer*
140  buffer_sequence_begin(const mutable_buffer& __b)
141  { return std::addressof(__b); }
142
143  inline const const_buffer*
144  buffer_sequence_begin(const const_buffer& __b)
145  { return std::addressof(__b); }
146
147  inline const mutable_buffer*
148  buffer_sequence_end(const mutable_buffer& __b)
149  { return std::addressof(__b) + 1; }
150
151  inline const const_buffer*
152  buffer_sequence_end(const const_buffer& __b)
153  { return std::addressof(__b) + 1; }
154
155  template<typename _Cont>
156    auto
157    buffer_sequence_begin(_Cont& __c) -> decltype(__c.begin())
158    { return __c.begin(); }
159
160  template<typename _Cont>
161    auto
162    buffer_sequence_begin(const _Cont& __c) -> decltype(__c.begin())
163    { return __c.begin(); }
164
165  template<typename _Cont>
166    auto
167    buffer_sequence_end(_Cont& __c) -> decltype(__c.end())
168    { return __c.end(); }
169
170  template<typename _Cont>
171    auto
172    buffer_sequence_end(const _Cont& __c) -> decltype(__c.end())
173    { return __c.end(); }
174
175  /// @}
176
177
178  /** @brief buffer type traits
179   *
180   * @{
181   */
182
183  template<typename _Tp, typename _Buffer,
184	   typename _Begin
185	    = decltype(net::buffer_sequence_begin(std::declval<_Tp&>())),
186	   typename _End
187	    = decltype(net::buffer_sequence_end(std::declval<_Tp&>()))>
188    using __buffer_sequence = enable_if_t<__and_<
189      __is_value_constructible<_Tp>, is_same<_Begin, _End>,
190      is_convertible<typename iterator_traits<_Begin>::value_type, _Buffer>
191      >::value>;
192
193  template<typename _Tp, typename _Buffer, typename = void>
194    struct __is_buffer_sequence : false_type
195    { };
196
197  template<typename _Tp, typename _Buffer>
198    struct __is_buffer_sequence<_Tp, _Buffer, __buffer_sequence<_Tp, _Buffer>>
199    : true_type
200    { };
201
202  template<typename _Tp>
203    struct is_mutable_buffer_sequence
204    : __is_buffer_sequence<_Tp, mutable_buffer>::type
205    { };
206
207  template<typename _Tp>
208    struct is_const_buffer_sequence
209    : __is_buffer_sequence<_Tp, const_buffer>::type
210    { };
211
212  template<typename _Tp>
213    constexpr bool is_mutable_buffer_sequence_v
214      = is_mutable_buffer_sequence<_Tp>::value;
215
216  template<typename _Tp>
217    constexpr bool is_const_buffer_sequence_v
218      = is_const_buffer_sequence<_Tp>::value;
219
220  template<typename _Tp, typename = void>
221    struct __is_dynamic_buffer_impl : false_type
222    { };
223
224  // Check DynamicBuffer requirements.
225  template<typename _Tp, typename _Up = remove_const_t<_Tp>>
226    auto
227    __dynamic_buffer_reqs(_Up* __x = 0, const _Up* __x1 = 0, size_t __n = 0)
228    -> enable_if_t<__and_<
229      is_move_constructible<_Up>,
230      is_const_buffer_sequence<typename _Tp::const_buffers_type>,
231      is_mutable_buffer_sequence<typename _Tp::mutable_buffers_type>,
232      is_same<decltype(__x1->size()), size_t>,
233      is_same<decltype(__x1->max_size()), size_t>,
234      is_same<decltype(__x1->capacity()), size_t>,
235      is_same<decltype(__x1->data()), typename _Tp::const_buffers_type>,
236      is_same<decltype(__x->prepare(__n)), typename _Tp::mutable_buffers_type>,
237      is_void<decltype(__x->commit(__n), __x->consume(__n), void())>
238    >::value>;
239
240  template<typename _Tp>
241    struct __is_dynamic_buffer_impl<_Tp,
242				    decltype(__dynamic_buffer_reqs<_Tp>())>
243    : true_type
244    { };
245
246  template<typename _Tp>
247    struct is_dynamic_buffer : __is_dynamic_buffer_impl<_Tp>::type
248    { };
249
250  template<typename _Tp>
251    constexpr bool is_dynamic_buffer_v = is_dynamic_buffer<_Tp>::value;
252
253  /// @}
254
255  /// buffer size
256  template<typename _ConstBufferSequence>
257    size_t
258    buffer_size(const _ConstBufferSequence& __buffers) noexcept
259    {
260      size_t __total_size = 0;
261      auto __i = net::buffer_sequence_begin(__buffers);
262      const auto __end = net::buffer_sequence_end(__buffers);
263      for (; __i != __end; ++__i)
264	__total_size += const_buffer(*__i).size();
265      return __total_size;
266    }
267
268  template<typename _ConstBufferSequence>
269    bool
270    __buffer_empty(const _ConstBufferSequence& __buffers) noexcept
271    {
272      auto __i = net::buffer_sequence_begin(__buffers);
273      const auto __end = net::buffer_sequence_end(__buffers);
274      for (; __i != __end; ++__i)
275	if (const_buffer(*__i).size() != 0)
276	  return false;
277      return true;
278    }
279
280  // buffer copy:
281
282  template<typename _MutableBufferSequence, typename _ConstBufferSequence>
283    size_t
284    buffer_copy(const _MutableBufferSequence& __dest,
285		const _ConstBufferSequence& __source,
286		size_t __max_size) noexcept
287    {
288      size_t __total_size = 0;
289      auto __to_i = net::buffer_sequence_begin(__dest);
290      const auto __to_end = net::buffer_sequence_end(__dest);
291      auto __from_i = net::buffer_sequence_begin(__source);
292      const auto __from_end = net::buffer_sequence_end(__source);
293      mutable_buffer __to;
294      const_buffer __from;
295      while (((__from_i != __from_end && __to_i != __to_end)
296	    || (__from.size() && __to.size()))
297	  && __total_size < __max_size)
298	{
299	  if (__from.size() == 0)
300	    __from = const_buffer{*__from_i++};
301	  if (__to.size() == 0)
302	    __to = mutable_buffer{*__to_i++};
303
304	  size_t __n = std::min(__from.size(), __to.size());
305	  __n = std::min(__n, __max_size - __total_size);
306	  std::memcpy(__to.data(), __from.data(), __n);
307	  __from = { (const char*)__from.data() + __n, __from.size() - __n };
308	  __to = { (char*)__to.data() + __n, __to.size() - __n };
309	  __total_size += __n;
310	}
311      return __total_size;
312    }
313
314  template<typename _MutableBufferSequence, typename _ConstBufferSequence>
315    inline size_t
316    buffer_copy(const _MutableBufferSequence& __dest,
317		const _ConstBufferSequence& __source) noexcept
318    { return net::buffer_copy(__dest, __source, size_t{-1}); }
319
320
321  // buffer arithmetic:
322
323  inline mutable_buffer
324  operator+(const mutable_buffer& __b, size_t __n) noexcept
325  {
326    if (__n > __b.size())
327      __n = __b.size();
328    return { static_cast<char*>(__b.data()) + __n, __b.size() - __n };
329  }
330
331  inline mutable_buffer
332  operator+(size_t __n, const mutable_buffer& __b) noexcept
333  { return __b + __n; }
334
335  inline const_buffer
336  operator+(const const_buffer& __b, size_t __n) noexcept
337  {
338    if (__n > __b.size())
339      __n = __b.size();
340    return { static_cast<const char*>(__b.data()) + __n, __b.size() - __n };
341  }
342
343  inline const_buffer
344  operator+(size_t __n, const const_buffer& __b) noexcept
345  { return __b + __n; }
346
347  // buffer creation:
348
349  inline mutable_buffer
350  buffer(void* __p, size_t __n) noexcept
351  { return { __p, __n }; }
352
353  inline const_buffer
354  buffer(const void* __p, size_t __n) noexcept
355  { return { __p, __n }; }
356
357  inline mutable_buffer
358  buffer(const mutable_buffer& __b) noexcept
359  { return __b; }
360
361  inline mutable_buffer
362  buffer(const mutable_buffer& __b, size_t __n) noexcept
363  { return { __b.data(), std::min(__b.size(), __n) }; }
364
365  inline const_buffer
366  buffer(const const_buffer& __b) noexcept
367  { return __b; }
368
369  inline const_buffer
370  buffer(const const_buffer& __b, size_t __n) noexcept
371  { return { __b.data(), std::min(__b.size(), __n) }; }
372
373  template<typename _Tp>
374    inline mutable_buffer
375    __to_mbuf(_Tp* __data, size_t __n)
376    { return { __n ? __data : nullptr, __n * sizeof(_Tp) }; }
377
378  template<typename _Tp>
379    inline const_buffer
380    __to_cbuf(const _Tp* __data, size_t __n)
381    { return { __n ? __data : nullptr, __n * sizeof(_Tp) }; }
382
383  template<typename _Tp, size_t _Nm>
384    inline mutable_buffer
385    buffer(_Tp (&__data)[_Nm]) noexcept
386    { return net::__to_mbuf(__data, _Nm); }
387
388  template<typename _Tp, size_t _Nm>
389    inline const_buffer
390    buffer(const _Tp (&__data)[_Nm]) noexcept
391    { return net::__to_cbuf(__data, _Nm); }
392
393  template<typename _Tp, size_t _Nm>
394    inline mutable_buffer
395    buffer(array<_Tp, _Nm>& __data) noexcept
396    { return net::__to_mbuf(__data.data(), _Nm); }
397
398  template<typename _Tp, size_t _Nm>
399    inline const_buffer
400    buffer(array<const _Tp, _Nm>& __data) noexcept
401    { return net::__to_cbuf(__data.data(), __data.size()); }
402
403  template<typename _Tp, size_t _Nm>
404    inline const_buffer
405    buffer(const array<_Tp, _Nm>& __data) noexcept
406    { return net::__to_cbuf(__data.data(), __data.size()); }
407
408  template<typename _Tp, typename _Allocator>
409    inline mutable_buffer
410    buffer(vector<_Tp, _Allocator>& __data) noexcept
411    { return net::__to_mbuf(__data.data(), __data.size()); }
412
413  template<typename _Tp, typename _Allocator>
414    inline const_buffer
415    buffer(const vector<_Tp, _Allocator>& __data) noexcept
416    { return net::__to_cbuf(__data.data(), __data.size()); }
417
418  template<typename _CharT, typename _Traits, typename _Allocator>
419    inline mutable_buffer
420    buffer(basic_string<_CharT, _Traits, _Allocator>& __data) noexcept
421    { return net::__to_mbuf(&__data.front(), __data.size()); }
422
423  template<typename _CharT, typename _Traits, typename _Allocator>
424    inline const_buffer
425    buffer(const basic_string<_CharT, _Traits, _Allocator>& __data) noexcept
426    { return net::__to_cbuf(&__data.front(), __data.size()); }
427
428  template<typename _CharT, typename _Traits>
429    inline const_buffer
430    buffer(basic_string_view<_CharT, _Traits> __data) noexcept
431    { return net::__to_cbuf(__data.data(), __data.size()); }
432
433  template<typename _Tp, size_t _Nm>
434    inline mutable_buffer
435    buffer(_Tp (&__data)[_Nm], size_t __n) noexcept
436    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
437
438  template<typename _Tp, size_t _Nm>
439    inline const_buffer
440    buffer(const _Tp (&__data)[_Nm], size_t __n) noexcept
441    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
442
443  template<typename _Tp, size_t _Nm>
444    inline mutable_buffer
445    buffer(array<_Tp, _Nm>& __data, size_t __n) noexcept
446    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
447
448  template<typename _Tp, size_t _Nm>
449    inline const_buffer
450    buffer(array<const _Tp, _Nm>& __data, size_t __n) noexcept
451    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
452
453  template<typename _Tp, size_t _Nm>
454    inline const_buffer
455    buffer(const array<_Tp, _Nm>& __data, size_t __n) noexcept
456    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
457
458  template<typename _Tp, typename _Allocator>
459    inline mutable_buffer
460    buffer(vector<_Tp, _Allocator>& __data, size_t __n) noexcept
461    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
462
463  template<typename _Tp, typename _Allocator>
464    inline const_buffer
465    buffer(const vector<_Tp, _Allocator>& __data, size_t __n) noexcept
466    { return buffer(net::buffer(__data), __n * sizeof(_Tp)); }
467
468  template<typename _CharT, typename _Traits, typename _Allocator>
469    inline mutable_buffer
470    buffer(basic_string<_CharT, _Traits, _Allocator>& __data,
471	   size_t __n) noexcept
472    { return buffer(net::buffer(__data), __n * sizeof(_CharT)); }
473
474  template<typename _CharT, typename _Traits, typename _Allocator>
475    inline const_buffer
476    buffer(const basic_string<_CharT, _Traits, _Allocator>& __data,
477	   size_t __n) noexcept
478    { return buffer(net::buffer(__data), __n * sizeof(_CharT)); }
479
480  template<typename _CharT, typename _Traits>
481    inline const_buffer
482    buffer(basic_string_view<_CharT, _Traits> __data, size_t __n) noexcept
483    { return buffer(net::buffer(__data), __n * sizeof(_CharT)); }
484
485
486  template<typename _Sequence>
487    class __dynamic_buffer_base
488    {
489    public:
490      // types:
491      typedef const_buffer const_buffers_type;
492      typedef mutable_buffer mutable_buffers_type;
493
494      // constructors:
495      explicit
496      __dynamic_buffer_base(_Sequence& __seq) noexcept
497      : _M_seq(__seq), _M_size(__seq.size()), _M_max_size(__seq.max_size())
498      { }
499
500      __dynamic_buffer_base(_Sequence& __seq, size_t __maximum_size) noexcept
501      : _M_seq(__seq), _M_size(__seq.size()), _M_max_size(__maximum_size)
502      { __glibcxx_assert(__seq.size() <= __maximum_size); }
503
504      __dynamic_buffer_base(__dynamic_buffer_base&&) = default;
505
506      // members:
507      size_t size() const noexcept { return _M_size; }
508      size_t max_size() const noexcept { return _M_max_size; }
509      size_t capacity() const noexcept { return _M_seq.capacity(); }
510
511      const_buffers_type
512      data() const noexcept
513      { return net::buffer(_M_seq, _M_size); }
514
515      mutable_buffers_type
516      prepare(size_t __n)
517      {
518	if ((_M_size + __n) > _M_max_size)
519	  __throw_length_error("dynamic_vector_buffer::prepare");
520
521	_M_seq.resize(_M_size + __n);
522	return buffer(net::buffer(_M_seq) + _M_size, __n);
523      }
524
525      void
526      commit(size_t __n)
527      {
528	_M_size += std::min(__n, _M_seq.size() - _M_size);
529	_M_seq.resize(_M_size);
530      }
531
532      void
533      consume(size_t __n)
534      {
535	size_t __m = std::min(__n, _M_size);
536	_M_seq.erase(_M_seq.begin(), _M_seq.begin() + __m);
537	_M_size -= __m;
538      }
539
540    private:
541      _Sequence&	_M_seq;
542      size_t		_M_size;
543      const size_t	_M_max_size;
544    };
545
546  template<typename _Tp, typename _Allocator>
547    class dynamic_vector_buffer
548    : public __dynamic_buffer_base<vector<_Tp, _Allocator>>
549    {
550    public:
551      using __dynamic_buffer_base<vector<_Tp, _Allocator>>::__dynamic_buffer_base;
552    };
553
554  template<typename _CharT, typename _Traits, typename _Allocator>
555    class dynamic_string_buffer
556    : public __dynamic_buffer_base<basic_string<_CharT, _Traits, _Allocator>>
557    {
558    public:
559      using __dynamic_buffer_base<basic_string<_CharT, _Traits, _Allocator>>::
560	__dynamic_buffer_base;
561    };
562
563  // dynamic buffer creation:
564
565  template<typename _Tp, typename _Allocator>
566    inline dynamic_vector_buffer<_Tp, _Allocator>
567    dynamic_buffer(vector<_Tp, _Allocator>& __vec) noexcept
568    { return dynamic_vector_buffer<_Tp, _Allocator>{__vec}; }
569
570  template<typename _Tp, typename _Allocator>
571    inline dynamic_vector_buffer<_Tp, _Allocator>
572    dynamic_buffer(vector<_Tp, _Allocator>& __vec, size_t __n) noexcept
573    { return {__vec, __n}; }
574
575  template<typename _CharT, typename _Traits, typename _Allocator>
576    inline dynamic_string_buffer<_CharT, _Traits, _Allocator>
577    dynamic_buffer(basic_string<_CharT, _Traits, _Allocator>& __str) noexcept
578    { return dynamic_string_buffer<_CharT, _Traits, _Allocator>{__str}; }
579
580  template<typename _CharT, typename _Traits, typename _Allocator>
581    inline dynamic_string_buffer<_CharT, _Traits, _Allocator>
582    dynamic_buffer(basic_string<_CharT, _Traits, _Allocator>& __str,
583		   size_t __n) noexcept
584    { return {__str, __n}; }
585
586  class transfer_all
587  {
588  public:
589    size_t operator()(const error_code& __ec, size_t) const
590    { return !__ec ? 1500 : 0; }
591  };
592
593  class transfer_at_least
594  {
595  public:
596    explicit transfer_at_least(size_t __m) : _M_minimum(__m) { }
597
598    size_t operator()(const error_code& __ec, size_t __n) const
599    { return !__ec  && __n < _M_minimum ? _M_minimum - __n : 0; }
600
601  private:
602    size_t _M_minimum;
603  };
604
605  class transfer_exactly
606  {
607  public:
608    explicit transfer_exactly(size_t __e) : _M_exact(__e) { }
609
610    size_t operator()(const error_code& __ec, size_t __n) const
611    {
612      size_t _Nm = -1;
613      return !__ec  && __n < _M_exact ? std::min(_M_exact - __n, _Nm) : 0;
614    }
615
616  private:
617    size_t _M_exact;
618  };
619
620  /** @brief synchronous read operations
621   * @{
622   */
623
624  template<typename _SyncReadStream, typename _MutableBufferSequence,
625	   typename _CompletionCondition>
626    enable_if_t<is_mutable_buffer_sequence<_MutableBufferSequence>::value,
627		size_t>
628    read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers,
629	 _CompletionCondition __completion_condition, error_code& __ec)
630    {
631      __ec.clear();
632      auto __i = net::buffer_sequence_begin(__buffers);
633      auto __end = net::buffer_sequence_end(__buffers);
634      mutable_buffer __to;
635      size_t __total = 0;
636      size_t __n;
637      while ((__n = __completion_condition(__ec, __total))
638	  && (__i != __end || __to.size()))
639	{
640	  if (__to.size() == 0)
641	    __to = mutable_buffer(*__i++);
642	  __n = __stream.read_some(buffer(__to, __n), __ec);
643	  __to = __to + __n;
644	  __total += __n;
645	}
646      return __total;
647    }
648
649  template<typename _SyncReadStream, typename _MutableBufferSequence>
650    inline
651    enable_if_t<is_mutable_buffer_sequence<_MutableBufferSequence>::value,
652		size_t>
653    read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers)
654    {
655      error_code __ec;
656      return net::read(__stream, __buffers, transfer_all{}, __ec);
657    }
658
659  template<typename _SyncReadStream, typename _MutableBufferSequence>
660    inline
661    enable_if_t<is_mutable_buffer_sequence<_MutableBufferSequence>::value,
662		size_t>
663    read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers,
664	 error_code& __ec)
665    { return net::read(__stream, __buffers, transfer_all{}, __ec); }
666
667  template<typename _SyncReadStream, typename _MutableBufferSequence,
668	   typename _CompletionCondition>
669    inline
670    enable_if_t<is_mutable_buffer_sequence<_MutableBufferSequence>::value,
671		size_t>
672    read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers,
673	 _CompletionCondition __completion_condition)
674    {
675      error_code __ec;
676      return net::read(__stream, __buffers, __completion_condition, __ec);
677    }
678
679
680  template<typename _SyncReadStream, typename _DynamicBuffer,
681	   typename _CompletionCondition>
682    enable_if_t<is_dynamic_buffer<decay_t<_DynamicBuffer>>::value, size_t>
683    read(_SyncReadStream& __stream, _DynamicBuffer&& __b,
684	 _CompletionCondition __completion_condition, error_code& __ec)
685    {
686      const size_t __limit = 64;
687      __ec.clear();
688      size_t __cap = std::max(__b.capacity() - __b.size(), __limit);
689      size_t __total = 0;
690      size_t __n;
691      while ((__n = __completion_condition(__ec, __total))
692	  && __b.size() != __b.max_size())
693	{
694	  __n =  std::min(__n, __b.max_size() - __b.size());
695	  size_t __cap = std::max(__b.capacity() - __b.size(), __limit);
696	  mutable_buffer __to = __b.prepare(std::min(__cap, __n));
697	  __n = __stream.read_some(__to, __ec);
698	  __to = __to + __n;
699	  __total += __n;
700	  __b.commit(__n);
701	}
702      return __total;
703    }
704
705  template<typename _SyncReadStream, typename _DynamicBuffer>
706    inline enable_if_t<is_dynamic_buffer<_DynamicBuffer>::value, size_t>
707    read(_SyncReadStream& __stream, _DynamicBuffer&& __b)
708    {
709      error_code __ec;
710      return net::read(__stream, __b, transfer_all{}, __ec);
711    }
712
713  template<typename _SyncReadStream, typename _DynamicBuffer>
714    inline enable_if_t<is_dynamic_buffer<_DynamicBuffer>::value, size_t>
715    read(_SyncReadStream& __stream, _DynamicBuffer&& __b, error_code& __ec)
716    {
717      return net::read(__stream, __b, transfer_all{}, __ec);
718    }
719
720  template<typename _SyncReadStream, typename _DynamicBuffer,
721	   typename _CompletionCondition>
722    inline enable_if_t<is_dynamic_buffer<_DynamicBuffer>::value, size_t>
723    read(_SyncReadStream& __stream, _DynamicBuffer&& __b,
724	 _CompletionCondition __completion_condition)
725    {
726      error_code __ec;
727      return net::read(__stream, __b, __completion_condition, __ec);
728    }
729
730  /// @}
731
732  /** @brief asynchronous read operations
733   * @{
734   */
735
736  template<typename _AsyncReadStream, typename _MutableBufferSequence,
737	   typename _CompletionCondition, typename _CompletionToken>
738    __deduced_t<_CompletionToken, void(error_code, size_t)>
739    async_read(_AsyncReadStream& __stream,
740	       const _MutableBufferSequence& __buffers,
741	       _CompletionCondition __completion_condition,
742	       _CompletionToken&& __token)
743    {
744      error_code __ec;
745    }
746
747  template<typename _AsyncReadStream, typename _MutableBufferSequence,
748	   typename _CompletionToken>
749    inline __deduced_t<_CompletionToken, void(error_code, size_t)>
750    async_read(_AsyncReadStream& __stream,
751	       const _MutableBufferSequence& __buffers,
752	       _CompletionToken&& __token)
753    {
754      return net::async_read(__stream, __buffers, transfer_all{},
755			     std::forward<_CompletionToken>(__token));
756    }
757
758  template<typename _AsyncReadStream, typename _DynamicBuffer,
759	   typename _CompletionCondition, typename _CompletionToken>
760    __deduced_t<_CompletionToken, void(error_code, size_t)>
761    async_read(_AsyncReadStream& __stream, _DynamicBuffer&& __b,
762	       _CompletionCondition __completion_condition,
763	       _CompletionToken&& __token)
764    {
765      error_code __ec;
766    }
767
768  template<typename _AsyncReadStream, typename _DynamicBuffer,
769	   typename _CompletionToken>
770    inline __deduced_t<_CompletionToken, void(error_code, size_t)>
771    async_read(_AsyncReadStream& __stream, _DynamicBuffer&& __b,
772	       _CompletionToken&& __token)
773    {
774      return net::async_read(__stream, __b, transfer_all{},
775			     std::forward<_CompletionToken>(__token));
776    }
777
778  /// @}
779
780#if 0
781  /** @brief synchronous write operations:
782   * @{
783   */
784
785  template<typename _SyncWriteStream, typename _ConstBufferSequence>
786    size_t write(_SyncWriteStream& __stream,
787                 const _ConstBufferSequence& __buffers);
788  template<typename _SyncWriteStream, typename _ConstBufferSequence>
789    size_t write(_SyncWriteStream& __stream,
790                 const _ConstBufferSequence& __buffers, error_code& __ec);
791  template<typename _SyncWriteStream, typename _ConstBufferSequence,
792    typename _CompletionCondition>
793      size_t write(_SyncWriteStream& __stream,
794                   const _ConstBufferSequence& __buffers,
795                   _CompletionCondition __completion_condition);
796  template<typename _SyncWriteStream, typename _ConstBufferSequence,
797    typename _CompletionCondition>
798      size_t write(_SyncWriteStream& __stream,
799                   const _ConstBufferSequence& __buffers,
800                   _CompletionCondition __completion_condition,
801                   error_code& __ec);
802
803  template<typename _SyncWriteStream, typename _DynamicBuffer>
804    size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b);
805  template<typename _SyncWriteStream, typename _DynamicBuffer>
806    size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b, error_code& __ec);
807  template<typename _SyncWriteStream, typename _DynamicBuffer, typename _CompletionCondition>
808    size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b,
809                 _CompletionCondition __completion_condition);
810  template<typename _SyncWriteStream, typename _DynamicBuffer, typename _CompletionCondition>
811    size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b,
812                 _CompletionCondition __completion_condition, error_code& __ec);
813
814  /// @}
815
816  /** @brief asynchronous write operations
817   * @{
818   */
819
820  template<typename _AsyncWriteStream, typename _ConstBufferSequence,
821    typename _CompletionToken>
822      DEDUCED async_write(_AsyncWriteStream& __stream,
823                       const _ConstBufferSequence& __buffers,
824                       _CompletionToken&& __token);
825  template<typename _AsyncWriteStream, typename _ConstBufferSequence,
826    typename _CompletionCondition, typename _CompletionToken>
827      DEDUCED async_write(_AsyncWriteStream& __stream,
828                       const _ConstBufferSequence& __buffers,
829                       _CompletionCondition __completion_condition,
830                       _CompletionToken&& __token);
831
832  template<typename _AsyncWriteStream, typename _DynamicBuffer, typename _CompletionToken>
833    DEDUCED async_write(_AsyncWriteStream& __stream,
834                     _DynamicBuffer&& __b, _CompletionToken&& __token);
835  template<typename _AsyncWriteStream, typename _DynamicBuffer,
836    typename _CompletionCondition, typename _CompletionToken>
837      DEDUCED async_write(_AsyncWriteStream& __stream,
838                       _DynamicBuffer&& __b,
839                       _CompletionCondition __completion_condition,
840                       _CompletionToken&& __token);
841
842  /// @}
843
844  /** @brief synchronous delimited read operations
845   * @{
846   */
847
848  template<typename _SyncReadStream, typename _DynamicBuffer>
849    size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b, char __delim);
850  template<typename _SyncReadStream, typename _DynamicBuffer>
851    size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b,
852                      char __delim, error_code& __ec);
853  template<typename _SyncReadStream, typename _DynamicBuffer>
854    size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b, string_view __delim);
855  template<typename _SyncReadStream, typename _DynamicBuffer>
856    size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b,
857                      string_view __delim, error_code& __ec);
858
859  /// @}
860
861  /** @brief asynchronous delimited read operations
862   * @{
863   */
864
865  template<typename _AsyncReadStream, typename _DynamicBuffer, typename _CompletionToken>
866    DEDUCED async_read_until(_AsyncReadStream& __s,
867                          _DynamicBuffer&& __b, char __delim,
868                          _CompletionToken&& __token);
869  template<typename _AsyncReadStream, typename _DynamicBuffer, typename _CompletionToken>
870    DEDUCED async_read_until(_AsyncReadStream& __s,
871                          _DynamicBuffer&& __b, string_view __delim,
872                          _CompletionToken&& __token);
873
874  /// @}
875
876#endif
877  /// @}
878
879} // namespace v1
880} // namespace net
881} // namespace experimental
882
883  template<>
884    struct is_error_code_enum<experimental::net::v1::stream_errc>
885    : public true_type {};
886
887_GLIBCXX_END_NAMESPACE_VERSION
888} // namespace std
889
890#endif // C++14
891
892#endif // _GLIBCXX_EXPERIMENTAL_BUFFER
893