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/results.hpp> 14   #include <boost/capy/results.hpp>
15   #include <boost/capy/task.hpp> 15   #include <boost/capy/task.hpp>
16   #include <boost/capy/buffers.hpp> 16   #include <boost/capy/buffers.hpp>
17   #include <boost/capy/buffers/consuming_buffers.hpp> 17   #include <boost/capy/buffers/consuming_buffers.hpp>
18   #include <boost/capy/concept/write_stream.hpp> 18   #include <boost/capy/concept/write_stream.hpp>
19   19  
20   #include <cstddef> 20   #include <cstddef>
21   #include <system_error> 21   #include <system_error>
22   22  
23   namespace boost { 23   namespace boost {
24   namespace capy { 24   namespace capy {
25   25  
26   /** Write at least a minimum number of bytes to a stream. 26   /** Write at least a minimum number of bytes to a stream.
27   27  
28   This is a straightforward extension of @ref write. While @ref write 28   This is a straightforward extension of @ref write. While @ref write
29   transfers exactly `buffer_size(buffers)` bytes, `write_at_least` 29   transfers exactly `buffer_size(buffers)` bytes, `write_at_least`
30   transfers at least `n` bytes. The loop stops as soon as `n` bytes 30   transfers at least `n` bytes. The loop stops as soon as `n` bytes
31   have been written, even if `buffers` has not been fully consumed. 31   have been written, even if `buffers` has not been fully consumed.
32   Any bytes beyond `n` that a single `stream.write_some` happens to 32   Any bytes beyond `n` that a single `stream.write_some` happens to
33   transfer are counted. No further awaiting is performed to write the 33   transfer are counted. No further awaiting is performed to write the
34   remainder. 34   remainder.
35   35  
36   Provided for symmetry with @ref read_at_least. 36   Provided for symmetry with @ref read_at_least.
37   37  
38   @par Await-effects 38   @par Await-effects
39   39  
40   If `n > buffer_size(buffers)` the request is impossible to satisfy 40   If `n > buffer_size(buffers)` the request is impossible to satisfy
41   and the operation fails immediately with 41   and the operation fails immediately with
42   `{std::errc::invalid_argument, 0}` without awaiting `stream.write_some`. 42   `{std::errc::invalid_argument, 0}` without awaiting `stream.write_some`.
43   43  
44   Otherwise writes the contents of `buffers` to `stream` via awaiting 44   Otherwise writes the contents of `buffers` to `stream` via awaiting
45   `stream.write_some` with consecutive portions of data from `buffers` 45   `stream.write_some` with consecutive portions of data from `buffers`
46   until: 46   until:
47   47  
48   @li either at least `n` bytes have been written, 48   @li either at least `n` bytes have been written,
49   @li or a contingency in `stream.write_some` occurs. 49   @li or a contingency in `stream.write_some` occurs.
50   50  
51   If `n == 0` then no awaiting `stream.write_some` is performed. This is 51   If `n == 0` then no awaiting `stream.write_some` is performed. This is
52   not a contingency. 52   not a contingency.
53   53  
54   @par Await-returns 54   @par Await-returns
55   An object of type `results<std::size_t>` destructuring as `[ec, n]`. 55   An object of type `results<std::size_t>` destructuring as `[ec, n]`.
56   56  
57   Upon a contingency, the count represents the number of bytes written 57   Upon a contingency, the count represents the number of bytes written
58   so far. 58   so far.
59   59  
60   Contingencies: 60   Contingencies:
61   61  
62   @li The first contingency reported from awaiting @c stream.write_some 62   @li The first contingency reported from awaiting @c stream.write_some
63   while fewer than `n` bytes have been written. A contingency that 63   while fewer than `n` bytes have been written. A contingency that
64   accompanies the write which reaches `n` is not reported: a 64   accompanies the write which reaches `n` is not reported: a
65   satisfied request is a success. 65   satisfied request is a success.
66   66  
67   Notable conditions: 67   Notable conditions:
68   68  
69   @li @c std::errc::invalid_argument — `n` exceeds `buffer_size(buffers)`, 69   @li @c std::errc::invalid_argument — `n` exceeds `buffer_size(buffers)`,
70   @li @c cond::canceled — Operation was cancelled, 70   @li @c cond::canceled — Operation was cancelled,
71   @li @c std::errc::broken_pipe — Peer closed connection. 71   @li @c std::errc::broken_pipe — Peer closed connection.
72   72  
73   @par Await-postcondition 73   @par Await-postcondition
74   On success the returned count is greater than or equal to `n` and 74   On success the returned count is greater than or equal to `n` and
75   less than or equal to `buffer_size(buffers)`, and `ec` is success. 75   less than or equal to `buffer_size(buffers)`, and `ec` is success.
76   Otherwise `ec` is set. 76   Otherwise `ec` is set.
77   77  
78   @param stream The stream to write to. If the lifetime of `stream` ends 78   @param stream The stream to write to. If the lifetime of `stream` ends
79   before the coroutine finishes, the behavior is undefined. 79   before the coroutine finishes, the behavior is undefined.
80   80  
81   @param buffers The buffer sequence to write. If the lifetime of the 81   @param buffers The buffer sequence to write. If the lifetime of the
82   buffer sequence represented by `buffers` ends before the coroutine 82   buffer sequence represented by `buffers` ends before the coroutine
83   finishes, the behavior is undefined. 83   finishes, the behavior is undefined.
84   84  
85   @param n The minimum number of bytes to write. Must not exceed 85   @param n The minimum number of bytes to write. Must not exceed
86   `buffer_size(buffers)`. 86   `buffer_size(buffers)`.
87   87  
88   @return A task yielding `results<std::size_t>` whose second element 88   @return A task yielding `results<std::size_t>` whose second element
89   is the number of bytes written. 89   is the number of bytes written.
90   90  
91   @par Remarks 91   @par Remarks
92   Supports _ContextAwaitable cancellation_. 92   Supports _ContextAwaitable cancellation_.
93   93  
94   @par Example 94   @par Example
95   95  
96   @par !example example 96   @par !example example
97   97  
98   98  
99   @see write, WriteStream, ConstBufferSequence 99   @see write, WriteStream, ConstBufferSequence
100   */ 100   */
101   template <WriteStream S, ConstBufferSequence CB> 101   template <WriteStream S, ConstBufferSequence CB>
102   auto 102   auto
HITCBC 103   33 write_at_least(S& stream, CB buffers, std::size_t n) -> task<results<std::size_t>> 103   33 write_at_least(S& stream, CB buffers, std::size_t n) -> task<results<std::size_t>>
104   { 104   {
105   consuming_buffers consuming(buffers); 105   consuming_buffers consuming(buffers);
106   std::size_t const total_size = buffer_size(buffers); 106   std::size_t const total_size = buffer_size(buffers);
107   107  
108   if(n > total_size) 108   if(n > total_size)
109   co_return {make_error_code(std::errc::invalid_argument), 0}; 109   co_return {make_error_code(std::errc::invalid_argument), 0};
110   110  
111   std::size_t total_written = 0; 111   std::size_t total_written = 0;
112   112  
113   while(total_written < n) 113   while(total_written < n)
114   { 114   {
115   auto [ec, m] = co_await stream.write_some(consuming.data()); 115   auto [ec, m] = co_await stream.write_some(consuming.data());
116   consuming.consume(m); 116   consuming.consume(m);
117   total_written += m; 117   total_written += m;
118   // A contingency that still satisfied the request is a success: 118   // A contingency that still satisfied the request is a success:
119   // report it only when fewer than n bytes were written. 119   // report it only when fewer than n bytes were written.
120   if(ec && total_written < n) 120   if(ec && total_written < n)
121   co_return {ec, total_written}; 121   co_return {ec, total_written};
122   } 122   }
123   123  
124   co_return {std::error_code(), total_written}; 124   co_return {std::error_code(), total_written};
HITCBC 125   66 } 125   66 }
126   126  
127   } // namespace capy 127   } // namespace capy
128   } // namespace boost 128   } // namespace boost
129   129  
130   #endif 130   #endif