Added thirdparty: boost library

This commit is contained in:
Viacheslav Demydiuk
2024-01-06 19:55:56 +02:00
parent bf49f439e1
commit bccd1e7051
15683 changed files with 3239840 additions and 0 deletions
+113
View File
@@ -0,0 +1,113 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_ASYNC_BASE_HPP
#define BOOST_BEAST_CORE_IMPL_ASYNC_BASE_HPP
#include <boost/core/exchange.hpp>
namespace boost {
namespace beast {
namespace detail {
template<class State, class Allocator>
struct allocate_stable_state final
: stable_base
, boost::empty_value<Allocator>
{
State value;
template<class... Args>
explicit
allocate_stable_state(
Allocator const& alloc,
Args&&... args)
: boost::empty_value<Allocator>(
boost::empty_init_t{}, alloc)
, value{std::forward<Args>(args)...}
{
}
void destroy() override
{
using A = typename allocator_traits<
Allocator>::template rebind_alloc<
allocate_stable_state>;
A a(this->get());
auto* p = this;
p->~allocate_stable_state();
a.deallocate(p, 1);
}
};
} // detail
template<
class Handler,
class Executor1,
class Allocator>
bool
asio_handler_is_continuation(
async_base<Handler, Executor1, Allocator>* p)
{
using boost::asio::asio_handler_is_continuation;
return asio_handler_is_continuation(
p->get_legacy_handler_pointer());
}
template<
class State,
class Handler,
class Executor1,
class Allocator,
class... Args>
State&
allocate_stable(
stable_async_base<
Handler, Executor1, Allocator>& base,
Args&&... args)
{
using allocator_type = typename stable_async_base<
Handler, Executor1, Allocator>::allocator_type;
using state = detail::allocate_stable_state<
State, allocator_type>;
using A = typename detail::allocator_traits<
allocator_type>::template rebind_alloc<state>;
struct deleter
{
allocator_type alloc;
state* ptr;
~deleter()
{
if(ptr)
{
A a(alloc);
a.deallocate(ptr, 1);
}
}
};
A a(base.get_allocator());
deleter d{base.get_allocator(), a.allocate(1)};
::new(static_cast<void*>(d.ptr))
state(d.alloc, std::forward<Args>(args)...);
d.ptr->next_ = base.list_;
base.list_ = d.ptr;
return boost::exchange(d.ptr, nullptr)->value;
}
} // beast
} // boost
#endif
File diff suppressed because it is too large Load Diff
+244
View File
@@ -0,0 +1,244 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_BUFFERED_READ_STREAM_HPP
#define BOOST_BEAST_IMPL_BUFFERED_READ_STREAM_HPP
#include <boost/beast/core/async_base.hpp>
#include <boost/beast/core/bind_handler.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/read_size.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/core/detail/is_invocable.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/throw_exception.hpp>
namespace boost {
namespace beast {
template<class Stream, class DynamicBuffer>
struct buffered_read_stream<Stream, DynamicBuffer>::ops
{
template<class MutableBufferSequence, class Handler>
class read_op
: public async_base<Handler,
beast::executor_type<buffered_read_stream>>
{
buffered_read_stream& s_;
MutableBufferSequence b_;
int step_ = 0;
public:
read_op(read_op&&) = default;
read_op(read_op const&) = delete;
template<class Handler_>
read_op(
Handler_&& h,
buffered_read_stream& s,
MutableBufferSequence const& b)
: async_base<
Handler, beast::executor_type<buffered_read_stream>>(
std::forward<Handler_>(h), s.get_executor())
, s_(s)
, b_(b)
{
(*this)({}, 0);
}
void
operator()(
error_code ec,
std::size_t bytes_transferred)
{
// VFALCO TODO Rewrite this using reenter/yield
switch(step_)
{
case 0:
if(s_.buffer_.size() == 0)
{
if(s_.capacity_ == 0)
{
// read (unbuffered)
step_ = 1;
return s_.next_layer_.async_read_some(
b_, std::move(*this));
}
// read
step_ = 2;
return s_.next_layer_.async_read_some(
s_.buffer_.prepare(read_size(
s_.buffer_, s_.capacity_)),
std::move(*this));
}
step_ = 3;
{
const auto ex = this->get_immediate_executor();
return net::dispatch(
ex,
beast::bind_front_handler(
std::move(*this), ec, 0));
}
case 1:
// upcall
break;
case 2:
s_.buffer_.commit(bytes_transferred);
BOOST_FALLTHROUGH;
case 3:
bytes_transferred =
net::buffer_copy(b_, s_.buffer_.data());
s_.buffer_.consume(bytes_transferred);
break;
}
this->complete_now(ec, bytes_transferred);
}
};
struct run_read_op
{
template<class ReadHandler, class Buffers>
void
operator()(
ReadHandler&& h,
buffered_read_stream* s,
Buffers const* b)
{
// If you get an error on the following line it means
// that your handler does not meet the documented type
// requirements for the handler.
static_assert(
beast::detail::is_invocable<ReadHandler,
void(error_code, std::size_t)>::value,
"ReadHandler type requirements not met");
read_op<
Buffers,
typename std::decay<ReadHandler>::type>(
std::forward<ReadHandler>(h), *s, *b);
}
};
};
//------------------------------------------------------------------------------
template<class Stream, class DynamicBuffer>
template<class... Args>
buffered_read_stream<Stream, DynamicBuffer>::
buffered_read_stream(Args&&... args)
: next_layer_(std::forward<Args>(args)...)
{
}
template<class Stream, class DynamicBuffer>
template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
buffered_read_stream<Stream, DynamicBuffer>::
async_write_some(
ConstBufferSequence const& buffers,
WriteHandler&& handler)
{
static_assert(is_async_write_stream<next_layer_type>::value,
"AsyncWriteStream type requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
static_assert(detail::is_completion_token_for<WriteHandler,
void(error_code, std::size_t)>::value,
"WriteHandler type requirements not met");
return next_layer_.async_write_some(buffers,
std::forward<WriteHandler>(handler));
}
template<class Stream, class DynamicBuffer>
template<class MutableBufferSequence>
std::size_t
buffered_read_stream<Stream, DynamicBuffer>::
read_some(
MutableBufferSequence const& buffers)
{
static_assert(is_sync_read_stream<next_layer_type>::value,
"SyncReadStream type requirements not met");
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence type requirements not met");
error_code ec;
auto n = read_some(buffers, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
return n;
}
template<class Stream, class DynamicBuffer>
template<class MutableBufferSequence>
std::size_t
buffered_read_stream<Stream, DynamicBuffer>::
read_some(MutableBufferSequence const& buffers,
error_code& ec)
{
static_assert(is_sync_read_stream<next_layer_type>::value,
"SyncReadStream type requirements not met");
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence type requirements not met");
if(buffer_.size() == 0)
{
if(capacity_ == 0)
return next_layer_.read_some(buffers, ec);
buffer_.commit(next_layer_.read_some(
buffer_.prepare(read_size(buffer_,
capacity_)), ec));
if(ec)
return 0;
}
else
{
ec = {};
}
auto bytes_transferred =
net::buffer_copy(buffers, buffer_.data());
buffer_.consume(bytes_transferred);
return bytes_transferred;
}
template<class Stream, class DynamicBuffer>
template<class MutableBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
buffered_read_stream<Stream, DynamicBuffer>::
async_read_some(
MutableBufferSequence const& buffers,
ReadHandler&& handler)
{
static_assert(is_async_read_stream<next_layer_type>::value,
"AsyncReadStream type requirements not met");
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence type requirements not met");
if(buffer_.size() == 0 && capacity_ == 0)
return next_layer_.async_read_some(buffers,
std::forward<ReadHandler>(handler));
return net::async_initiate<
ReadHandler,
void(error_code, std::size_t)>(
typename ops::run_read_op{},
handler,
this,
&buffers);
}
} // beast
} // boost
#endif
+707
View File
@@ -0,0 +1,707 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_BUFFERS_ADAPTOR_HPP
#define BOOST_BEAST_IMPL_BUFFERS_ADAPTOR_HPP
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/buffers_adaptor.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/config/workaround.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <stdexcept>
#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
//------------------------------------------------------------------------------
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
# pragma warning (push)
# pragma warning (disable: 4521) // multiple copy constructors specified
# pragma warning (disable: 4522) // multiple assignment operators specified
#endif
template<class MutableBufferSequence>
template<bool isMutable>
class buffers_adaptor<MutableBufferSequence>::subrange
{
public:
using value_type = typename std::conditional<
isMutable,
net::mutable_buffer,
net::const_buffer>::type;
struct iterator;
// construct from two iterators plus optionally subrange definition
subrange(
iter_type first, // iterator to first buffer in storage
iter_type last, // iterator to last buffer in storage
std::size_t pos = 0, // the offset in bytes from the beginning of the storage
std::size_t n = // the total length of the subrange
(std::numeric_limits<std::size_t>::max)());
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
subrange(
subrange const& other)
: first_(other.first_)
, last_(other.last_)
, first_offset_(other.first_offset_)
, last_size_(other.last_size_)
{
}
subrange& operator=(
subrange const& other)
{
first_ = other.first_;
last_ = other.last_;
first_offset_ = other.first_offset_;
last_size_ = other.last_size_;
return *this;
}
#else
subrange(
subrange const&) = default;
subrange& operator=(
subrange const&) = default;
#endif
// allow conversion from mutable to const
template<bool isMutable_ = isMutable, typename
std::enable_if<!isMutable_>::type * = nullptr>
subrange(subrange<true> const &other)
: first_(other.first_)
, last_(other.last_)
, first_offset_(other.first_offset_)
, last_size_(other.last_size_)
{
}
iterator
begin() const;
iterator
end() const;
private:
friend subrange<!isMutable>;
void
adjust(
std::size_t pos,
std::size_t n);
private:
// points to the first buffer in the sequence
iter_type first_;
// Points to one past the end of the underlying buffer sequence
iter_type last_;
// The initial offset into the first buffer
std::size_t first_offset_;
// how many bytes in the penultimate buffer are used (if any)
std::size_t last_size_;
};
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
# pragma warning (pop)
#endif
//------------------------------------------------------------------------------
template<class MutableBufferSequence>
template<bool isMutable>
struct buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator
{
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename
buffers_adaptor<MutableBufferSequence>::
template subrange<isMutable>::
value_type;
using reference = value_type&;
using pointer = value_type*;
using difference_type = std::ptrdiff_t;
iterator(
subrange<isMutable> const *parent,
iter_type it);
iterator();
value_type
operator*() const;
pointer
operator->() const = delete;
iterator &
operator++();
iterator
operator++(int);
iterator &
operator--();
iterator
operator--(int);
bool
operator==(iterator const &b) const;
bool
operator!=(iterator const &b) const;
private:
subrange<isMutable> const *parent_;
iter_type it_;
};
//------------------------------------------------------------------------------
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
end_impl() const ->
iter_type
{
return out_ == end_ ? end_ : std::next(out_);
}
template<class MutableBufferSequence>
buffers_adaptor<MutableBufferSequence>::
buffers_adaptor(
buffers_adaptor const& other,
std::size_t nbegin,
std::size_t nout,
std::size_t nend)
: bs_(other.bs_)
, begin_(std::next(net::buffer_sequence_begin(bs_), nbegin))
, out_(std::next(net::buffer_sequence_begin(bs_), nout))
, end_(std::next(net::buffer_sequence_begin(bs_), nend))
, max_size_(other.max_size_)
, in_pos_(other.in_pos_)
, in_size_(other.in_size_)
, out_pos_(other.out_pos_)
, out_end_(other.out_end_)
{
}
template<class MutableBufferSequence>
buffers_adaptor<MutableBufferSequence>::
buffers_adaptor(MutableBufferSequence const& bs)
: bs_(bs)
, begin_(net::buffer_sequence_begin(bs_))
, out_ (net::buffer_sequence_begin(bs_))
, end_ (net::buffer_sequence_begin(bs_))
, max_size_(
[&bs]
{
return buffer_bytes(bs);
}())
{
}
template<class MutableBufferSequence>
template<class... Args>
buffers_adaptor<MutableBufferSequence>::
buffers_adaptor(
boost::in_place_init_t, Args&&... args)
: bs_{std::forward<Args>(args)...}
, begin_(net::buffer_sequence_begin(bs_))
, out_ (net::buffer_sequence_begin(bs_))
, end_ (net::buffer_sequence_begin(bs_))
, max_size_(
[&]
{
return buffer_bytes(bs_);
}())
{
}
template<class MutableBufferSequence>
buffers_adaptor<MutableBufferSequence>::
buffers_adaptor(buffers_adaptor const& other)
: buffers_adaptor(
other,
std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.begin_),
std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.out_),
std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.end_))
{
}
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
operator=(buffers_adaptor const& other) ->
buffers_adaptor&
{
if(this == &other)
return *this;
auto const nbegin = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.begin_);
auto const nout = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.out_);
auto const nend = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.end_);
bs_ = other.bs_;
begin_ = std::next(
net::buffer_sequence_begin(bs_), nbegin);
out_ = std::next(
net::buffer_sequence_begin(bs_), nout);
end_ = std::next(
net::buffer_sequence_begin(bs_), nend);
max_size_ = other.max_size_;
in_pos_ = other.in_pos_;
in_size_ = other.in_size_;
out_pos_ = other.out_pos_;
out_end_ = other.out_end_;
return *this;
}
//
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
data() const noexcept ->
const_buffers_type
{
return const_buffers_type(
begin_, end_,
in_pos_, in_size_);
}
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
data() noexcept ->
mutable_buffers_type
{
return mutable_buffers_type(
begin_, end_,
in_pos_, in_size_);
}
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
prepare(std::size_t n) ->
mutable_buffers_type
{
auto prepared = n;
end_ = out_;
if(end_ != net::buffer_sequence_end(bs_))
{
auto size = buffer_bytes(*end_) - out_pos_;
if(n > size)
{
n -= size;
while(++end_ !=
net::buffer_sequence_end(bs_))
{
size = buffer_bytes(*end_);
if(n < size)
{
out_end_ = n;
n = 0;
++end_;
break;
}
n -= size;
out_end_ = size;
}
}
else
{
++end_;
out_end_ = out_pos_ + n;
n = 0;
}
}
if(n > 0)
BOOST_THROW_EXCEPTION(std::length_error{
"buffers_adaptor too long"});
return mutable_buffers_type(out_, end_, out_pos_, prepared);
}
template<class MutableBufferSequence>
void
buffers_adaptor<MutableBufferSequence>::
commit(std::size_t n) noexcept
{
if(out_ == end_)
return;
auto const last = std::prev(end_);
while(out_ != last)
{
auto const avail =
buffer_bytes(*out_) - out_pos_;
if(n < avail)
{
out_pos_ += n;
in_size_ += n;
return;
}
++out_;
n -= avail;
out_pos_ = 0;
in_size_ += avail;
}
n = std::min<std::size_t>(
n, out_end_ - out_pos_);
out_pos_ += n;
in_size_ += n;
if(out_pos_ == buffer_bytes(*out_))
{
++out_;
out_pos_ = 0;
out_end_ = 0;
}
}
template<class MutableBufferSequence>
void
buffers_adaptor<MutableBufferSequence>::
consume(std::size_t n) noexcept
{
while(begin_ != out_)
{
auto const avail =
buffer_bytes(*begin_) - in_pos_;
if(n < avail)
{
in_size_ -= n;
in_pos_ += n;
return;
}
n -= avail;
in_size_ -= avail;
in_pos_ = 0;
++begin_;
}
auto const avail = out_pos_ - in_pos_;
if(n < avail)
{
in_size_ -= n;
in_pos_ += n;
}
else
{
in_size_ -= avail;
in_pos_ = out_pos_;
}
}
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
make_subrange(std::size_t pos, std::size_t n) ->
subrange<true>
{
return subrange<true>(
begin_, net::buffer_sequence_end(bs_),
in_pos_ + pos, n);
}
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
make_subrange(std::size_t pos, std::size_t n) const ->
subrange<false>
{
return subrange<false>(
begin_, net::buffer_sequence_end(bs_),
in_pos_ + pos, n);
}
// -------------------------------------------------------------------------
// subrange
template<class MutableBufferSequence>
template<bool isMutable>
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
subrange(
iter_type first, // iterator to first buffer in storage
iter_type last, // iterator to last buffer in storage
std::size_t pos, // the offset in bytes from the beginning of the storage
std::size_t n) // the total length of the subrange
: first_(first)
, last_(last)
, first_offset_(0)
, last_size_((std::numeric_limits<std::size_t>::max)())
{
adjust(pos, n);
}
template<class MutableBufferSequence>
template<bool isMutable>
void
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
adjust(
std::size_t pos,
std::size_t n)
{
if (n == 0)
last_ = first_;
if (first_ == last_)
{
first_offset_ = 0;
last_size_ = 0;
return;
}
auto is_last = [this](iter_type iter) {
return std::next(iter) == last_;
};
pos += first_offset_;
while (pos)
{
auto adjust = (std::min)(pos, first_->size());
if (adjust >= first_->size())
{
++first_;
first_offset_ = 0;
pos -= adjust;
}
else
{
first_offset_ = adjust;
pos = 0;
break;
}
}
auto current = first_;
auto max_elem = current->size() - first_offset_;
if (is_last(current))
{
// both first and last element
last_size_ = (std::min)(max_elem, n);
last_ = std::next(current);
return;
}
else if (max_elem >= n)
{
last_ = std::next(current);
last_size_ = n;
}
else
{
n -= max_elem;
++current;
}
for (;;)
{
max_elem = current->size();
if (is_last(current))
{
last_size_ = (std::min)(n, last_size_);
return;
}
else if (max_elem < n)
{
n -= max_elem;
++current;
}
else
{
last_size_ = n;
last_ = std::next(current);
return;
}
}
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
begin() const ->
iterator
{
return iterator(this, first_);
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
end() const ->
iterator
{
return iterator(this, last_);
}
// -------------------------------------------------------------------------
// buffers_adaptor::subrange::iterator
template<class MutableBufferSequence>
template<bool isMutable>
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
iterator()
: parent_(nullptr)
, it_()
{
}
template<class MutableBufferSequence>
template<bool isMutable>
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
iterator(subrange<isMutable> const *parent,
iter_type it)
: parent_(parent)
, it_(it)
{
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
operator*() const ->
value_type
{
value_type result = *it_;
if (it_ == parent_->first_)
result += parent_->first_offset_;
if (std::next(it_) == parent_->last_)
{
result = value_type(
result.data(),
(std::min)(
parent_->last_size_,
result.size()));
}
return result;
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
operator++() ->
iterator &
{
++it_;
return *this;
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
operator++(int) ->
iterator
{
auto result = *this;
++it_;
return result;
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
operator--() ->
iterator &
{
--it_;
return *this;
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
operator--(int) ->
iterator
{
auto result = *this;
--it_;
return result;
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
operator==(iterator const &b) const ->
bool
{
return it_ == b.it_;
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
operator!=(iterator const &b) const ->
bool
{
return !(*this == b);
}
} // beast
} // boost
#endif
+458
View File
@@ -0,0 +1,458 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_BUFFERS_CAT_HPP
#define BOOST_BEAST_IMPL_BUFFERS_CAT_HPP
#include <boost/beast/core/detail/tuple.hpp>
#include <boost/beast/core/detail/variant.hpp>
#include <boost/asio/buffer.hpp>
#include <cstdint>
#include <iterator>
#include <new>
#include <stdexcept>
#include <utility>
namespace boost {
namespace beast {
template<class Buffer>
class buffers_cat_view<Buffer>
{
Buffer buffer_;
public:
using value_type = buffers_type<Buffer>;
using const_iterator = buffers_iterator_type<Buffer>;
explicit
buffers_cat_view(Buffer const& buffer)
: buffer_(buffer)
{
}
const_iterator
begin() const
{
return net::buffer_sequence_begin(buffer_);
}
const_iterator
end() const
{
return net::buffer_sequence_end(buffer_);
}
};
#if defined(_MSC_VER) && ! defined(__clang__)
# define BOOST_BEAST_UNREACHABLE() __assume(false)
# define BOOST_BEAST_UNREACHABLE_RETURN(v) return v
#else
# define BOOST_BEAST_UNREACHABLE() __builtin_unreachable()
# define BOOST_BEAST_UNREACHABLE_RETURN(v) \
do { __builtin_unreachable(); return v; } while(false)
#endif
#ifdef BOOST_BEAST_TESTS
#define BOOST_BEAST_LOGIC_ERROR(s) \
{ \
BOOST_THROW_EXCEPTION(std::logic_error((s))); \
BOOST_BEAST_UNREACHABLE(); \
}
#else
#define BOOST_BEAST_LOGIC_ERROR(s) \
{ \
BOOST_ASSERT_MSG(false, s); \
BOOST_BEAST_UNREACHABLE(); \
}
#endif
namespace detail {
struct buffers_cat_view_iterator_base
{
struct past_end
{
char unused = 0; // make g++8 happy
BOOST_NORETURN net::mutable_buffer
operator*() const
{
BOOST_BEAST_LOGIC_ERROR(
"Dereferencing a one-past-the-end iterator");
}
operator bool() const noexcept
{
return true;
}
};
};
} // detail
template<class... Bn>
class buffers_cat_view<Bn...>::const_iterator
: private detail::buffers_cat_view_iterator_base
{
// VFALCO The logic to skip empty sequences fails
// if there is just one buffer in the list.
static_assert(sizeof...(Bn) >= 2,
"A minimum of two sequences are required");
detail::tuple<Bn...> const* bn_ = nullptr;
detail::variant<
buffers_iterator_type<Bn>..., past_end> it_{};
friend class buffers_cat_view<Bn...>;
template<std::size_t I>
using C = std::integral_constant<std::size_t, I>;
public:
using value_type = typename
buffers_cat_view<Bn...>::value_type;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(
const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const;
bool
operator!=(const_iterator const& other) const
{
return ! (*this == other);
}
reference
operator*() const;
pointer
operator->() const = delete;
const_iterator&
operator++();
const_iterator
operator++(int);
const_iterator&
operator--();
const_iterator
operator--(int);
private:
const_iterator(
detail::tuple<Bn...> const& bn,
std::true_type);
const_iterator(
detail::tuple<Bn...> const& bn,
std::false_type);
struct dereference
{
const_iterator const& self;
BOOST_NORETURN reference
operator()(mp11::mp_size_t<0>)
{
BOOST_BEAST_LOGIC_ERROR(
"Dereferencing a default-constructed iterator");
}
template<class I>
reference operator()(I)
{
return *self.it_.template get<I::value>();
}
};
struct increment
{
const_iterator& self;
void
operator()(mp11::mp_size_t<0>)
{
BOOST_BEAST_LOGIC_ERROR(
"Incrementing a default-constructed iterator");
}
template<std::size_t I>
void
operator()(mp11::mp_size_t<I>)
{
++self.it_.template get<I>();
next(mp11::mp_size_t<I>{});
}
template<std::size_t I>
void
next(mp11::mp_size_t<I>)
{
auto& it = self.it_.template get<I>();
for(;;)
{
if (it == net::buffer_sequence_end(
detail::get<I-1>(*self.bn_)))
break;
if(net::const_buffer(*it).size() > 0)
return;
++it;
}
self.it_.template emplace<I+1>(
net::buffer_sequence_begin(
detail::get<I>(*self.bn_)));
next(mp11::mp_size_t<I+1>{});
}
void
operator()(mp11::mp_size_t<sizeof...(Bn)>)
{
auto constexpr I = sizeof...(Bn);
++self.it_.template get<I>();
next(mp11::mp_size_t<I>{});
}
void
next(mp11::mp_size_t<sizeof...(Bn)>)
{
auto constexpr I = sizeof...(Bn);
auto& it = self.it_.template get<I>();
for(;;)
{
if (it == net::buffer_sequence_end(
detail::get<I-1>(*self.bn_)))
break;
if(net::const_buffer(*it).size() > 0)
return;
++it;
}
// end
self.it_.template emplace<I+1>();
}
void
operator()(mp11::mp_size_t<sizeof...(Bn)+1>)
{
BOOST_BEAST_LOGIC_ERROR(
"Incrementing a one-past-the-end iterator");
}
};
struct decrement
{
const_iterator& self;
void
operator()(mp11::mp_size_t<0>)
{
BOOST_BEAST_LOGIC_ERROR(
"Decrementing a default-constructed iterator");
}
void
operator()(mp11::mp_size_t<1>)
{
auto constexpr I = 1;
auto& it = self.it_.template get<I>();
for(;;)
{
if(it == net::buffer_sequence_begin(
detail::get<I-1>(*self.bn_)))
{
BOOST_BEAST_LOGIC_ERROR(
"Decrementing an iterator to the beginning");
}
--it;
if(net::const_buffer(*it).size() > 0)
return;
}
}
template<std::size_t I>
void
operator()(mp11::mp_size_t<I>)
{
auto& it = self.it_.template get<I>();
for(;;)
{
if(it == net::buffer_sequence_begin(
detail::get<I-1>(*self.bn_)))
break;
--it;
if(net::const_buffer(*it).size() > 0)
return;
}
self.it_.template emplace<I-1>(
net::buffer_sequence_end(
detail::get<I-2>(*self.bn_)));
(*this)(mp11::mp_size_t<I-1>{});
}
void
operator()(mp11::mp_size_t<sizeof...(Bn)+1>)
{
auto constexpr I = sizeof...(Bn)+1;
self.it_.template emplace<I-1>(
net::buffer_sequence_end(
detail::get<I-2>(*self.bn_)));
(*this)(mp11::mp_size_t<I-1>{});
}
};
};
//------------------------------------------------------------------------------
template<class... Bn>
buffers_cat_view<Bn...>::
const_iterator::
const_iterator(
detail::tuple<Bn...> const& bn,
std::true_type)
: bn_(&bn)
{
// one past the end
it_.template emplace<sizeof...(Bn)+1>();
}
template<class... Bn>
buffers_cat_view<Bn...>::
const_iterator::
const_iterator(
detail::tuple<Bn...> const& bn,
std::false_type)
: bn_(&bn)
{
it_.template emplace<1>(
net::buffer_sequence_begin(
detail::get<0>(*bn_)));
increment{*this}.next(
mp11::mp_size_t<1>{});
}
template<class... Bn>
bool
buffers_cat_view<Bn...>::
const_iterator::
operator==(const_iterator const& other) const
{
return bn_ == other.bn_ && it_ == other.it_;
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator*() const ->
reference
{
return mp11::mp_with_index<
sizeof...(Bn) + 2>(
it_.index(),
dereference{*this});
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator++() ->
const_iterator&
{
mp11::mp_with_index<
sizeof...(Bn) + 2>(
it_.index(),
increment{*this});
return *this;
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator++(int) ->
const_iterator
{
auto temp = *this;
++(*this);
return temp;
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator--() ->
const_iterator&
{
mp11::mp_with_index<
sizeof...(Bn) + 2>(
it_.index(),
decrement{*this});
return *this;
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator--(int) ->
const_iterator
{
auto temp = *this;
--(*this);
return temp;
}
//------------------------------------------------------------------------------
template<class... Bn>
buffers_cat_view<Bn...>::
buffers_cat_view(Bn const&... bn)
: bn_(bn...)
{
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::begin() const ->
const_iterator
{
return const_iterator{bn_, std::false_type{}};
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::end() const->
const_iterator
{
return const_iterator{bn_, std::true_type{}};
}
} // beast
} // boost
#endif
+173
View File
@@ -0,0 +1,173 @@
//
// Copyright (c) 2022 Seth Heeren (sgheeren at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_BUFFERS_GENERATOR_HPP
#define BOOST_BEAST_CORE_IMPL_BUFFERS_GENERATOR_HPP
#include <boost/beast/core/buffers_generator.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/compose.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/throw_exception.hpp>
#include <type_traits>
namespace boost {
namespace beast {
namespace detail {
template <
class AsyncWriteStream,
class BuffersGenerator>
struct write_buffers_generator_op
: boost::asio::coroutine
{
write_buffers_generator_op(
AsyncWriteStream& s, BuffersGenerator g)
: s_(s)
, g_(std::move(g))
{
}
template<class Self>
void operator()(
Self& self, error_code ec = {}, std::size_t n = 0)
{
BOOST_ASIO_CORO_REENTER(*this)
{
while(! g_.is_done())
{
BOOST_ASIO_CORO_YIELD
{
auto cb = g_.prepare(ec);
if(ec)
goto complete;
s_.async_write_some(
cb, std::move(self));
}
if(ec)
goto complete;
g_.consume(n);
total_ += n;
}
complete:
self.complete(ec, total_);
}
}
private:
AsyncWriteStream& s_;
BuffersGenerator g_;
std::size_t total_ = 0;
};
} // detail
template<
class SyncWriteStream,
class BuffersGenerator,
typename std::enable_if< //
is_buffers_generator<typename std::decay<
BuffersGenerator>::type>::value>::type* /*= nullptr*/
>
size_t
write(
SyncWriteStream& stream,
BuffersGenerator&& generator,
beast::error_code& ec)
{
static_assert(
is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream type requirements not met");
ec.clear();
size_t total = 0;
while(! generator.is_done())
{
auto cb = generator.prepare(ec);
if(ec)
break;
size_t n = net::write(stream, cb, ec);
if(ec)
break;
generator.consume(n);
total += n;
}
return total;
}
//----------------------------------------------------------
template<
class SyncWriteStream,
class BuffersGenerator,
typename std::enable_if<is_buffers_generator<
typename std::decay<BuffersGenerator>::type>::value>::
type* /*= nullptr*/
>
std::size_t
write(SyncWriteStream& stream, BuffersGenerator&& generator)
{
static_assert(
is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream type requirements not met");
beast::error_code ec;
std::size_t n = write(
stream, std::forward<BuffersGenerator>(generator), ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ ec });
return n;
}
//----------------------------------------------------------
template<
class AsyncWriteStream,
class BuffersGenerator,
BOOST_BEAST_ASYNC_TPARAM2 CompletionToken,
typename std::enable_if<is_buffers_generator<
BuffersGenerator>::value>::type* /*= nullptr*/
>
BOOST_BEAST_ASYNC_RESULT2(CompletionToken)
async_write(
AsyncWriteStream& stream,
BuffersGenerator generator,
CompletionToken&& token)
{
static_assert(
beast::is_async_write_stream<AsyncWriteStream>::value,
"AsyncWriteStream type requirements not met");
return net::async_compose< //
CompletionToken,
void(error_code, std::size_t)>(
detail::write_buffers_generator_op<
AsyncWriteStream,
BuffersGenerator>{ stream, std::move(generator) },
token,
stream);
}
} // namespace beast
} // namespace boost
#endif
+326
View File
@@ -0,0 +1,326 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_BUFFERS_PREFIX_HPP
#define BOOST_BEAST_IMPL_BUFFERS_PREFIX_HPP
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/config/workaround.hpp>
#include <algorithm>
#include <cstdint>
#include <iterator>
#include <stdexcept>
#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
template<class Buffers>
class buffers_prefix_view<Buffers>::const_iterator
{
friend class buffers_prefix_view<Buffers>;
buffers_prefix_view const* b_ = nullptr;
std::size_t remain_ = 0;
iter_type it_{};
public:
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
using value_type = typename std::conditional<
boost::is_convertible<typename
std::iterator_traits<iter_type>::value_type,
net::mutable_buffer>::value,
net::mutable_buffer,
net::const_buffer>::type;
#else
using value_type = buffers_type<Buffers>;
#endif
BOOST_STATIC_ASSERT(std::is_same<
typename const_iterator::value_type,
typename buffers_prefix_view::value_type>::value);
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(
const_iterator const& other) = default;
const_iterator& operator=(
const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return b_ == other.b_ && it_ == other.it_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
value_type v(*it_);
if(remain_ < v.size())
return {v.data(), remain_};
return v;
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
value_type const v = *it_++;
remain_ -= v.size();
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
value_type const v = *it_++;
remain_ -= v.size();
return temp;
}
const_iterator&
operator--()
{
value_type const v = *--it_;
remain_ += v.size();
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
value_type const v = *--it_;
remain_ += v.size();
return temp;
}
private:
const_iterator(
buffers_prefix_view const& b,
std::true_type)
: b_(&b)
, remain_(b.remain_)
, it_(b_->end_)
{
}
const_iterator(
buffers_prefix_view const& b,
std::false_type)
: b_(&b)
, remain_(b_->size_)
, it_(net::buffer_sequence_begin(b_->bs_))
{
}
};
//------------------------------------------------------------------------------
template<class Buffers>
void
buffers_prefix_view<Buffers>::
setup(std::size_t size)
{
size_ = 0;
remain_ = 0;
end_ = net::buffer_sequence_begin(bs_);
auto const last = bs_.end();
while(end_ != last)
{
auto const len = buffer_bytes(*end_++);
if(len >= size)
{
size_ += size;
// by design, this subtraction can wrap
BOOST_STATIC_ASSERT(std::is_unsigned<
decltype(remain_)>::value);
remain_ = size - len;
break;
}
size -= len;
size_ += len;
}
}
template<class Buffers>
buffers_prefix_view<Buffers>::
buffers_prefix_view(
buffers_prefix_view const& other,
std::size_t dist)
: bs_(other.bs_)
, size_(other.size_)
, remain_(other.remain_)
, end_(std::next(bs_.begin(), dist))
{
}
template<class Buffers>
buffers_prefix_view<Buffers>::
buffers_prefix_view(buffers_prefix_view const& other)
: buffers_prefix_view(other,
std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.end_))
{
}
template<class Buffers>
auto
buffers_prefix_view<Buffers>::
operator=(buffers_prefix_view const& other) ->
buffers_prefix_view&
{
auto const dist = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.end_);
bs_ = other.bs_;
size_ = other.size_;
remain_ = other.remain_;
end_ = std::next(
net::buffer_sequence_begin(bs_),
dist);
return *this;
}
template<class Buffers>
buffers_prefix_view<Buffers>::
buffers_prefix_view(
std::size_t size,
Buffers const& bs)
: bs_(bs)
{
setup(size);
}
template<class Buffers>
template<class... Args>
buffers_prefix_view<Buffers>::
buffers_prefix_view(
std::size_t size,
boost::in_place_init_t,
Args&&... args)
: bs_(std::forward<Args>(args)...)
{
setup(size);
}
template<class Buffers>
auto
buffers_prefix_view<Buffers>::
begin() const ->
const_iterator
{
return const_iterator{
*this, std::false_type{}};
}
template<class Buffers>
auto
buffers_prefix_view<Buffers>::
end() const ->
const_iterator
{
return const_iterator{
*this, std::true_type{}};
}
//------------------------------------------------------------------------------
template<>
class buffers_prefix_view<net::const_buffer>
: public net::const_buffer
{
public:
using net::const_buffer::const_buffer;
buffers_prefix_view(buffers_prefix_view const&) = default;
buffers_prefix_view& operator=(buffers_prefix_view const&) = default;
buffers_prefix_view(
std::size_t size,
net::const_buffer buffer)
: net::const_buffer(
buffer.data(),
std::min<std::size_t>(size, buffer.size())
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
, buffer.get_debug_check()
#endif
)
{
}
template<class... Args>
buffers_prefix_view(
std::size_t size,
boost::in_place_init_t,
Args&&... args)
: buffers_prefix_view(size,
net::const_buffer(
std::forward<Args>(args)...))
{
}
};
//------------------------------------------------------------------------------
template<>
class buffers_prefix_view<net::mutable_buffer>
: public net::mutable_buffer
{
public:
using net::mutable_buffer::mutable_buffer;
buffers_prefix_view(buffers_prefix_view const&) = default;
buffers_prefix_view& operator=(buffers_prefix_view const&) = default;
buffers_prefix_view(
std::size_t size,
net::mutable_buffer buffer)
: net::mutable_buffer(
buffer.data(),
std::min<std::size_t>(size, buffer.size())
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
, buffer.get_debug_check()
#endif
)
{
}
template<class... Args>
buffers_prefix_view(
std::size_t size,
boost::in_place_init_t,
Args&&... args)
: buffers_prefix_view(size,
net::mutable_buffer(
std::forward<Args>(args)...))
{
}
};
} // beast
} // boost
#endif
+225
View File
@@ -0,0 +1,225 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_BUFFERS_SUFFIX_HPP
#define BOOST_BEAST_IMPL_BUFFERS_SUFFIX_HPP
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/type_traits.hpp>
#include <algorithm>
#include <cstdint>
#include <iterator>
#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
template<class Buffers>
class buffers_suffix<Buffers>::const_iterator
{
friend class buffers_suffix<Buffers>;
using iter_type = buffers_iterator_type<Buffers>;
iter_type it_{};
buffers_suffix const* b_ = nullptr;
public:
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
using value_type = typename std::conditional<
boost::is_convertible<typename
std::iterator_traits<iter_type>::value_type,
net::mutable_buffer>::value,
net::mutable_buffer,
net::const_buffer>::type;
#else
using value_type = buffers_type<Buffers>;
#endif
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(
const_iterator const& other) = default;
const_iterator& operator=(
const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return b_ == other.b_ && it_ == other.it_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
if(it_ == b_->begin_)
return value_type(*it_) + b_->skip_;
return value_type(*it_);
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
++it_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
--it_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
const_iterator(
buffers_suffix const& b,
iter_type it)
: it_(it)
, b_(&b)
{
}
};
//------------------------------------------------------------------------------
template<class Buffers>
buffers_suffix<Buffers>::
buffers_suffix()
: begin_(net::buffer_sequence_begin(bs_))
{
}
template<class Buffers>
buffers_suffix<Buffers>::
buffers_suffix(buffers_suffix const& other)
: buffers_suffix(other,
std::distance<iter_type>(
net::buffer_sequence_begin(
other.bs_), other.begin_))
{
}
template<class Buffers>
buffers_suffix<Buffers>::
buffers_suffix(Buffers const& bs)
: bs_(bs)
, begin_(net::buffer_sequence_begin(bs_))
{
static_assert(
net::is_const_buffer_sequence<Buffers>::value ||
net::is_mutable_buffer_sequence<Buffers>::value,
"BufferSequence type requirements not met");
}
template<class Buffers>
template<class... Args>
buffers_suffix<Buffers>::
buffers_suffix(boost::in_place_init_t, Args&&... args)
: bs_(std::forward<Args>(args)...)
, begin_(net::buffer_sequence_begin(bs_))
{
static_assert(sizeof...(Args) > 0,
"Missing constructor arguments");
static_assert(
std::is_constructible<Buffers, Args...>::value,
"Buffers not constructible from arguments");
}
template<class Buffers>
auto
buffers_suffix<Buffers>::
operator=(buffers_suffix const& other) ->
buffers_suffix&
{
auto const dist = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.begin_);
bs_ = other.bs_;
begin_ = std::next(
net::buffer_sequence_begin(bs_), dist);
skip_ = other.skip_;
return *this;
}
template<class Buffers>
auto
buffers_suffix<Buffers>::
begin() const ->
const_iterator
{
return const_iterator{*this, begin_};
}
template<class Buffers>
auto
buffers_suffix<Buffers>::
end() const ->
const_iterator
{
return const_iterator{*this,
net::buffer_sequence_end(bs_)};
}
template<class Buffers>
void
buffers_suffix<Buffers>::
consume(std::size_t amount)
{
auto const end =
net::buffer_sequence_end(bs_);
for(;amount > 0 && begin_ != end; ++begin_)
{
auto const len =
buffer_bytes(*begin_) - skip_;
if(amount < len)
{
skip_ += amount;
break;
}
amount -= len;
skip_ = 0;
}
}
} // beast
} // boost
#endif
+44
View File
@@ -0,0 +1,44 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_ERROR_HPP
#define BOOST_BEAST_IMPL_ERROR_HPP
#include <type_traits>
namespace boost {
namespace system {
template<>
struct is_error_code_enum<::boost::beast::error>
{
static bool const value = true;
};
template<>
struct is_error_condition_enum<::boost::beast::condition>
{
static bool const value = true;
};
} // system
} // boost
namespace boost {
namespace beast {
BOOST_BEAST_DECL
error_code
make_error_code(error e);
BOOST_BEAST_DECL
error_condition
make_error_condition(condition c);
} // beast
} // boost
#endif
+105
View File
@@ -0,0 +1,105 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_ERROR_IPP
#define BOOST_BEAST_IMPL_ERROR_IPP
#include <boost/beast/core/error.hpp>
namespace boost {
namespace beast {
namespace detail {
class error_codes : public error_category
{
public:
const char*
name() const noexcept override
{
return "boost.beast";
}
error_codes() : error_category(0x002f6e94401c6e8bu) {}
BOOST_BEAST_DECL
std::string
message(int ev) const override
{
switch(static_cast<error>(ev))
{
default:
case error::timeout: return
"The socket was closed due to a timeout";
}
}
BOOST_BEAST_DECL
error_condition
default_error_condition(int ev) const noexcept override
{
switch(static_cast<error>(ev))
{
default:
// return {ev, *this};
case error::timeout:
return condition::timeout;
}
}
};
class error_conditions : public error_category
{
public:
BOOST_BEAST_DECL
const char*
name() const noexcept override
{
return "boost.beast";
}
error_conditions() : error_category(0x3dd0b0ce843c5b10u) {}
BOOST_BEAST_DECL
std::string
message(int cv) const override
{
switch(static_cast<condition>(cv))
{
default:
case condition::timeout:
return "The operation timed out";
}
}
};
} // detail
error_code
make_error_code(error e)
{
static detail::error_codes const cat{};
return error_code{static_cast<
std::underlying_type<error>::type>(e), cat};
}
error_condition
make_error_condition(condition c)
{
static detail::error_conditions const cat{};
return error_condition{static_cast<
std::underlying_type<condition>::type>(c), cat};
}
} // beast
} // boost
#endif
+339
View File
@@ -0,0 +1,339 @@
//
// Copyright (c) 2015-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_FILE_POSIX_IPP
#define BOOST_BEAST_CORE_IMPL_FILE_POSIX_IPP
#include <boost/beast/core/file_posix.hpp>
#if BOOST_BEAST_USE_POSIX_FILE
#include <boost/core/exchange.hpp>
#include <limits>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#if ! defined(BOOST_BEAST_NO_POSIX_FADVISE)
# if defined(__APPLE__) || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
# define BOOST_BEAST_NO_POSIX_FADVISE
# endif
#endif
#if ! defined(BOOST_BEAST_USE_POSIX_FADVISE)
# if ! defined(BOOST_BEAST_NO_POSIX_FADVISE)
# define BOOST_BEAST_USE_POSIX_FADVISE 1
# else
# define BOOST_BEAST_USE_POSIX_FADVISE 0
# endif
#endif
namespace boost {
namespace beast {
int
file_posix::
native_close(native_handle_type& fd)
{
/* https://github.com/boostorg/beast/issues/1445
This function is tuned for Linux / Mac OS:
* only calls close() once
* returns the error directly to the caller
* does not loop on EINTR
If this is incorrect for the platform, then the
caller will need to implement their own type
meeting the File requirements and use the correct
behavior.
See:
http://man7.org/linux/man-pages/man2/close.2.html
*/
int ev = 0;
if(fd != -1)
{
if(::close(fd) != 0)
ev = errno;
fd = -1;
}
return ev;
}
file_posix::
~file_posix()
{
native_close(fd_);
}
file_posix::
file_posix(file_posix&& other)
: fd_(boost::exchange(other.fd_, -1))
{
}
file_posix&
file_posix::
operator=(file_posix&& other)
{
if(&other == this)
return *this;
native_close(fd_);
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
void
file_posix::
native_handle(native_handle_type fd)
{
native_close(fd_);
fd_ = fd;
}
void
file_posix::
close(error_code& ec)
{
auto const ev = native_close(fd_);
if(ev)
ec.assign(ev, system_category());
else
ec = {};
}
void
file_posix::
open(char const* path, file_mode mode, error_code& ec)
{
auto const ev = native_close(fd_);
if(ev)
ec.assign(ev, system_category());
else
ec = {};
int f = 0;
#if BOOST_BEAST_USE_POSIX_FADVISE
int advise = 0;
#endif
switch(mode)
{
default:
case file_mode::read:
f = O_RDONLY;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_RANDOM;
#endif
break;
case file_mode::scan:
f = O_RDONLY;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_SEQUENTIAL;
#endif
break;
case file_mode::write:
f = O_RDWR | O_CREAT | O_TRUNC;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_RANDOM;
#endif
break;
case file_mode::write_new:
f = O_RDWR | O_CREAT | O_EXCL;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_RANDOM;
#endif
break;
case file_mode::write_existing:
f = O_RDWR | O_EXCL;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_RANDOM;
#endif
break;
case file_mode::append:
f = O_WRONLY | O_CREAT | O_APPEND;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_SEQUENTIAL;
#endif
break;
case file_mode::append_existing:
f = O_WRONLY | O_APPEND;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_SEQUENTIAL;
#endif
break;
}
for(;;)
{
fd_ = ::open(path, f, 0644);
if(fd_ != -1)
break;
auto const ev = errno;
if(ev != EINTR)
{
ec.assign(ev, system_category());
return;
}
}
#if BOOST_BEAST_USE_POSIX_FADVISE
if(::posix_fadvise(fd_, 0, 0, advise))
{
auto const ev = errno;
native_close(fd_);
ec.assign(ev, system_category());
return;
}
#endif
ec = {};
}
std::uint64_t
file_posix::
size(error_code& ec) const
{
if(fd_ == -1)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
struct stat st;
if(::fstat(fd_, &st) != 0)
{
ec.assign(errno, system_category());
return 0;
}
ec = {};
return st.st_size;
}
std::uint64_t
file_posix::
pos(error_code& ec) const
{
if(fd_ == -1)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
auto const result = ::lseek(fd_, 0, SEEK_CUR);
if(result == (off_t)-1)
{
ec.assign(errno, system_category());
return 0;
}
ec = {};
return result;
}
void
file_posix::
seek(std::uint64_t offset, error_code& ec)
{
if(fd_ == -1)
{
ec = make_error_code(errc::bad_file_descriptor);
return;
}
auto const result = ::lseek(fd_, offset, SEEK_SET);
if(result == static_cast<off_t>(-1))
{
ec.assign(errno, system_category());
return;
}
ec = {};
}
std::size_t
file_posix::
read(void* buffer, std::size_t n, error_code& ec) const
{
if(fd_ == -1)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
std::size_t nread = 0;
while(n > 0)
{
// <limits> not required to define SSIZE_MAX so we avoid it
constexpr auto ssmax =
static_cast<std::size_t>((std::numeric_limits<
decltype(::read(fd_, buffer, n))>::max)());
auto const amount = (std::min)(
n, ssmax);
auto const result = ::read(fd_, buffer, amount);
if(result == -1)
{
auto const ev = errno;
if(ev == EINTR)
continue;
ec.assign(ev, system_category());
return nread;
}
if(result == 0)
{
// short read
return nread;
}
n -= result;
nread += result;
buffer = static_cast<char*>(buffer) + result;
}
return nread;
}
std::size_t
file_posix::
write(void const* buffer, std::size_t n, error_code& ec)
{
if(fd_ == -1)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
std::size_t nwritten = 0;
while(n > 0)
{
// <limits> not required to define SSIZE_MAX so we avoid it
constexpr auto ssmax =
static_cast<std::size_t>((std::numeric_limits<
decltype(::write(fd_, buffer, n))>::max)());
auto const amount = (std::min)(
n, ssmax);
auto const result = ::write(fd_, buffer, amount);
if(result == -1)
{
auto const ev = errno;
if(ev == EINTR)
continue;
ec.assign(ev, system_category());
return nwritten;
}
n -= result;
nwritten += result;
buffer = static_cast<char const*>(buffer) + result;
}
return nwritten;
}
} // beast
} // boost
#endif
#endif
+327
View File
@@ -0,0 +1,327 @@
//
// Copyright (c) 2015-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_FILE_STDIO_IPP
#define BOOST_BEAST_CORE_IMPL_FILE_STDIO_IPP
#include <boost/beast/core/file_stdio.hpp>
#include <boost/beast/core/detail/win32_unicode_path.hpp>
#include <boost/config/workaround.hpp>
#include <boost/core/exchange.hpp>
#include <limits>
namespace boost {
namespace beast {
file_stdio::
~file_stdio()
{
if(f_)
fclose(f_);
}
file_stdio::
file_stdio(file_stdio&& other)
: f_(boost::exchange(other.f_, nullptr))
{
}
file_stdio&
file_stdio::
operator=(file_stdio&& other)
{
if(&other == this)
return *this;
if(f_)
fclose(f_);
f_ = other.f_;
other.f_ = nullptr;
return *this;
}
void
file_stdio::
native_handle(std::FILE* f)
{
if(f_)
fclose(f_);
f_ = f;
}
void
file_stdio::
close(error_code& ec)
{
if(f_)
{
int failed = fclose(f_);
f_ = nullptr;
if(failed)
{
ec.assign(errno, generic_category());
return;
}
}
ec = {};
}
void
file_stdio::
open(char const* path, file_mode mode, error_code& ec)
{
if(f_)
{
fclose(f_);
f_ = nullptr;
}
ec = {};
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
boost::winapi::WCHAR_ const* s;
detail::win32_unicode_path unicode_path(path, ec);
if (ec)
return;
#else
char const* s;
#endif
switch(mode)
{
default:
case file_mode::read:
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
s = L"rb";
#else
s = "rb";
#endif
break;
case file_mode::scan:
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
s = L"rbS";
#else
s = "rb";
#endif
break;
case file_mode::write:
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
s = L"wb+";
#else
s = "wb+";
#endif
break;
case file_mode::write_new:
{
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
# if (defined(BOOST_MSVC) && BOOST_MSVC >= 1910) || (defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION >= 141)
s = L"wbx";
# else
std::FILE* f0;
auto const ev = ::_wfopen_s(&f0, unicode_path.c_str(), L"rb");
if(! ev)
{
std::fclose(f0);
ec = make_error_code(errc::file_exists);
return;
}
else if(ev !=
errc::no_such_file_or_directory)
{
ec.assign(ev, generic_category());
return;
}
s = L"wb";
# endif
#else
s = "wbx";
#endif
break;
}
case file_mode::write_existing:
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
s = L"rb+";
#else
s = "rb+";
#endif
break;
case file_mode::append:
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
s = L"ab";
#else
s = "ab";
#endif
break;
case file_mode::append_existing:
{
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
std::FILE* f0;
auto const ev =
::_wfopen_s(&f0, unicode_path.c_str(), L"rb+");
if(ev)
{
ec.assign(ev, generic_category());
return;
}
#else
auto const f0 =
std::fopen(path, "rb+");
if(! f0)
{
ec.assign(errno, generic_category());
return;
}
#endif
std::fclose(f0);
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
s = L"ab";
#else
s = "ab";
#endif
break;
}
}
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
auto const ev = ::_wfopen_s(&f_, unicode_path.c_str(), s);
if(ev)
{
f_ = nullptr;
ec.assign(ev, generic_category());
return;
}
#else
f_ = std::fopen(path, s);
if(! f_)
{
ec.assign(errno, generic_category());
return;
}
#endif
}
std::uint64_t
file_stdio::
size(error_code& ec) const
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
long pos = std::ftell(f_);
if(pos == -1L)
{
ec.assign(errno, generic_category());
return 0;
}
int result = std::fseek(f_, 0, SEEK_END);
if(result != 0)
{
ec.assign(errno, generic_category());
return 0;
}
long size = std::ftell(f_);
if(size == -1L)
{
ec.assign(errno, generic_category());
std::fseek(f_, pos, SEEK_SET);
return 0;
}
result = std::fseek(f_, pos, SEEK_SET);
if(result != 0)
ec.assign(errno, generic_category());
else
ec = {};
return size;
}
std::uint64_t
file_stdio::
pos(error_code& ec) const
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
long pos = std::ftell(f_);
if(pos == -1L)
{
ec.assign(errno, generic_category());
return 0;
}
ec = {};
return pos;
}
void
file_stdio::
seek(std::uint64_t offset, error_code& ec)
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return;
}
if(offset > static_cast<std::uint64_t>((std::numeric_limits<long>::max)()))
{
ec = make_error_code(errc::invalid_seek);
return;
}
int result = std::fseek(f_,
static_cast<long>(offset), SEEK_SET);
if(result != 0)
ec.assign(errno, generic_category());
else
ec = {};
}
std::size_t
file_stdio::
read(void* buffer, std::size_t n, error_code& ec) const
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
auto nread = std::fread(buffer, 1, n, f_);
if(std::ferror(f_))
{
ec.assign(errno, generic_category());
return 0;
}
return nread;
}
std::size_t
file_stdio::
write(void const* buffer, std::size_t n, error_code& ec)
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
auto nwritten = std::fwrite(buffer, 1, n, f_);
if(std::ferror(f_))
{
ec.assign(errno, generic_category());
return 0;
}
return nwritten;
}
} // beast
} // boost
#endif
+374
View File
@@ -0,0 +1,374 @@
//
// Copyright (c) 2015-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_FILE_WIN32_IPP
#define BOOST_BEAST_CORE_IMPL_FILE_WIN32_IPP
#include <boost/beast/core/file_win32.hpp>
#if BOOST_BEAST_USE_WIN32_FILE
#include <boost/beast/core/detail/win32_unicode_path.hpp>
#include <boost/core/exchange.hpp>
#include <boost/winapi/access_rights.hpp>
#include <boost/winapi/error_codes.hpp>
#include <boost/winapi/get_last_error.hpp>
#include <limits>
#include <utility>
namespace boost {
namespace beast {
namespace detail {
// VFALCO Can't seem to get boost/detail/winapi to work with
// this so use the non-Ex version for now.
BOOST_BEAST_DECL
boost::winapi::BOOL_
set_file_pointer_ex(
boost::winapi::HANDLE_ hFile,
boost::winapi::LARGE_INTEGER_ lpDistanceToMove,
boost::winapi::PLARGE_INTEGER_ lpNewFilePointer,
boost::winapi::DWORD_ dwMoveMethod)
{
auto dwHighPart = lpDistanceToMove.u.HighPart;
auto dwLowPart = boost::winapi::SetFilePointer(
hFile,
lpDistanceToMove.u.LowPart,
&dwHighPart,
dwMoveMethod);
if(dwLowPart == boost::winapi::INVALID_SET_FILE_POINTER_)
return 0;
if(lpNewFilePointer)
{
lpNewFilePointer->u.LowPart = dwLowPart;
lpNewFilePointer->u.HighPart = dwHighPart;
}
return 1;
}
} // detail
file_win32::
~file_win32()
{
if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
boost::winapi::CloseHandle(h_);
}
file_win32::
file_win32(file_win32&& other)
: h_(boost::exchange(other.h_,
boost::winapi::INVALID_HANDLE_VALUE_))
{
}
file_win32&
file_win32::
operator=(file_win32&& other)
{
if(&other == this)
return *this;
if(h_)
boost::winapi::CloseHandle(h_);
h_ = other.h_;
other.h_ = boost::winapi::INVALID_HANDLE_VALUE_;
return *this;
}
void
file_win32::
native_handle(native_handle_type h)
{
if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
boost::winapi::CloseHandle(h_);
h_ = h;
}
void
file_win32::
close(error_code& ec)
{
if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
{
if(! boost::winapi::CloseHandle(h_))
ec.assign(boost::winapi::GetLastError(),
system_category());
else
ec = {};
h_ = boost::winapi::INVALID_HANDLE_VALUE_;
}
else
{
ec = {};
}
}
void
file_win32::
open(char const* path, file_mode mode, error_code& ec)
{
if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
{
boost::winapi::CloseHandle(h_);
h_ = boost::winapi::INVALID_HANDLE_VALUE_;
}
boost::winapi::DWORD_ share_mode = 0;
boost::winapi::DWORD_ desired_access = 0;
boost::winapi::DWORD_ creation_disposition = 0;
boost::winapi::DWORD_ flags_and_attributes = 0;
/*
| When the file...
This argument: | Exists Does not exist
-------------------------+------------------------------------------------------
CREATE_ALWAYS | Truncates Creates
CREATE_NEW +-----------+ Fails Creates
OPEN_ALWAYS ===| does this |===> Opens Creates
OPEN_EXISTING +-----------+ Opens Fails
TRUNCATE_EXISTING | Truncates Fails
*/
switch(mode)
{
default:
case file_mode::read:
desired_access = boost::winapi::GENERIC_READ_;
share_mode = boost::winapi::FILE_SHARE_READ_;
creation_disposition = boost::winapi::OPEN_EXISTING_;
flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
break;
case file_mode::scan:
desired_access = boost::winapi::GENERIC_READ_;
share_mode = boost::winapi::FILE_SHARE_READ_;
creation_disposition = boost::winapi::OPEN_EXISTING_;
flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
break;
case file_mode::write:
desired_access = boost::winapi::GENERIC_READ_ |
boost::winapi::GENERIC_WRITE_;
creation_disposition = boost::winapi::CREATE_ALWAYS_;
flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
break;
case file_mode::write_new:
desired_access = boost::winapi::GENERIC_READ_ |
boost::winapi::GENERIC_WRITE_;
creation_disposition = boost::winapi::CREATE_NEW_;
flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
break;
case file_mode::write_existing:
desired_access = boost::winapi::GENERIC_READ_ |
boost::winapi::GENERIC_WRITE_;
creation_disposition = boost::winapi::OPEN_EXISTING_;
flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
break;
case file_mode::append:
desired_access = boost::winapi::GENERIC_READ_ |
boost::winapi::GENERIC_WRITE_;
creation_disposition = boost::winapi::OPEN_ALWAYS_;
flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
break;
case file_mode::append_existing:
desired_access = boost::winapi::GENERIC_READ_ |
boost::winapi::GENERIC_WRITE_;
creation_disposition = boost::winapi::OPEN_EXISTING_;
flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
break;
}
detail::win32_unicode_path unicode_path(path, ec);
if (ec)
return;
h_ = ::CreateFileW(
unicode_path.c_str(),
desired_access,
share_mode,
NULL,
creation_disposition,
flags_and_attributes,
NULL);
if (h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
ec.assign(boost::winapi::GetLastError(),
system_category());
return;
}
if (mode == file_mode::append ||
mode == file_mode::append_existing)
{
boost::winapi::LARGE_INTEGER_ in;
in.QuadPart = 0;
if (!detail::set_file_pointer_ex(h_, in, 0,
boost::winapi::FILE_END_))
{
ec.assign(boost::winapi::GetLastError(),
system_category());
boost::winapi::CloseHandle(h_);
h_ = boost::winapi::INVALID_HANDLE_VALUE_;
return;
}
}
ec = {};
}
std::uint64_t
file_win32::
size(error_code& ec) const
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
boost::winapi::LARGE_INTEGER_ fileSize;
if(! boost::winapi::GetFileSizeEx(h_, &fileSize))
{
ec.assign(boost::winapi::GetLastError(),
system_category());
return 0;
}
ec = {};
return fileSize.QuadPart;
}
std::uint64_t
file_win32::
pos(error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
boost::winapi::LARGE_INTEGER_ in;
boost::winapi::LARGE_INTEGER_ out;
in.QuadPart = 0;
if(! detail::set_file_pointer_ex(h_, in, &out,
boost::winapi::FILE_CURRENT_))
{
ec.assign(boost::winapi::GetLastError(),
system_category());
return 0;
}
ec = {};
return out.QuadPart;
}
void
file_win32::
seek(std::uint64_t offset, error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
ec = make_error_code(errc::bad_file_descriptor);
return;
}
boost::winapi::LARGE_INTEGER_ in;
in.QuadPart = offset;
if(! detail::set_file_pointer_ex(h_, in, 0,
boost::winapi::FILE_BEGIN_))
{
ec.assign(boost::winapi::GetLastError(),
system_category());
return;
}
ec = {};
}
std::size_t
file_win32::
read(void* buffer, std::size_t n, error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
std::size_t nread = 0;
while(n > 0)
{
boost::winapi::DWORD_ amount;
if(n > (std::numeric_limits<
boost::winapi::DWORD_>::max)())
amount = (std::numeric_limits<
boost::winapi::DWORD_>::max)();
else
amount = static_cast<
boost::winapi::DWORD_>(n);
boost::winapi::DWORD_ bytesRead;
if(! ::ReadFile(h_, buffer, amount, &bytesRead, 0))
{
auto const dwError = boost::winapi::GetLastError();
if(dwError != boost::winapi::ERROR_HANDLE_EOF_)
ec.assign(dwError, system_category());
else
ec = {};
return nread;
}
if(bytesRead == 0)
return nread;
n -= bytesRead;
nread += bytesRead;
buffer = static_cast<char*>(buffer) + bytesRead;
}
ec = {};
return nread;
}
std::size_t
file_win32::
write(void const* buffer, std::size_t n, error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
std::size_t nwritten = 0;
while(n > 0)
{
boost::winapi::DWORD_ amount;
if(n > (std::numeric_limits<
boost::winapi::DWORD_>::max)())
amount = (std::numeric_limits<
boost::winapi::DWORD_>::max)();
else
amount = static_cast<
boost::winapi::DWORD_>(n);
boost::winapi::DWORD_ bytesWritten;
if(! ::WriteFile(h_, buffer, amount, &bytesWritten, 0))
{
auto const dwError = boost::winapi::GetLastError();
if(dwError != boost::winapi::ERROR_HANDLE_EOF_)
ec.assign(dwError, system_category());
else
ec = {};
return nwritten;
}
if(bytesWritten == 0)
return nwritten;
n -= bytesWritten;
nwritten += bytesWritten;
buffer = static_cast<char const*>(buffer) + bytesWritten;
}
ec = {};
return nwritten;
}
} // beast
} // boost
#endif
#endif
+544
View File
@@ -0,0 +1,544 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_FLAT_BUFFER_HPP
#define BOOST_BEAST_IMPL_FLAT_BUFFER_HPP
#include <boost/core/exchange.hpp>
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
#include <memory>
#include <stdexcept>
namespace boost {
namespace beast {
/* Layout:
begin_ in_ out_ last_ end_
|<------->|<---------->|<---------->|<------->|
| readable | writable |
*/
template<class Allocator>
basic_flat_buffer<Allocator>::
~basic_flat_buffer()
{
if(! begin_)
return;
alloc_traits::deallocate(
this->get(), begin_, capacity());
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer() noexcept(default_nothrow)
: begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(alloc_traits::max_size(
this->get()))
{
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
std::size_t limit) noexcept(default_nothrow)
: begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(limit)
{
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(Allocator const& alloc) noexcept
: boost::empty_value<base_alloc_type>(
boost::empty_init_t{}, alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(alloc_traits::max_size(
this->get()))
{
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
std::size_t limit,
Allocator const& alloc) noexcept
: boost::empty_value<base_alloc_type>(
boost::empty_init_t{}, alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(limit)
{
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer&& other) noexcept
: boost::empty_value<base_alloc_type>(
boost::empty_init_t{}, std::move(other.get()))
, begin_(boost::exchange(other.begin_, nullptr))
, in_(boost::exchange(other.in_, nullptr))
, out_(boost::exchange(other.out_, nullptr))
, last_(boost::exchange(other.last_, nullptr))
, end_(boost::exchange(other.end_, nullptr))
, max_(other.max_)
{
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
basic_flat_buffer&& other,
Allocator const& alloc)
: boost::empty_value<base_alloc_type>(
boost::empty_init_t{}, alloc)
{
if(this->get() != other.get())
{
begin_ = nullptr;
in_ = nullptr;
out_ = nullptr;
last_ = nullptr;
end_ = nullptr;
max_ = other.max_;
copy_from(other);
return;
}
begin_ = other.begin_;
in_ = other.in_;
out_ = other.out_;
last_ = other.out_; // invalidate
end_ = other.end_;
max_ = other.max_;
BOOST_ASSERT(
alloc_traits::max_size(this->get()) ==
alloc_traits::max_size(other.get()));
other.begin_ = nullptr;
other.in_ = nullptr;
other.out_ = nullptr;
other.last_ = nullptr;
other.end_ = nullptr;
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer const& other)
: boost::empty_value<base_alloc_type>(boost::empty_init_t{},
alloc_traits::select_on_container_copy_construction(
other.get()))
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(other.max_)
{
copy_from(other);
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
basic_flat_buffer const& other,
Allocator const& alloc)
: boost::empty_value<base_alloc_type>(
boost::empty_init_t{}, alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(other.max_)
{
copy_from(other);
}
template<class Allocator>
template<class OtherAlloc>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
basic_flat_buffer<OtherAlloc> const& other)
noexcept(default_nothrow)
: begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(other.max_)
{
copy_from(other);
}
template<class Allocator>
template<class OtherAlloc>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
basic_flat_buffer<OtherAlloc> const& other,
Allocator const& alloc)
: boost::empty_value<base_alloc_type>(
boost::empty_init_t{}, alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(other.max_)
{
copy_from(other);
}
template<class Allocator>
auto
basic_flat_buffer<Allocator>::
operator=(basic_flat_buffer&& other) noexcept ->
basic_flat_buffer&
{
if(this == &other)
return *this;
move_assign(other, pocma{});
return *this;
}
template<class Allocator>
auto
basic_flat_buffer<Allocator>::
operator=(basic_flat_buffer const& other) ->
basic_flat_buffer&
{
if(this == &other)
return *this;
copy_assign(other, pocca{});
return *this;
}
template<class Allocator>
template<class OtherAlloc>
auto
basic_flat_buffer<Allocator>::
operator=(
basic_flat_buffer<OtherAlloc> const& other) ->
basic_flat_buffer&
{
copy_from(other);
return *this;
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
reserve(std::size_t n)
{
if(max_ < n)
max_ = n;
if(n > capacity())
prepare(n - size());
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
shrink_to_fit() noexcept
{
auto const len = size();
if(len == capacity())
return;
char* p;
if(len > 0)
{
BOOST_ASSERT(begin_);
BOOST_ASSERT(in_);
#ifndef BOOST_NO_EXCEPTIONS
try
{
#endif
p = alloc(len);
#ifndef BOOST_NO_EXCEPTIONS
}
catch(std::exception const&)
{
// request could not be fulfilled,
// squelch the exception
return;
}
#endif
std::memcpy(p, in_, len);
}
else
{
p = nullptr;
}
alloc_traits::deallocate(
this->get(), begin_, this->capacity());
begin_ = p;
in_ = begin_;
out_ = begin_ + len;
last_ = out_;
end_ = out_;
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
clear() noexcept
{
in_ = begin_;
out_ = begin_;
last_ = begin_;
}
//------------------------------------------------------------------------------
template<class Allocator>
auto
basic_flat_buffer<Allocator>::
prepare(std::size_t n) ->
mutable_buffers_type
{
auto const len = size();
if(len > max_ || n > (max_ - len))
BOOST_THROW_EXCEPTION(std::length_error{
"basic_flat_buffer too long"});
if(n <= dist(out_, end_))
{
// existing capacity is sufficient
last_ = out_ + n;
return{out_, n};
}
if(n <= capacity() - len)
{
// after a memmove,
// existing capacity is sufficient
if(len > 0)
{
BOOST_ASSERT(begin_);
BOOST_ASSERT(in_);
std::memmove(begin_, in_, len);
}
in_ = begin_;
out_ = in_ + len;
last_ = out_ + n;
return {out_, n};
}
// allocate a new buffer
auto const new_size = (std::min<std::size_t>)(
max_,
(std::max<std::size_t>)(2 * len, len + n));
auto const p = alloc(new_size);
if(begin_)
{
BOOST_ASSERT(p);
BOOST_ASSERT(in_);
std::memcpy(p, in_, len);
alloc_traits::deallocate(
this->get(), begin_, capacity());
}
begin_ = p;
in_ = begin_;
out_ = in_ + len;
last_ = out_ + n;
end_ = begin_ + new_size;
return {out_, n};
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
consume(std::size_t n) noexcept
{
if(n >= dist(in_, out_))
{
in_ = begin_;
out_ = begin_;
return;
}
in_ += n;
}
//------------------------------------------------------------------------------
template<class Allocator>
template<class OtherAlloc>
void
basic_flat_buffer<Allocator>::
copy_from(
basic_flat_buffer<OtherAlloc> const& other)
{
std::size_t const n = other.size();
if(n == 0 || n > capacity())
{
if(begin_ != nullptr)
{
alloc_traits::deallocate(
this->get(), begin_,
this->capacity());
begin_ = nullptr;
in_ = nullptr;
out_ = nullptr;
last_ = nullptr;
end_ = nullptr;
}
if(n == 0)
return;
begin_ = alloc(n);
in_ = begin_;
out_ = begin_ + n;
last_ = begin_ + n;
end_ = begin_ + n;
}
in_ = begin_;
out_ = begin_ + n;
last_ = begin_ + n;
if(begin_)
{
BOOST_ASSERT(other.begin_);
std::memcpy(begin_, other.in_, n);
}
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
move_assign(basic_flat_buffer& other, std::true_type)
{
clear();
shrink_to_fit();
this->get() = std::move(other.get());
begin_ = other.begin_;
in_ = other.in_;
out_ = other.out_;
last_ = out_;
end_ = other.end_;
max_ = other.max_;
other.begin_ = nullptr;
other.in_ = nullptr;
other.out_ = nullptr;
other.last_ = nullptr;
other.end_ = nullptr;
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
move_assign(basic_flat_buffer& other, std::false_type)
{
if(this->get() != other.get())
{
copy_from(other);
}
else
{
move_assign(other, std::true_type{});
}
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
copy_assign(basic_flat_buffer const& other, std::true_type)
{
max_ = other.max_;
this->get() = other.get();
copy_from(other);
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
copy_assign(basic_flat_buffer const& other, std::false_type)
{
clear();
shrink_to_fit();
max_ = other.max_;
copy_from(other);
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
swap(basic_flat_buffer& other)
{
swap(other, typename
alloc_traits::propagate_on_container_swap{});
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
swap(basic_flat_buffer& other, std::true_type)
{
using std::swap;
swap(this->get(), other.get());
swap(max_, other.max_);
swap(begin_, other.begin_);
swap(in_, other.in_);
swap(out_, other.out_);
last_ = this->out_;
other.last_ = other.out_;
swap(end_, other.end_);
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
swap(basic_flat_buffer& other, std::false_type)
{
BOOST_ASSERT(this->get() == other.get());
using std::swap;
swap(max_, other.max_);
swap(begin_, other.begin_);
swap(in_, other.in_);
swap(out_, other.out_);
last_ = this->out_;
other.last_ = other.out_;
swap(end_, other.end_);
}
template<class Allocator>
void
swap(
basic_flat_buffer<Allocator>& lhs,
basic_flat_buffer<Allocator>& rhs)
{
lhs.swap(rhs);
}
template<class Allocator>
char*
basic_flat_buffer<Allocator>::
alloc(std::size_t n)
{
if(n > alloc_traits::max_size(this->get()))
BOOST_THROW_EXCEPTION(std::length_error(
"A basic_flat_buffer exceeded the allocator's maximum size"));
return alloc_traits::allocate(this->get(), n);
}
} // beast
} // boost
#endif
+43
View File
@@ -0,0 +1,43 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_FLAT_STATIC_BUFFER_HPP
#define BOOST_BEAST_IMPL_FLAT_STATIC_BUFFER_HPP
namespace boost {
namespace beast {
template<std::size_t N>
flat_static_buffer<N>::
flat_static_buffer(
flat_static_buffer const& other)
: flat_static_buffer_base(buf_, N)
{
this->commit(net::buffer_copy(
this->prepare(other.size()), other.data()));
}
template<std::size_t N>
auto
flat_static_buffer<N>::
operator=(flat_static_buffer const& other) ->
flat_static_buffer<N>&
{
if(this == &other)
return *this;
this->consume(this->size());
this->commit(net::buffer_copy(
this->prepare(other.size()), other.data()));
return *this;
}
} // beast
} // boost
#endif
+89
View File
@@ -0,0 +1,89 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_FLAT_STATIC_BUFFER_IPP
#define BOOST_BEAST_IMPL_FLAT_STATIC_BUFFER_IPP
#include <boost/beast/core/flat_static_buffer.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <memory>
#include <stdexcept>
namespace boost {
namespace beast {
/* Layout:
begin_ in_ out_ last_ end_
|<------->|<---------->|<---------->|<------->|
| readable | writable |
*/
void
flat_static_buffer_base::
clear() noexcept
{
in_ = begin_;
out_ = begin_;
last_ = begin_;
}
auto
flat_static_buffer_base::
prepare(std::size_t n) ->
mutable_buffers_type
{
if(n <= dist(out_, end_))
{
last_ = out_ + n;
return {out_, n};
}
auto const len = size();
if(n > capacity() - len)
BOOST_THROW_EXCEPTION(std::length_error{
"buffer overflow"});
if(len > 0)
std::memmove(begin_, in_, len);
in_ = begin_;
out_ = in_ + len;
last_ = out_ + n;
return {out_, n};
}
void
flat_static_buffer_base::
consume(std::size_t n) noexcept
{
if(n >= size())
{
in_ = begin_;
out_ = in_;
return;
}
in_ += n;
}
void
flat_static_buffer_base::
reset(void* p, std::size_t n) noexcept
{
begin_ = static_cast<char*>(p);
in_ = begin_;
out_ = begin_;
last_ = begin_;
end_ = begin_ + n;
}
} // beast
} // boost
#endif
+284
View File
@@ -0,0 +1,284 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_FLAT_STREAM_HPP
#define BOOST_BEAST_CORE_IMPL_FLAT_STREAM_HPP
#include <boost/beast/core/async_base.hpp>
#include <boost/beast/core/buffers_prefix.hpp>
#include <boost/beast/core/static_buffer.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/websocket/teardown.hpp>
#include <boost/asio/buffer.hpp>
#include <memory>
namespace boost {
namespace beast {
template<class NextLayer>
struct flat_stream<NextLayer>::ops
{
template<class Handler>
class write_op
: public async_base<Handler,
beast::executor_type<flat_stream>>
{
public:
template<
class ConstBufferSequence,
class Handler_>
write_op(
Handler_&& h,
flat_stream<NextLayer>& s,
ConstBufferSequence const& b)
: async_base<Handler,
beast::executor_type<flat_stream>>(
std::forward<Handler_>(h),
s.get_executor())
{
auto const result =
flatten(b, max_size);
if(result.flatten)
{
s.buffer_.clear();
s.buffer_.commit(net::buffer_copy(
s.buffer_.prepare(result.size),
b, result.size));
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"flat_stream::async_write_some"));
s.stream_.async_write_some(
s.buffer_.data(), std::move(*this));
}
else
{
s.buffer_.clear();
s.buffer_.shrink_to_fit();
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"flat_stream::async_write_some"));
s.stream_.async_write_some(
beast::buffers_prefix(
result.size, b), std::move(*this));
}
}
void
operator()(
boost::system::error_code ec,
std::size_t bytes_transferred)
{
this->complete_now(ec, bytes_transferred);
}
};
struct run_write_op
{
template<class WriteHandler, class Buffers>
void
operator()(
WriteHandler&& h,
flat_stream* s,
Buffers const& b)
{
// If you get an error on the following line it means
// that your handler does not meet the documented type
// requirements for the handler.
static_assert(
beast::detail::is_invocable<WriteHandler,
void(error_code, std::size_t)>::value,
"WriteHandler type requirements not met");
write_op<
typename std::decay<WriteHandler>::type>(
std::forward<WriteHandler>(h), *s, b);
}
};
};
//------------------------------------------------------------------------------
template<class NextLayer>
template<class... Args>
flat_stream<NextLayer>::
flat_stream(Args&&... args)
: stream_(std::forward<Args>(args)...)
{
}
template<class NextLayer>
template<class MutableBufferSequence>
std::size_t
flat_stream<NextLayer>::
read_some(MutableBufferSequence const& buffers)
{
static_assert(boost::beast::is_sync_read_stream<next_layer_type>::value,
"SyncReadStream type requirements not met");
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence type requirements not met");
error_code ec;
auto n = read_some(buffers, ec);
if(ec)
BOOST_THROW_EXCEPTION(boost::system::system_error{ec});
return n;
}
template<class NextLayer>
template<class MutableBufferSequence>
std::size_t
flat_stream<NextLayer>::
read_some(MutableBufferSequence const& buffers, error_code& ec)
{
static_assert(boost::beast::is_sync_read_stream<next_layer_type>::value,
"SyncReadStream type requirements not met");
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence type requirements not met");
return stream_.read_some(buffers, ec);
}
template<class NextLayer>
template<
class MutableBufferSequence,
BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
flat_stream<NextLayer>::
async_read_some(
MutableBufferSequence const& buffers,
ReadHandler&& handler)
{
static_assert(boost::beast::is_async_read_stream<next_layer_type>::value,
"AsyncReadStream type requirements not met");
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence >::value,
"MutableBufferSequence type requirements not met");
return stream_.async_read_some(
buffers, std::forward<ReadHandler>(handler));
}
template<class NextLayer>
template<class ConstBufferSequence>
std::size_t
flat_stream<NextLayer>::
write_some(ConstBufferSequence const& buffers)
{
static_assert(boost::beast::is_sync_write_stream<next_layer_type>::value,
"SyncWriteStream type requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
error_code ec;
auto n = write_some(buffers, ec);
if(ec)
BOOST_THROW_EXCEPTION(boost::system::system_error{ec});
return n;
}
template<class NextLayer>
template<class ConstBufferSequence>
std::size_t
flat_stream<NextLayer>::
stack_write_some(
std::size_t size,
ConstBufferSequence const& buffers,
error_code& ec)
{
static_buffer<max_stack> b;
b.commit(net::buffer_copy(
b.prepare(size), buffers));
return stream_.write_some(b.data(), ec);
}
template<class NextLayer>
template<class ConstBufferSequence>
std::size_t
flat_stream<NextLayer>::
write_some(ConstBufferSequence const& buffers, error_code& ec)
{
static_assert(boost::beast::is_sync_write_stream<next_layer_type>::value,
"SyncWriteStream type requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
auto const result = flatten(buffers, max_size);
if(result.flatten)
{
if(result.size <= max_stack)
return stack_write_some(result.size, buffers, ec);
buffer_.clear();
buffer_.commit(net::buffer_copy(
buffer_.prepare(result.size),
buffers));
return stream_.write_some(buffer_.data(), ec);
}
buffer_.clear();
buffer_.shrink_to_fit();
return stream_.write_some(
boost::beast::buffers_prefix(result.size, buffers), ec);
}
template<class NextLayer>
template<
class ConstBufferSequence,
BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
flat_stream<NextLayer>::
async_write_some(
ConstBufferSequence const& buffers,
WriteHandler&& handler)
{
static_assert(boost::beast::is_async_write_stream<next_layer_type>::value,
"AsyncWriteStream type requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
return net::async_initiate<
WriteHandler,
void(error_code, std::size_t)>(
typename ops::run_write_op{},
handler,
this,
buffers);
}
template<class NextLayer>
void
teardown(
boost::beast::role_type role,
flat_stream<NextLayer>& s,
error_code& ec)
{
using boost::beast::websocket::teardown;
teardown(role, s.next_layer(), ec);
}
template<class NextLayer, class TeardownHandler>
void
async_teardown(
boost::beast::role_type role,
flat_stream<NextLayer>& s,
TeardownHandler&& handler)
{
using boost::beast::websocket::async_teardown;
async_teardown(role, s.next_layer(), std::move(handler));
}
} // beast
} // boost
#endif
File diff suppressed because it is too large Load Diff
+83
View File
@@ -0,0 +1,83 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_READ_SIZE_HPP
#define BOOST_BEAST_IMPL_READ_SIZE_HPP
#include <boost/asio/buffer.hpp>
#include <boost/assert.hpp>
#include <stdexcept>
#include <type_traits>
namespace boost {
namespace beast {
namespace detail {
template<class T, class = void>
struct has_read_size_helper : std::false_type {};
template<class T>
struct has_read_size_helper<T, decltype(
read_size_helper(std::declval<T&>(), 512),
(void)0)> : std::true_type
{
};
template<class DynamicBuffer>
std::size_t
read_size(DynamicBuffer& buffer,
std::size_t max_size, std::true_type)
{
return read_size_helper(buffer, max_size);
}
template<class DynamicBuffer>
std::size_t
read_size(DynamicBuffer& buffer,
std::size_t max_size, std::false_type)
{
static_assert(
net::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer type requirements not met");
auto const size = buffer.size();
auto const limit = buffer.max_size() - size;
BOOST_ASSERT(size <= buffer.max_size());
return std::min<std::size_t>(
std::max<std::size_t>(512, buffer.capacity() - size),
std::min<std::size_t>(max_size, limit));
}
} // detail
template<class DynamicBuffer>
std::size_t
read_size(
DynamicBuffer& buffer, std::size_t max_size)
{
return detail::read_size(buffer, max_size,
detail::has_read_size_helper<DynamicBuffer>{});
}
template<class DynamicBuffer>
std::size_t
read_size_or_throw(
DynamicBuffer& buffer, std::size_t max_size)
{
auto const n = read_size(buffer, max_size);
if(n == 0)
BOOST_THROW_EXCEPTION(std::length_error{
"buffer overflow"});
return n;
}
} // beast
} // boost
#endif
+210
View File
@@ -0,0 +1,210 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_HPP
#define BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_HPP
#include <boost/beast/core/detail/allocator.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_cancellation_slot.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/assert.hpp>
#include <boost/core/empty_value.hpp>
#include <boost/core/exchange.hpp>
#include <utility>
namespace boost {
namespace beast {
//------------------------------------------------------------------------------
class saved_handler::base
{
protected:
~base() = default;
saved_handler * owner_;
public:
base(saved_handler * owner) : owner_(owner){}
void set_owner(saved_handler * new_owner) { owner_ = new_owner;}
virtual void destroy() = 0;
virtual void invoke() = 0;
};
//------------------------------------------------------------------------------
template<class Handler, class Alloc>
class saved_handler::impl final : public base
{
using alloc_type = typename
beast::detail::allocator_traits<
Alloc>::template rebind_alloc<impl>;
using alloc_traits =
beast::detail::allocator_traits<alloc_type>;
struct ebo_pair : boost::empty_value<alloc_type>
{
Handler h;
template<class Handler_>
ebo_pair(
alloc_type const& a,
Handler_&& h_)
: boost::empty_value<alloc_type>(
boost::empty_init_t{}, a)
, h(std::forward<Handler_>(h_))
{
}
};
ebo_pair v_;
#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
typename std::decay<decltype(net::prefer(std::declval<
net::associated_executor_t<Handler>>(),
net::execution::outstanding_work.tracked))>::type
wg2_;
#else // defined(BOOST_ASIO_NO_TS_EXECUTORS)
net::executor_work_guard<
net::associated_executor_t<Handler>> wg2_;
#endif // defined(BOOST_ASIO_NO_TS_EXECUTORS)
net::cancellation_slot slot_{net::get_associated_cancellation_slot(v_.h)};
public:
template<class Handler_>
impl(alloc_type const& a, Handler_&& h,
saved_handler * owner)
: base(owner), v_(a, std::forward<Handler_>(h))
#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
, wg2_(net::prefer(
net::get_associated_executor(v_.h),
net::execution::outstanding_work.tracked))
#else // defined(BOOST_ASIO_NO_TS_EXECUTORS)
, wg2_(net::get_associated_executor(v_.h))
#endif // defined(BOOST_ASIO_NO_TS_EXECUTORS)
{
}
~impl()
{
}
void
destroy() override
{
auto v = std::move(v_);
slot_.clear();
alloc_traits::destroy(v.get(), this);
alloc_traits::deallocate(v.get(), this, 1);
}
void
invoke() override
{
slot_.clear();
auto v = std::move(v_);
alloc_traits::destroy(v.get(), this);
alloc_traits::deallocate(v.get(), this, 1);
v.h();
}
void self_complete()
{
slot_.clear();
owner_->p_ = nullptr;
auto v = std::move(v_);
alloc_traits::destroy(v.get(), this);
alloc_traits::deallocate(v.get(), this, 1);
v.h(net::error::operation_aborted);
}
};
//------------------------------------------------------------------------------
template<class Handler, class Allocator>
void
saved_handler::
emplace(Handler&& handler, Allocator const& alloc,
net::cancellation_type cancel_type)
{
// Can't delete a handler before invoking
BOOST_ASSERT(! has_value());
using handler_type =
typename std::decay<Handler>::type;
using alloc_type = typename
detail::allocator_traits<Allocator>::
template rebind_alloc<impl<
handler_type, Allocator>>;
using alloc_traits =
beast::detail::allocator_traits<alloc_type>;
struct storage
{
alloc_type a;
impl<Handler, Allocator>* p;
explicit
storage(Allocator const& a_)
: a(a_)
, p(alloc_traits::allocate(a, 1))
{
}
~storage()
{
if(p)
alloc_traits::deallocate(a, p, 1);
}
};
auto cancel_slot = net::get_associated_cancellation_slot(handler);
storage s(alloc);
alloc_traits::construct(s.a, s.p,
s.a, std::forward<Handler>(handler), this);
auto tmp = boost::exchange(s.p, nullptr);
p_ = tmp;
if (cancel_slot.is_connected())
{
struct cancel_op
{
impl<Handler, Allocator>* p;
net::cancellation_type accepted_ct;
cancel_op(impl<Handler, Allocator>* p,
net::cancellation_type accepted_ct)
: p(p), accepted_ct(accepted_ct) {}
void operator()(net::cancellation_type ct)
{
if ((ct & accepted_ct) != net::cancellation_type::none)
p->self_complete();
}
};
cancel_slot.template emplace<cancel_op>(tmp, cancel_type);
}
}
template<class Handler>
void
saved_handler::
emplace(Handler&& handler, net::cancellation_type cancel_type)
{
// Can't delete a handler before invoking
BOOST_ASSERT(! has_value());
emplace(
std::forward<Handler>(handler),
net::get_associated_allocator(handler),
cancel_type);
}
} // beast
} // boost
#endif
+78
View File
@@ -0,0 +1,78 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_IPP
#define BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_IPP
#include <boost/beast/core/saved_handler.hpp>
#include <boost/core/exchange.hpp>
namespace boost {
namespace beast {
saved_handler::
~saved_handler()
{
if(p_)
p_->destroy();
}
saved_handler::
saved_handler(saved_handler&& other) noexcept
: p_(boost::exchange(other.p_, nullptr))
{
p_->set_owner(this);
}
saved_handler&
saved_handler::
operator=(saved_handler&& other) noexcept
{
// Can't delete a handler before invoking
BOOST_ASSERT(! has_value());
p_ = boost::exchange(other.p_, nullptr);
p_->set_owner(this);
return *this;
}
bool
saved_handler::
reset() noexcept
{
if(! p_)
return false;
boost::exchange(p_, nullptr)->destroy();
return true;
}
void
saved_handler::
invoke()
{
// Can't invoke without a value
BOOST_ASSERT(has_value());
boost::exchange(
p_, nullptr)->invoke();
}
bool
saved_handler::
maybe_invoke()
{
if(! p_)
return false;
boost::exchange(
p_, nullptr)->invoke();
return true;
}
} // beast
} // boost
#endif
+45
View File
@@ -0,0 +1,45 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_STATIC_BUFFER_HPP
#define BOOST_BEAST_IMPL_STATIC_BUFFER_HPP
#include <boost/asio/buffer.hpp>
#include <stdexcept>
namespace boost {
namespace beast {
template<std::size_t N>
static_buffer<N>::
static_buffer(static_buffer const& other) noexcept
: static_buffer_base(buf_, N)
{
this->commit(net::buffer_copy(
this->prepare(other.size()), other.data()));
}
template<std::size_t N>
auto
static_buffer<N>::
operator=(static_buffer const& other) noexcept ->
static_buffer<N>&
{
if(this == &other)
return *this;
this->consume(this->size());
this->commit(net::buffer_copy(
this->prepare(other.size()), other.data()));
return *this;
}
} // beast
} // boost
#endif
+129
View File
@@ -0,0 +1,129 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_STATIC_BUFFER_IPP
#define BOOST_BEAST_IMPL_STATIC_BUFFER_IPP
#include <boost/beast/core/static_buffer.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/throw_exception.hpp>
#include <stdexcept>
namespace boost {
namespace beast {
static_buffer_base::
static_buffer_base(
void* p, std::size_t size) noexcept
: begin_(static_cast<char*>(p))
, capacity_(size)
{
}
void
static_buffer_base::
clear() noexcept
{
in_off_ = 0;
in_size_ = 0;
out_size_ = 0;
}
auto
static_buffer_base::
data() const noexcept ->
const_buffers_type
{
if(in_off_ + in_size_ <= capacity_)
return {
net::const_buffer{
begin_ + in_off_, in_size_},
net::const_buffer{
begin_, 0}};
return {
net::const_buffer{
begin_ + in_off_, capacity_ - in_off_},
net::const_buffer{
begin_, in_size_ - (capacity_ - in_off_)}};
}
auto
static_buffer_base::
data() noexcept ->
mutable_buffers_type
{
if(in_off_ + in_size_ <= capacity_)
return {
net::mutable_buffer{
begin_ + in_off_, in_size_},
net::mutable_buffer{
begin_, 0}};
return {
net::mutable_buffer{
begin_ + in_off_, capacity_ - in_off_},
net::mutable_buffer{
begin_, in_size_ - (capacity_ - in_off_)}};
}
auto
static_buffer_base::
prepare(std::size_t n) ->
mutable_buffers_type
{
using net::mutable_buffer;
if(n > capacity_ - in_size_)
BOOST_THROW_EXCEPTION(std::length_error{
"static_buffer overflow"});
out_size_ = n;
auto const out_off =
(in_off_ + in_size_) % capacity_;
if(out_off + out_size_ <= capacity_ )
return {
net::mutable_buffer{
begin_ + out_off, out_size_},
net::mutable_buffer{
begin_, 0}};
return {
net::mutable_buffer{
begin_ + out_off, capacity_ - out_off},
net::mutable_buffer{
begin_, out_size_ - (capacity_ - out_off)}};
}
void
static_buffer_base::
commit(std::size_t n) noexcept
{
in_size_ += (std::min)(n, out_size_);
out_size_ = 0;
}
void
static_buffer_base::
consume(std::size_t n) noexcept
{
if(n < in_size_)
{
in_off_ = (in_off_ + n) % capacity_;
in_size_ -= n;
}
else
{
// rewind the offset, so the next call to prepare
// can have a longer contiguous segment. this helps
// algorithms optimized for larger buffers.
in_off_ = 0;
in_size_ = 0;
}
}
} // beast
} // boost
#endif
+73
View File
@@ -0,0 +1,73 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_STRING_IPP
#define BOOST_BEAST_IMPL_STRING_IPP
#include <boost/beast/core/string.hpp>
#include <boost/beast/core/detail/string.hpp>
#include <algorithm>
namespace boost {
namespace beast {
bool
iequals(
beast::string_view lhs,
beast::string_view rhs)
{
auto n = lhs.size();
if(rhs.size() != n)
return false;
auto p1 = lhs.data();
auto p2 = rhs.data();
char a, b;
// fast loop
while(n--)
{
a = *p1++;
b = *p2++;
if(a != b)
goto slow;
}
return true;
slow:
do
{
if( detail::ascii_tolower(a) !=
detail::ascii_tolower(b))
return false;
a = *p1++;
b = *p2++;
}
while(n--);
return true;
}
bool
iless::operator()(
string_view lhs,
string_view rhs) const
{
using std::begin;
using std::end;
return std::lexicographical_compare(
begin(lhs), end(lhs), begin(rhs), end(rhs),
[](char c1, char c2)
{
return detail::ascii_tolower(c1) < detail::ascii_tolower(c2);
}
);
}
} // beast
} // boost
#endif
+108
View File
@@ -0,0 +1,108 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_STRING_PARAM_HPP
#define BOOST_BEAST_IMPL_STRING_PARAM_HPP
namespace boost {
namespace beast {
template<class T>
typename std::enable_if<
std::is_integral<T>::value>::type
string_param::
print(T const& t)
{
auto const last = buf_ + sizeof(buf_);
auto const it = detail::raw_to_string<
char, T, std::char_traits<char>>(
last, sizeof(buf_), t);
sv_ = {it, static_cast<std::size_t>(
last - it)};
}
template<class T>
typename std::enable_if<
! std::is_integral<T>::value &&
! std::is_convertible<T, string_view>::value
>::type
string_param::
print(T const& t)
{
os_.emplace(buf_, sizeof(buf_));
*os_ << t;
os_->flush();
sv_ = os_->str();
}
inline
void
string_param::
print(string_view sv)
{
sv_ = sv;
}
template<class T>
typename std::enable_if<
std::is_integral<T>::value>::type
string_param::
print_1(T const& t)
{
char buf[detail::max_digits(sizeof(T))];
auto const last = buf + sizeof(buf);
auto const it = detail::raw_to_string<
char, T, std::char_traits<char>>(
last, sizeof(buf), t);
*os_ << string_view{it,
static_cast<std::size_t>(last - it)};
}
template<class T>
typename std::enable_if<
! std::is_integral<T>::value>::type
string_param::
print_1(T const& t)
{
*os_ << t;
}
template<class T0, class... TN>
void
string_param::
print_n(T0 const& t0, TN const&... tn)
{
print_1(t0);
print_n(tn...);
}
template<class T0, class T1, class... TN>
void
string_param::
print(T0 const& t0, T1 const& t1, TN const&... tn)
{
os_.emplace(buf_, sizeof(buf_));
print_1(t0);
print_1(t1);
print_n(tn...);
os_->flush();
sv_ = os_->str();
}
template<class... Args>
string_param::
string_param(Args const&... args)
{
print(args...);
}
} // beast
} // boost
#endif