// <experimental/buffer> -*- C++ -*-

// Copyright (C) 2015-2022 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.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       