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