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_READER_H_ 6*6777b538SAndroid Build Coastguard Worker #define BASE_CONTAINERS_SPAN_READER_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include <concepts> 9*6777b538SAndroid Build Coastguard Worker #include <optional> 10*6777b538SAndroid Build Coastguard Worker 11*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h" 12*6777b538SAndroid Build Coastguard Worker #include "base/numerics/byte_conversions.h" 13*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions.h" 14*6777b538SAndroid Build Coastguard Worker 15*6777b538SAndroid Build Coastguard Worker namespace base { 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Worker // A Reader to consume elements from the front of a span dynamically. 18*6777b538SAndroid Build Coastguard Worker // 19*6777b538SAndroid Build Coastguard Worker // SpanReader 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 SpanReader { 24*6777b538SAndroid Build Coastguard Worker public: 25*6777b538SAndroid Build Coastguard Worker // Construct SpanReader from a span. SpanReader(span<T> buf)26*6777b538SAndroid Build Coastguard Worker explicit SpanReader(span<T> buf) : buf_(buf), original_size_(buf_.size()) {} 27*6777b538SAndroid Build Coastguard Worker 28*6777b538SAndroid Build Coastguard Worker // Returns a span over the next `n` objects, if there are enough objects left. 29*6777b538SAndroid Build Coastguard Worker // Otherwise, it returns nullopt and does nothing. Read(base::StrictNumeric<size_t> n)30*6777b538SAndroid Build Coastguard Worker std::optional<span<T>> Read(base::StrictNumeric<size_t> n) { 31*6777b538SAndroid Build Coastguard Worker if (n > remaining()) { 32*6777b538SAndroid Build Coastguard Worker return std::nullopt; 33*6777b538SAndroid Build Coastguard Worker } 34*6777b538SAndroid Build Coastguard Worker auto [lhs, rhs] = buf_.split_at(n); 35*6777b538SAndroid Build Coastguard Worker buf_ = rhs; 36*6777b538SAndroid Build Coastguard Worker return lhs; 37*6777b538SAndroid Build Coastguard Worker } 38*6777b538SAndroid Build Coastguard Worker 39*6777b538SAndroid Build Coastguard Worker // Returns a fixed-size span over the next `N` objects, if there are enough 40*6777b538SAndroid Build Coastguard Worker // objects left. Otherwise, it returns nullopt and does nothing. 41*6777b538SAndroid Build Coastguard Worker template <size_t N> Read()42*6777b538SAndroid Build Coastguard Worker std::optional<span<T, N>> Read() { 43*6777b538SAndroid Build Coastguard Worker if (N > remaining()) { 44*6777b538SAndroid Build Coastguard Worker return std::nullopt; 45*6777b538SAndroid Build Coastguard Worker } 46*6777b538SAndroid Build Coastguard Worker auto [lhs, rhs] = buf_.template split_at<N>(); 47*6777b538SAndroid Build Coastguard Worker buf_ = rhs; 48*6777b538SAndroid Build Coastguard Worker return lhs; 49*6777b538SAndroid Build Coastguard Worker } 50*6777b538SAndroid Build Coastguard Worker 51*6777b538SAndroid Build Coastguard Worker // Returns true and writes a span over the next `n` objects into `out`, if 52*6777b538SAndroid Build Coastguard Worker // there are enough objects left. Otherwise, it returns false and does 53*6777b538SAndroid Build Coastguard Worker // nothing. ReadInto(base::StrictNumeric<size_t> n,span<T> & out)54*6777b538SAndroid Build Coastguard Worker bool ReadInto(base::StrictNumeric<size_t> n, span<T>& out) { 55*6777b538SAndroid Build Coastguard Worker if (n > remaining()) { 56*6777b538SAndroid Build Coastguard Worker return false; 57*6777b538SAndroid Build Coastguard Worker } 58*6777b538SAndroid Build Coastguard Worker auto [lhs, rhs] = buf_.split_at(n); 59*6777b538SAndroid Build Coastguard Worker out = lhs; 60*6777b538SAndroid Build Coastguard Worker buf_ = rhs; 61*6777b538SAndroid Build Coastguard Worker return true; 62*6777b538SAndroid Build Coastguard Worker } 63*6777b538SAndroid Build Coastguard Worker 64*6777b538SAndroid Build Coastguard Worker // Returns true and copies objects into `out`, if there are enough objects 65*6777b538SAndroid Build Coastguard Worker // left to fill `out`. Otherwise, it returns false and does nothing. ReadCopy(span<std::remove_const_t<T>> out)66*6777b538SAndroid Build Coastguard Worker bool ReadCopy(span<std::remove_const_t<T>> out) { 67*6777b538SAndroid Build Coastguard Worker if (out.size() > remaining()) { 68*6777b538SAndroid Build Coastguard Worker return false; 69*6777b538SAndroid Build Coastguard Worker } 70*6777b538SAndroid Build Coastguard Worker auto [lhs, rhs] = buf_.split_at(out.size()); 71*6777b538SAndroid Build Coastguard Worker out.copy_from(lhs); 72*6777b538SAndroid Build Coastguard Worker buf_ = rhs; 73*6777b538SAndroid Build Coastguard Worker return true; 74*6777b538SAndroid Build Coastguard Worker } 75*6777b538SAndroid Build Coastguard Worker 76*6777b538SAndroid Build Coastguard Worker // Returns true and skips over the next `n` objects, if there are enough 77*6777b538SAndroid Build Coastguard Worker // objects left. Otherwise, it returns false and does nothing. Skip(base::StrictNumeric<size_t> n)78*6777b538SAndroid Build Coastguard Worker std::optional<base::span<T>> Skip(base::StrictNumeric<size_t> n) { 79*6777b538SAndroid Build Coastguard Worker if (n > remaining()) { 80*6777b538SAndroid Build Coastguard Worker return std::nullopt; 81*6777b538SAndroid Build Coastguard Worker } 82*6777b538SAndroid Build Coastguard Worker auto [lhs, rhs] = buf_.split_at(n); 83*6777b538SAndroid Build Coastguard Worker buf_ = rhs; 84*6777b538SAndroid Build Coastguard Worker return lhs; 85*6777b538SAndroid Build Coastguard Worker } 86*6777b538SAndroid Build Coastguard Worker 87*6777b538SAndroid Build Coastguard Worker // For a SpanReader over bytes, we can read integer values directly from those 88*6777b538SAndroid Build Coastguard Worker // bytes as a memcpy. Returns true if there was room remaining and the bytes 89*6777b538SAndroid Build Coastguard Worker // were read. 90*6777b538SAndroid Build Coastguard Worker // 91*6777b538SAndroid Build Coastguard Worker // These treat the bytes from the buffer as being in big endian order. ReadU8BigEndian(uint8_t & value)92*6777b538SAndroid Build Coastguard Worker bool ReadU8BigEndian(uint8_t& value) 93*6777b538SAndroid Build Coastguard Worker requires(std::same_as<std::remove_const_t<T>, uint8_t>) 94*6777b538SAndroid Build Coastguard Worker { 95*6777b538SAndroid Build Coastguard Worker return ReadAnd<1>([&](auto buf) { value = U8FromBigEndian(buf); }); 96*6777b538SAndroid Build Coastguard Worker } ReadU16BigEndian(uint16_t & value)97*6777b538SAndroid Build Coastguard Worker bool ReadU16BigEndian(uint16_t& value) 98*6777b538SAndroid Build Coastguard Worker requires(std::same_as<std::remove_const_t<T>, uint8_t>) 99*6777b538SAndroid Build Coastguard Worker { 100*6777b538SAndroid Build Coastguard Worker return ReadAnd<2>([&](auto buf) { value = U16FromBigEndian(buf); }); 101*6777b538SAndroid Build Coastguard Worker } ReadU32BigEndian(uint32_t & value)102*6777b538SAndroid Build Coastguard Worker bool ReadU32BigEndian(uint32_t& value) 103*6777b538SAndroid Build Coastguard Worker requires(std::same_as<std::remove_const_t<T>, uint8_t>) 104*6777b538SAndroid Build Coastguard Worker { 105*6777b538SAndroid Build Coastguard Worker return ReadAnd<4>([&](auto buf) { value = U32FromBigEndian(buf); }); 106*6777b538SAndroid Build Coastguard Worker } ReadU64BigEndian(uint64_t & value)107*6777b538SAndroid Build Coastguard Worker bool ReadU64BigEndian(uint64_t& value) 108*6777b538SAndroid Build Coastguard Worker requires(std::same_as<std::remove_const_t<T>, uint8_t>) 109*6777b538SAndroid Build Coastguard Worker { 110*6777b538SAndroid Build Coastguard Worker return ReadAnd<8>([&](auto buf) { value = U64FromBigEndian(buf); }); 111*6777b538SAndroid Build Coastguard Worker } 112*6777b538SAndroid Build Coastguard Worker 113*6777b538SAndroid Build Coastguard Worker // For a SpanReader over bytes, we can read integer values directly from those 114*6777b538SAndroid Build Coastguard Worker // bytes as a memcpy. Returns true if there was room remaining and the bytes 115*6777b538SAndroid Build Coastguard Worker // were read. 116*6777b538SAndroid Build Coastguard Worker // 117*6777b538SAndroid Build Coastguard Worker // These treat the bytes from the buffer as being in little endian order. ReadU8LittleEndian(uint8_t & value)118*6777b538SAndroid Build Coastguard Worker bool ReadU8LittleEndian(uint8_t& value) 119*6777b538SAndroid Build Coastguard Worker requires(std::same_as<std::remove_const_t<T>, uint8_t>) 120*6777b538SAndroid Build Coastguard Worker { 121*6777b538SAndroid Build Coastguard Worker return ReadAnd<1>([&](auto buf) { value = U8FromLittleEndian(buf); }); 122*6777b538SAndroid Build Coastguard Worker } ReadU16LittleEndian(uint16_t & value)123*6777b538SAndroid Build Coastguard Worker bool ReadU16LittleEndian(uint16_t& value) 124*6777b538SAndroid Build Coastguard Worker requires(std::same_as<std::remove_const_t<T>, uint8_t>) 125*6777b538SAndroid Build Coastguard Worker { 126*6777b538SAndroid Build Coastguard Worker return ReadAnd<2>([&](auto buf) { value = U16FromLittleEndian(buf); }); 127*6777b538SAndroid Build Coastguard Worker } ReadU32LittleEndian(uint32_t & value)128*6777b538SAndroid Build Coastguard Worker bool ReadU32LittleEndian(uint32_t& value) 129*6777b538SAndroid Build Coastguard Worker requires(std::same_as<std::remove_const_t<T>, uint8_t>) 130*6777b538SAndroid Build Coastguard Worker { 131*6777b538SAndroid Build Coastguard Worker return ReadAnd<4>([&](auto buf) { value = U32FromLittleEndian(buf); }); 132*6777b538SAndroid Build Coastguard Worker } ReadU64LittleEndian(uint64_t & value)133*6777b538SAndroid Build Coastguard Worker bool ReadU64LittleEndian(uint64_t& value) 134*6777b538SAndroid Build Coastguard Worker requires(std::same_as<std::remove_const_t<T>, uint8_t>) 135*6777b538SAndroid Build Coastguard Worker { 136*6777b538SAndroid Build Coastguard Worker return ReadAnd<8>([&](auto buf) { value = U64FromLittleEndian(buf); }); 137*6777b538SAndroid Build Coastguard Worker } 138*6777b538SAndroid Build Coastguard Worker 139*6777b538SAndroid Build Coastguard Worker // For a SpanReader over bytes, we can read integer values directly from those 140*6777b538SAndroid Build Coastguard Worker // bytes as a memcpy. Returns true if there was room remaining and the bytes 141*6777b538SAndroid Build Coastguard Worker // were read. 142*6777b538SAndroid Build Coastguard Worker // 143*6777b538SAndroid Build Coastguard Worker // These treat the bytes from the buffer as being in native endian order. Note 144*6777b538SAndroid Build Coastguard Worker // that this is almost never what you want to do. Native ordering only makes 145*6777b538SAndroid Build Coastguard Worker // sense for byte buffers that are only meant to stay in memory and never be 146*6777b538SAndroid Build Coastguard Worker // written to the disk or network. ReadU8NativeEndian(uint8_t & value)147*6777b538SAndroid Build Coastguard Worker bool ReadU8NativeEndian(uint8_t& value) 148*6777b538SAndroid Build Coastguard Worker requires(std::same_as<std::remove_const_t<T>, uint8_t>) 149*6777b538SAndroid Build Coastguard Worker { 150*6777b538SAndroid Build Coastguard Worker return ReadAnd<1>([&](auto buf) { value = U8FromNativeEndian(buf); }); 151*6777b538SAndroid Build Coastguard Worker } ReadU16NativeEndian(uint16_t & value)152*6777b538SAndroid Build Coastguard Worker bool ReadU16NativeEndian(uint16_t& value) 153*6777b538SAndroid Build Coastguard Worker requires(std::same_as<std::remove_const_t<T>, uint8_t>) 154*6777b538SAndroid Build Coastguard Worker { 155*6777b538SAndroid Build Coastguard Worker return ReadAnd<2>([&](auto buf) { value = U16FromNativeEndian(buf); }); 156*6777b538SAndroid Build Coastguard Worker } ReadU32NativeEndian(uint32_t & value)157*6777b538SAndroid Build Coastguard Worker bool ReadU32NativeEndian(uint32_t& value) 158*6777b538SAndroid Build Coastguard Worker requires(std::same_as<std::remove_const_t<T>, uint8_t>) 159*6777b538SAndroid Build Coastguard Worker { 160*6777b538SAndroid Build Coastguard Worker return ReadAnd<4>([&](auto buf) { value = U32FromNativeEndian(buf); }); 161*6777b538SAndroid Build Coastguard Worker } ReadU64NativeEndian(uint64_t & value)162*6777b538SAndroid Build Coastguard Worker bool ReadU64NativeEndian(uint64_t& value) 163*6777b538SAndroid Build Coastguard Worker requires(std::same_as<std::remove_const_t<T>, uint8_t>) 164*6777b538SAndroid Build Coastguard Worker { 165*6777b538SAndroid Build Coastguard Worker return ReadAnd<8>([&](auto buf) { value = U64FromNativeEndian(buf); }); 166*6777b538SAndroid Build Coastguard Worker } 167*6777b538SAndroid Build Coastguard Worker 168*6777b538SAndroid Build Coastguard Worker // For a SpanReader over bytes, reads one byte and returns it as a `char`, 169*6777b538SAndroid Build Coastguard Worker // which may be signed or unsigned depending on the platform. Returns true if 170*6777b538SAndroid Build Coastguard Worker // there was room remaining and the byte was read. ReadChar(char & value)171*6777b538SAndroid Build Coastguard Worker bool ReadChar(char& value) 172*6777b538SAndroid Build Coastguard Worker requires(std::same_as<std::remove_const_t<T>, uint8_t>) 173*6777b538SAndroid Build Coastguard Worker { 174*6777b538SAndroid Build Coastguard Worker return ReadAnd<1>([&](auto buf) { value = static_cast<char>(buf[0u]); }); 175*6777b538SAndroid Build Coastguard Worker } 176*6777b538SAndroid Build Coastguard Worker 177*6777b538SAndroid Build Coastguard Worker // Returns the number of objects remaining to be read from the original span. remaining()178*6777b538SAndroid Build Coastguard Worker size_t remaining() const { return buf_.size(); } 179*6777b538SAndroid Build Coastguard Worker // Returns the objects that have not yet been read, as a span. remaining_span()180*6777b538SAndroid Build Coastguard Worker span<T> remaining_span() const { return buf_; } 181*6777b538SAndroid Build Coastguard Worker 182*6777b538SAndroid Build Coastguard Worker // Returns the number of objects read (or skipped) in the original span. num_read()183*6777b538SAndroid Build Coastguard Worker size_t num_read() const { return original_size_ - buf_.size(); } 184*6777b538SAndroid Build Coastguard Worker 185*6777b538SAndroid Build Coastguard Worker private: 186*6777b538SAndroid Build Coastguard Worker template <size_t N, class F> requires(std::invocable<F,span<T,N>>)187*6777b538SAndroid Build Coastguard Worker requires(std::invocable<F, span<T, N>>) 188*6777b538SAndroid Build Coastguard Worker bool ReadAnd(F f) { 189*6777b538SAndroid Build Coastguard Worker auto buf = Read<N>(); 190*6777b538SAndroid Build Coastguard Worker if (buf.has_value()) { 191*6777b538SAndroid Build Coastguard Worker f(*buf); 192*6777b538SAndroid Build Coastguard Worker } 193*6777b538SAndroid Build Coastguard Worker return buf.has_value(); 194*6777b538SAndroid Build Coastguard Worker } 195*6777b538SAndroid Build Coastguard Worker 196*6777b538SAndroid Build Coastguard Worker span<T> buf_; 197*6777b538SAndroid Build Coastguard Worker size_t original_size_; 198*6777b538SAndroid Build Coastguard Worker }; 199*6777b538SAndroid Build Coastguard Worker 200*6777b538SAndroid Build Coastguard Worker template <class T, size_t N> 201*6777b538SAndroid Build Coastguard Worker SpanReader(span<T, N>) -> SpanReader<T>; 202*6777b538SAndroid Build Coastguard Worker 203*6777b538SAndroid Build Coastguard Worker } // namespace base 204*6777b538SAndroid Build Coastguard Worker 205*6777b538SAndroid Build Coastguard Worker #endif // BASE_CONTAINERS_SPAN_READER_H_ 206