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