blob: 661e3c3bd407e90f744df775be7e5a248b50597c [file] [log] [blame]
Samuel Huang06f1ae92018-03-13 18:19:34 +00001// 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
Hans Wennborgd5ccca82020-06-24 13:46:35 +000014#include "base/check_op.h"
Samuel Huang06f1ae92018-03-13 18:19:34 +000015#include "components/zucchini/algorithm.h"
16
17namespace zucchini {
18
19// Describes a region within a buffer, with starting offset and size.
20struct 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).
23 size_t lo() const { return offset; }
24 size_t hi() const { return offset + size; }
25
26 // Returns whether the Region fits in |[0, container_size)|. Special case:
Samuel Huangd758cb72018-07-19 14:32:28 +000027 // a size-0 region starting at |container_size| fits.
Samuel Huang06f1ae92018-03-13 18:19:34 +000028 bool FitsIn(size_t container_size) const {
Samuel Huangd758cb72018-07-19 14:32:28 +000029 return offset <= container_size && container_size - offset >= size;
Samuel Huang06f1ae92018-03-13 18:19:34 +000030 }
31
32 // Returns |v| clipped to the inclusive range |[lo(), hi()]|.
33 size_t InclusiveClamp(size_t v) const {
34 return zucchini::InclusiveClamp(v, lo(), hi());
35 }
Samuel Huang06f1ae92018-03-13 18:19:34 +000036
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
43namespace 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.
48template <class T>
49class 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
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
69 BufferViewBase(iterator first, size_type size)
70 : first_(first), last_(first_ + size) {
71 DCHECK_GE(last_, first_);
72 }
73
74 template <class U>
75 BufferViewBase(const BufferViewBase<U>& that)
76 : first_(that.begin()), last_(that.end()) {}
77
78 template <class U>
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
87 iterator begin() const { return first_; }
88 iterator end() const { return last_; }
89 const_iterator cbegin() const { return begin(); }
90 const_iterator cend() const { return end(); }
91
92 // Capacity
93
94 bool empty() const { return first_ == last_; }
95 size_type size() const { return last_ - first_; }
96
97 // Returns whether the buffer is large enough to cover |region|.
98 bool covers(const BufferRegion& region) const {
99 return region.FitsIn(size());
100 }
101
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +0000102 // Returns whether the buffer is large enough to cover an array starting at
103 // |offset| with |num| elements, each taking |elt_size| bytes.
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.
Samuel Huanga09f4e22018-07-11 19:16:21 +0000107 return offset <= size() && (size() - offset) / elt_size >= num;
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +0000108 }
109
Samuel Huang06f1ae92018-03-13 18:19:34 +0000110 // 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>
127 const U& read(size_type pos) const {
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +0000128 // TODO(huangs): Use can_access<U>(pos) after fixing can_access().
129 CHECK_LE(sizeof(U), size());
130 CHECK_LE(pos, size() - sizeof(U));
Samuel Huang06f1ae92018-03-13 18:19:34 +0000131 return *reinterpret_cast<const U*>(begin() + pos);
132 }
133
134 template <class U>
135 void write(size_type pos, const U& value) {
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +0000136 // TODO(huangs): Use can_access<U>(pos) after fixing can_access().
137 CHECK_LE(sizeof(U), size());
138 CHECK_LE(pos, size() - sizeof(U));
Samuel Huang06f1ae92018-03-13 18:19:34 +0000139 *reinterpret_cast<U*>(begin() + pos) = value;
140 }
141
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +0000142 // Returns a mutable reference to an object type U whose raw storage starts
143 // at location |pos|.
144 template <class U>
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
Samuel Huang06f1ae92018-03-13 18:19:34 +0000152 template <class U>
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").
160 BufferRegion local_region() const { return BufferRegion{0, size()}; }
161
162 bool equals(BufferViewBase other) const {
163 return size() == other.size() && std::equal(begin(), end(), other.begin());
164 }
165
166 // Modifiers
167
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.
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()).
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.
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 =
Samuel Huang607ce602018-06-13 17:47:39 +0000195 AlignCeil(static_cast<size_type>(first_ - origin.first_), alignment);
Samuel Huang06f1ae92018-03-13 18:19:34 +0000196 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
212using ConstBufferView = internal::BufferViewBase<const uint8_t>;
213using MutableBufferView = internal::BufferViewBase<uint8_t>;
214
215} // namespace zucchini
216
217#endif // COMPONENTS_ZUCCHINI_BUFFER_VIEW_H_