userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
iovec_advance.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/utils/iovec_advance.hpp
4
/// @brief Helpers for advancing `iovec` buffers used in scatter/gather I/O
5
/// (`readv`/`writev`).
6
7
#
include
<
sys
/
uio
.
h
>
8
#
include
<
cstddef
>
9
10
#
include
<
userver
/
utils
/
assert
.
hpp
>
11
12
USERVER_NAMESPACE_BEGIN
13
14
namespace
utils
{
15
16
/// @ingroup userver_universal
17
///
18
/// @brief Trims the first `n` bytes off a single `iovec`: moves `iov_base`
19
/// forward and decreases `iov_len` by `n`.
20
///
21
/// Typically called after a partial transfer to adjust the buffer for the
22
/// next I/O call.
23
///
24
/// @param iov the buffer to trim.
25
/// @param n number of bytes already transferred.
26
///
27
/// @warning `n` must be strictly less than `iov.iov_len`, so that the resulting
28
/// buffer is never empty. The precondition is only validated by `UASSERT`, i.e.
29
/// in debug builds; violating it in a release build yields a buffer pointing
30
/// outside of the original memory region.
31
inline
void
Advance
(
struct
iovec& iov, std::size_t n) {
32
UASSERT
(n < iov.iov_len);
33
iov.iov_base =
static_cast
<
char
*>(iov.iov_base) + n;
34
iov.iov_len -= n;
35
}
36
37
/// @ingroup userver_universal
38
///
39
/// @brief A cursor over an array of `iovec` entries, used to track progress
40
/// across multiple scatter/gather buffers.
41
struct
IovIter
{
42
/// Points to the first entry that has not been transferred completely.
43
/// May point past the end of the array when `iov_size == 0`, so it must not
44
/// be dereferenced without checking `iov_size` first.
45
const
struct
iovec*
iov
{};
46
47
/// Number of `iovec` entries remaining, starting at `iov`.
48
std::size_t
iov_size
{};
49
50
/// Byte offset within `*iov`, i.e. the number of bytes of the current entry
51
/// that were already transferred. `0` means the current entry has not been
52
/// partially consumed and the list can be reused as is.
53
std::size_t
iov_offset
{0};
54
};
55
56
/// @ingroup userver_universal
57
///
58
/// @brief Advances the iterator by `n` transferred bytes across the `iovec`
59
/// array.
60
///
61
/// After the call:
62
/// - `iov_size == 0` means that everything was transferred; `iov` points past
63
/// the end of the array and must not be dereferenced;
64
/// - `iov_offset == 0` with a non-zero `iov_size` means the iterator points
65
/// exactly at the start of the next unconsumed entry, so `{iov, iov_size}`
66
/// can be passed to the next I/O call as is;
67
/// - a non-zero `iov_offset` means that `*iov` is partially consumed and has to
68
/// be trimmed by `iov_offset` bytes (e.g. via
69
/// utils::Advance(struct iovec&, std::size_t)) before reuse. The entries
70
/// themselves are never modified by this overload, as they are pointed to by
71
/// a pointer-to-const.
72
inline
void
Advance
(
IovIter
& iter, std::size_t n) {
73
while
(0 < iter
.
iov_size
) {
74
const
std::size_t iov_len = iter
.
iov
->iov_len;
75
if
(iov_len <= n) {
76
++iter
.
iov
;
77
--iter
.
iov_size
;
78
n -= iov_len;
79
UASSERT
(0 < iter
.
iov_size
|| 0 == n);
80
}
else
[[unlikely]] {
81
iter
.
iov_offset
= n;
82
return
;
83
}
84
}
85
}
86
87
}
// namespace utils
88
89
USERVER_NAMESPACE_END
userver
utils
iovec_advance.hpp
Generated on
for userver by
Doxygen
1.17.0