// -*- C++ -*- // Copyright (C) 2015-2023 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // . /** @file experimental/buffer * This is a TS C++ Library header. * @ingroup networking-ts */ #ifndef _GLIBCXX_EXPERIMENTAL_BUFFER #define _GLIBCXX_EXPERIMENTAL_BUFFER 1 #pragma GCC system_header #include // experimental is currently omitted #if __cplusplus >= 201402L #include #include #include #include #include #include #include namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace experimental { namespace net { inline namespace v1 { /** @addtogroup networking-ts * @{ */ enum class stream_errc { // TODO decide values eof = 1, not_found = 2 }; const error_category& stream_category() noexcept // TODO not inline { struct __cat : error_category { const char* name() const noexcept { return "stream"; } std::string message(int __e) const { if (__e == (int)stream_errc::eof) return "EOF"; else if (__e == (int)stream_errc::not_found) return "not found"; return "stream"; } virtual void __message(int) { } // TODO dual ABI XXX }; static __cat __c; return __c; } inline error_code make_error_code(stream_errc __e) noexcept { return error_code(static_cast(__e), stream_category()); } inline error_condition make_error_condition(stream_errc __e) noexcept { return error_condition(static_cast(__e), stream_category()); } class mutable_buffer { public: // constructors: mutable_buffer() noexcept : _M_data(), _M_size() { } mutable_buffer(void* __p, size_t __n) noexcept : _M_data(__p), _M_size(__n) { } // members: void* data() const noexcept { return _M_data; } size_t size() const noexcept { return _M_size; } private: void* _M_data; size_t _M_size; }; class const_buffer { public: // constructors: const_buffer() noexcept : _M_data(), _M_size() { } const_buffer(const void* __p, size_t __n) noexcept : _M_data(__p), _M_size(__n) { } const_buffer(const mutable_buffer& __b) noexcept : _M_data(__b.data()), _M_size(__b.size()) { } // members: const void* data() const noexcept { return _M_data; } size_t size() const noexcept { return _M_size; } private: const void* _M_data; size_t _M_size; }; /** @brief buffer sequence access * * Uniform access to types that meet the BufferSequence requirements. * @{ */ inline const mutable_buffer* buffer_sequence_begin(const mutable_buffer& __b) { return std::addressof(__b); } inline const const_buffer* buffer_sequence_begin(const const_buffer& __b) { return std::addressof(__b); } inline const mutable_buffer* buffer_sequence_end(const mutable_buffer& __b) { return std::addressof(__b) + 1; } inline const const_buffer* buffer_sequence_end(const const_buffer& __b) { return std::addressof(__b) + 1; } template auto buffer_sequence_begin(_Cont& __c) -> decltype(__c.begin()) { return __c.begin(); } template auto buffer_sequence_begin(const _Cont& __c) -> decltype(__c.begin()) { return __c.begin(); } template auto buffer_sequence_end(_Cont& __c) -> decltype(__c.end()) { return __c.end(); } template auto buffer_sequence_end(const _Cont& __c) -> decltype(__c.end()) { return __c.end(); } /// @} /** @brief buffer type traits * * @{ */ template())), typename _End = decltype(net::buffer_sequence_end(std::declval<_Tp&>()))> using __buffer_sequence = enable_if_t<__and_< __is_value_constructible<_Tp>, is_same<_Begin, _End>, is_convertible::value_type, _Buffer> >::value>; template struct __is_buffer_sequence : false_type { }; template struct __is_buffer_sequence<_Tp, _Buffer, __buffer_sequence<_Tp, _Buffer>> : true_type { }; template struct is_mutable_buffer_sequence : __is_buffer_sequence<_Tp, mutable_buffer>::type { }; template struct is_const_buffer_sequence : __is_buffer_sequence<_Tp, const_buffer>::type { }; template constexpr bool is_mutable_buffer_sequence_v = is_mutable_buffer_sequence<_Tp>::value; template constexpr bool is_const_buffer_sequence_v = is_const_buffer_sequence<_Tp>::value; template struct __is_dynamic_buffer_impl : false_type { }; // Check DynamicBuffer requirements. template> auto __dynamic_buffer_reqs(_Up* __x = 0, const _Up* __x1 = 0, size_t __n = 0) -> enable_if_t<__and_< is_move_constructible<_Up>, is_const_buffer_sequence, is_mutable_buffer_sequence, is_samesize()), size_t>, is_samemax_size()), size_t>, is_samecapacity()), size_t>, is_samedata()), typename _Tp::const_buffers_type>, is_sameprepare(__n)), typename _Tp::mutable_buffers_type>, is_voidcommit(__n), __x->consume(__n), void())> >::value>; template struct __is_dynamic_buffer_impl<_Tp, decltype(__dynamic_buffer_reqs<_Tp>())> : true_type { }; template struct is_dynamic_buffer : __is_dynamic_buffer_impl<_Tp>::type { }; template constexpr bool is_dynamic_buffer_v = is_dynamic_buffer<_Tp>::value; /// @} /// buffer size template size_t buffer_size(const _ConstBufferSequence& __buffers) noexcept { size_t __total_size = 0; auto __i = net::buffer_sequence_begin(__buffers); const auto __end = net::buffer_sequence_end(__buffers); for (; __i != __end; ++__i) __total_size += const_buffer(*__i).size(); return __total_size; } template bool __buffer_empty(const _ConstBufferSequence& __buffers) noexcept { auto __i = net::buffer_sequence_begin(__buffers); const auto __end = net::buffer_sequence_end(__buffers); for (; __i != __end; ++__i) if (const_buffer(*__i).size() != 0) return false; return true; } // buffer copy: template size_t buffer_copy(const _MutableBufferSequence& __dest, const _ConstBufferSequence& __source, size_t __max_size) noexcept { size_t __total_size = 0; auto __to_i = net::buffer_sequence_begin(__dest); const auto __to_end = net::buffer_sequence_end(__dest); auto __from_i = net::buffer_sequence_begin(__source); const auto __from_end = net::buffer_sequence_end(__source); mutable_buffer __to; const_buffer __from; while (((__from_i != __from_end && __to_i != __to_end) || (__from.size() && __to.size())) && __total_size < __max_size) { if (__from.size() == 0) __from = const_buffer{*__from_i++}; if (__to.size() == 0) __to = mutable_buffer{*__to_i++}; size_t __n = std::min(__from.size(), __to.size()); __n = std::min(__n, __max_size - __total_size); std::memcpy(__to.data(), __from.data(), __n); __from = { (const char*)__from.data() + __n, __from.size() - __n }; __to = { (char*)__to.data() + __n, __to.size() - __n }; __total_size += __n; } return __total_size; } template inline size_t buffer_copy(const _MutableBufferSequence& __dest, const _ConstBufferSequence& __source) noexcept { return net::buffer_copy(__dest, __source, size_t(-1)); } // buffer arithmetic: inline mutable_buffer operator+(const mutable_buffer& __b, size_t __n) noexcept { if (__n > __b.size()) __n = __b.size(); return { static_cast(__b.data()) + __n, __b.size() - __n }; } inline mutable_buffer operator+(size_t __n, const mutable_buffer& __b) noexcept { return __b + __n; } inline const_buffer operator+(const const_buffer& __b, size_t __n) noexcept { if (__n > __b.size()) __n = __b.size(); return { static_cast(__b.data()) + __n, __b.size() - __n }; } inline const_buffer operator+(size_t __n, const const_buffer& __b) noexcept { return __b + __n; } // buffer creation: inline mutable_buffer buffer(void* __p, size_t __n) noexcept { return { __p, __n }; } inline const_buffer buffer(const void* __p, size_t __n) noexcept { return { __p, __n }; } inline mutable_buffer buffer(const mutable_buffer& __b) noexcept { return __b; } inline mutable_buffer buffer(const mutable_buffer& __b, size_t __n) noexcept { return { __b.data(), std::min(__b.size(), __n) }; } inline const_buffer buffer(const const_buffer& __b) noexcept { return __b; } inline const_buffer buffer(const const_buffer& __b, size_t __n) noexcept { return { __b.data(), std::min(__b.size(), __n) }; } template inline mutable_buffer __to_mbuf(_Tp* __data, size_t __n) { return { __n ? __data : nullptr, __n * sizeof(_Tp) }; } template inline const_buffer __to_cbuf(const _Tp* __data, size_t __n) { return { __n ? __data : nullptr, __n * sizeof(_Tp) }; } template inline mutable_buffer buffer(_Tp (&__data)[_Nm]) noexcept { return net::__to_mbuf(__data, _Nm); } template inline const_buffer buffer(const _Tp (&__data)[_Nm]) noexcept { return net::__to_cbuf(__data, _Nm); } template inline mutable_buffer buffer(array<_Tp, _Nm>& __data) noexcept { return net::__to_mbuf(__data.data(), _Nm); } template inline const_buffer buffer(array& __data) noexcept { return net::__to_cbuf(__data.data(), __data.size()); } template inline const_buffer buffer(const array<_Tp, _Nm>& __data) noexcept { return net::__to_cbuf(__data.data(), __data.size()); } template inline mutable_buffer buffer(vector<_Tp, _Allocator>& __data) noexcept { return net::__to_mbuf(__data.data(), __data.size()); } template inline const_buffer buffer(const vector<_Tp, _Allocator>& __data) noexcept { return net::__to_cbuf(__data.data(), __data.size()); } template inline mutable_buffer buffer(basic_string<_CharT, _Traits, _Allocator>& __data) noexcept { return net::__to_mbuf(&__data.front(), __data.size()); } template inline const_buffer buffer(const basic_string<_CharT, _Traits, _Allocator>& __data) noexcept { return net::__to_cbuf(&__data.front(), __data.size()); } template inline const_buffer buffer(basic_string_view<_CharT, _Traits> __data) noexcept { return net::__to_cbuf(__data.data(), __data.size()); } template inline mutable_buffer buffer(_Tp (&__data)[_Nm], size_t __n) noexcept { return buffer(net::buffer(__data), __n * sizeof(_Tp)); } template inline const_buffer buffer(const _Tp (&__data)[_Nm], size_t __n) noexcept { return buffer(net::buffer(__data), __n * sizeof(_Tp)); } template inline mutable_buffer buffer(array<_Tp, _Nm>& __data, size_t __n) noexcept { return buffer(net::buffer(__data), __n * sizeof(_Tp)); } template inline const_buffer buffer(array& __data, size_t __n) noexcept { return buffer(net::buffer(__data), __n * sizeof(_Tp)); } template inline const_buffer buffer(const array<_Tp, _Nm>& __data, size_t __n) noexcept { return buffer(net::buffer(__data), __n * sizeof(_Tp)); } template inline mutable_buffer buffer(vector<_Tp, _Allocator>& __data, size_t __n) noexcept { return buffer(net::buffer(__data), __n * sizeof(_Tp)); } template inline const_buffer buffer(const vector<_Tp, _Allocator>& __data, size_t __n) noexcept { return buffer(net::buffer(__data), __n * sizeof(_Tp)); } template inline mutable_buffer buffer(basic_string<_CharT, _Traits, _Allocator>& __data, size_t __n) noexcept { return buffer(net::buffer(__data), __n * sizeof(_CharT)); } template inline const_buffer buffer(const basic_string<_CharT, _Traits, _Allocator>& __data, size_t __n) noexcept { return buffer(net::buffer(__data), __n * sizeof(_CharT)); } template inline const_buffer buffer(basic_string_view<_CharT, _Traits> __data, size_t __n) noexcept { return buffer(net::buffer(__data), __n * sizeof(_CharT)); } template class __dynamic_buffer_base { public: // types: using const_buffers_type = const_buffer; using mutable_buffers_type = mutable_buffer; // constructors: explicit __dynamic_buffer_base(_Sequence& __seq) noexcept : _M_seq(__seq), _M_size(__seq.size()), _M_max_size(__seq.max_size()) { } __dynamic_buffer_base(_Sequence& __seq, size_t __maximum_size) noexcept : _M_seq(__seq), _M_size(__seq.size()), _M_max_size(__maximum_size) { __glibcxx_assert(__seq.size() <= __maximum_size); } __dynamic_buffer_base(__dynamic_buffer_base&&) = default; // members: size_t size() const noexcept { return _M_size; } size_t max_size() const noexcept { return _M_max_size; } size_t capacity() const noexcept { return _M_seq.capacity(); } const_buffers_type data() const noexcept { return net::buffer(_M_seq, _M_size); } mutable_buffers_type prepare(size_t __n) { if ((_M_size + __n) > _M_max_size) __throw_length_error("dynamic_vector_buffer::prepare"); _M_seq.resize(_M_size + __n); return buffer(net::buffer(_M_seq) + _M_size, __n); } void commit(size_t __n) { _M_size += std::min(__n, _M_seq.size() - _M_size); _M_seq.resize(_M_size); } void consume(size_t __n) { size_t __m = std::min(__n, _M_size); _M_seq.erase(_M_seq.begin(), _M_seq.begin() + __m); _M_size -= __m; } private: _Sequence& _M_seq; size_t _M_size; const size_t _M_max_size; }; template class dynamic_vector_buffer : public __dynamic_buffer_base> { public: using __dynamic_buffer_base>::__dynamic_buffer_base; }; template class dynamic_string_buffer : public __dynamic_buffer_base> { public: using __dynamic_buffer_base>:: __dynamic_buffer_base; }; // dynamic buffer creation: template inline dynamic_vector_buffer<_Tp, _Allocator> dynamic_buffer(vector<_Tp, _Allocator>& __vec) noexcept { return dynamic_vector_buffer<_Tp, _Allocator>{__vec}; } template inline dynamic_vector_buffer<_Tp, _Allocator> dynamic_buffer(vector<_Tp, _Allocator>& __vec, size_t __n) noexcept { return {__vec, __n}; } template inline dynamic_string_buffer<_CharT, _Traits, _Allocator> dynamic_buffer(basic_string<_CharT, _Traits, _Allocator>& __str) noexcept { return dynamic_string_buffer<_CharT, _Traits, _Allocator>{__str}; } template inline dynamic_string_buffer<_CharT, _Traits, _Allocator> dynamic_buffer(basic_string<_CharT, _Traits, _Allocator>& __str, size_t __n) noexcept { return {__str, __n}; } class transfer_all { public: size_t operator()(const error_code& __ec, size_t) const { return !__ec ? 1500 : 0; } }; class transfer_at_least { public: explicit transfer_at_least(size_t __m) : _M_minimum(__m) { } size_t operator()(const error_code& __ec, size_t __n) const { return !__ec && __n < _M_minimum ? _M_minimum - __n : 0; } private: size_t _M_minimum; }; class transfer_exactly { public: explicit transfer_exactly(size_t __e) : _M_exact(__e) { } size_t operator()(const error_code& __ec, size_t __n) const { size_t _Nm = -1; return !__ec && __n < _M_exact ? std::min(_M_exact - __n, _Nm) : 0; } private: size_t _M_exact; }; /** @brief synchronous read operations * @{ */ template enable_if_t::value, size_t> read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers, _CompletionCondition __completion_condition, error_code& __ec) { __ec.clear(); auto __i = net::buffer_sequence_begin(__buffers); auto __end = net::buffer_sequence_end(__buffers); mutable_buffer __to; size_t __total = 0; size_t __n; while ((__n = __completion_condition(__ec, __total)) && (__i != __end || __to.size())) { if (__to.size() == 0) __to = mutable_buffer(*__i++); __n = __stream.read_some(buffer(__to, __n), __ec); __to = __to + __n; __total += __n; } return __total; } template inline enable_if_t::value, size_t> read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers) { error_code __ec; return net::read(__stream, __buffers, transfer_all{}, __ec); } template inline enable_if_t::value, size_t> read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers, error_code& __ec) { return net::read(__stream, __buffers, transfer_all{}, __ec); } template inline enable_if_t::value, size_t> read(_SyncReadStream& __stream, const _MutableBufferSequence& __buffers, _CompletionCondition __completion_condition) { error_code __ec; return net::read(__stream, __buffers, __completion_condition, __ec); } template enable_if_t>::value, size_t> read(_SyncReadStream& __stream, _DynamicBuffer&& __b, _CompletionCondition __completion_condition, error_code& __ec) { const size_t __limit = 64; __ec.clear(); size_t __cap = std::max(__b.capacity() - __b.size(), __limit); size_t __total = 0; size_t __n; while ((__n = __completion_condition(__ec, __total)) && __b.size() != __b.max_size()) { __n = std::min(__n, __b.max_size() - __b.size()); size_t __cap = std::max(__b.capacity() - __b.size(), __limit); mutable_buffer __to = __b.prepare(std::min(__cap, __n)); __n = __stream.read_some(__to, __ec); __to = __to + __n; __total += __n; __b.commit(__n); } return __total; } template inline enable_if_t::value, size_t> read(_SyncReadStream& __stream, _DynamicBuffer&& __b) { error_code __ec; return net::read(__stream, __b, transfer_all{}, __ec); } template inline enable_if_t::value, size_t> read(_SyncReadStream& __stream, _DynamicBuffer&& __b, error_code& __ec) { return net::read(__stream, __b, transfer_all{}, __ec); } template inline enable_if_t::value, size_t> read(_SyncReadStream& __stream, _DynamicBuffer&& __b, _CompletionCondition __completion_condition) { error_code __ec; return net::read(__stream, __b, __completion_condition, __ec); } /// @} /** @brief asynchronous read operations * @{ */ template __deduced_t<_CompletionToken, void(error_code, size_t)> async_read(_AsyncReadStream& __stream, const _MutableBufferSequence& __buffers, _CompletionCondition __completion_condition, _CompletionToken&& __token) { error_code __ec; } template inline __deduced_t<_CompletionToken, void(error_code, size_t)> async_read(_AsyncReadStream& __stream, const _MutableBufferSequence& __buffers, _CompletionToken&& __token) { return net::async_read(__stream, __buffers, transfer_all{}, std::forward<_CompletionToken>(__token)); } template __deduced_t<_CompletionToken, void(error_code, size_t)> async_read(_AsyncReadStream& __stream, _DynamicBuffer&& __b, _CompletionCondition __completion_condition, _CompletionToken&& __token) { error_code __ec; } template inline __deduced_t<_CompletionToken, void(error_code, size_t)> async_read(_AsyncReadStream& __stream, _DynamicBuffer&& __b, _CompletionToken&& __token) { return net::async_read(__stream, __b, transfer_all{}, std::forward<_CompletionToken>(__token)); } /// @} #if 0 /** @brief synchronous write operations: * @{ */ template size_t write(_SyncWriteStream& __stream, const _ConstBufferSequence& __buffers); template size_t write(_SyncWriteStream& __stream, const _ConstBufferSequence& __buffers, error_code& __ec); template size_t write(_SyncWriteStream& __stream, const _ConstBufferSequence& __buffers, _CompletionCondition __completion_condition); template size_t write(_SyncWriteStream& __stream, const _ConstBufferSequence& __buffers, _CompletionCondition __completion_condition, error_code& __ec); template size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b); template size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b, error_code& __ec); template size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b, _CompletionCondition __completion_condition); template size_t write(_SyncWriteStream& __stream, _DynamicBuffer&& __b, _CompletionCondition __completion_condition, error_code& __ec); /// @} /** @brief asynchronous write operations * @{ */ template DEDUCED async_write(_AsyncWriteStream& __stream, const _ConstBufferSequence& __buffers, _CompletionToken&& __token); template DEDUCED async_write(_AsyncWriteStream& __stream, const _ConstBufferSequence& __buffers, _CompletionCondition __completion_condition, _CompletionToken&& __token); template DEDUCED async_write(_AsyncWriteStream& __stream, _DynamicBuffer&& __b, _CompletionToken&& __token); template DEDUCED async_write(_AsyncWriteStream& __stream, _DynamicBuffer&& __b, _CompletionCondition __completion_condition, _CompletionToken&& __token); /// @} /** @brief synchronous delimited read operations * @{ */ template size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b, char __delim); template size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b, char __delim, error_code& __ec); template size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b, string_view __delim); template size_t read_until(_SyncReadStream& __s, _DynamicBuffer&& __b, string_view __delim, error_code& __ec); /// @} /** @brief asynchronous delimited read operations * @{ */ template DEDUCED async_read_until(_AsyncReadStream& __s, _DynamicBuffer&& __b, char __delim, _CompletionToken&& __token); template DEDUCED async_read_until(_AsyncReadStream& __s, _DynamicBuffer&& __b, string_view __delim, _CompletionToken&& __token); /// @} #endif /// @} } // namespace v1 } // namespace net } // namespace experimental template<> struct is_error_code_enum : public true_type {}; _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++14 #endif // _GLIBCXX_EXPERIMENTAL_BUFFER