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