1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
base / containers / span_writer.h [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_CONTAINERS_SPAN_WRITER_H_
#define BASE_CONTAINERS_SPAN_WRITER_H_
#include <optional>
#include "base/containers/span.h"
#include "base/memory/raw_span.h"
#include "base/numerics/byte_conversions.h"
namespace base {
// A Writer to write into and consume elements from the front of a span
// dynamically.
//
// SpanWriter is used to split off prefix spans from a larger span, reporting
// errors if there's not enough room left (instead of crashing, as would happen
// with span directly).
template <typename T>
class SpanWriter {
static_assert(!std::is_const_v<T>,
"SpanWriter needs mutable access to its buffer");
public:
// Construct SpanWriter that writes to `buf`.
constexpr explicit SpanWriter(span<T> buf)
: buf_(buf), original_size_(buf_.size()) {}
// Returns true and writes the span `data` into the front of the inner span,
// if there is enough room left. Otherwise, it returns false and does
// nothing.
constexpr bool Write(span<const T> data) {
if (data.size() > remaining()) {
return false;
}
auto [lhs, rhs] = buf_.split_at(data.size());
lhs.copy_from(data);
buf_ = rhs;
return true;
}
// Returns true and writes `value` into the front of the inner span if there
// is space remaining. Otherwise, it returns false and does nothing.
template <typename V>
requires(std::same_as<T, std::remove_cvref_t<V>>)
bool Write(V&& value) {
if (!remaining()) {
return false;
}
buf_[0] = std::forward<V>(value);
buf_ = buf_.last(remaining() - 1);
return true;
}
// Skips over the next `n` objects, and returns a span that points to the
// skipped objects, if there are enough objects left. Otherwise, it returns
// nullopt and does nothing.
constexpr std::optional<span<T>> Skip(StrictNumeric<size_t> n) {
if (n > remaining()) {
return std::nullopt;
}
auto [lhs, rhs] = buf_.split_at(n);
buf_ = rhs;
return lhs;
}
template <size_t N>
constexpr std::optional<span<T, N>> Skip() {
if (N > remaining()) {
return std::nullopt;
}
auto [lhs, rhs] = buf_.template split_at<N>();
buf_ = rhs;
return lhs;
}
// For a SpanWriter over bytes, we can write integer values directly to those
// bytes as a memcpy. Returns true if there was room remaining and the bytes
// were written.
//
// This provides big, little, and native endian writing orders. Note that
// "native" order is almost never what you want; it only makes sense for byte
// buffers that stay in memory and are never written to the disk or network.
#define BASE_SPANWRITER_WRITE(signchar, bitsize, endian, typeprefix) \
constexpr bool Write##signchar##bitsize##endian##Endian( \
typeprefix##int##bitsize##_t value) \
requires(std::same_as<T, uint8_t>) \
{ \
return Write(signchar##bitsize##To##endian##Endian(value)); \
}
#define BASE_SPANWRITER_WRITE_BOTH_SIGNS(bitsize, endian) \
BASE_SPANWRITER_WRITE(U, bitsize, endian, u) \
BASE_SPANWRITER_WRITE(I, bitsize, endian, )
#define BASE_SPANWRITER_WRITE_BOTH_SIGNS_ALL_SIZES(endian) \
BASE_SPANWRITER_WRITE_BOTH_SIGNS(8, endian) \
BASE_SPANWRITER_WRITE_BOTH_SIGNS(16, endian) \
BASE_SPANWRITER_WRITE_BOTH_SIGNS(32, endian) \
BASE_SPANWRITER_WRITE_BOTH_SIGNS(64, endian)
BASE_SPANWRITER_WRITE_BOTH_SIGNS_ALL_SIZES(Big)
BASE_SPANWRITER_WRITE_BOTH_SIGNS_ALL_SIZES(Little)
BASE_SPANWRITER_WRITE_BOTH_SIGNS_ALL_SIZES(Native)
#undef BASE_SPANWRITER_WRITE_BOTH_SIGNS_ALL_SIZES
#undef BASE_SPANWRITER_WRITE_BOTH_SIGNS
#undef BASE_SPANWRITER_WRITE
// Returns the remaining not-yet-written-to object count.
constexpr size_t remaining() const { return buf_.size(); }
// Returns the remaining not-yet-written-to objects.
constexpr span<T> remaining_span() const { return buf_; }
// Returns the number of objects already written (or skipped).
constexpr size_t num_written() const { return original_size_ - buf_.size(); }
private:
raw_span<T> buf_;
size_t original_size_;
};
template <class T, size_t N>
SpanWriter(span<T, N>) -> SpanWriter<T>;
} // namespace base
#endif // BASE_CONTAINERS_SPAN_WRITER_H_