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 @@
AsyncStreamFile
+ RatePolicy 🞲StreamSyncStream
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 {