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 + @par !example example
96 - capy::task<> flush_at_least(capy::WriteStream auto& stream, std::string_view data)  
97 - {  
98 - auto [ec, n] = co_await capy::write_at_least(  
99 - stream, capy::make_buffer(data), 8);  
100 - if(ec)  
101 - throw std::system_error(ec);  
102 - // at least 8 bytes written; n may be larger  
103 - }  
104 - @endcode  
105   96  
106   97  
107   @see write, WriteStream, ConstBufferSequence 98   @see write, WriteStream, ConstBufferSequence
108   */ 99   */
109   template <WriteStream S, ConstBufferSequence CB> 100   template <WriteStream S, ConstBufferSequence CB>
110   auto 101   auto
HITCBC 111   33 write_at_least(S& stream, CB buffers, std::size_t n) -> io_task<std::size_t> 102   33 write_at_least(S& stream, CB buffers, std::size_t n) -> io_task<std::size_t>
112   { 103   {
113   consuming_buffers consuming(buffers); 104   consuming_buffers consuming(buffers);
114   std::size_t const total_size = buffer_size(buffers); 105   std::size_t const total_size = buffer_size(buffers);
115   106  
116   if(n > total_size) 107   if(n > total_size)
117   co_return {make_error_code(std::errc::invalid_argument), 0}; 108   co_return {make_error_code(std::errc::invalid_argument), 0};
118   109  
119   std::size_t total_written = 0; 110   std::size_t total_written = 0;
120   111  
121   while(total_written < n) 112   while(total_written < n)
122   { 113   {
123   auto [ec, m] = co_await stream.write_some(consuming.data()); 114   auto [ec, m] = co_await stream.write_some(consuming.data());
124   consuming.consume(m); 115   consuming.consume(m);
125   total_written += m; 116   total_written += m;
126   // A contingency that still satisfied the request is a success: 117   // A contingency that still satisfied the request is a success:
127   // report it only when fewer than n bytes were written. 118   // report it only when fewer than n bytes were written.
128   if(ec && total_written < n) 119   if(ec && total_written < n)
129   co_return {ec, total_written}; 120   co_return {ec, total_written};
130   } 121   }
131   122  
132   co_return {std::error_code(), total_written}; 123   co_return {std::error_code(), total_written};
HITCBC 133   66 } 124   66 }
134   125  
135   } // namespace capy 126   } // namespace capy
136   } // namespace boost 127   } // namespace boost
137   128  
138   #endif 129   #endif