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