xref: /aosp_15_r20/external/zucchini/buffer_view.h (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
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