123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef BASE_CONTAINERS_BUFFER_ITERATOR_H_
- #define BASE_CONTAINERS_BUFFER_ITERATOR_H_
- #include <type_traits>
- #include "base/bit_cast.h"
- #include "base/containers/span.h"
- #include "base/numerics/checked_math.h"
- namespace base {
- // BufferIterator is a bounds-checked container utility to access variable-
- // length, heterogeneous structures contained within a buffer. If the data are
- // homogeneous, use base::span<> instead.
- //
- // After being created with a weakly-owned buffer, BufferIterator returns
- // pointers to structured data within the buffer. After each method call that
- // returns data in the buffer, the iterator position is advanced by the byte
- // size of the object (or span of objects) returned. If there are not enough
- // bytes remaining in the buffer to return the requested object(s), a nullptr
- // or empty span is returned.
- //
- // This class is similar to base::Pickle, which should be preferred for
- // serializing to disk. Pickle versions its header and does not support writing
- // structures, which are problematic for serialization due to struct padding and
- // version shear concerns.
- //
- // Example usage:
- //
- // std::vector<uint8_t> buffer(4096);
- // if (!ReadSomeData(&buffer, buffer.size())) {
- // LOG(ERROR) << "Failed to read data.";
- // return false;
- // }
- //
- // BufferIterator<uint8_t> iterator(buffer);
- // uint32_t* num_items = iterator.Object<uint32_t>();
- // if (!num_items) {
- // LOG(ERROR) << "No num_items field."
- // return false;
- // }
- //
- // base::span<const item_struct> items =
- // iterator.Span<item_struct>(*num_items);
- // if (items.size() != *num_items) {
- // LOG(ERROR) << "Not enough items.";
- // return false;
- // }
- //
- // // ... validate the objects in |items|.
- template <typename B>
- class BufferIterator {
- public:
- static_assert(std::is_same<std::remove_const_t<B>, char>::value ||
- std::is_same<std::remove_const_t<B>, unsigned char>::value,
- "Underlying buffer type must be char-type.");
- BufferIterator() {}
- BufferIterator(B* data, size_t size)
- : BufferIterator(make_span(data, size)) {}
- explicit BufferIterator(span<B> buffer)
- : buffer_(buffer), remaining_(buffer) {}
- ~BufferIterator() {}
- // Returns a pointer to a mutable structure T in the buffer at the current
- // position. On success, the iterator position is advanced by sizeof(T). If
- // there are not sizeof(T) bytes remaining in the buffer, returns nullptr.
- template <typename T,
- typename =
- typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
- T* MutableObject() {
- size_t size = sizeof(T);
- size_t next_position;
- if (!CheckAdd(position(), size).AssignIfValid(&next_position))
- return nullptr;
- if (next_position > total_size())
- return nullptr;
- T* t = bit_cast<T*>(remaining_.data());
- remaining_ = remaining_.subspan(size);
- return t;
- }
- // Returns a const pointer to an object of type T in the buffer at the current
- // position.
- template <typename T,
- typename =
- typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
- const T* Object() {
- return MutableObject<const T>();
- }
- // Returns a span of |count| T objects in the buffer at the current position.
- // On success, the iterator position is advanced by |sizeof(T) * count|. If
- // there are not enough bytes remaining in the buffer to fulfill the request,
- // returns an empty span.
- template <typename T,
- typename =
- typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
- span<T> MutableSpan(size_t count) {
- size_t size;
- if (!CheckMul(sizeof(T), count).AssignIfValid(&size))
- return span<T>();
- size_t next_position;
- if (!CheckAdd(position(), size).AssignIfValid(&next_position))
- return span<T>();
- if (next_position > total_size())
- return span<T>();
- auto result = span<T>(bit_cast<T*>(remaining_.data()), count);
- remaining_ = remaining_.subspan(size);
- return result;
- }
- // Returns a span to |count| const objects of type T in the buffer at the
- // current position.
- template <typename T,
- typename =
- typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
- span<const T> Span(size_t count) {
- return MutableSpan<const T>(count);
- }
- // Resets the iterator position to the absolute offset |to|.
- void Seek(size_t to) { remaining_ = buffer_.subspan(to); }
- // Returns the total size of the underlying buffer.
- size_t total_size() { return buffer_.size(); }
- // Returns the current position in the buffer.
- size_t position() { return buffer_.size_bytes() - remaining_.size_bytes(); }
- private:
- // The original buffer that the iterator was constructed with.
- const span<B> buffer_;
- // A subspan of |buffer_| containing the remaining bytes to iterate over.
- span<B> remaining_;
- // Copy and assign allowed.
- };
- } // namespace base
- #endif // BASE_CONTAINERS_BUFFER_ITERATOR_H_
|