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