Home | History | Annotate | Line # | Download | only in experimental
      1 // <experimental/buffer> -*- C++ -*-
      2 
      3 // Copyright (C) 2015-2022 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  *  @ingroup networking-ts
     28  */
     29 
     30 #ifndef _GLIBCXX_EXPERIMENTAL_BUFFER
     31 #define _GLIBCXX_EXPERIMENTAL_BUFFER 1
     32 
     33 #pragma GCC system_header
     34 
     35 #if __cplusplus >= 201402L
     36 
     37 #include <array>
     38 #include <string>
     39 #include <system_error>
     40 #include <vector>
     41 #include <cstring>
     42 #include <experimental/string_view>
     43 #include <experimental/bits/net.h>
     44 
     45 namespace std _GLIBCXX_VISIBILITY(default)
     46 {
     47 _GLIBCXX_BEGIN_NAMESPACE_VERSION
     48 namespace experimental
     49 {
     50 namespace net
     51 {
     52 inline namespace v1
     53 {
     54 
     55   /** @addtogroup networking-ts
     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       using const_buffers_type = const_buffer;
    492       using mutable_buffers_type = mutable_buffer;
    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