1*a03ca8b9SKrzysztof Kosiński // Copyright 2017 The Chromium Authors. All rights reserved. 2*a03ca8b9SKrzysztof Kosiński // Use of this source code is governed by a BSD-style license that can be 3*a03ca8b9SKrzysztof Kosiński // found in the LICENSE file. 4*a03ca8b9SKrzysztof Kosiński 5*a03ca8b9SKrzysztof Kosiński #ifndef COMPONENTS_ZUCCHINI_BUFFER_VIEW_H_ 6*a03ca8b9SKrzysztof Kosiński #define COMPONENTS_ZUCCHINI_BUFFER_VIEW_H_ 7*a03ca8b9SKrzysztof Kosiński 8*a03ca8b9SKrzysztof Kosiński #include <stddef.h> 9*a03ca8b9SKrzysztof Kosiński #include <stdint.h> 10*a03ca8b9SKrzysztof Kosiński 11*a03ca8b9SKrzysztof Kosiński #include <algorithm> 12*a03ca8b9SKrzysztof Kosiński #include <type_traits> 13*a03ca8b9SKrzysztof Kosiński 14*a03ca8b9SKrzysztof Kosiński #include "base/check_op.h" 15*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/algorithm.h" 16*a03ca8b9SKrzysztof Kosiński 17*a03ca8b9SKrzysztof Kosiński namespace zucchini { 18*a03ca8b9SKrzysztof Kosiński 19*a03ca8b9SKrzysztof Kosiński // Describes a region within a buffer, with starting offset and size. 20*a03ca8b9SKrzysztof Kosiński struct BufferRegion { 21*a03ca8b9SKrzysztof Kosiński // The region data are stored as |offset| and |size|, but often it is useful 22*a03ca8b9SKrzysztof Kosiński // to represent it as an interval [lo(), hi()) = [offset, offset + size). loBufferRegion23*a03ca8b9SKrzysztof Kosiński size_t lo() const { return offset; } hiBufferRegion24*a03ca8b9SKrzysztof Kosiński size_t hi() const { return offset + size; } 25*a03ca8b9SKrzysztof Kosiński 26*a03ca8b9SKrzysztof Kosiński // Returns whether the Region fits in |[0, container_size)|. Special case: 27*a03ca8b9SKrzysztof Kosiński // a size-0 region starting at |container_size| fits. FitsInBufferRegion28*a03ca8b9SKrzysztof Kosiński bool FitsIn(size_t container_size) const { 29*a03ca8b9SKrzysztof Kosiński return offset <= container_size && container_size - offset >= size; 30*a03ca8b9SKrzysztof Kosiński } 31*a03ca8b9SKrzysztof Kosiński 32*a03ca8b9SKrzysztof Kosiński // Returns |v| clipped to the inclusive range |[lo(), hi()]|. InclusiveClampBufferRegion33*a03ca8b9SKrzysztof Kosiński size_t InclusiveClamp(size_t v) const { 34*a03ca8b9SKrzysztof Kosiński return zucchini::InclusiveClamp(v, lo(), hi()); 35*a03ca8b9SKrzysztof Kosiński } 36*a03ca8b9SKrzysztof Kosiński 37*a03ca8b9SKrzysztof Kosiński // Region data use size_t to match BufferViewBase::size_type, to make it 38*a03ca8b9SKrzysztof Kosiński // convenient to index into buffer view. 39*a03ca8b9SKrzysztof Kosiński size_t offset; 40*a03ca8b9SKrzysztof Kosiński size_t size; 41*a03ca8b9SKrzysztof Kosiński }; 42*a03ca8b9SKrzysztof Kosiński 43*a03ca8b9SKrzysztof Kosiński namespace internal { 44*a03ca8b9SKrzysztof Kosiński 45*a03ca8b9SKrzysztof Kosiński // TODO(huangs): Rename to BasicBufferView. 46*a03ca8b9SKrzysztof Kosiński // BufferViewBase should not be used directly; it is an implementation used for 47*a03ca8b9SKrzysztof Kosiński // both BufferView and MutableBufferView. 48*a03ca8b9SKrzysztof Kosiński template <class T> 49*a03ca8b9SKrzysztof Kosiński class BufferViewBase { 50*a03ca8b9SKrzysztof Kosiński public: 51*a03ca8b9SKrzysztof Kosiński using value_type = T; 52*a03ca8b9SKrzysztof Kosiński using reference = T&; 53*a03ca8b9SKrzysztof Kosiński using pointer = T*; 54*a03ca8b9SKrzysztof Kosiński using iterator = T*; 55*a03ca8b9SKrzysztof Kosiński using const_iterator = typename std::add_const<T>::type*; 56*a03ca8b9SKrzysztof Kosiński using size_type = std::size_t; 57*a03ca8b9SKrzysztof Kosiński using difference_type = std::ptrdiff_t; 58*a03ca8b9SKrzysztof Kosiński FromRange(iterator first,iterator last)59*a03ca8b9SKrzysztof Kosiński static BufferViewBase FromRange(iterator first, iterator last) { 60*a03ca8b9SKrzysztof Kosiński DCHECK_GE(last, first); 61*a03ca8b9SKrzysztof Kosiński BufferViewBase ret; 62*a03ca8b9SKrzysztof Kosiński ret.first_ = first; 63*a03ca8b9SKrzysztof Kosiński ret.last_ = last; 64*a03ca8b9SKrzysztof Kosiński return ret; 65*a03ca8b9SKrzysztof Kosiński } 66*a03ca8b9SKrzysztof Kosiński 67*a03ca8b9SKrzysztof Kosiński BufferViewBase() = default; 68*a03ca8b9SKrzysztof Kosiński BufferViewBase(iterator first,size_type size)69*a03ca8b9SKrzysztof Kosiński BufferViewBase(iterator first, size_type size) 70*a03ca8b9SKrzysztof Kosiński : first_(first), last_(first_ + size) { 71*a03ca8b9SKrzysztof Kosiński DCHECK_GE(last_, first_); 72*a03ca8b9SKrzysztof Kosiński } 73*a03ca8b9SKrzysztof Kosiński 74*a03ca8b9SKrzysztof Kosiński template <class U> BufferViewBase(const BufferViewBase<U> & that)75*a03ca8b9SKrzysztof Kosiński BufferViewBase(const BufferViewBase<U>& that) 76*a03ca8b9SKrzysztof Kosiński : first_(that.begin()), last_(that.end()) {} 77*a03ca8b9SKrzysztof Kosiński 78*a03ca8b9SKrzysztof Kosiński template <class U> BufferViewBase(BufferViewBase<U> && that)79*a03ca8b9SKrzysztof Kosiński BufferViewBase(BufferViewBase<U>&& that) 80*a03ca8b9SKrzysztof Kosiński : first_(that.begin()), last_(that.end()) {} 81*a03ca8b9SKrzysztof Kosiński 82*a03ca8b9SKrzysztof Kosiński BufferViewBase(const BufferViewBase&) = default; 83*a03ca8b9SKrzysztof Kosiński BufferViewBase& operator=(const BufferViewBase&) = default; 84*a03ca8b9SKrzysztof Kosiński 85*a03ca8b9SKrzysztof Kosiński // Iterators 86*a03ca8b9SKrzysztof Kosiński begin()87*a03ca8b9SKrzysztof Kosiński iterator begin() const { return first_; } end()88*a03ca8b9SKrzysztof Kosiński iterator end() const { return last_; } cbegin()89*a03ca8b9SKrzysztof Kosiński const_iterator cbegin() const { return begin(); } cend()90*a03ca8b9SKrzysztof Kosiński const_iterator cend() const { return end(); } 91*a03ca8b9SKrzysztof Kosiński 92*a03ca8b9SKrzysztof Kosiński // Capacity 93*a03ca8b9SKrzysztof Kosiński empty()94*a03ca8b9SKrzysztof Kosiński bool empty() const { return first_ == last_; } size()95*a03ca8b9SKrzysztof Kosiński size_type size() const { return last_ - first_; } 96*a03ca8b9SKrzysztof Kosiński 97*a03ca8b9SKrzysztof Kosiński // Returns whether the buffer is large enough to cover |region|. covers(const BufferRegion & region)98*a03ca8b9SKrzysztof Kosiński bool covers(const BufferRegion& region) const { 99*a03ca8b9SKrzysztof Kosiński return region.FitsIn(size()); 100*a03ca8b9SKrzysztof Kosiński } 101*a03ca8b9SKrzysztof Kosiński 102*a03ca8b9SKrzysztof Kosiński // Returns whether the buffer is large enough to cover an array starting at 103*a03ca8b9SKrzysztof Kosiński // |offset| with |num| elements, each taking |elt_size| bytes. covers_array(size_t offset,size_t num,size_t elt_size)104*a03ca8b9SKrzysztof Kosiński bool covers_array(size_t offset, size_t num, size_t elt_size) { 105*a03ca8b9SKrzysztof Kosiński DCHECK_GT(elt_size, 0U); 106*a03ca8b9SKrzysztof Kosiński // Use subtraction and division to avoid overflow. 107*a03ca8b9SKrzysztof Kosiński return offset <= size() && (size() - offset) / elt_size >= num; 108*a03ca8b9SKrzysztof Kosiński } 109*a03ca8b9SKrzysztof Kosiński 110*a03ca8b9SKrzysztof Kosiński // Element access 111*a03ca8b9SKrzysztof Kosiński 112*a03ca8b9SKrzysztof Kosiński // Returns the raw value at specified location |pos|. 113*a03ca8b9SKrzysztof Kosiński // If |pos| is not within the range of the buffer, the process is terminated. 114*a03ca8b9SKrzysztof Kosiński reference operator[](size_type pos) const { 115*a03ca8b9SKrzysztof Kosiński CHECK_LT(pos, size()); 116*a03ca8b9SKrzysztof Kosiński return first_[pos]; 117*a03ca8b9SKrzysztof Kosiński } 118*a03ca8b9SKrzysztof Kosiński 119*a03ca8b9SKrzysztof Kosiński // Returns a sub-buffer described by |region|. 120*a03ca8b9SKrzysztof Kosiński BufferViewBase operator[](BufferRegion region) const { 121*a03ca8b9SKrzysztof Kosiński DCHECK_LE(region.offset, size()); 122*a03ca8b9SKrzysztof Kosiński DCHECK_LE(region.size, size() - region.offset); 123*a03ca8b9SKrzysztof Kosiński return {begin() + region.offset, region.size}; 124*a03ca8b9SKrzysztof Kosiński } 125*a03ca8b9SKrzysztof Kosiński 126*a03ca8b9SKrzysztof Kosiński template <class U> read(size_type pos)127*a03ca8b9SKrzysztof Kosiński const U& read(size_type pos) const { 128*a03ca8b9SKrzysztof Kosiński // TODO(huangs): Use can_access<U>(pos) after fixing can_access(). 129*a03ca8b9SKrzysztof Kosiński CHECK_LE(sizeof(U), size()); 130*a03ca8b9SKrzysztof Kosiński CHECK_LE(pos, size() - sizeof(U)); 131*a03ca8b9SKrzysztof Kosiński return *reinterpret_cast<const U*>(begin() + pos); 132*a03ca8b9SKrzysztof Kosiński } 133*a03ca8b9SKrzysztof Kosiński 134*a03ca8b9SKrzysztof Kosiński template <class U> write(size_type pos,const U & value)135*a03ca8b9SKrzysztof Kosiński void write(size_type pos, const U& value) { 136*a03ca8b9SKrzysztof Kosiński // TODO(huangs): Use can_access<U>(pos) after fixing can_access(). 137*a03ca8b9SKrzysztof Kosiński CHECK_LE(sizeof(U), size()); 138*a03ca8b9SKrzysztof Kosiński CHECK_LE(pos, size() - sizeof(U)); 139*a03ca8b9SKrzysztof Kosiński *reinterpret_cast<U*>(begin() + pos) = value; 140*a03ca8b9SKrzysztof Kosiński } 141*a03ca8b9SKrzysztof Kosiński 142*a03ca8b9SKrzysztof Kosiński // Returns a mutable reference to an object type U whose raw storage starts 143*a03ca8b9SKrzysztof Kosiński // at location |pos|. 144*a03ca8b9SKrzysztof Kosiński template <class U> modify(size_type pos)145*a03ca8b9SKrzysztof Kosiński U& modify(size_type pos) { 146*a03ca8b9SKrzysztof Kosiński // TODO(huangs): Use can_access<U>(pos) after fixing can_access(). 147*a03ca8b9SKrzysztof Kosiński CHECK_LE(sizeof(U), size()); 148*a03ca8b9SKrzysztof Kosiński CHECK_LE(pos, size() - sizeof(U)); 149*a03ca8b9SKrzysztof Kosiński return *reinterpret_cast<U*>(begin() + pos); 150*a03ca8b9SKrzysztof Kosiński } 151*a03ca8b9SKrzysztof Kosiński 152*a03ca8b9SKrzysztof Kosiński template <class U> can_access(size_type pos)153*a03ca8b9SKrzysztof Kosiński bool can_access(size_type pos) const { 154*a03ca8b9SKrzysztof Kosiński return pos < size() && size() - pos >= sizeof(U); 155*a03ca8b9SKrzysztof Kosiński } 156*a03ca8b9SKrzysztof Kosiński 157*a03ca8b9SKrzysztof Kosiński // Returns a BufferRegion describing the full view, with offset = 0. If the 158*a03ca8b9SKrzysztof Kosiński // BufferViewBase is derived from another, this does *not* return the 159*a03ca8b9SKrzysztof Kosiński // original region used for its definition (hence "local"). local_region()160*a03ca8b9SKrzysztof Kosiński BufferRegion local_region() const { return BufferRegion{0, size()}; } 161*a03ca8b9SKrzysztof Kosiński equals(BufferViewBase other)162*a03ca8b9SKrzysztof Kosiński bool equals(BufferViewBase other) const { 163*a03ca8b9SKrzysztof Kosiński return size() == other.size() && std::equal(begin(), end(), other.begin()); 164*a03ca8b9SKrzysztof Kosiński } 165*a03ca8b9SKrzysztof Kosiński 166*a03ca8b9SKrzysztof Kosiński // Modifiers 167*a03ca8b9SKrzysztof Kosiński shrink(size_type new_size)168*a03ca8b9SKrzysztof Kosiński void shrink(size_type new_size) { 169*a03ca8b9SKrzysztof Kosiński DCHECK_LE(first_ + new_size, last_); 170*a03ca8b9SKrzysztof Kosiński last_ = first_ + new_size; 171*a03ca8b9SKrzysztof Kosiński } 172*a03ca8b9SKrzysztof Kosiński 173*a03ca8b9SKrzysztof Kosiński // Moves the start of the view forward by n bytes. remove_prefix(size_type n)174*a03ca8b9SKrzysztof Kosiński void remove_prefix(size_type n) { 175*a03ca8b9SKrzysztof Kosiński DCHECK_LE(n, size()); 176*a03ca8b9SKrzysztof Kosiński first_ += n; 177*a03ca8b9SKrzysztof Kosiński } 178*a03ca8b9SKrzysztof Kosiński 179*a03ca8b9SKrzysztof Kosiński // Moves the start of the view to |it|, which is in range [begin(), end()). seek(iterator it)180*a03ca8b9SKrzysztof Kosiński void seek(iterator it) { 181*a03ca8b9SKrzysztof Kosiński DCHECK_GE(it, begin()); 182*a03ca8b9SKrzysztof Kosiński DCHECK_LE(it, end()); 183*a03ca8b9SKrzysztof Kosiński first_ = it; 184*a03ca8b9SKrzysztof Kosiński } 185*a03ca8b9SKrzysztof Kosiński 186*a03ca8b9SKrzysztof Kosiński // Given |origin| that contains |*this|, minimally increase |first_| (possibly 187*a03ca8b9SKrzysztof Kosiński // by 0) so that |first_ <= last_|, and |first_ - origin.first_| is a multiple 188*a03ca8b9SKrzysztof Kosiński // of |alignment|. On success, updates |first_| and returns true. Otherwise 189*a03ca8b9SKrzysztof Kosiński // returns false. AlignOn(BufferViewBase origin,size_type alignment)190*a03ca8b9SKrzysztof Kosiński bool AlignOn(BufferViewBase origin, size_type alignment) { 191*a03ca8b9SKrzysztof Kosiński DCHECK_GT(alignment, 0U); 192*a03ca8b9SKrzysztof Kosiński DCHECK_LE(origin.first_, first_); 193*a03ca8b9SKrzysztof Kosiński DCHECK_GE(origin.last_, last_); 194*a03ca8b9SKrzysztof Kosiński size_type aligned_size = 195*a03ca8b9SKrzysztof Kosiński AlignCeil(static_cast<size_type>(first_ - origin.first_), alignment); 196*a03ca8b9SKrzysztof Kosiński if (aligned_size > static_cast<size_type>(last_ - origin.first_)) 197*a03ca8b9SKrzysztof Kosiński return false; 198*a03ca8b9SKrzysztof Kosiński first_ = origin.first_ + aligned_size; 199*a03ca8b9SKrzysztof Kosiński return true; 200*a03ca8b9SKrzysztof Kosiński } 201*a03ca8b9SKrzysztof Kosiński 202*a03ca8b9SKrzysztof Kosiński private: 203*a03ca8b9SKrzysztof Kosiński iterator first_ = nullptr; 204*a03ca8b9SKrzysztof Kosiński iterator last_ = nullptr; 205*a03ca8b9SKrzysztof Kosiński }; 206*a03ca8b9SKrzysztof Kosiński 207*a03ca8b9SKrzysztof Kosiński } // namespace internal 208*a03ca8b9SKrzysztof Kosiński 209*a03ca8b9SKrzysztof Kosiński // Classes to encapsulate a contiguous sequence of raw data, without owning the 210*a03ca8b9SKrzysztof Kosiński // encapsulated memory regions. These are intended to be used as value types. 211*a03ca8b9SKrzysztof Kosiński 212*a03ca8b9SKrzysztof Kosiński using ConstBufferView = internal::BufferViewBase<const uint8_t>; 213*a03ca8b9SKrzysztof Kosiński using MutableBufferView = internal::BufferViewBase<uint8_t>; 214*a03ca8b9SKrzysztof Kosiński 215*a03ca8b9SKrzysztof Kosiński } // namespace zucchini 216*a03ca8b9SKrzysztof Kosiński 217*a03ca8b9SKrzysztof Kosiński #endif // COMPONENTS_ZUCCHINI_BUFFER_VIEW_H_ 218