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. No further awaiting is performed to write the 32   transfer are counted. No further awaiting is performed to write the
33   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   86  
87   @return A task yielding `io_result<std::size_t>` whose second element 87   @return A task yielding `io_result<std::size_t>` whose second element
88   is the number of bytes written. 88   is the number of bytes written.
89   89  
90   @par Remarks 90   @par Remarks
91   Supports _IoAwaitable cancellation_. 91   Supports _IoAwaitable cancellation_.
92   92  
93   @par Example 93   @par Example
94   94  
95   @code 95   @code
96   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)
97   { 97   {
98   auto [ec, n] = co_await capy::write_at_least( 98   auto [ec, n] = co_await capy::write_at_least(
99   stream, capy::make_buffer(data), 8); 99   stream, capy::make_buffer(data), 8);
100   if(ec) 100   if(ec)
101   throw std::system_error(ec); 101   throw std::system_error(ec);
102   102  
103   // at least 8 bytes written; n may be larger 103   // at least 8 bytes written; n may be larger
104   } 104   }
105   @endcode 105   @endcode
106   106  
107   @see write, WriteStream, ConstBufferSequence 107   @see write, WriteStream, ConstBufferSequence
108   */ 108   */
109   template <WriteStream S, ConstBufferSequence CB> 109   template <WriteStream S, ConstBufferSequence CB>
110   auto 110   auto
HITCBC 111   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>
112   { 112   {
113   consuming_buffers consuming(buffers); 113   consuming_buffers consuming(buffers);
114   std::size_t const total_size = buffer_size(buffers); 114   std::size_t const total_size = buffer_size(buffers);
115   115  
116   if(n > total_size) 116   if(n > total_size)
117   co_return {make_error_code(std::errc::invalid_argument), 0}; 117   co_return {make_error_code(std::errc::invalid_argument), 0};
118   118  
119   std::size_t total_written = 0; 119   std::size_t total_written = 0;
120   120  
121   while(total_written < n) 121   while(total_written < n)
122   { 122   {
123   auto [ec, m] = co_await stream.write_some(consuming.data()); 123   auto [ec, m] = co_await stream.write_some(consuming.data());
124   consuming.consume(m); 124   consuming.consume(m);
125   total_written += m; 125   total_written += m;
126   // A contingency that still satisfied the request is a success: 126   // A contingency that still satisfied the request is a success:
127   // report it only when fewer than n bytes were written. 127   // report it only when fewer than n bytes were written.
128   if(ec && total_written < n) 128   if(ec && total_written < n)
129   co_return {ec, total_written}; 129   co_return {ec, total_written};
130   } 130   }
131   131  
132   co_return {std::error_code(), total_written}; 132   co_return {std::error_code(), total_written};
HITCBC 133   66 } 133   66 }
134   134  
135   } // namespace capy 135   } // namespace capy
136   } // namespace boost 136   } // namespace boost
137   137  
138   #endif 138   #endif