diff --git a/CHANGELOG.md b/CHANGELOG.md index d189cb04..6df81f4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ Version 217: * websocket idle pings +* RatePolicy documentation -------------------------------------------------------------------------------- diff --git a/doc/qbk/07_concepts/0_concepts.qbk b/doc/qbk/07_concepts/0_concepts.qbk index 11c9c4db..f70b5565 100644 --- a/doc/qbk/07_concepts/0_concepts.qbk +++ b/doc/qbk/07_concepts/0_concepts.qbk @@ -19,6 +19,7 @@ This section describes all of the concepts defined by the library. [include Fields.qbk] [include FieldsWriter.qbk] [include File.qbk] +[include RatePolicy.qbk] [include Streams.qbk] [endsect] diff --git a/doc/qbk/07_concepts/RatePolicy.qbk b/doc/qbk/07_concepts/RatePolicy.qbk new file mode 100644 index 00000000..80a4cef8 --- /dev/null +++ b/doc/qbk/07_concepts/RatePolicy.qbk @@ -0,0 +1,124 @@ +[/ + Copyright (c) 2019 Vinnie Falco (vinnie dot falco at gmail dot com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Official repository: https://github.com/boostorg/beast +] + +[section:RatePolicy RatePolicy] + +An instance of [*RatePolicy] is associated with a +[link beast.ref.boost__beast__basic_stream `basic_stream`], +and controls the rate at which bytes may be independently sent and +received. This may be used to achieve fine-grained bandwidth management +and flow control. + +[heading Associated Types] + +* [link beast.ref.boost__beast__rate_policy_access `rate_policy_access`] + +[warning + These requirements may undergo non-backward compatible + changes in subsequent versions. +] + +[heading Requirements] + +In this table: + +* `P` denotes a type that meets the requirements of [*RatePolicy]. +* `x` denotes an xvalue of type `P` +* `a` denotes a value of type `P`. +* `n` denotes a value of type `std::size_t` + +[table Valid expressions +[[Expression] [Type] [Semantics, Pre/Post-conditions]] +[ + [`P a(x)`] + [] + [ + Requires ['MoveConstructible]. + ] +][ + [`friend rate_policy_access`] + [] + [ + The member functions required in `P` should be private. + [link beast.ref.boost__beast__rate_policy_access `rate_policy_access`] + must be a friend of `P` for the implementation to gain access + to the required member functions. + ] +][ + [`a.available_read_bytes()`] + [`std::size_t`] + [ + This function is called by the implementation to determine + the maximum number of allowed bytes to be transferred + in the next read operation. The actual number of bytes + subsequently transferred may be less than this number. + + If the policy returns a value of zero, the read operation + will asynchronously wait until the next timer interval + before retrying. When the retry occurs, this function will + be called again. + ] +][ + [`a.available_write_bytes()`] + [`std::size_t`] + [ + This function is called by the implementation to determine + the maximum number of allowed bytes to be transferred + in the next write operation. The actual number of bytes + subsequently transferred may be less than this number. + + If the policy returns a value of zero, the read operation + will asynchronously wait until the next timer interval + before retrying. When the retry occurs, this function will + be called again. + ] +][ + [`a.transfer_read_bytes(n)`] + [] + [ + The implementation calls this function to inform the + policy that `n` bytes were successfully transferred + in the most recent read operation. The policy object + may optionally use this information to calculate + throughputs and/or inform the algorithm used to + determine subsequently queried transfer maximums. + ] +][ + [`a.transfer_write_bytes(n)`] + [] + [ + The implementation calls this function to inform the + policy that `n` bytes were successfully transferred + in the most recent write operation. The policy object + may optionally use this information to calculate + throughputs and/or inform the algorithm used to + determine subsequently queried transfer limits. + ] +][ + [`a.on_timer()`] + [] + [ + The implementation calls this function every time the + internal timer expires. The policy object may optionally + use this opportunity to calculate elapsed time and + throughput, and/or inform the algorithm used to + determine subsequently queried transfer limits. + ] +]] + +[heading Exemplar] + +[concept_RatePolicy] + +[heading Models] + +* [link beast.ref.boost__beast__simple_rate_policy `simple_rate_policy`] +* [link beast.ref.boost__beast__unlimited_rate_policy `unlimited_rate_policy`] + +[endsect] diff --git a/doc/qbk/main.qbk b/doc/qbk/main.qbk index 2f6a91c5..1fd2fceb 100644 --- a/doc/qbk/main.qbk +++ b/doc/qbk/main.qbk @@ -134,6 +134,8 @@ [import ../../test/doc/core_3_layers.cpp] [import ../../test/doc/websocket_3_handshake.cpp] +[import ../../test/beast/core/rate_policy.cpp] + [section:quickref Reference] ''' 🞲 indicates an item that is new in this version. diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml index 96b8c780..b572d09c 100644 --- a/doc/qbk/quickref.xml +++ b/doc/qbk/quickref.xml @@ -104,6 +104,7 @@ AsyncStream File + RatePolicy 🞲 Stream SyncStream diff --git a/doc/xsl/class_detail.xsl b/doc/xsl/class_detail.xsl index 70cff029..69f2dc0b 100644 --- a/doc/xsl/class_detail.xsl +++ b/doc/xsl/class_detail.xsl @@ -63,6 +63,9 @@ class __RangeConnectHandler__ + + class ``[link beast.concepts.RatePolicy [*RatePolicy]]`` + class __ReadHandler__ diff --git a/include/boost/beast/core/basic_stream.hpp b/include/boost/beast/core/basic_stream.hpp index ab593c33..d7b670d1 100644 --- a/include/boost/beast/core/basic_stream.hpp +++ b/include/boost/beast/core/basic_stream.hpp @@ -239,7 +239,12 @@ private: template explicit - impl_type(Args&&...); + impl_type(std::false_type, Args&&...); + + template + explicit + impl_type(std::true_type, + RatePolicy_&& policy, Args&&...); impl_type& operator=(impl_type&&) = delete; @@ -317,9 +322,43 @@ public: @param args A list of parameters forwarded to the constructor of the underlying socket. */ +#if BOOST_BEAST_DOXYGEN template explicit basic_stream(Args&&... args); +#else + template::value>::type> + explicit + basic_stream(Arg0&& argo, Args&&... args); +#endif + + /** Constructor + + This constructor creates the stream with the specified rate + policy, and forwards all remaining arguments to the underlying + socket. The socket then needs to be open and connected or + accepted before data can be sent or received on it. + + @param policy The rate policy object to use. The stream will + take ownership of this object by decay-copy. + + @param args A list of parameters forwarded to the constructor of + the underlying socket. + */ +#if BOOST_BEAST_DOXYGEN + template + explicit + basic_stream(RatePolicy_&& policy, Args&&... args); +#else + template::value>::type> + basic_stream( + RatePolicy_&& policy, Arg0&& arg, Args&&... args); +#endif /** Move constructor diff --git a/include/boost/beast/core/impl/basic_stream.hpp b/include/boost/beast/core/impl/basic_stream.hpp index 9db330ee..3c1d56ea 100644 --- a/include/boost/beast/core/impl/basic_stream.hpp +++ b/include/boost/beast/core/impl/basic_stream.hpp @@ -33,7 +33,7 @@ template template basic_stream:: impl_type:: -impl_type(Args&&... args) +impl_type(std::false_type, Args&&... args) : socket(std::forward(args)...) , read(ex()) , write(ex()) @@ -42,6 +42,23 @@ impl_type(Args&&... args) reset(); } +template +template +basic_stream:: +impl_type:: +impl_type(std::true_type, + RatePolicy_&& policy, Args&&... args) + : boost::empty_value( + boost::empty_init_t{}, + std::forward(policy)) + , socket(std::forward(args)...) + , read(ex()) + , write(ex()) + , timer(ex()) +{ + reset(); +} + template template void @@ -650,10 +667,25 @@ basic_stream:: } template -template +template basic_stream:: -basic_stream(Args&&... args) +basic_stream(Arg0&& arg0, Args&&... args) : impl_(boost::make_shared( + std::false_type{}, + std::forward(arg0), + std::forward(args)...)) +{ +} + +template +template +basic_stream:: +basic_stream( + RatePolicy_&& policy, Arg0&& arg0, Args&&... args) + : impl_(boost::make_shared( + std::true_type{}, + std::forward(policy), + std::forward(arg0), std::forward(args)...)) { } diff --git a/include/boost/beast/core/rate_policy.hpp b/include/boost/beast/core/rate_policy.hpp index 49876318..c9b4230b 100644 --- a/include/boost/beast/core/rate_policy.hpp +++ b/include/boost/beast/core/rate_policy.hpp @@ -102,36 +102,35 @@ private: */ class unlimited_rate_policy { + friend class rate_policy_access; + static std::size_t constexpr all = (std::numeric_limits::max)(); -private: - friend class rate_policy_access; - std::size_t - available_read_bytes() + available_read_bytes() const noexcept { return all; } std::size_t - available_write_bytes() + available_write_bytes() const noexcept { return all; } void - transfer_read_bytes(std::size_t) + transfer_read_bytes(std::size_t) const noexcept { } void - transfer_write_bytes(std::size_t) + transfer_write_bytes(std::size_t) const noexcept { } void - on_timer() + on_timer() const noexcept { } }; @@ -162,13 +161,13 @@ class simple_rate_policy std::size_t wr_limit_ = all; std::size_t - available_read_bytes() + available_read_bytes() const noexcept { return rd_remain_; } std::size_t - available_write_bytes() + available_write_bytes() const noexcept { return wr_remain_; } diff --git a/test/beast/core/basic_stream.cpp b/test/beast/core/basic_stream.cpp index cddb0caa..147e4cfa 100644 --- a/test/beast/core/basic_stream.cpp +++ b/test/beast/core/basic_stream.cpp @@ -417,6 +417,34 @@ public: opt = false; BEAST_EXPECT(! opt.value()); } + + // rate policies + + { + basic_stream s(ioc); + } + + { + basic_stream s( + simple_rate_policy{}, ioc); + } + + { + basic_stream s(ioc); + } + + { + basic_stream s( + unlimited_rate_policy{}, ioc); + } } class handler diff --git a/test/beast/core/rate_policy.cpp b/test/beast/core/rate_policy.cpp index 4f81a5ff..00e0e6c6 100644 --- a/test/beast/core/rate_policy.cpp +++ b/test/beast/core/rate_policy.cpp @@ -13,6 +13,31 @@ #include +//[concept_RatePolicy +class RatePolicy +{ + friend class rate_policy_access; + + static std::size_t constexpr all = + (std::numeric_limits::max)(); + + std::size_t + available_read_bytes(); + + std::size_t + available_write_bytes(); + + void + transfer_read_bytes(std::size_t); + + void + transfer_write_bytes(std::size_t); + + void + on_timer(); +}; +//] + namespace boost { namespace beast {