• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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. `push_back_n`) 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 
pop_back()126     void pop_back() {
127         SkASSERT(fSize > 0);
128         --fSize;
129     }
130 
removeShuffle(int n)131     void removeShuffle(int n) {
132         SkASSERT(n < fSize);
133         int last = fSize - 1;
134         if (n != last) {
135             fData[n] = fData[last];
136         }
137         fSize = last;
138     }
139 
data()140     T* data() {
141         return fData;
142     }
143 
data()144     const T* data() const {
145         return fData;
146     }
147 
begin()148     T* begin() {
149         return fData;
150     }
151 
begin()152     const T* begin() const {
153         return fData;
154     }
155 
end()156     T* end() {
157         return fData + fSize;
158     }
159 
end()160     const T* end() const {
161         return fData + fSize;
162     }
163 
front()164     T& front() {
165         SkASSERT(fSize > 0);
166         return fData[0];
167     }
168 
front()169     const T& front() const {
170         SkASSERT(fSize > 0);
171         return fData[0];
172     }
173 
back()174     T& back() {
175         SkASSERT(fSize > 0);
176         return fData[fSize - 1];
177     }
178 
back()179     const T& back() const {
180         SkASSERT(fSize > 0);
181         return fData[fSize - 1];
182     }
183 
reserve(int size)184     void reserve(int size) {
185         // This is here to satisfy the TArray interface.
186         SkASSERT(size >= 0);
187         SkASSERT(size <= N);
188     }
189 
capacity()190     constexpr int capacity() const {
191         return N;
192     }
193 
194 private:
195     static_assert(std::is_trivial_v<T>);
196     static_assert(N > 0);
197     static_assert(N < 256);  // limited by `uint8_t fSize`
198 
199     T fData[N];
200     uint8_t fSize = 0;
201 };
202 
203 }  // namespace skia_private
204 
205 #endif
206