xref: /aosp_15_r20/external/cronet/base/containers/span_writer.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2024 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_CONTAINERS_SPAN_WRITER_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_CONTAINERS_SPAN_WRITER_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <optional>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_span.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/numerics/byte_conversions.h"
13*6777b538SAndroid Build Coastguard Worker 
14*6777b538SAndroid Build Coastguard Worker namespace base {
15*6777b538SAndroid Build Coastguard Worker 
16*6777b538SAndroid Build Coastguard Worker // A Writer to write into and consume elements from the front of a span
17*6777b538SAndroid Build Coastguard Worker // dynamically.
18*6777b538SAndroid Build Coastguard Worker //
19*6777b538SAndroid Build Coastguard Worker // SpanWriter is used to split off prefix spans from a larger span, reporting
20*6777b538SAndroid Build Coastguard Worker // errors if there's not enough room left (instead of crashing, as would happen
21*6777b538SAndroid Build Coastguard Worker // with span directly).
22*6777b538SAndroid Build Coastguard Worker template <class T>
23*6777b538SAndroid Build Coastguard Worker class SpanWriter {
24*6777b538SAndroid Build Coastguard Worker   static_assert(!std::is_const_v<T>,
25*6777b538SAndroid Build Coastguard Worker                 "SpanWriter needs mutable access to its buffer");
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker  public:
28*6777b538SAndroid Build Coastguard Worker   // Construct SpanWriter that writes to `buf`.
SpanWriter(span<T> buf)29*6777b538SAndroid Build Coastguard Worker   explicit SpanWriter(span<T> buf) : buf_(buf), original_size_(buf_.size()) {}
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker   // Returns true and writes the span `data` into the front of the inner span,
32*6777b538SAndroid Build Coastguard Worker   // if there is enough room left. Otherwise, it returns false and does
33*6777b538SAndroid Build Coastguard Worker   // nothing.
Write(span<const T> data)34*6777b538SAndroid Build Coastguard Worker   bool Write(span<const T> data) {
35*6777b538SAndroid Build Coastguard Worker     if (data.size() > remaining()) {
36*6777b538SAndroid Build Coastguard Worker       return false;
37*6777b538SAndroid Build Coastguard Worker     }
38*6777b538SAndroid Build Coastguard Worker     auto [lhs, rhs] = buf_.split_at(data.size());
39*6777b538SAndroid Build Coastguard Worker     lhs.copy_from(data);
40*6777b538SAndroid Build Coastguard Worker     buf_ = rhs;
41*6777b538SAndroid Build Coastguard Worker     return true;
42*6777b538SAndroid Build Coastguard Worker   }
43*6777b538SAndroid Build Coastguard Worker 
44*6777b538SAndroid Build Coastguard Worker   // Skips over the next `n` objects, and returns a span that points to the
45*6777b538SAndroid Build Coastguard Worker   // skipped objects, if there are enough objects left. Otherwise, it returns
46*6777b538SAndroid Build Coastguard Worker   // nullopt and does nothing.
Skip(StrictNumeric<size_t> n)47*6777b538SAndroid Build Coastguard Worker   std::optional<span<T>> Skip(StrictNumeric<size_t> n) {
48*6777b538SAndroid Build Coastguard Worker     if (n > remaining()) {
49*6777b538SAndroid Build Coastguard Worker       return std::nullopt;
50*6777b538SAndroid Build Coastguard Worker     }
51*6777b538SAndroid Build Coastguard Worker     auto [lhs, rhs] = buf_.split_at(n);
52*6777b538SAndroid Build Coastguard Worker     buf_ = rhs;
53*6777b538SAndroid Build Coastguard Worker     return lhs;
54*6777b538SAndroid Build Coastguard Worker   }
55*6777b538SAndroid Build Coastguard Worker   // Skips over the next `N` objects, and returns a fixed-size span that points
56*6777b538SAndroid Build Coastguard Worker   // to the skipped objects, if there are enough objects left. Otherwise, it
57*6777b538SAndroid Build Coastguard Worker   // returns nullopt and does nothing.
58*6777b538SAndroid Build Coastguard Worker   template <size_t N>
Skip()59*6777b538SAndroid Build Coastguard Worker   std::optional<span<T, N>> Skip() {
60*6777b538SAndroid Build Coastguard Worker     if (N > remaining()) {
61*6777b538SAndroid Build Coastguard Worker       return std::nullopt;
62*6777b538SAndroid Build Coastguard Worker     }
63*6777b538SAndroid Build Coastguard Worker     auto [lhs, rhs] = buf_.template split_at<N>();
64*6777b538SAndroid Build Coastguard Worker     buf_ = rhs;
65*6777b538SAndroid Build Coastguard Worker     return lhs;
66*6777b538SAndroid Build Coastguard Worker   }
67*6777b538SAndroid Build Coastguard Worker 
68*6777b538SAndroid Build Coastguard Worker   // For a SpanWriter over bytes, we can write integer values directly to those
69*6777b538SAndroid Build Coastguard Worker   // bytes as a memcpy. Returns true if there was room remaining and the bytes
70*6777b538SAndroid Build Coastguard Worker   // were written.
71*6777b538SAndroid Build Coastguard Worker   //
72*6777b538SAndroid Build Coastguard Worker   // These copy the bytes into the buffer in big endian order.
WriteU8BigEndian(uint8_t value)73*6777b538SAndroid Build Coastguard Worker   bool WriteU8BigEndian(uint8_t value)
74*6777b538SAndroid Build Coastguard Worker     requires(std::same_as<T, uint8_t>)
75*6777b538SAndroid Build Coastguard Worker   {
76*6777b538SAndroid Build Coastguard Worker     return Write(U8ToBigEndian(value));
77*6777b538SAndroid Build Coastguard Worker   }
WriteU16BigEndian(uint16_t value)78*6777b538SAndroid Build Coastguard Worker   bool WriteU16BigEndian(uint16_t value)
79*6777b538SAndroid Build Coastguard Worker     requires(std::same_as<T, uint8_t>)
80*6777b538SAndroid Build Coastguard Worker   {
81*6777b538SAndroid Build Coastguard Worker     return Write(U16ToBigEndian(value));
82*6777b538SAndroid Build Coastguard Worker   }
WriteU32BigEndian(uint32_t value)83*6777b538SAndroid Build Coastguard Worker   bool WriteU32BigEndian(uint32_t value)
84*6777b538SAndroid Build Coastguard Worker     requires(std::same_as<T, uint8_t>)
85*6777b538SAndroid Build Coastguard Worker   {
86*6777b538SAndroid Build Coastguard Worker     return Write(U32ToBigEndian(value));
87*6777b538SAndroid Build Coastguard Worker   }
WriteU64BigEndian(uint64_t value)88*6777b538SAndroid Build Coastguard Worker   bool WriteU64BigEndian(uint64_t value)
89*6777b538SAndroid Build Coastguard Worker     requires(std::same_as<T, uint8_t>)
90*6777b538SAndroid Build Coastguard Worker   {
91*6777b538SAndroid Build Coastguard Worker     return Write(U64ToBigEndian(value));
92*6777b538SAndroid Build Coastguard Worker   }
93*6777b538SAndroid Build Coastguard Worker 
94*6777b538SAndroid Build Coastguard Worker   // For a SpanWriter over bytes, we can write integer values directly to those
95*6777b538SAndroid Build Coastguard Worker   // bytes as a memcpy. Returns true if there was room remaining and the bytes
96*6777b538SAndroid Build Coastguard Worker   // were written.
97*6777b538SAndroid Build Coastguard Worker   //
98*6777b538SAndroid Build Coastguard Worker   // These copy the bytes into the buffer in little endian order.
WriteU8LittleEndian(uint8_t value)99*6777b538SAndroid Build Coastguard Worker   bool WriteU8LittleEndian(uint8_t value)
100*6777b538SAndroid Build Coastguard Worker     requires(std::same_as<T, uint8_t>)
101*6777b538SAndroid Build Coastguard Worker   {
102*6777b538SAndroid Build Coastguard Worker     return Write(U8ToLittleEndian(value));
103*6777b538SAndroid Build Coastguard Worker   }
WriteU16LittleEndian(uint16_t value)104*6777b538SAndroid Build Coastguard Worker   bool WriteU16LittleEndian(uint16_t value)
105*6777b538SAndroid Build Coastguard Worker     requires(std::same_as<T, uint8_t>)
106*6777b538SAndroid Build Coastguard Worker   {
107*6777b538SAndroid Build Coastguard Worker     return Write(U16ToLittleEndian(value));
108*6777b538SAndroid Build Coastguard Worker   }
WriteU32LittleEndian(uint32_t value)109*6777b538SAndroid Build Coastguard Worker   bool WriteU32LittleEndian(uint32_t value)
110*6777b538SAndroid Build Coastguard Worker     requires(std::same_as<T, uint8_t>)
111*6777b538SAndroid Build Coastguard Worker   {
112*6777b538SAndroid Build Coastguard Worker     return Write(U32ToLittleEndian(value));
113*6777b538SAndroid Build Coastguard Worker   }
WriteU64LittleEndian(uint64_t value)114*6777b538SAndroid Build Coastguard Worker   bool WriteU64LittleEndian(uint64_t value)
115*6777b538SAndroid Build Coastguard Worker     requires(std::same_as<T, uint8_t>)
116*6777b538SAndroid Build Coastguard Worker   {
117*6777b538SAndroid Build Coastguard Worker     return Write(U64ToLittleEndian(value));
118*6777b538SAndroid Build Coastguard Worker   }
119*6777b538SAndroid Build Coastguard Worker 
120*6777b538SAndroid Build Coastguard Worker   // For a SpanWriter over bytes, we can write integer values directly to those
121*6777b538SAndroid Build Coastguard Worker   // bytes as a memcpy. Returns true if there was room remaining and the bytes
122*6777b538SAndroid Build Coastguard Worker   // were written.
123*6777b538SAndroid Build Coastguard Worker   //
124*6777b538SAndroid Build Coastguard Worker   // These copy the bytes into the buffer in native endian order. Note that this
125*6777b538SAndroid Build Coastguard Worker   // is almost never what you want to do. Native ordering only makes sense for
126*6777b538SAndroid Build Coastguard Worker   // byte buffers that are only meant to stay in memory and never be written to
127*6777b538SAndroid Build Coastguard Worker   // the disk or network.
WriteU8NativeEndian(uint8_t value)128*6777b538SAndroid Build Coastguard Worker   bool WriteU8NativeEndian(uint8_t value)
129*6777b538SAndroid Build Coastguard Worker     requires(std::same_as<T, uint8_t>)
130*6777b538SAndroid Build Coastguard Worker   {
131*6777b538SAndroid Build Coastguard Worker     return Write(U8ToNativeEndian(value));
132*6777b538SAndroid Build Coastguard Worker   }
WriteU16NativeEndian(uint16_t value)133*6777b538SAndroid Build Coastguard Worker   bool WriteU16NativeEndian(uint16_t value)
134*6777b538SAndroid Build Coastguard Worker     requires(std::same_as<T, uint8_t>)
135*6777b538SAndroid Build Coastguard Worker   {
136*6777b538SAndroid Build Coastguard Worker     return Write(U16ToNativeEndian(value));
137*6777b538SAndroid Build Coastguard Worker   }
WriteU32NativeEndian(uint32_t value)138*6777b538SAndroid Build Coastguard Worker   bool WriteU32NativeEndian(uint32_t value)
139*6777b538SAndroid Build Coastguard Worker     requires(std::same_as<T, uint8_t>)
140*6777b538SAndroid Build Coastguard Worker   {
141*6777b538SAndroid Build Coastguard Worker     return Write(U32ToNativeEndian(value));
142*6777b538SAndroid Build Coastguard Worker   }
WriteU64NativeEndian(uint64_t value)143*6777b538SAndroid Build Coastguard Worker   bool WriteU64NativeEndian(uint64_t value)
144*6777b538SAndroid Build Coastguard Worker     requires(std::same_as<T, uint8_t>)
145*6777b538SAndroid Build Coastguard Worker   {
146*6777b538SAndroid Build Coastguard Worker     return Write(U64ToNativeEndian(value));
147*6777b538SAndroid Build Coastguard Worker   }
148*6777b538SAndroid Build Coastguard Worker 
149*6777b538SAndroid Build Coastguard Worker   // Returns the number of objects remaining to be written to the original span.
remaining()150*6777b538SAndroid Build Coastguard Worker   size_t remaining() const { return buf_.size(); }
151*6777b538SAndroid Build Coastguard Worker   // Returns the objects that have not yet been written to, as a span.
remaining_span()152*6777b538SAndroid Build Coastguard Worker   span<T> remaining_span() const { return buf_; }
153*6777b538SAndroid Build Coastguard Worker 
154*6777b538SAndroid Build Coastguard Worker   // Returns the number of objects written (or skipped) in the original span.
num_written()155*6777b538SAndroid Build Coastguard Worker   size_t num_written() const { return original_size_ - buf_.size(); }
156*6777b538SAndroid Build Coastguard Worker 
157*6777b538SAndroid Build Coastguard Worker  private:
158*6777b538SAndroid Build Coastguard Worker   raw_span<T> buf_;
159*6777b538SAndroid Build Coastguard Worker   size_t original_size_;
160*6777b538SAndroid Build Coastguard Worker };
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker template <class T, size_t N>
163*6777b538SAndroid Build Coastguard Worker SpanWriter(span<T, N>) -> SpanWriter<T>;
164*6777b538SAndroid Build Coastguard Worker 
165*6777b538SAndroid Build Coastguard Worker }  // namespace base
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker #endif  // BASE_CONTAINERS_SPAN_WRITER_H_
168