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