Files
rippled/beast/asio/static_streambuf.h
Vinnie Falco 3461bafaa2 Beast.Asio:
New classes:

  class async_completion:
    Helper class for implementing asynchronous initiation functions.
    See n3964:
        Library Foundations for Asynchronous Operations, Revision 1
        http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3964.pdf

  class basic_streambuf:
    Meets the requirements of Streambuf.

  class buffered_readstream:
    Buffers a ReadStream with a ConstBufferSequence.

  class consuming_buffers:
    Adapts a BufferSequence which wraps the underlying buffer
    sequence and presents fewer bytes, with the retained bytes
    occurring at the end of the sequence.

  class handler_alloc:
    A C++ Allocator the uses asio handler allocation hooks.

  class static_streambuf:
    An implementation of the Streambuf concept that uses a
    fixed size buffer with size determined at compile-time.

  class streambuf_readstream:
    Buffers a ReadStream with a Streambuf.

New functions:

  append_buffers()
    Returns a new BufferSequence which efficiently concatenates
    two or more buffer sequences together.

  prepare_buffers()
    Shortens a buffer sequence. The bytes excluded are at the
    end of the underlying buffer sequence.

  boost::asio::read_until()
    A copy of boost::asio::read_until overloads, modified to work
    with a beast::asio::basic_streambuf.

Debugging:

  buffers_to_string()

    Convert a ConstBufferSequence to a human readable string
    suitable for diagnostics.

type_check.h:

  Metafunctions for checking asio concepts:
    AsyncReadStream, AsyncWriteStream
    SyncReadStream, SyncWriteStream
    ConstBufferSequence, MutableBufferSequence
    Streambuf
    Handler

Changes:

* All symbols moved up a namespace level.
* streambuf provides all move and copy special members,
  behavior of moved from objects is well-defined.

Fixes:

* Fix basic_streambuf iterator category.
2016-04-20 05:16:38 -04:00

472 lines
10 KiB
C++

