xref: /aosp_15_r20/external/cronet/base/containers/buffer_iterator.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2019 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_BUFFER_ITERATOR_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_CONTAINERS_BUFFER_ITERATOR_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <string.h>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include <concepts>
11*6777b538SAndroid Build Coastguard Worker #include <optional>
12*6777b538SAndroid Build Coastguard Worker 
13*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/numerics/checked_math.h"
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker namespace base {
18*6777b538SAndroid Build Coastguard Worker 
19*6777b538SAndroid Build Coastguard Worker // BufferIterator is a bounds-checked container utility to access variable-
20*6777b538SAndroid Build Coastguard Worker // length, heterogeneous structures contained within a buffer. If the data are
21*6777b538SAndroid Build Coastguard Worker // homogeneous, use base::span<> instead.
22*6777b538SAndroid Build Coastguard Worker //
23*6777b538SAndroid Build Coastguard Worker // After being created with a weakly-owned buffer, BufferIterator returns
24*6777b538SAndroid Build Coastguard Worker // pointers to structured data within the buffer. After each method call that
25*6777b538SAndroid Build Coastguard Worker // returns data in the buffer, the iterator position is advanced by the byte
26*6777b538SAndroid Build Coastguard Worker // size of the object (or span of objects) returned. If there are not enough
27*6777b538SAndroid Build Coastguard Worker // bytes remaining in the buffer to return the requested object(s), a nullptr
28*6777b538SAndroid Build Coastguard Worker // or empty span is returned.
29*6777b538SAndroid Build Coastguard Worker //
30*6777b538SAndroid Build Coastguard Worker // This class is similar to base::Pickle, which should be preferred for
31*6777b538SAndroid Build Coastguard Worker // serializing to disk. Pickle versions its header and does not support writing
32*6777b538SAndroid Build Coastguard Worker // structures, which are problematic for serialization due to struct padding and
33*6777b538SAndroid Build Coastguard Worker // version shear concerns.
34*6777b538SAndroid Build Coastguard Worker //
35*6777b538SAndroid Build Coastguard Worker // Example usage:
36*6777b538SAndroid Build Coastguard Worker //
37*6777b538SAndroid Build Coastguard Worker //    std::vector<uint8_t> buffer(4096);
38*6777b538SAndroid Build Coastguard Worker //    if (!ReadSomeData(&buffer, buffer.size())) {
39*6777b538SAndroid Build Coastguard Worker //      LOG(ERROR) << "Failed to read data.";
40*6777b538SAndroid Build Coastguard Worker //      return false;
41*6777b538SAndroid Build Coastguard Worker //    }
42*6777b538SAndroid Build Coastguard Worker //
43*6777b538SAndroid Build Coastguard Worker //    BufferIterator<uint8_t> iterator(buffer);
44*6777b538SAndroid Build Coastguard Worker //    uint32_t* num_items = iterator.Object<uint32_t>();
45*6777b538SAndroid Build Coastguard Worker //    if (!num_items) {
46*6777b538SAndroid Build Coastguard Worker //      LOG(ERROR) << "No num_items field."
47*6777b538SAndroid Build Coastguard Worker //      return false;
48*6777b538SAndroid Build Coastguard Worker //    }
49*6777b538SAndroid Build Coastguard Worker //
50*6777b538SAndroid Build Coastguard Worker //    base::span<const item_struct> items =
51*6777b538SAndroid Build Coastguard Worker //        iterator.Span<item_struct>(*num_items);
52*6777b538SAndroid Build Coastguard Worker //    if (items.size() != *num_items) {
53*6777b538SAndroid Build Coastguard Worker //      LOG(ERROR) << "Not enough items.";
54*6777b538SAndroid Build Coastguard Worker //      return false;
55*6777b538SAndroid Build Coastguard Worker //    }
56*6777b538SAndroid Build Coastguard Worker //
57*6777b538SAndroid Build Coastguard Worker //    // ... validate the objects in |items|.
58*6777b538SAndroid Build Coastguard Worker template <typename B>
59*6777b538SAndroid Build Coastguard Worker class BufferIterator {
60*6777b538SAndroid Build Coastguard Worker  public:
61*6777b538SAndroid Build Coastguard Worker   static_assert(std::same_as<std::remove_const_t<B>, char> ||
62*6777b538SAndroid Build Coastguard Worker                     std::same_as<std::remove_const_t<B>, unsigned char>,
63*6777b538SAndroid Build Coastguard Worker                 "Underlying buffer type must be char-type.");
64*6777b538SAndroid Build Coastguard Worker   // Constructs an empty BufferIterator that will always return null pointers.
BufferIterator()65*6777b538SAndroid Build Coastguard Worker   BufferIterator() {}
66*6777b538SAndroid Build Coastguard Worker 
67*6777b538SAndroid Build Coastguard Worker   // Constructs a BufferIterator over the `buffer` span, that will return
68*6777b538SAndroid Build Coastguard Worker   // pointers into the span.
BufferIterator(span<B> buffer)69*6777b538SAndroid Build Coastguard Worker   explicit BufferIterator(span<B> buffer)
70*6777b538SAndroid Build Coastguard Worker       : buffer_(buffer), remaining_(buffer) {}
71*6777b538SAndroid Build Coastguard Worker 
72*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/40284755): Move all callers to use spans and remove this.
BufferIterator(B * data,size_t size)73*6777b538SAndroid Build Coastguard Worker   UNSAFE_BUFFER_USAGE BufferIterator(B* data, size_t size)
74*6777b538SAndroid Build Coastguard Worker       : BufferIterator(
75*6777b538SAndroid Build Coastguard Worker             // TODO(crbug.com/40284755): Remove this constructor entirely,
76*6777b538SAndroid Build Coastguard Worker             // callers should provide a span. There's no way to know that the
77*6777b538SAndroid Build Coastguard Worker             // size is correct here.
78*6777b538SAndroid Build Coastguard Worker             UNSAFE_BUFFERS(span(data, size))) {}
79*6777b538SAndroid Build Coastguard Worker 
80*6777b538SAndroid Build Coastguard Worker   // Copies out an object. As compared to using `Object`, this avoids potential
81*6777b538SAndroid Build Coastguard Worker   // unaligned access which may be undefined behavior.
82*6777b538SAndroid Build Coastguard Worker   template <typename T,
83*6777b538SAndroid Build Coastguard Worker             typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
CopyObject()84*6777b538SAndroid Build Coastguard Worker   std::optional<T> CopyObject() {
85*6777b538SAndroid Build Coastguard Worker     std::optional<T> t;
86*6777b538SAndroid Build Coastguard Worker     if (remaining_.size() >= sizeof(T)) {
87*6777b538SAndroid Build Coastguard Worker       auto [source, remain] = remaining_.template split_at<sizeof(T)>();
88*6777b538SAndroid Build Coastguard Worker       byte_span_from_ref(t.emplace()).copy_from(as_bytes(source));
89*6777b538SAndroid Build Coastguard Worker       remaining_ = remain;
90*6777b538SAndroid Build Coastguard Worker     }
91*6777b538SAndroid Build Coastguard Worker     return t;
92*6777b538SAndroid Build Coastguard Worker   }
93*6777b538SAndroid Build Coastguard Worker 
94*6777b538SAndroid Build Coastguard Worker   // Returns a const pointer to an object of type T in the buffer at the current
95*6777b538SAndroid Build Coastguard Worker   // position.
96*6777b538SAndroid Build Coastguard Worker   //
97*6777b538SAndroid Build Coastguard Worker   // # Safety
98*6777b538SAndroid Build Coastguard Worker   // Note that the buffer's current position must be aligned for the type T
99*6777b538SAndroid Build Coastguard Worker   // or using the pointer will cause Undefined Behaviour. Generally prefer
100*6777b538SAndroid Build Coastguard Worker   // `CopyObject` as it avoids this problem entirely.
101*6777b538SAndroid Build Coastguard Worker   // TODO(danakj): We should probably CHECK this instead of allowing UB into
102*6777b538SAndroid Build Coastguard Worker   // production.
103*6777b538SAndroid Build Coastguard Worker   template <typename T,
104*6777b538SAndroid Build Coastguard Worker             typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
Object()105*6777b538SAndroid Build Coastguard Worker   const T* Object() {
106*6777b538SAndroid Build Coastguard Worker     return MutableObject<const T>();
107*6777b538SAndroid Build Coastguard Worker   }
108*6777b538SAndroid Build Coastguard Worker 
109*6777b538SAndroid Build Coastguard Worker   // Returns a pointer to a mutable structure T in the buffer at the current
110*6777b538SAndroid Build Coastguard Worker   // position. On success, the iterator position is advanced by sizeof(T). If
111*6777b538SAndroid Build Coastguard Worker   // there are not sizeof(T) bytes remaining in the buffer, returns nullptr.
112*6777b538SAndroid Build Coastguard Worker   //
113*6777b538SAndroid Build Coastguard Worker   // # Safety
114*6777b538SAndroid Build Coastguard Worker   // Note that the buffer's current position must be aligned for the type T or
115*6777b538SAndroid Build Coastguard Worker   // using the pointer will cause Undefined Behaviour. Generally prefer
116*6777b538SAndroid Build Coastguard Worker   // `CopyObject` as it avoids this problem entirely.
117*6777b538SAndroid Build Coastguard Worker   // TODO(danakj): We should probably CHECK this instead of allowing UB into
118*6777b538SAndroid Build Coastguard Worker   // production.
119*6777b538SAndroid Build Coastguard Worker   template <typename T,
120*6777b538SAndroid Build Coastguard Worker             typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
MutableObject()121*6777b538SAndroid Build Coastguard Worker   T* MutableObject() {
122*6777b538SAndroid Build Coastguard Worker     T* t = nullptr;
123*6777b538SAndroid Build Coastguard Worker     if (remaining_.size() >= sizeof(T)) {
124*6777b538SAndroid Build Coastguard Worker       auto [source, remain] = remaining_.template split_at<sizeof(T)>();
125*6777b538SAndroid Build Coastguard Worker       // TODO(danakj): This is UB without creating a lifetime for the object in
126*6777b538SAndroid Build Coastguard Worker       // the compiler, which we can not do before C++23:
127*6777b538SAndroid Build Coastguard Worker       // https://en.cppreference.com/w/cpp/memory/start_lifetime_as
128*6777b538SAndroid Build Coastguard Worker       t = reinterpret_cast<T*>(source.data());
129*6777b538SAndroid Build Coastguard Worker       remaining_ = remain;
130*6777b538SAndroid Build Coastguard Worker     }
131*6777b538SAndroid Build Coastguard Worker     return t;
132*6777b538SAndroid Build Coastguard Worker   }
133*6777b538SAndroid Build Coastguard Worker 
134*6777b538SAndroid Build Coastguard Worker   // Returns a span of |count| T objects in the buffer at the current position.
135*6777b538SAndroid Build Coastguard Worker   // On success, the iterator position is advanced by |sizeof(T) * count|. If
136*6777b538SAndroid Build Coastguard Worker   // there are not enough bytes remaining in the buffer to fulfill the request,
137*6777b538SAndroid Build Coastguard Worker   // returns an empty span.
138*6777b538SAndroid Build Coastguard Worker   //
139*6777b538SAndroid Build Coastguard Worker   // # Safety
140*6777b538SAndroid Build Coastguard Worker   // Note that the buffer's current position must be aligned for the type T or
141*6777b538SAndroid Build Coastguard Worker   // using the span will cause Undefined Behaviour.
142*6777b538SAndroid Build Coastguard Worker   // TODO(danakj): We should probably CHECK this instead of allowing UB into
143*6777b538SAndroid Build Coastguard Worker   // production.
144*6777b538SAndroid Build Coastguard Worker   template <typename T,
145*6777b538SAndroid Build Coastguard Worker             typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
MutableSpan(size_t count)146*6777b538SAndroid Build Coastguard Worker   span<T> MutableSpan(size_t count) {
147*6777b538SAndroid Build Coastguard Worker     size_t byte_size;
148*6777b538SAndroid Build Coastguard Worker     if (!CheckMul(sizeof(T), count).AssignIfValid(&byte_size)) {
149*6777b538SAndroid Build Coastguard Worker       return span<T>();
150*6777b538SAndroid Build Coastguard Worker     }
151*6777b538SAndroid Build Coastguard Worker     if (byte_size > remaining_.size()) {
152*6777b538SAndroid Build Coastguard Worker       return span<T>();
153*6777b538SAndroid Build Coastguard Worker     }
154*6777b538SAndroid Build Coastguard Worker     auto [lhs, rhs] = remaining_.split_at(byte_size);
155*6777b538SAndroid Build Coastguard Worker     remaining_ = rhs;
156*6777b538SAndroid Build Coastguard Worker     // SAFETY: The byte size of `span<T>` with size `count` is `count *
157*6777b538SAndroid Build Coastguard Worker     // sizeof(T)` which is exactly `byte_size`, the byte size of `lhs`.
158*6777b538SAndroid Build Coastguard Worker     //
159*6777b538SAndroid Build Coastguard Worker     // TODO(danakj): This is UB without creating a lifetime for the object in
160*6777b538SAndroid Build Coastguard Worker     // the compiler, which we can not do before C++23:
161*6777b538SAndroid Build Coastguard Worker     // https://en.cppreference.com/w/cpp/memory/start_lifetime_as
162*6777b538SAndroid Build Coastguard Worker     return UNSAFE_BUFFERS(span<T>(reinterpret_cast<T*>(lhs.data()), count));
163*6777b538SAndroid Build Coastguard Worker   }
164*6777b538SAndroid Build Coastguard Worker 
165*6777b538SAndroid Build Coastguard Worker   // An overload for when the size is known at compile time. The result will be
166*6777b538SAndroid Build Coastguard Worker   // a fixed-size span.
167*6777b538SAndroid Build Coastguard Worker   template <typename T,
168*6777b538SAndroid Build Coastguard Worker             size_t N,
169*6777b538SAndroid Build Coastguard Worker             typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
170*6777b538SAndroid Build Coastguard Worker     requires(N <= std::numeric_limits<size_t>::max() / sizeof(T))
MutableSpan()171*6777b538SAndroid Build Coastguard Worker   std::optional<span<T, N>> MutableSpan() {
172*6777b538SAndroid Build Coastguard Worker     constexpr size_t byte_size =
173*6777b538SAndroid Build Coastguard Worker         N * sizeof(T);  // Overflow is checked by `requires`.
174*6777b538SAndroid Build Coastguard Worker     if (byte_size > remaining_.size()) {
175*6777b538SAndroid Build Coastguard Worker       return std::nullopt;
176*6777b538SAndroid Build Coastguard Worker     }
177*6777b538SAndroid Build Coastguard Worker     auto [lhs, rhs] = remaining_.split_at(byte_size);
178*6777b538SAndroid Build Coastguard Worker     remaining_ = rhs;
179*6777b538SAndroid Build Coastguard Worker     // SAFETY: The byte size of `span<T>` with size `count` is `count *
180*6777b538SAndroid Build Coastguard Worker     // sizeof(T)` which is exactly `byte_size`, the byte size of `lhs`.
181*6777b538SAndroid Build Coastguard Worker     //
182*6777b538SAndroid Build Coastguard Worker     // TODO(danakj): This is UB without creating a lifetime for the object in
183*6777b538SAndroid Build Coastguard Worker     // the compiler, which we can not do before C++23:
184*6777b538SAndroid Build Coastguard Worker     // https://en.cppreference.com/w/cpp/memory/start_lifetime_as
185*6777b538SAndroid Build Coastguard Worker     return UNSAFE_BUFFERS(span<T, N>(reinterpret_cast<T*>(lhs.data()), N));
186*6777b538SAndroid Build Coastguard Worker   }
187*6777b538SAndroid Build Coastguard Worker 
188*6777b538SAndroid Build Coastguard Worker   // Returns a span to |count| const objects of type T in the buffer at the
189*6777b538SAndroid Build Coastguard Worker   // current position.
190*6777b538SAndroid Build Coastguard Worker   //
191*6777b538SAndroid Build Coastguard Worker   // # Safety
192*6777b538SAndroid Build Coastguard Worker   // Note that the buffer's current position must be aligned for the type T or
193*6777b538SAndroid Build Coastguard Worker   // using the span will cause Undefined Behaviour.
194*6777b538SAndroid Build Coastguard Worker   // TODO(danakj): We should probably CHECK this instead of allowing UB into
195*6777b538SAndroid Build Coastguard Worker   // production.
196*6777b538SAndroid Build Coastguard Worker   template <typename T,
197*6777b538SAndroid Build Coastguard Worker             typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
Span(size_t count)198*6777b538SAndroid Build Coastguard Worker   span<const T> Span(size_t count) {
199*6777b538SAndroid Build Coastguard Worker     return MutableSpan<const T>(count);
200*6777b538SAndroid Build Coastguard Worker   }
201*6777b538SAndroid Build Coastguard Worker 
202*6777b538SAndroid Build Coastguard Worker   // An overload for when the size is known at compile time. The result will be
203*6777b538SAndroid Build Coastguard Worker   // a fixed-size span.
204*6777b538SAndroid Build Coastguard Worker   template <typename T,
205*6777b538SAndroid Build Coastguard Worker             size_t N,
206*6777b538SAndroid Build Coastguard Worker             typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
207*6777b538SAndroid Build Coastguard Worker     requires(N <= std::numeric_limits<size_t>::max() / sizeof(T))
Span()208*6777b538SAndroid Build Coastguard Worker   std::optional<span<const T, N>> Span() {
209*6777b538SAndroid Build Coastguard Worker     return MutableSpan<const T, N>();
210*6777b538SAndroid Build Coastguard Worker   }
211*6777b538SAndroid Build Coastguard Worker 
212*6777b538SAndroid Build Coastguard Worker   // Resets the iterator position to the absolute offset |to|.
Seek(size_t to)213*6777b538SAndroid Build Coastguard Worker   void Seek(size_t to) { remaining_ = buffer_.subspan(to); }
214*6777b538SAndroid Build Coastguard Worker 
215*6777b538SAndroid Build Coastguard Worker   // Limits the remaining data to the specified size.
216*6777b538SAndroid Build Coastguard Worker   // Seeking to an absolute offset reverses this.
TruncateTo(size_t size)217*6777b538SAndroid Build Coastguard Worker   void TruncateTo(size_t size) { remaining_ = remaining_.first(size); }
218*6777b538SAndroid Build Coastguard Worker 
219*6777b538SAndroid Build Coastguard Worker   // Returns the total size of the underlying buffer.
total_size()220*6777b538SAndroid Build Coastguard Worker   size_t total_size() const { return buffer_.size(); }
221*6777b538SAndroid Build Coastguard Worker 
222*6777b538SAndroid Build Coastguard Worker   // Returns the current position in the buffer.
position()223*6777b538SAndroid Build Coastguard Worker   size_t position() const {
224*6777b538SAndroid Build Coastguard Worker     // SAFETY: `remaining_` is a subspan always constructed from `buffer_` (or
225*6777b538SAndroid Build Coastguard Worker     // from itself) so its `data()` pointer is always inside `buffer_`. This
226*6777b538SAndroid Build Coastguard Worker     // means the subtraction is well-defined and the result is always
227*6777b538SAndroid Build Coastguard Worker     // non-negative.
228*6777b538SAndroid Build Coastguard Worker     return static_cast<size_t>(
229*6777b538SAndroid Build Coastguard Worker         UNSAFE_BUFFERS(remaining_.data() - buffer_.data()));
230*6777b538SAndroid Build Coastguard Worker   }
231*6777b538SAndroid Build Coastguard Worker 
232*6777b538SAndroid Build Coastguard Worker  private:
233*6777b538SAndroid Build Coastguard Worker   // The original buffer that the iterator was constructed with.
234*6777b538SAndroid Build Coastguard Worker   const span<B> buffer_;
235*6777b538SAndroid Build Coastguard Worker   // A subspan of `buffer_` containing the remaining bytes to iterate over.
236*6777b538SAndroid Build Coastguard Worker   span<B> remaining_;
237*6777b538SAndroid Build Coastguard Worker   // Copy and assign allowed.
238*6777b538SAndroid Build Coastguard Worker };
239*6777b538SAndroid Build Coastguard Worker 
240*6777b538SAndroid Build Coastguard Worker }  // namespace base
241*6777b538SAndroid Build Coastguard Worker 
242*6777b538SAndroid Build Coastguard Worker #endif  // BASE_CONTAINERS_BUFFER_ITERATOR_H_
243