xref: /aosp_15_r20/external/skia/src/base/SkFixedArray.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2024 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkTFixedArray_DEFINED
9 #define SkTFixedArray_DEFINED
10 
11 #include "include/private/base/SkAssert.h"
12 
13 #include <cstdint>
14 #include <cstring>
15 #include <initializer_list>
16 #include <type_traits>  // IWYU pragma: keep for std::is_trivial_v
17 
18 namespace skia_private {
19 
20 /**
21  * Represents an array of `T` (must be a trivial type) that cannot grow past a fixed size `N`.
22  * The fixed-size restriction allows for tighter codegen and a smaller memory footprint.
23  * Missing methods from TArray (e.g. `fromBack`) can be added on demand.
24  *
25  * The trivial-type restriction is only to simplify implementation; if there is a need, we can
26  * adopt proper move/copy semantics in this class as well.
27  */
28 template <int N, typename T>
29 class FixedArray {
30 public:
31     using value_type = T;
32 
33     FixedArray() = default;
34 
FixedArray(std::initializer_list<T> values)35     FixedArray(std::initializer_list<T> values) {
36         SkASSERT(values.size() <= N);
37         for (T value : values) {
38             fData[fSize++] = value;
39         }
40     }
41 
FixedArray(int reserveCount)42     FixedArray(int reserveCount) {
43         // This is here to satisfy the TArray interface. Setting a reserve count on a fixed array
44         // isn't useful.
45         SkASSERT(reserveCount >= 0);
46         SkASSERT(reserveCount <= N);
47     }
48 
FixedArray(const T * array,int count)49     FixedArray(const T* array, int count) {
50         this->reset(array, count);
51     }
52 
FixedArray(const FixedArray<N,T> & that)53     FixedArray(const FixedArray<N, T>& that) {
54         this->reset(that.data(), that.size());
55     }
56 
57     FixedArray<N, T>& operator=(const FixedArray<N, T>& that) {
58         if (this != &that) {
59             this->reset(that.data(), that.size());
60         }
61         return *this;
62     }
63 
64     T& operator[](size_t index) {
65         SkASSERT(index < fSize);
66         return fData[index];
67     }
68 
69     const T& operator[](size_t index) const {
70         SkASSERT(index < fSize);
71         return fData[index];
72     }
73 
74     bool operator==(const FixedArray<N, T>& that) const {
75         return fSize == that.fSize && (0 == memcmp(fData, that.fData, fSize * sizeof(T)));
76     }
77 
78     bool operator!=(const FixedArray<N, T>& that) const {
79         return !this->operator==(that);
80     }
81 
size()82     int size() const {
83         return fSize;
84     }
85 
empty()86     bool empty() const {
87         return fSize == 0;
88     }
89 
clear()90     void clear() {
91         fSize = 0;
92     }
93 
reset(const T * array,int count)94     void reset(const T* array, int count) {
95         SkASSERT(count >= 0);
96         SkASSERT(count <= N);
97         fSize = count;
98         std::memcpy(fData, array, count * sizeof(T));
99     }
100 
resize(int newSize)101     void resize(int newSize) {
102         SkASSERT(newSize >= 0);
103         SkASSERT(newSize <= N);
104 
105         if (fSize > newSize) {
106             fSize = newSize;
107         } else {
108             while (fSize < newSize) {
109                 fData[fSize++] = T();
110             }
111         }
112     }
113 
push_back()114     T& push_back() {
115         SkASSERT(fSize < N);
116         T& ref = fData[fSize++];
117         ref = T();
118         return ref;
119     }
120 
push_back(T x)121     void push_back(T x) {
122         SkASSERT(fSize < N);
123         fData[fSize++] = x;
124     }
125 
push_back_n(int n)126     T* push_back_n(int n) {
127         SkASSERT(n >= 0);
128         SkASSERT(fSize + n <= N);
129         T* ptr = fData + fSize;
130         for (int index = 0; index < n; ++index) {
131             ptr[index] = T();
132         }
133         fSize += n;
134         return ptr;
135     }
136 
push_back_n(int n,const T & t)137     T* push_back_n(int n, const T& t) {
138         SkASSERT(n >= 0);
139         SkASSERT(fSize + n <= N);
140         T* ptr = fData + fSize;
141         for (int index = 0; index < n; ++index) {
142             ptr[index] = t;
143         }
144         fSize += n;
145         return ptr;
146     }
147 
pop_back()148     void pop_back() {
149         SkASSERT(fSize >= 1);
150         --fSize;
151     }
152 
pop_back_n(int n)153     void pop_back_n(int n) {
154         SkASSERT(fSize >= n);
155         fSize -= n;
156     }
157 
removeShuffle(int n)158     void removeShuffle(int n) {
159         SkASSERT(n < fSize);
160         int last = fSize - 1;
161         if (n != last) {
162             fData[n] = fData[last];
163         }
164         fSize = last;
165     }
166 
data()167     T* data() {
168         return fData;
169     }
170 
data()171     const T* data() const {
172         return fData;
173     }
174 
begin()175     T* begin() {
176         return fData;
177     }
178 
begin()179     const T* begin() const {
180         return fData;
181     }
182 
end()183     T* end() {
184         return fData + fSize;
185     }
186 
end()187     const T* end() const {
188         return fData + fSize;
189     }
190 
front()191     T& front() {
192         SkASSERT(fSize > 0);
193         return fData[0];
194     }
195 
front()196     const T& front() const {
197         SkASSERT(fSize > 0);
198         return fData[0];
199     }
200 
back()201     T& back() {
202         SkASSERT(fSize > 0);
203         return fData[fSize - 1];
204     }
205 
back()206     const T& back() const {
207         SkASSERT(fSize > 0);
208         return fData[fSize - 1];
209     }
210 
reserve(int size)211     void reserve(int size) {
212         // This is here to satisfy the TArray interface.
213         SkASSERT(size >= 0);
214         SkASSERT(size <= N);
215     }
216 
capacity()217     constexpr int capacity() const {
218         return N;
219     }
220 
221 private:
222     static_assert(std::is_trivial_v<T>);
223     static_assert(N > 0);
224     static_assert(N < 256);  // limited by `uint8_t fSize`
225 
226     T fData[N];
227     uint8_t fSize = 0;
228 };
229 
230 }  // namespace skia_private
231 
232 #endif
233