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