//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_STATIC_STREAMBUF_H_INLUDED
#define BEAST_ASIO_STATIC_STREAMBUF_H_INLUDED
#include <boost/asio/buffer.hpp>
#include <boost/utility/base_from_member.hpp>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <stdexcept>
namespace beast {
/** A `Streambuf` with a fixed size internal buffer.
Ownership of the underlying storage belongs to the derived class.
@note Variables are usually declared using the template class
`static_streambuf_n`; however, to reduce the number of instantiations
of template functions receiving static stream buffer arguments in a
deduced context, the signature of the receiving function should use
`static_streambuf`.
*/
class static_streambuf
{
#if GENERATING_DOCS
private:
#else
protected:
#endif
std::uint8_t* in_;
std::uint8_t* out_;
std::uint8_t* last_;
std::uint8_t* end_;
public:
class const_buffers_type;
class mutable_buffers_type;
#if GENERATING_DOCS
private:
#endif
static_streambuf(
static_streambuf const& other) noexcept = delete;
static_streambuf& operator=(
static_streambuf const&) noexcept = delete;
#if GENERATING_DOCS
public:
#endif
/// Returns the largest size output sequence possible.
std::size_t
max_size() const
{
return end_ - in_;
}
/// Get the size of the input sequence.
std::size_t
size() const
{
return out_ - in_;
}
/** Get a list of buffers that represents the output sequence, with the given size.
@throws std::length_error if the size would exceed the limit
imposed by the underlying mutable buffer sequence.
*/
mutable_buffers_type
prepare(std::size_t n);
/// Move bytes from the output sequence to the input sequence.
void
commit(std::size_t n)
{
out_ += std::min<std::size_t>(n, last_ - out_);
}
/// Get a list of buffers that represents the input sequence.
const_buffers_type
data() const;
/// Remove bytes from the input sequence.
void
consume(std::size_t n)
{
in_ += std::min<std::size_t>(n, out_ - in_);
}
#if GENERATING_DOCS
private:
#else
protected:
#endif
static_streambuf(std::uint8_t* p, std::size_t n)
{
reset(p, n);
}
void
reset(std::uint8_t* p, std::size_t n)
{
in_ = p;
out_ = p;
last_ = p;
end_ = p + n;
}
};
//------------------------------------------------------------------------------
/// The type used to represent the input sequence as a list of buffers.
class static_streambuf::const_buffers_type
{
std::size_t n_;
std::uint8_t const* p_;
public:
using value_type = boost::asio::const_buffer;
class const_iterator;
const_buffers_type() = default;
const_buffers_type(
const_buffers_type const&) = default;
const_buffers_type& operator=(
const_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
private:
friend class static_streambuf;
const_buffers_type(
std::uint8_t const* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
class static_streambuf::const_buffers_type::const_iterator
{
std::size_t n_;
std::uint8_t const* p_;
public:
using value_type = boost::asio::const_buffer;
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&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return p_ == other.p_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return value_type{p_, n_};
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
p_ += n_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
p_ -= n_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
friend class const_buffers_type;
const_iterator(
std::uint8_t const* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
inline
auto
static_streambuf::const_buffers_type::begin() const ->
const_iterator
{
return const_iterator{p_, n_};
}
inline
auto
static_streambuf::const_buffers_type::end() const ->
const_iterator
{
return const_iterator{p_ + n_, n_};
}
//------------------------------------------------------------------------------
/// The type used to represent the output sequence as a list of buffers.
class static_streambuf::mutable_buffers_type
{
std::size_t n_;
std::uint8_t* p_;
public:
using value_type = boost::asio::mutable_buffer;
class const_iterator;
mutable_buffers_type() = default;
mutable_buffers_type(
mutable_buffers_type const&) = default;
mutable_buffers_type& operator=(
mutable_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
private:
friend class static_streambuf;
mutable_buffers_type(
std::uint8_t* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
class static_streambuf::mutable_buffers_type::const_iterator
{
std::size_t n_;
std::uint8_t* p_;
public:
using value_type = boost::asio::mutable_buffer;
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&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return p_ == other.p_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return value_type{p_, n_};
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
p_ += n_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
p_ -= n_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
friend class mutable_buffers_type;
const_iterator(std::uint8_t* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
inline
auto
static_streambuf::mutable_buffers_type::begin() const ->
const_iterator
{
return const_iterator{p_, n_};
}
inline
auto
static_streambuf::mutable_buffers_type::end() const ->
const_iterator
{
return const_iterator{p_ + n_, n_};
}
//------------------------------------------------------------------------------
inline
auto
static_streambuf::prepare(std::size_t n) ->
mutable_buffers_type
{
if(n > static_cast<std::size_t>(end_ - out_))
throw std::length_error("no space in streambuf");
last_ = out_ + n;
return mutable_buffers_type{out_, n};
}
inline
auto
static_streambuf::data() const ->
const_buffers_type
{
return const_buffers_type{in_,
static_cast<std::size_t>(out_ - in_)};
}
//------------------------------------------------------------------------------
/** A `Streambuf` with a fixed size internal buffer.
@tparam N The number of bytes in the internal buffer.
@note To reduce the number of template instantiations when passing
objects of this type in a deduced context, the signature of the
receiving function should use `static_streambuf` instead.
*/
template<std::size_t N>
class static_streambuf_n
: private boost::base_from_member<
std::array<std::uint8_t, N>>
, public static_streambuf
{
using member_type = boost::base_from_member<
std::array<std::uint8_t, N>>;
public:
#if GENERATING_DOCS
private:
#endif
static_streambuf_n(
static_streambuf_n const&) = delete;
static_streambuf_n& operator=(
static_streambuf_n const&) = delete;
#if GENERATING_DOCS
public:
#endif
/// Construct a static stream buffer.
static_streambuf_n()
: static_streambuf(
member_type::member.data(),
member_type::member.size())
{
}
/** Reset the stream buffer.
Postconditions:
The input sequence and output sequence are empty,
`max_size()` returns `N`.
*/
void
reset()
{
static_streambuf::reset(
member_type::member.data(),
member_type::member.size());
}
};
} // beast
#endif