100.00% Lines (2/2) 100.00% Functions (1/1)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Michael Vandeberg 2   // Copyright (c) 2026 Michael Vandeberg
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 4   // Distributed under the Boost Software License, Version 1.0. (See accompanying
5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/capy 7   // Official repository: https://github.com/cppalliance/capy
8   // 8   //
9   9  
10   #ifndef BOOST_CAPY_WRITE_AT_LEAST_HPP 10   #ifndef BOOST_CAPY_WRITE_AT_LEAST_HPP
11   #define BOOST_CAPY_WRITE_AT_LEAST_HPP 11   #define BOOST_CAPY_WRITE_AT_LEAST_HPP
12   12  
13   #include <boost/capy/detail/config.hpp> 13   #include <boost/capy/detail/config.hpp>
14   #include <boost/capy/io_task.hpp> 14   #include <boost/capy/io_task.hpp>
15   #include <boost/capy/buffers.hpp> 15   #include <boost/capy/buffers.hpp>
16   #include <boost/capy/buffers/consuming_buffers.hpp> 16   #include <boost/capy/buffers/consuming_buffers.hpp>
17   #include <boost/capy/concept/write_stream.hpp> 17   #include <boost/capy/concept/write_stream.hpp>
18   18  
19   #include <cstddef> 19   #include <cstddef>
20   #include <system_error> 20   #include <system_error>
21   21  
22   namespace boost { 22   namespace boost {
23   namespace capy { 23   namespace capy {
24   24  
25   /** Write at least a minimum number of bytes to a stream. 25   /** Write at least a minimum number of bytes to a stream.
26   26  
27   This is a straightforward extension of @ref write. While @ref write 27   This is a straightforward extension of @ref write. While @ref write
28   transfers exactly `buffer_size(buffers)` bytes, `write_at_least` 28   transfers exactly `buffer_size(buffers)` bytes, `write_at_least`
29 - transfers at least `n` bytes: the loop stops as soon as `n` bytes 29 + transfers at least `n` bytes. The loop stops as soon as `n` bytes
30   have been written, even if `buffers` has not been fully consumed. 30   have been written, even if `buffers` has not been fully consumed.
31   Any bytes beyond `n` that a single `stream.write_some` happens to 31   Any bytes beyond `n` that a single `stream.write_some` happens to
32 - transfer are counted, but no further awaiting is performed to write 32 + transfer are counted. No further awaiting is performed to write the
33 - the remainder. 33 + remainder.
34   34  
35   Provided for symmetry with @ref read_at_least. 35   Provided for symmetry with @ref read_at_least.
36   36  
37   @par Await-effects 37   @par Await-effects
38   38  
39   If `n > buffer_size(buffers)` the request is impossible to satisfy 39   If `n > buffer_size(buffers)` the request is impossible to satisfy
40   and the operation fails immediately with 40   and the operation fails immediately with
41   `{std::errc::invalid_argument, 0}` without awaiting `stream.write_some`. 41   `{std::errc::invalid_argument, 0}` without awaiting `stream.write_some`.
42   42  
43   Otherwise writes the contents of `buffers` to `stream` via awaiting 43   Otherwise writes the contents of `buffers` to `stream` via awaiting
44   `stream.write_some` with consecutive portions of data from `buffers` 44   `stream.write_some` with consecutive portions of data from `buffers`
45   until: 45   until:
46   46  
47   @li either at least `n` bytes have been written, 47   @li either at least `n` bytes have been written,
48   @li or a contingency in `stream.write_some` occurs. 48   @li or a contingency in `stream.write_some` occurs.
49   49  
50   If `n == 0` then no awaiting `stream.write_some` is performed. This is 50   If `n == 0` then no awaiting `stream.write_some` is performed. This is
51   not a contingency. 51   not a contingency.
52   52  
53   @par Await-returns 53   @par Await-returns
54   An object of type `io_result<std::size_t>` destructuring as `[ec, n]`. 54   An object of type `io_result<std::size_t>` destructuring as `[ec, n]`.
55   55  
56   Upon a contingency, the count represents the number of bytes written 56   Upon a contingency, the count represents the number of bytes written
57   so far. 57   so far.
58   58  
59   Contingencies: 59   Contingencies:
60   60  
61   @li The first contingency reported from awaiting @c stream.write_some 61   @li The first contingency reported from awaiting @c stream.write_some
62   while fewer than `n` bytes have been written. A contingency that 62   while fewer than `n` bytes have been written. A contingency that
63   accompanies the write which reaches `n` is not reported: a 63   accompanies the write which reaches `n` is not reported: a
64   satisfied request is a success. 64   satisfied request is a success.
65   65  
66   Notable conditions: 66   Notable conditions:
67   67  
68   @li @c std::errc::invalid_argument — `n` exceeds `buffer_size(buffers)`, 68   @li @c std::errc::invalid_argument — `n` exceeds `buffer_size(buffers)`,
69   @li @c cond::canceled — Operation was cancelled, 69   @li @c cond::canceled — Operation was cancelled,
70   @li @c std::errc::broken_pipe — Peer closed connection. 70   @li @c std::errc::broken_pipe — Peer closed connection.
71   71  
72   @par Await-postcondition 72   @par Await-postcondition
73   On success the returned count is greater than or equal to `n` and 73   On success the returned count is greater than or equal to `n` and
74 - less than or equal to `buffer_size(buffers)`, and `ec` is success; 74 + less than or equal to `buffer_size(buffers)`, and `ec` is success.
75 - otherwise `ec` is set. 75 + Otherwise `ec` is set.
76   76  
77   @param stream The stream to write to. If the lifetime of `stream` ends 77   @param stream The stream to write to. If the lifetime of `stream` ends
78   before the coroutine finishes, the behavior is undefined. 78   before the coroutine finishes, the behavior is undefined.
79   79  
80   @param buffers The buffer sequence to write. If the lifetime of the 80   @param buffers The buffer sequence to write. If the lifetime of the
81   buffer sequence represented by `buffers` ends before the coroutine 81   buffer sequence represented by `buffers` ends before the coroutine
82   finishes, the behavior is undefined. 82   finishes, the behavior is undefined.
83   83  
84   @param n The minimum number of bytes to write. Must not exceed 84   @param n The minimum number of bytes to write. Must not exceed
85   `buffer_size(buffers)`. 85   `buffer_size(buffers)`.
  86 +
  87 + @return A task yielding `io_result<std::size_t>` whose second element
  88 + is the number of bytes written.
86   89  
87   @par Remarks 90   @par Remarks
88   Supports _IoAwaitable cancellation_. 91   Supports _IoAwaitable cancellation_.
89   92  
90   @par Example 93   @par Example
91   94  
92   @code 95   @code
93   capy::task<> flush_at_least(capy::WriteStream auto& stream, std::string_view data) 96   capy::task<> flush_at_least(capy::WriteStream auto& stream, std::string_view data)
94   { 97   {
95   auto [ec, n] = co_await capy::write_at_least( 98   auto [ec, n] = co_await capy::write_at_least(
96   stream, capy::make_buffer(data), 8); 99   stream, capy::make_buffer(data), 8);
97   if(ec) 100   if(ec)
98   throw std::system_error(ec); 101   throw std::system_error(ec);
99   102  
100   // at least 8 bytes written; n may be larger 103   // at least 8 bytes written; n may be larger
101   } 104   }
102   @endcode 105   @endcode
103   106  
104   @see write, WriteStream, ConstBufferSequence 107   @see write, WriteStream, ConstBufferSequence
105   */ 108   */
106   template <WriteStream S, ConstBufferSequence CB> 109   template <WriteStream S, ConstBufferSequence CB>
107   auto 110   auto
HITCBC 108   33 write_at_least(S& stream, CB buffers, std::size_t n) -> io_task<std::size_t> 111   33 write_at_least(S& stream, CB buffers, std::size_t n) -> io_task<std::size_t>
109   { 112   {
110   consuming_buffers consuming(buffers); 113   consuming_buffers consuming(buffers);
111   std::size_t const total_size = buffer_size(buffers); 114   std::size_t const total_size = buffer_size(buffers);
112   115  
113   if(n > total_size) 116   if(n > total_size)
114   co_return {make_error_code(std::errc::invalid_argument), 0}; 117   co_return {make_error_code(std::errc::invalid_argument), 0};
115   118  
116   std::size_t total_written = 0; 119   std::size_t total_written = 0;
117   120  
118   while(total_written < n) 121   while(total_written < n)
119   { 122   {
120   auto [ec, m] = co_await stream.write_some(consuming.data()); 123   auto [ec, m] = co_await stream.write_some(consuming.data());
121   consuming.consume(m); 124   consuming.consume(m);
122   total_written += m; 125   total_written += m;
123   // A contingency that still satisfied the request is a success: 126   // A contingency that still satisfied the request is a success:
124   // report it only when fewer than n bytes were written. 127   // report it only when fewer than n bytes were written.
125   if(ec && total_written < n) 128   if(ec && total_written < n)
126   co_return {ec, total_written}; 129   co_return {ec, total_written};
127   } 130   }
128   131  
129   co_return {{}, total_written}; 132   co_return {{}, total_written};
HITCBC 130   66 } 133   66 }
131   134  
132   } // namespace capy 135   } // namespace capy
133   } // namespace boost 136   } // namespace boost
134   137  
135   #endif 138   #endif