diff --git a/TODO.txt b/TODO.txt index 54add0c1..0d255ab7 100644 --- a/TODO.txt +++ b/TODO.txt @@ -17,3 +17,8 @@ * Remove or change http::headers alias * Do something about the methods.hpp and fields.hpp type headers * Fix index in docs +* Fix integer warning in file_body.hpp +* Use make_error_code in websocket to set the category right +* Figure out why namespace rfc2616 is included in docs + (currently disabled via GENERATING_DOCS macro) +* Include Example program listings in the docs diff --git a/doc/beast.dox b/doc/beast.dox index 36328445..311c06a3 100644 --- a/doc/beast.dox +++ b/doc/beast.dox @@ -51,13 +51,13 @@ LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = YES -EXTRACT_PACKAGE = YES -EXTRACT_STATIC = YES +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = NO EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO -HIDE_UNDOC_CLASSES = YES +HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO diff --git a/doc/http.qbk b/doc/http.qbk index 7f184712..19132ee7 100644 --- a/doc/http.qbk +++ b/doc/http.qbk @@ -41,64 +41,24 @@ both Boost.Asio and the HTTP protocol specification described in -[section:example Example] +[section:usage Usage] -All examples and identifiers mentioned in this document are written as -if the following declarations are in effect: -``` -#include -#include -using namespace beast; -using namespace boost::asio; -``` - -Create a HTTP request: -``` -http::request req({http::method_t::http_get, "/", 11}); -req.headers.insert("Host", "127.0.0.1:80"); -req.headers.insert("User-Agent", "Beast.HTTP"); - -``` - -When sending a message, the Content-Length and Transfer-Encoding are set -automatically based on the properties of the body. Depending on the HTTP -version of the message and properties of the message body, the implementation -will automaticaly chunk-encode the data sent on the wire: -``` - ip::tcp::socket sock(ios); - ... - http::response resp({200, "OK", 11}); - resp.headers.insert("Server", "Beast.HTTP"); - resp.body = "The command was successful"; - - write(sock, resp); -} -``` - -Receiving a message is simple, declare a value of type message and call `read`. -This example reads a message, builds a response, and sends it. -``` -void handle_connection(ip::tcp::socket& sock) -{ - request req; - read(sock, req); - response resp; - ... - write(sock, resp); -} -``` - -[endsect] - - - -[section:message Message model] +[note + Sample code and identifiers mentioned in this section are written + as if the following declarations are in effect: + ``` + #include + using namespace beast; + ``` +] A HTTP message (referred to hereafter as "message") contains a request or response line, a series of zero or more name/value pairs (collectively termed "headers"), and a series of octets called the message body which may -be zero in length. Applications using HTTP often perform these operations -on messages: +be zero in length. The HTTP protocol defines the client and server roles: +clients send messages called requests and servers send back messages called +responses. `http::message` models both requests and responses. The library +provides interfaces to perform these operations on messages: * [*Parse] a new message from a series of octets. @@ -112,6 +72,205 @@ operation; a network read, followed by a [*parse]. * [*Write] a message to a stream. This can be thought of as a compound operation: a [*serialize] followed by a network write. +In the paragraphs that follow we describe simple interfaces that will serve +the majority of users looking merely to interact with a HTTP server, or +handle simple HTTP requests from clients. Subsequent sections cover the +message model in more depth, for advanced applications. + +[heading Declarations] + +To do anything, a message must be declared. The message class template +requires at mininum, a bool indicating whether the message is a request +(versus a response), and a `Body` type. The choice of `Body` determines the +kind of container used to represent the message body. Here we will +declare a request that has a `std::string` for the body container: +``` + http::message req; +``` + +Two type aliases are provided for notational convenience when declaring +messages. These two statements declare a request and a response respectively: +``` + http::request req; + http::response resp; +``` + +[heading Members] + +Message objects are default constructible, with public access to data members. +Request and response objects have some common members, and some members unique +to the message type. These statements set all the members in each message: +``` + http::request req; + req.method = http::method_t::http_get; + req.url = "/index.html"; + req.version = 11; // HTTP/1.1 + req.headers.insert("User-Agent", "hello_world"); + req.body = ""; + + http::response resp; + resp.status = 404; + resp.reason = "Not Found"; + resp.version = 10; // HTTP/1.0 + resp.headers.insert("Server", "Beast.HTTP"); + resp.body = "The requested resource was not found."; +``` + +The following statements achieve the same effects as the statements above: +``` + http::request req({http::method_t::http_get, "/index.html", 11}); + req.headers.insert("User-Agent", "hello_world"); + req.body = ""; + + http::response resp({404, "Not Found", 10}); + resp.headers.insert("Server", "Beast.HTTP"); + resp.body = "The requested resource was not found."; +``` + +[heading Headers] + +The `message::headers` member is a container for setting the field/value +pairs in the message. These statements change the values of the headers +in the message passed: +``` + template + void set_fields(http::request& req) + { + if(! req.exists("User-Agent")) + req.insert("User-Agent", "myWebClient"); + + if(req.exists("Accept-Charset")) + req.erase("Accept-Charset"); + + req.replace("Accept", "text/plain"); + } +``` + +[heading Body] + +The `message::body` member represents the message body. Depending on the +`Body` template argument type, this could be a writable container. The +following types, provided by the library, are suitable choices for the +`Body` type: + +* [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body. +Used in GET requests where there is no message body. Example: +``` + http::request req({http::method_t::http_get, "/index.html", 11}); +``` + +* [link beast.ref.http__string_body [*`string_body`:]] A body with a +`value_type` as `std::string`. Useful for quickly putting together a request +or response with simple text in the message body (such as an error message). +Has the same insertion complexity of `std::string`. This is the type of body +used in the examples: +``` + http::response resp; + static_assert(std::is_same::value); + resp.body = "Here is the data you requested"; +``` + +* [link beast.ref.http__basic_streambuf_body [*`basic_streambuf_body`:]] A body with a +`value_type` of `streambuf`. A streambuf is an efficient storage object which +uses multiple octet arrays of varying lengths to represent data. Here is +a body that uses a `boost::asio::streambuf` as its container: +``` + template + http::response> + make_response(ConstBufferSequence const& buffers) + { + http::response> resp; + resp.body.commit(boost::asio::buffer_copy(resp.body.prepare( + boost::asio::buffer_size(buffers)), buffers)); + return resp; + } +``` + +[heading Sockets] + +The library provides simple free functions modeled after Boost.Asio to +send and receive messages on TCP/IP sockets, SSL streams, or any object +which meets the Boost.Asio type requirements (SyncReadStream, SyncWriteStream, +AsyncReadStream, and AsyncWriteStream depending on the types of operations +performed). To send messages synchronously, use one of the `http:write` +functions: +``` + void send_request(boost::asio::ip::tcp::socket& sock) + { + http::request req({http::method_t::http_get, "/index.html", 11}); + ... + http::write(sock, req); // Throws exception on error + ... + // Alternatively + boost::system::error:code ec; + http::write(sock, req, ec); + if(ec) + std::cerr << "error writing http message: " << ec.message(); + } +``` + +An asynchronous interface is available: +``` + void handle_write(boost::system::error_code); + ... + http::request req; + ... + http::async_write(sock, req, std::bind(&handle_write, std::placeholders::_1)); +``` + +When the implementation reads messages from a socket, it can read bytes lying +after the end of the message if they are present (the alternative is to read +a single byte at a time which is unsuitable for performance reasons). To +store and re-use these extra bytes on subsequent messages, the read interface +requires an additional paramter: a [link beast.types.Streambuf [*`Streambuf`]] +object. This example reads a message from the socket, with the extra bytes +stored in the streambuf parameter for use in a subsequent call to read: +``` + boost::asio::streambuf sb; + ... + http::response resp; + http::read(sock, sb, resp); // Throws exception on error + ... + // Alternatively + boost::system::error:code ec; + http::read(sock, sb, resp, ec); + if(ec) + std::cerr << "error reading http message: " << ec.message(); +``` + +As with the write function, an asynchronous interface is available. The +stream buffer parameter must remain valid until the completion handler is +called: +``` + void handle_read(boost::system::error_code); + ... + boost::asio::streambuf sb; + http::response resp; + ... + http::async_read(sock, resp, std::bind(&handle_read, std::placeholders::_1)); +``` + +An alternative to using a `boost::asio::streambuf` is to use a +[link beast.ref.streambuf `beast::streambuf`], which meets the requirements of +[*`Streambuf`] and is optimized for performance: +``` + void handle_read(boost::system::error_code); + ... + beast::streambuf sb; + http::response resp; + http::read(sock, sb, resp); +``` + +The `read` implementation can use any object meeting the requirements of +[link beast.types.Streambuf [*`Streambuf`]], allowing callers to define custom +memory management strategies used by the implementation. + +[endsect] + + + +[section:advanced Advanced] + The spectrum of hardware and software platforms which perform these typical HTTP operations is vast, ranging from powerful servers in large datacenters to tiny resource-limited embedded devices. No single concrete implementation @@ -122,10 +281,15 @@ message body as a disk file may support sending but not parsing. Many efficient and correct models of messages exist, supporting some or all of the operations listed above. -To support a variety of implementation strategies, we introduce customization -points for the header and body via class template arguments. This illustration -shows the message class template (boilerplate present in the actual -declaration has been removed for clarity): +[heading Message model] + +The message class template and provided Body types are suitable for casual +library users. This section explains the message model for advanced users +who wish to take control over aspects of the implementation. We introduce +customization points for the header and body via class template arguments. +This illustration shows more detail about the +[link beast.ref.http__message [*`message`]] class template (boilerplate +present in the actual declaration has been removed for clarity): [$images/message.png [width 580px] [height 225px]] @@ -143,45 +307,7 @@ overloaded on the type of message. -[section:body Body parameter] - -The `Body` template argument in the `message` class must meet the -[link beast.types.Body [*`Body`] requirements]. It provides customization -of the data member in the message, the algorithm for parsing, and the -algorithm for serialization: - -[$images/body.png [width 510px] [height 210px]] - -The following types, provided by the library, meet the `Body` requirements: - -* [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body. -Used in GET requests where there is no message body. - -* [link beast.ref.http__string_body [*`string_body`:]] A body with a -`value_type` of `std::string`. Useful for quickly putting together a request -or response with simple text in the message body (such as an error message). -Subject to the performance limit of strings if large amounts of data are -inserted. - -* [link beast.ref.http__basic_streambuf_body [*`basic_streambuf_body`:]] A body with a -`value_type` of `streambuf`. A streambuf is an efficient storage object which -uses multiple octet arrays of varying lengths to represent data. - -Instances of the optional nested types `writer` and `reader` perform -serialization and deserialization of the message body. If either or -both of these types are present, the message becomes serializable, parsable, -or both. They model [link beast.types.Reader [*`Reader`]] and -[link beast.types.Writer [*`Writer`]] respectively. - -For specialized applications, users may implement their own types which -meet the requirements. The examples included with this library provide a -Body implementation used to serve files in a HTTP server. - -[endsect] - - - -[section:headers Headers container] +[section:headers Headers Type] The `Headers` type represents the field/value pairs present in every HTTP message. These types implement the @@ -208,5 +334,27 @@ has_connect(FieldSequence const& fs) +[section:body Body Type] + +The `Body` template argument in the `message` class must meet the +[link beast.types.Body [*`Body`] requirements]. It provides customization +of the data member in the message, the algorithm for parsing, and the +algorithm for serialization: + +[$images/body.png [width 510px] [height 210px]] + +Instances of the optional nested types `writer` and `reader` perform +serialization and deserialization of the message body. If either or +both of these types are present, the message becomes serializable, parsable, +or both. They model [link beast.types.Reader [*`Reader`]] and +[link beast.types.Writer [*`Writer`]] respectively. + +For specialized applications, users may implement their own types which +meet the requirements. The examples included with this library provide a +Body implementation used to serve files in a HTTP server. + +[endsect] + + [endsect] diff --git a/doc/reference.xsl b/doc/reference.xsl index fd2cbb31..51d64ee2 100644 --- a/doc/reference.xsl +++ b/doc/reference.xsl @@ -40,31 +40,22 @@ - - - - - - - [endsect] @@ -288,6 +279,14 @@ + + [@ + + + + ] + + @@ -673,18 +672,16 @@ [heading Requirements] ['Header: ][^ - + ] - ['Convenience header: ] - - [^beast/asio.h] - - [^beast/http.h] + ['Convenience header: ][^beast/http.hpp] - - [^beast/wsproto.h] + + ['Convenience header: ][^beast/websocket.hpp] + + @@ -911,7 +908,7 @@ ] - + [heading Private Member Functions] [table [[Name][Description]] @@ -988,7 +985,7 @@ ] - + [heading Private Data Members] [table [[Name][Description]] @@ -1274,7 +1271,7 @@ ``` - + @@ -1423,91 +1420,12 @@ - - - + + class ``[link beast.types.Body [*Body]]`` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class ``[link beast.types.Streambuf [*Streambuf]]`` @@ -1518,22 +1436,14 @@ - + + + - - - - - - - - - - - - + + @@ -1557,6 +1467,10 @@ + + + && + & diff --git a/examples/http_stream.ipp b/examples/http_stream.ipp index b026651e..6a952b41 100644 --- a/examples/http_stream.ipp +++ b/examples/http_stream.ipp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/include/beast/async_completion.hpp b/include/beast/async_completion.hpp index 325e996b..121c037f 100644 --- a/include/beast/async_completion.hpp +++ b/include/beast/async_completion.hpp @@ -16,13 +16,12 @@ namespace beast { -/** Completion helper for implementing the extensible asynchronous model. +/** Helper for customizing the return type of asynchronous initiation functions. - This class template is used to transform caller-provided - completion tokens in calls to asynchronous initiation - functions. The transformation allows customization of - the return type of the initiating function, and the type - of the final handler. + This class template is used to transform caller-provided completion + tokens in calls to asynchronous initiation functions. The transformation + allows customization of the return type of the initiating function, and the + function signature of the final handler. @tparam CompletionToken A CompletionHandler, or a user defined type with specializations for customizing the return type (for example, @@ -30,14 +29,16 @@ namespace beast { @tparam Signature The callable signature of the final completion handler. - Usage: + Example: @code ... template - typename async_completion::result_type + typename async_completion::result_type async_initfn(..., CompletionToken&& token) { - async_completion completion(token); + async_completion completion(token); ... return completion.result.get(); } @@ -49,19 +50,19 @@ namespace beast { template struct async_completion { - /** The type of the final handler. + /** The type of the final handler called by the asynchronous initiation function. - Objects of this type will be callable with the - specified signature. + Objects of this type will be callable with the specified signature. */ using handler_type = typename boost::asio::handler_type< CompletionToken, Signature>::type; + /// The type of the value returned by the asynchronous initiation function. using result_type = typename boost::asio::async_result::type; - /** Construct the completion helper. + /** Construct the helper. @param token The completion token. Copies will be made as required. If `CompletionToken` is movable, it may also be moved. @@ -74,10 +75,10 @@ struct async_completion "Handler requirements not met"); } - /** The final completion handler, callable with the specified signature. */ + /// The final completion handler, callable with the specified signature. handler_type handler; - /** The return value of the asynchronous initiation function. */ + /// The return value of the asynchronous initiation function. boost::asio::async_result result; }; diff --git a/include/beast/basic_streambuf.hpp b/include/beast/basic_streambuf.hpp index 96003323..9ff52af5 100644 --- a/include/beast/basic_streambuf.hpp +++ b/include/beast/basic_streambuf.hpp @@ -36,6 +36,7 @@ class basic_streambuf #endif { public: + /// The type of allocator used. using allocator_type = typename std::allocator_traits:: template rebind_alloc; @@ -73,10 +74,20 @@ private: size_type out_end_ = 0; // output end offset in list_.back() public: +#if GENERATING_DOCS + /// The type used to represent the input sequence as a list of buffers. + using const_buffers_type = implementation_defined; + + /// The type used to represent the output sequence as a list of buffers. + using mutable_buffers_type = implementation_defined; + +#else class const_buffers_type; class mutable_buffers_type; +#endif + /// Destructor. ~basic_streambuf(); @@ -175,7 +186,7 @@ public: template basic_streambuf& operator=(basic_streambuf const& other); - /** Construct a stream buffer. + /** Default constructor. @param alloc_size The size of buffer to allocate. This is a soft limit, calls to prepare for buffers exceeding this size will allocate @@ -258,60 +269,6 @@ private: debug_check() const; }; -/// The type used to represent the input sequence as a list of buffers. -template -class basic_streambuf::const_buffers_type -{ - basic_streambuf const* sb_ = nullptr; - - friend class basic_streambuf; - - explicit - const_buffers_type(basic_streambuf const& sb); - -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; -}; - -/// The type used to represent the output sequence as a list of buffers. -template -class basic_streambuf::mutable_buffers_type -{ - basic_streambuf const* sb_; - - friend class basic_streambuf; - - explicit - mutable_buffers_type(basic_streambuf const& sb); - -public: - using value_type = 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; -}; - /** Format output to a stream buffer. @param streambuf The streambuf to write to. @@ -322,7 +279,7 @@ public: */ template basic_streambuf& -operator<<(basic_streambuf& buf, T const& t); +operator<<(basic_streambuf& streambuf, T const& t); /** Convert the entire basic_streambuf to a string. diff --git a/include/beast/bind_handler.hpp b/include/beast/bind_handler.hpp index e0dcdda2..cd40645c 100644 --- a/include/beast/bind_handler.hpp +++ b/include/beast/bind_handler.hpp @@ -121,7 +121,7 @@ public: Example: @code - template + template void do_cancel(AsyncReadStream& stream, ReadHandler&& handler) { diff --git a/include/beast/buffers_adapter.hpp b/include/beast/buffers_adapter.hpp index b6c6f369..708b8144 100644 --- a/include/beast/buffers_adapter.hpp +++ b/include/beast/buffers_adapter.hpp @@ -9,11 +9,6 @@ #define BEAST_BUFFERS_ADAPTER_HPP #include -#include -#include -#include -#include -#include #include namespace beast { @@ -70,19 +65,30 @@ private: } public: +#if GENERATING_DOCS + /// The type used to represent the input sequence as a list of buffers. + using const_buffers_type = implementation_defined; + + /// The type used to represent the output sequence as a list of buffers. + using mutable_buffers_type = implementation_defined; + +#else class const_buffers_type; + class mutable_buffers_type; - // Move constructor. +#endif + + /// Move constructor. buffers_adapter(buffers_adapter&& other); - // Copy constructor. + /// Copy constructor. buffers_adapter(buffers_adapter const& other); - // Move assignment. + /// Move assignment. buffers_adapter& operator=(buffers_adapter&& other); - // Copy assignment. + /// Copy assignment. buffers_adapter& operator=(buffers_adapter const&); /** Construct a buffers adapter. @@ -129,508 +135,8 @@ public: consume(std::size_t n); }; -//------------------------------------------------------------------------------ - -/// The type used to represent the input sequence as a list of buffers. -template -class buffers_adapter::const_buffers_type -{ - buffers_adapter const* ba_; - -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 buffers_adapter; - - const_buffers_type(buffers_adapter const& ba) - : ba_(&ba) - { - } -}; - -template -class buffers_adapter::const_buffers_type::const_iterator -{ - iter_type it_; - buffers_adapter const* ba_; - -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 ba_ == other.ba_ && - it_ == other.it_; - } - - bool - operator!=(const_iterator const& other) const - { - return !(*this == other); - } - - reference - operator*() const - { - using boost::asio::buffer_cast; - using boost::asio::buffer_size; - return value_type{buffer_cast(*it_), - (ba_->out_ == ba_->bs_.end() || - it_ != ba_->out_) ? buffer_size(*it_) : ba_->out_pos_} + - (it_ == ba_->begin_ ? ba_->in_pos_ : 0); - } - - 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: - friend class const_buffers_type; - - const_iterator(buffers_adapter const& ba, - iter_type iter) - : it_(iter) - , ba_(&ba) - { - } -}; - -template -inline -auto -buffers_adapter::const_buffers_type::begin() const -> - const_iterator -{ - return const_iterator{*ba_, ba_->begin_}; -} - -template -inline -auto -buffers_adapter::const_buffers_type::end() const -> - const_iterator -{ - return const_iterator{*ba_, ba_->out_ == - ba_->end_ ? ba_->end_ : std::next(ba_->out_)}; -} - -//------------------------------------------------------------------------------ - -/// The type used to represent the output sequence as a list of buffers. -template -class buffers_adapter::mutable_buffers_type -{ - buffers_adapter const* ba_; - -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 buffers_adapter; - - mutable_buffers_type( - buffers_adapter const& ba) - : ba_(&ba) - { - } -}; - -template -class buffers_adapter::mutable_buffers_type::const_iterator -{ - iter_type it_; - buffers_adapter const* ba_; - -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 ba_ == other.ba_ && - it_ == other.it_; - } - - bool - operator!=(const_iterator const& other) const - { - return !(*this == other); - } - - reference - operator*() const - { - using boost::asio::buffer_cast; - using boost::asio::buffer_size; - return value_type{buffer_cast(*it_), - it_ == std::prev(ba_->end_) ? - ba_->out_end_ : buffer_size(*it_)} + - (it_ == ba_->out_ ? ba_->out_pos_ : 0); - } - - 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: - friend class mutable_buffers_type; - - const_iterator(buffers_adapter const& ba, - iter_type iter) - : it_(iter) - , ba_(&ba) - { - } -}; - -template -inline -auto -buffers_adapter::mutable_buffers_type::begin() const -> - const_iterator -{ - return const_iterator{*ba_, ba_->out_}; -} - -template -inline -auto -buffers_adapter::mutable_buffers_type::end() const -> - const_iterator -{ - return const_iterator{*ba_, ba_->end_}; -} - -//------------------------------------------------------------------------------ - -template -buffers_adapter::buffers_adapter( - buffers_adapter&& other) - : buffers_adapter(std::move(other), - std::distance(other.bs_.begin(), other.begin_), - std::distance(other.bs_.begin(), other.out_), - std::distance(other.bs_.begin(), other.end_)) -{ -} - -template -buffers_adapter::buffers_adapter( - buffers_adapter const& other) - : buffers_adapter(other, - std::distance(other.bs_.begin(), other.begin_), - std::distance(other.bs_.begin(), other.out_), - std::distance(other.bs_.begin(), other.end_)) -{ -} - -template -auto -buffers_adapter::operator=( - buffers_adapter&& other) -> buffers_adapter& -{ - auto const nbegin = std::distance( - other.bs_.begin(), other.begin_); - auto const nout = std::distance( - other.bs_.begin(), other.out_); - auto const nend = std::distance( - other.bs_.begin(), other.end_); - bs_ = std::move(other.bs_); - begin_ = std::next(bs_.begin(), nbegin); - out_ = std::next(bs_.begin(), nout); - end_ = std::next(bs_.begin(), 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 -auto -buffers_adapter::operator=( - buffers_adapter const& other) -> buffers_adapter& -{ - auto const nbegin = std::distance( - other.bs_.begin(), other.begin_); - auto const nout = std::distance( - other.bs_.begin(), other.out_); - auto const nend = std::distance( - other.bs_.begin(), other.end_); - bs_ = other.bs_; - begin_ = std::next(bs_.begin(), nbegin); - out_ = std::next(bs_.begin(), nout); - end_ = std::next(bs_.begin(), 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 -buffers_adapter::buffers_adapter( - Buffers const& bs) - : bs_(bs) - , begin_(bs_.begin()) - , out_(bs_.begin()) - , end_(bs_.begin()) - , max_size_(boost::asio::buffer_size(bs_)) -{ -} - -template -auto -buffers_adapter::prepare(std::size_t n) -> - mutable_buffers_type -{ - using boost::asio::buffer_size; - static_assert(is_mutable, - "Operation not valid for ConstBufferSequence"); - end_ = out_; - if(end_ != bs_.end()) - { - auto size = buffer_size(*end_) - out_pos_; - if(n > size) - { - n -= size; - while(++end_ != bs_.end()) - { - size = buffer_size(*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) - throw std::length_error( - "no space in buffers_adapter"); - return mutable_buffers_type{*this}; -} - -template -void -buffers_adapter::commit(std::size_t n) -{ - using boost::asio::buffer_size; - static_assert(is_mutable, - "Operation not valid for ConstBufferSequence"); - if(out_ == end_) - return; - auto const last = std::prev(end_); - while(out_ != last) - { - auto const avail = - buffer_size(*out_) - out_pos_; - if(n < avail) - { - out_pos_ += n; - in_size_ += n; - max_size_ -= n; - return; - } - ++out_; - n -= avail; - out_pos_ = 0; - in_size_ += avail; - max_size_ -= avail; - } - - n = std::min(n, out_end_ - out_pos_); - out_pos_ += n; - in_size_ += n; - max_size_ -= n; - if(out_pos_ == buffer_size(*out_)) - { - ++out_; - out_pos_ = 0; - out_end_ = 0; - } -} - -template -inline -auto -buffers_adapter::data() const -> - const_buffers_type -{ - return const_buffers_type{*this}; -} - -template -void -buffers_adapter::consume(std::size_t n) -{ - for(;;) - { - if(begin_ != out_) - { - auto const avail = - buffer_size(*begin_) - in_pos_; - if(n < avail) - { - in_size_ -= n; - in_pos_ += n; - break; - } - n -= avail; - in_size_ -= avail; - in_pos_ = 0; - ++begin_; - } - else - { - auto const avail = out_pos_ - in_pos_; - if(n < avail) - { - in_size_ -= n; - in_pos_ += n; - } - else - { - in_size_ -= avail; - if(out_pos_ != out_end_|| - out_ != std::prev(bs_.end())) - { - in_pos_ = out_pos_; - } - else - { - // Use the whole buffer now. - in_pos_ = 0; - out_pos_ = 0; - out_end_ = 0; - } - } - break; - } - } -} - } // beast +#include + #endif diff --git a/include/beast/buffers_debug.hpp b/include/beast/buffers_debug.hpp index b25349f9..61566863 100644 --- a/include/beast/buffers_debug.hpp +++ b/include/beast/buffers_debug.hpp @@ -14,6 +14,11 @@ namespace beast { namespace debug { +/** Diagnostic utility to convert a `ConstBufferSequence` to a string. + + @note Carriage returns and linefeeds will have additional escape + representations printed for visibility. +*/ template std::string buffers_to_string(Buffers const& bs) diff --git a/include/beast/consuming_buffers.hpp b/include/beast/consuming_buffers.hpp index 57d34f0e..752c3dbe 100644 --- a/include/beast/consuming_buffers.hpp +++ b/include/beast/consuming_buffers.hpp @@ -8,7 +8,6 @@ #ifndef BEAST_CONSUMING_BUFFERS_HPP #define BEAST_CONSUMING_BUFFERS_HPP -#include #include #include #include @@ -64,8 +63,15 @@ public: /// The type for each element in the list of buffers. using value_type = ValueType; +#if GENERATING_DOCS + /// A bidirectional iterator type that may be used to read elements. + using const_iterator = implementation_defined; + +#else class const_iterator; +#endif + /// Move constructor. consuming_buffers(consuming_buffers&&); @@ -104,194 +110,13 @@ public: consume(std::size_t n); }; -/// A bidirectional iterator type that may be used to read elements. -template -class consuming_buffers::const_iterator -{ - friend class consuming_buffers; - - using iter_type = - typename Buffers::const_iterator; - - iter_type it_; - consuming_buffers const* b_; - -public: - using value_type = - typename std::iterator_traits::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&& 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 b_ == other.b_ && it_ == other.it_; - } - - bool - operator!=(const_iterator const& other) const - { - return !(*this == other); - } - - reference - operator*() const - { - if(it_ == b_->begin_) - return *it_ + b_->skip_; - return *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(consuming_buffers const& b, - iter_type it) - : it_(it) - , b_(&b) - { - } -}; - -template -consuming_buffers:: -consuming_buffers(consuming_buffers&& other) - : consuming_buffers(std::move(other), - std::distance( - other.bs_.begin(), other.begin_)) -{ -} - -template -consuming_buffers:: -consuming_buffers(consuming_buffers const& other) - : consuming_buffers(other, - std::distance( - other.bs_.begin(), other.begin_)) -{ -} - -template -auto -consuming_buffers:: -operator=(consuming_buffers&& other) -> - consuming_buffers& -{ - auto const nbegin = std::distance( - other.bs_.begin(), other.begin_); - bs_ = std::move(other.bs_); - begin_ = std::next(bs_.begin(), nbegin); - skip_ = other.skip_; - return *this; -} - -template -auto -consuming_buffers:: -operator=(consuming_buffers const& other) -> - consuming_buffers& -{ - auto const nbegin = std::distance( - other.bs_.begin(), other.begin_); - bs_ = other.bs_; - begin_ = std::next(bs_.begin(), nbegin); - skip_ = other.skip_; - return *this; -} - -template -consuming_buffers:: -consuming_buffers(Buffers const& bs) - : bs_(bs) - , begin_(bs_.begin()) -{ -} - -template -auto -consuming_buffers::begin() const -> - const_iterator -{ - return const_iterator{*this, begin_}; -} - -template -auto -consuming_buffers::end() const -> - const_iterator -{ - return const_iterator{*this, bs_.end()}; -} - -template -void -consuming_buffers::consume(std::size_t n) -{ - using boost::asio::buffer_size; - for(;n > 0 && begin_ != bs_.end(); ++begin_) - { - auto const len = - buffer_size(*begin_) - skip_; - if(n < len) - { - skip_ += n; - break; - } - n -= len; - skip_ = 0; - } -} - /// Returns a consumed buffer template consuming_buffers -consumed_buffers(Buffers const& bs, std::size_t n) -{ - consuming_buffers cb(bs); - cb.consume(n); - return cb; -} +consumed_buffers(Buffers const& bs, std::size_t n); } // beast +#include + #endif diff --git a/include/beast/handler_alloc.hpp b/include/beast/handler_alloc.hpp index afde93e9..37ca25b1 100644 --- a/include/beast/handler_alloc.hpp +++ b/include/beast/handler_alloc.hpp @@ -22,12 +22,21 @@ namespace beast { /** An allocator that uses handler customizations. This allocator uses the handler customizations `asio_handler_allocate` - and `asio_handler_deallocate` to manage memory. + and `asio_handler_deallocate` to manage memory. It meets the requirements + of `Allocator` and can be used anywhere a `std::allocator` is + accepted. - @tparam T The type of object + @tparam T The type of objects allocated by the allocator. @tparam Handler The type of handler. + + @note Allocated memory is only valid until the handler is called. The + caller is still responsible for freeing memory. */ +#if GENERATING_DOCS +template +class handler_alloc; +#else template class handler_alloc { @@ -132,6 +141,7 @@ public: return !(lhs == rhs); } }; +#endif } // beast diff --git a/include/beast/http.hpp b/include/beast/http.hpp index 61db5985..47bc45b3 100644 --- a/include/beast/http.hpp +++ b/include/beast/http.hpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #endif diff --git a/include/beast/http/empty_body.hpp b/include/beast/http/empty_body.hpp index d1d076fe..11d2ff91 100644 --- a/include/beast/http/empty_body.hpp +++ b/include/beast/http/empty_body.hpp @@ -22,9 +22,16 @@ namespace http { */ struct empty_body { - struct value_type - { - }; +#if GENERATING_DOCS + /// The type of the `message::body` member + using value_type = void; +#else + struct value_type {}; +#endif + +#if GENERATING_DOCS +private: +#endif struct reader { diff --git a/include/beast/http/impl/message.ipp b/include/beast/http/impl/message.ipp index 8e25a6c6..23d748d9 100644 --- a/include/beast/http/impl/message.ipp +++ b/include/beast/http/impl/message.ipp @@ -9,7 +9,6 @@ #define BEAST_HTTP_IMPL_MESSAGE_IPP #include -#include #include #include #include @@ -26,16 +25,12 @@ template message:: message() { - static_assert(is_Body::value, - "Body requirements not met"); } template message:: message(request_params params) { - static_assert(is_Body::value, - "Body requirements not met"); static_assert(isRequest, "message is not a request"); this->method = params.method; this->url = std::move(params.url); @@ -46,8 +41,6 @@ template message:: message(response_params params) { - static_assert(is_Body::value, - "Body requirements not met"); static_assert(! isRequest, "message is not a response"); this->status = params.status; this->reason = std::move(params.reason); @@ -160,8 +153,6 @@ std::ostream& operator<<(std::ostream& os, message const& msg) { - static_assert(is_WritableBody::value, - "WritableBody requirements not met"); error_code ec; detail::write_preparation wp(msg); wp.init(ec); diff --git a/include/beast/http/impl/read.ipp b/include/beast/http/impl/read.ipp index 4c5b86d0..a507d28a 100644 --- a/include/beast/http/impl/read.ipp +++ b/include/beast/http/impl/read.ipp @@ -8,7 +8,6 @@ #ifndef BEAST_HTTP_IMPL_READ_IPP_HPP #define BEAST_HTTP_IMPL_READ_IPP_HPP -#include #include #include #include @@ -219,8 +218,6 @@ read(SyncReadStream& stream, Streambuf& streambuf, "SyncReadStream requirements not met"); static_assert(is_Streambuf::value, "Streambuf requirements not met"); - static_assert(is_ReadableBody::value, - "ReadableBody requirements not met"); parser p; for(;;) { @@ -268,8 +265,6 @@ async_read(AsyncReadStream& stream, Streambuf& streambuf, "AsyncReadStream requirements not met"); static_assert(is_Streambuf::value, "Streambuf requirements not met"); - static_assert(is_ReadableBody::value, - "ReadableBody requirements not met"); beast::async_completion completion(handler); detail::read_op #include -#include #include #include #include @@ -265,9 +264,9 @@ operator()(error_code ec, std::size_t, bool again) case 4: // VFALCO Unfortunately the current interface to the - // Writer concept prevents us from using coalescing the + // Writer concept prevents us from coalescing the // final body chunk with the final chunk delimiter. - // + // // write final chunk d.state = 5; boost::asio::async_write(d.s, @@ -359,8 +358,6 @@ write(SyncWriteStream& stream, message const& msg, boost::system::error_code& ec) { - static_assert(is_WritableBody::value, - "WritableBody requirements not met"); detail::write_preparation wp(msg); wp.init(ec); if(ec) @@ -447,8 +444,6 @@ async_write(AsyncWriteStream& stream, static_assert( is_AsyncWriteStream::value, "AsyncWriteStream requirements not met"); - static_assert(is_WritableBody::value, - "WritableBody requirements not met"); beast::async_completion completion(handler); detail::write_op - friend + friend std::ostream& operator<<(std::ostream& os, message const& m); diff --git a/include/beast/http/read.hpp b/include/beast/http/read.hpp index 6b2ef3ab..78cfa5a3 100644 --- a/include/beast/http/read.hpp +++ b/include/beast/http/read.hpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/include/beast/http/rfc2616.hpp b/include/beast/http/rfc2616.hpp index 254eca98..e3c4b844 100644 --- a/include/beast/http/rfc2616.hpp +++ b/include/beast/http/rfc2616.hpp @@ -21,6 +21,8 @@ namespace beast { +#if ! GENERATING_DOCS + /** Routines for performing RFC2616 compliance. RFC2616: Hypertext Transfer Protocol -- HTTP/1.1 @@ -454,6 +456,8 @@ token_in_list(boost::string_ref const& value, } // rfc2616 +#endif + } // beast #endif diff --git a/include/beast/http/streambuf_body.hpp b/include/beast/http/streambuf_body.hpp index 7271da7d..745935d1 100644 --- a/include/beast/http/streambuf_body.hpp +++ b/include/beast/http/streambuf_body.hpp @@ -23,8 +23,13 @@ namespace http { template struct basic_streambuf_body { + /// The type of the `message::body` member using value_type = Streambuf; +#if GENERATING_DOCS +private: +#endif + class reader { value_type& sb_; diff --git a/include/beast/http/string_body.hpp b/include/beast/http/string_body.hpp index 19f98226..2711f8c1 100644 --- a/include/beast/http/string_body.hpp +++ b/include/beast/http/string_body.hpp @@ -23,8 +23,13 @@ namespace http { */ struct string_body { + /// The type of the `message::body` member using value_type = std::string; +#if GENERATING_DOCS +private: +#endif + class reader { value_type& s_; diff --git a/include/beast/http/type_check.hpp b/include/beast/http/type_check.hpp deleted file mode 100644 index 4e9dc457..00000000 --- a/include/beast/http/type_check.hpp +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (c) 2013-2016 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) -// - -#ifndef BEAST_HTTP_TYPE_CHECK_HPP -#define BEAST_HTTP_TYPE_CHECK_HPP - -#include - -namespace beast { -namespace http { - -/// Evaluates to std::true_type if `T` models Body -template -struct is_Body : std::true_type -{ -}; - -/// Evalulates to std::true_type if Body has a reader -template -struct is_ReadableBody : std::true_type -{ -}; - -/// Evalulates to std::true_type if Body has a writer -template -struct is_WritableBody : std::true_type -{ -}; - -/// Evaluates to std::true_type if `T` models HTTPMessage -template -struct is_HTTPMessage : std::false_type -{ -}; - -/// Evaluates to std::true_type if `HTTPMessage` is a request -template -struct is_HTTPRequest : std::true_type -{ -}; - -} // http -} // beast - -#endif diff --git a/include/beast/impl/basic_streambuf.ipp b/include/beast/impl/basic_streambuf.ipp index edf88eec..7ba989ee 100644 --- a/include/beast/impl/basic_streambuf.ipp +++ b/include/beast/impl/basic_streambuf.ipp @@ -115,6 +115,59 @@ public: } }; +template +class basic_streambuf::const_buffers_type +{ + basic_streambuf const* sb_ = nullptr; + + friend class basic_streambuf; + + explicit + const_buffers_type(basic_streambuf const& sb); + +public: + /// Why? + 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; +}; + +template +class basic_streambuf::mutable_buffers_type +{ + basic_streambuf const* sb_; + + friend class basic_streambuf; + + explicit + mutable_buffers_type(basic_streambuf const& sb); + +public: + using value_type = 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; +}; + //------------------------------------------------------------------------------ template @@ -798,16 +851,16 @@ basic_streambuf::debug_check() const template basic_streambuf& -operator<<(basic_streambuf& buf, T const& t) +operator<<(basic_streambuf& streambuf, T const& t) { using boost::asio::buffer; using boost::asio::buffer_copy; std::stringstream ss; ss << t; auto const& s = ss.str(); - buf.commit(buffer_copy(buf.prepare(s.size()), - boost::asio::buffer(s))); - return buf; + streambuf.commit(buffer_copy( + streambuf.prepare(s.size()), buffer(s))); + return streambuf; } //------------------------------------------------------------------------------ diff --git a/include/beast/impl/buffers_adapter.ipp b/include/beast/impl/buffers_adapter.ipp new file mode 100644 index 00000000..0040fd5a --- /dev/null +++ b/include/beast/impl/buffers_adapter.ipp @@ -0,0 +1,520 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_IMPL_BUFFERS_ADAPTER_IPP +#define BEAST_IMPL_BUFFERS_ADAPTER_IPP + +#include +#include +#include +#include +#include +#include + +namespace beast { + +template +class buffers_adapter::const_buffers_type +{ + buffers_adapter const* ba_; + +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 buffers_adapter; + + const_buffers_type(buffers_adapter const& ba) + : ba_(&ba) + { + } +}; + +template +class buffers_adapter::const_buffers_type::const_iterator +{ + iter_type it_; + buffers_adapter const* ba_; + +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 ba_ == other.ba_ && + it_ == other.it_; + } + + bool + operator!=(const_iterator const& other) const + { + return !(*this == other); + } + + reference + operator*() const + { + using boost::asio::buffer_cast; + using boost::asio::buffer_size; + return value_type{buffer_cast(*it_), + (ba_->out_ == ba_->bs_.end() || + it_ != ba_->out_) ? buffer_size(*it_) : ba_->out_pos_} + + (it_ == ba_->begin_ ? ba_->in_pos_ : 0); + } + + 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: + friend class const_buffers_type; + + const_iterator(buffers_adapter const& ba, + iter_type iter) + : it_(iter) + , ba_(&ba) + { + } +}; + +template +inline +auto +buffers_adapter::const_buffers_type::begin() const -> + const_iterator +{ + return const_iterator{*ba_, ba_->begin_}; +} + +template +inline +auto +buffers_adapter::const_buffers_type::end() const -> + const_iterator +{ + return const_iterator{*ba_, ba_->out_ == + ba_->end_ ? ba_->end_ : std::next(ba_->out_)}; +} + +//------------------------------------------------------------------------------ + +template +class buffers_adapter::mutable_buffers_type +{ + buffers_adapter const* ba_; + +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 buffers_adapter; + + mutable_buffers_type( + buffers_adapter const& ba) + : ba_(&ba) + { + } +}; + +template +class buffers_adapter::mutable_buffers_type::const_iterator +{ + iter_type it_; + buffers_adapter const* ba_; + +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 ba_ == other.ba_ && + it_ == other.it_; + } + + bool + operator!=(const_iterator const& other) const + { + return !(*this == other); + } + + reference + operator*() const + { + using boost::asio::buffer_cast; + using boost::asio::buffer_size; + return value_type{buffer_cast(*it_), + it_ == std::prev(ba_->end_) ? + ba_->out_end_ : buffer_size(*it_)} + + (it_ == ba_->out_ ? ba_->out_pos_ : 0); + } + + 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: + friend class mutable_buffers_type; + + const_iterator(buffers_adapter const& ba, + iter_type iter) + : it_(iter) + , ba_(&ba) + { + } +}; + +template +inline +auto +buffers_adapter::mutable_buffers_type::begin() const -> + const_iterator +{ + return const_iterator{*ba_, ba_->out_}; +} + +template +inline +auto +buffers_adapter::mutable_buffers_type::end() const -> + const_iterator +{ + return const_iterator{*ba_, ba_->end_}; +} + +//------------------------------------------------------------------------------ + +template +buffers_adapter::buffers_adapter( + buffers_adapter&& other) + : buffers_adapter(std::move(other), + std::distance(other.bs_.begin(), other.begin_), + std::distance(other.bs_.begin(), other.out_), + std::distance(other.bs_.begin(), other.end_)) +{ +} + +template +buffers_adapter::buffers_adapter( + buffers_adapter const& other) + : buffers_adapter(other, + std::distance(other.bs_.begin(), other.begin_), + std::distance(other.bs_.begin(), other.out_), + std::distance(other.bs_.begin(), other.end_)) +{ +} + +template +auto +buffers_adapter::operator=( + buffers_adapter&& other) -> buffers_adapter& +{ + auto const nbegin = std::distance( + other.bs_.begin(), other.begin_); + auto const nout = std::distance( + other.bs_.begin(), other.out_); + auto const nend = std::distance( + other.bs_.begin(), other.end_); + bs_ = std::move(other.bs_); + begin_ = std::next(bs_.begin(), nbegin); + out_ = std::next(bs_.begin(), nout); + end_ = std::next(bs_.begin(), 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 +auto +buffers_adapter::operator=( + buffers_adapter const& other) -> buffers_adapter& +{ + auto const nbegin = std::distance( + other.bs_.begin(), other.begin_); + auto const nout = std::distance( + other.bs_.begin(), other.out_); + auto const nend = std::distance( + other.bs_.begin(), other.end_); + bs_ = other.bs_; + begin_ = std::next(bs_.begin(), nbegin); + out_ = std::next(bs_.begin(), nout); + end_ = std::next(bs_.begin(), 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 +buffers_adapter::buffers_adapter( + Buffers const& bs) + : bs_(bs) + , begin_(bs_.begin()) + , out_(bs_.begin()) + , end_(bs_.begin()) + , max_size_(boost::asio::buffer_size(bs_)) +{ +} + +template +auto +buffers_adapter::prepare(std::size_t n) -> + mutable_buffers_type +{ + using boost::asio::buffer_size; + static_assert(is_mutable, + "Operation not valid for ConstBufferSequence"); + end_ = out_; + if(end_ != bs_.end()) + { + auto size = buffer_size(*end_) - out_pos_; + if(n > size) + { + n -= size; + while(++end_ != bs_.end()) + { + size = buffer_size(*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) + throw std::length_error( + "no space in buffers_adapter"); + return mutable_buffers_type{*this}; +} + +template +void +buffers_adapter::commit(std::size_t n) +{ + using boost::asio::buffer_size; + static_assert(is_mutable, + "Operation not valid for ConstBufferSequence"); + if(out_ == end_) + return; + auto const last = std::prev(end_); + while(out_ != last) + { + auto const avail = + buffer_size(*out_) - out_pos_; + if(n < avail) + { + out_pos_ += n; + in_size_ += n; + max_size_ -= n; + return; + } + ++out_; + n -= avail; + out_pos_ = 0; + in_size_ += avail; + max_size_ -= avail; + } + + n = std::min(n, out_end_ - out_pos_); + out_pos_ += n; + in_size_ += n; + max_size_ -= n; + if(out_pos_ == buffer_size(*out_)) + { + ++out_; + out_pos_ = 0; + out_end_ = 0; + } +} + +template +inline +auto +buffers_adapter::data() const -> + const_buffers_type +{ + return const_buffers_type{*this}; +} + +template +void +buffers_adapter::consume(std::size_t n) +{ + for(;;) + { + if(begin_ != out_) + { + auto const avail = + buffer_size(*begin_) - in_pos_; + if(n < avail) + { + in_size_ -= n; + in_pos_ += n; + break; + } + n -= avail; + in_size_ -= avail; + in_pos_ = 0; + ++begin_; + } + else + { + auto const avail = out_pos_ - in_pos_; + if(n < avail) + { + in_size_ -= n; + in_pos_ += n; + } + else + { + in_size_ -= avail; + if(out_pos_ != out_end_|| + out_ != std::prev(bs_.end())) + { + in_pos_ = out_pos_; + } + else + { + // Use the whole buffer now. + in_pos_ = 0; + out_pos_ = 0; + out_end_ = 0; + } + } + break; + } + } +} + +} // beast + +#endif diff --git a/include/beast/impl/consuming_buffers.ipp b/include/beast/impl/consuming_buffers.ipp new file mode 100644 index 00000000..4aa203f5 --- /dev/null +++ b/include/beast/impl/consuming_buffers.ipp @@ -0,0 +1,211 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_IMPL_CONSUMING_BUFFERS_IPP +#define BEAST_IMPL_CONSUMING_BUFFERS_IPP + +#include +#include +#include +#include +#include +#include +#include + +namespace beast { + +template +class consuming_buffers::const_iterator +{ + friend class consuming_buffers; + + using iter_type = + typename Buffers::const_iterator; + + iter_type it_; + consuming_buffers const* b_; + +public: + using value_type = + typename std::iterator_traits::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&& 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 b_ == other.b_ && it_ == other.it_; + } + + bool + operator!=(const_iterator const& other) const + { + return !(*this == other); + } + + reference + operator*() const + { + if(it_ == b_->begin_) + return *it_ + b_->skip_; + return *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(consuming_buffers const& b, + iter_type it) + : it_(it) + , b_(&b) + { + } +}; + +template +consuming_buffers:: +consuming_buffers(consuming_buffers&& other) + : consuming_buffers(std::move(other), + std::distance( + other.bs_.begin(), other.begin_)) +{ +} + +template +consuming_buffers:: +consuming_buffers(consuming_buffers const& other) + : consuming_buffers(other, + std::distance( + other.bs_.begin(), other.begin_)) +{ +} + +template +auto +consuming_buffers:: +operator=(consuming_buffers&& other) -> + consuming_buffers& +{ + auto const nbegin = std::distance( + other.bs_.begin(), other.begin_); + bs_ = std::move(other.bs_); + begin_ = std::next(bs_.begin(), nbegin); + skip_ = other.skip_; + return *this; +} + +template +auto +consuming_buffers:: +operator=(consuming_buffers const& other) -> + consuming_buffers& +{ + auto const nbegin = std::distance( + other.bs_.begin(), other.begin_); + bs_ = other.bs_; + begin_ = std::next(bs_.begin(), nbegin); + skip_ = other.skip_; + return *this; +} + +template +consuming_buffers:: +consuming_buffers(Buffers const& bs) + : bs_(bs) + , begin_(bs_.begin()) +{ + static_assert(is_BufferSequence::value, + "BufferSequence requirements not met"); +} + +template +auto +consuming_buffers::begin() const -> + const_iterator +{ + return const_iterator{*this, begin_}; +} + +template +auto +consuming_buffers::end() const -> + const_iterator +{ + return const_iterator{*this, bs_.end()}; +} + +template +void +consuming_buffers::consume(std::size_t n) +{ + using boost::asio::buffer_size; + for(;n > 0 && begin_ != bs_.end(); ++begin_) + { + auto const len = + buffer_size(*begin_) - skip_; + if(n < len) + { + skip_ += n; + break; + } + n -= len; + skip_ = 0; + } +} + +template +consuming_buffers +consumed_buffers(Buffers const& bs, std::size_t n) +{ + consuming_buffers cb(bs); + cb.consume(n); + return cb; +} + +} // beast + +#endif diff --git a/include/beast/impl/prepare_buffers.ipp b/include/beast/impl/prepare_buffers.ipp new file mode 100644 index 00000000..65de4a3b --- /dev/null +++ b/include/beast/impl/prepare_buffers.ipp @@ -0,0 +1,215 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_IMPL_PREPARE_BUFFERS_IPP +#define BEAST_IMPL_PREPARE_BUFFERS_IPP + +#include +#include +#include +#include +#include +#include + +namespace beast { + +template +void +prepared_buffers:: +setup(std::size_t n) +{ + for(end_ = bs_.begin(); end_ != bs_.end(); ++end_) + { + auto const len = + boost::asio::buffer_size(*end_); + if(n <= len) + { + size_ = n; + back_ = end_++; + return; + } + n -= len; + } + size_ = 0; + back_ = end_; +} + +template +class prepared_buffers::const_iterator +{ + friend class prepared_buffers; + + using iter_type = + typename BufferSequence::const_iterator; + + prepared_buffers const* b_; + typename BufferSequence::const_iterator it_; + +public: + using value_type = + typename std::iterator_traits::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&& 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 b_ == other.b_ && it_ == other.it_; + } + + bool + operator!=(const_iterator const& other) const + { + return !(*this == other); + } + + reference + operator*() const + { + if(it_ == b_->back_) + return prepare_buffer(b_->size_, *it_); + return *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(prepared_buffers const& b, + bool at_end) + : b_(&b) + , it_(at_end ? b.end_ : b.bs_.begin()) + { + } +}; + +template +prepared_buffers:: +prepared_buffers(prepared_buffers&& other) + : prepared_buffers(std::move(other), + std::distance(other.bs_.begin(), other.back_), + std::distance(other.bs_.begin(), other.end_)) +{ +} + +template +prepared_buffers:: +prepared_buffers(prepared_buffers const& other) + : prepared_buffers(other, + std::distance(other.bs_.begin(), other.back_), + std::distance(other.bs_.begin(), other.end_)) +{ +} + +template +auto +prepared_buffers:: +operator=(prepared_buffers&& other) -> + prepared_buffers& +{ + auto const nback = std::distance( + other.bs_.begin(), other.back_); + auto const nend = std::distance( + other.bs_.begin(), other.end_); + bs_ = std::move(other.bs_); + back_ = std::next(bs_.begin(), nback); + end_ = std::next(bs_.begin(), nend); + size_ = other.size_; + return *this; +} + +template +auto +prepared_buffers:: +operator=(prepared_buffers const& other) -> + prepared_buffers& +{ + auto const nback = std::distance( + other.bs_.begin(), other.back_); + auto const nend = std::distance( + other.bs_.begin(), other.end_); + bs_ = other.bs_; + back_ = std::next(bs_.begin(), nback); + end_ = std::next(bs_.begin(), nend); + size_ = other.size_; + return *this; +} + +template +prepared_buffers:: +prepared_buffers(std::size_t n, BufferSequence const& bs) + : bs_(bs) +{ + setup(n); +} + +template +auto +prepared_buffers::begin() const -> + const_iterator +{ + return const_iterator{*this, false}; +} + +template +auto +prepared_buffers::end() const -> + const_iterator +{ + return const_iterator{*this, true}; +} + +template +inline +prepared_buffers +prepare_buffers(std::size_t n, BufferSequence const& buffers) +{ + return prepared_buffers(n, buffers); +} + +} // beast + +#endif diff --git a/include/beast/impl/static_streambuf.ipp b/include/beast/impl/static_streambuf.ipp new file mode 100644 index 00000000..0d75a820 --- /dev/null +++ b/include/beast/impl/static_streambuf.ipp @@ -0,0 +1,304 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_IMPL_STATIC_STREAMBUF_IPP +#define BEAST_IMPL_STATIC_STREAMBUF_IPP + +#include +#include +#include +#include +#include + +namespace beast { + +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_}; +} + +//------------------------------------------------------------------------------ + +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(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(out_ - in_)}; +} + +} // beast + +#endif diff --git a/include/beast/prepare_buffers.hpp b/include/beast/prepare_buffers.hpp index e2009bc0..cb3a0099 100644 --- a/include/beast/prepare_buffers.hpp +++ b/include/beast/prepare_buffers.hpp @@ -85,8 +85,15 @@ public: using value_type = typename std::iterator_traits::value_type; +#if GENERATING_DOCS + /// A bidirectional iterator type that may be used to read elements. + using const_iterator = implementation_defined; + +#else class const_iterator; +#endif + /// Move constructor. prepared_buffers(prepared_buffers&&); @@ -120,190 +127,9 @@ public: private: void - setup(std::size_t n) - { - for(end_ = bs_.begin(); end_ != bs_.end(); ++end_) - { - auto const len = - boost::asio::buffer_size(*end_); - if(n <= len) - { - size_ = n; - back_ = end_++; - return; - } - n -= len; - } - size_ = 0; - back_ = end_; - } + setup(std::size_t n); }; -/// A bidirectional iterator type that may be used to read elements. -template -class prepared_buffers::const_iterator -{ - friend class prepared_buffers; - - using iter_type = - typename BufferSequence::const_iterator; - - prepared_buffers const* b_; - typename BufferSequence::const_iterator it_; - -public: - using value_type = - typename std::iterator_traits::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&& 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 b_ == other.b_ && it_ == other.it_; - } - - bool - operator!=(const_iterator const& other) const - { - return !(*this == other); - } - - reference - operator*() const - { - if(it_ == b_->back_) - return prepare_buffer(b_->size_, *it_); - return *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(prepared_buffers const& b, - bool at_end) - : b_(&b) - , it_(at_end ? b.end_ : b.bs_.begin()) - { - } -}; - -template -prepared_buffers:: -prepared_buffers(prepared_buffers&& other) - : prepared_buffers(std::move(other), - std::distance(other.bs_.begin(), other.back_), - std::distance(other.bs_.begin(), other.end_)) -{ -} - -template -prepared_buffers:: -prepared_buffers(prepared_buffers const& other) - : prepared_buffers(other, - std::distance(other.bs_.begin(), other.back_), - std::distance(other.bs_.begin(), other.end_)) -{ -} - -template -auto -prepared_buffers:: -operator=(prepared_buffers&& other) -> - prepared_buffers& -{ - auto const nback = std::distance( - other.bs_.begin(), other.back_); - auto const nend = std::distance( - other.bs_.begin(), other.end_); - bs_ = std::move(other.bs_); - back_ = std::next(bs_.begin(), nback); - end_ = std::next(bs_.begin(), nend); - size_ = other.size_; - return *this; -} - -template -auto -prepared_buffers:: -operator=(prepared_buffers const& other) -> - prepared_buffers& -{ - auto const nback = std::distance( - other.bs_.begin(), other.back_); - auto const nend = std::distance( - other.bs_.begin(), other.end_); - bs_ = other.bs_; - back_ = std::next(bs_.begin(), nback); - end_ = std::next(bs_.begin(), nend); - size_ = other.size_; - return *this; -} - -template -prepared_buffers:: -prepared_buffers(std::size_t n, BufferSequence const& bs) - : bs_(bs) -{ - setup(n); -} - -template -auto -prepared_buffers::begin() const -> - const_iterator -{ - return const_iterator{*this, false}; -} - -template -auto -prepared_buffers::end() const -> - const_iterator -{ - return const_iterator{*this, true}; -} - //------------------------------------------------------------------------------ /** Return a trimmed, wrapped buffer sequence. @@ -321,13 +147,11 @@ prepared_buffers::end() const -> will be made, but ownership of the underlying memory is not transferred. */ template -inline prepared_buffers -prepare_buffers(std::size_t n, BufferSequence const& buffers) -{ - return prepared_buffers(n, buffers); -} +prepare_buffers(std::size_t n, BufferSequence const& buffers); } // beast +#include + #endif diff --git a/include/beast/static_streambuf.hpp b/include/beast/static_streambuf.hpp index 65d6df95..36c298d6 100644 --- a/include/beast/static_streambuf.hpp +++ b/include/beast/static_streambuf.hpp @@ -8,12 +8,10 @@ #ifndef BEAST_STATIC_STREAMBUF_HPP #define BEAST_STATIC_STREAMBUF_HPP -#include #include #include +#include #include -#include -#include namespace beast { @@ -40,18 +38,23 @@ protected: std::uint8_t* end_; public: +#if GENERATING_DOCS + /// The type used to represent the input sequence as a list of buffers. + using const_buffers_type = implementation_defined; + + /// The type used to represent the output sequence as a list of buffers. + using mutable_buffers_type = implementation_defined; + +#else 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. @@ -116,293 +119,6 @@ protected: //------------------------------------------------------------------------------ -/// 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(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(out_ - in_)}; -} - -//------------------------------------------------------------------------------ - /** A `Streambuf` with a fixed size internal buffer. @tparam N The number of bytes in the internal buffer. @@ -456,4 +172,6 @@ public: } // beast +#include + #endif diff --git a/include/beast/websocket/error.hpp b/include/beast/websocket/error.hpp index 0283483f..09cbdcc1 100644 --- a/include/beast/websocket/error.hpp +++ b/include/beast/websocket/error.hpp @@ -13,6 +13,7 @@ namespace beast { namespace websocket { +/// The type of error used by functions and completion handlers. using error_code = boost::system::error_code; /// Error values diff --git a/test/Jamfile b/test/Jamfile index 329495b8..e384b441 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -45,7 +45,6 @@ unit-test http_tests : http/rfc2616.cpp http/streambuf_body.cpp http/string_body.cpp - http/type_check.cpp http/write.cpp ; diff --git a/test/http/type_check.cpp b/test/http/type_check.cpp deleted file mode 100644 index 82020206..00000000 --- a/test/http/type_check.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// -// Copyright (c) 2013-2016 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) -// - -// Test that header file is self-contained. -#include