xref: /aosp_15_r20/external/skia/include/private/base/SkTArray.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2011 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkTArray_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define SkTArray_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkASAN.h"  // IWYU pragma: keep
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAlignedStorage.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAttributes.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkContainers.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMalloc.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMath.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkSpan_impl.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTypeTraits.h"  // IWYU pragma: keep
22*c8dee2aaSAndroid Build Coastguard Worker 
23*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
24*c8dee2aaSAndroid Build Coastguard Worker #include <climits>
25*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
26*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
27*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
28*c8dee2aaSAndroid Build Coastguard Worker #include <initializer_list>
29*c8dee2aaSAndroid Build Coastguard Worker #include <new>
30*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker namespace skia_private {
33*c8dee2aaSAndroid Build Coastguard Worker /** TArray<T> implements a typical, mostly std::vector-like array.
34*c8dee2aaSAndroid Build Coastguard Worker     Each T will be default-initialized on allocation, and ~T will be called on destruction.
35*c8dee2aaSAndroid Build Coastguard Worker 
36*c8dee2aaSAndroid Build Coastguard Worker     MEM_MOVE controls the behavior when a T needs to be moved (e.g. when the array is resized)
37*c8dee2aaSAndroid Build Coastguard Worker       - true: T will be bit-copied via memcpy.
38*c8dee2aaSAndroid Build Coastguard Worker       - false: T will be moved via move-constructors.
39*c8dee2aaSAndroid Build Coastguard Worker */
40*c8dee2aaSAndroid Build Coastguard Worker template <typename T, bool MEM_MOVE = sk_is_trivially_relocatable_v<T>> class TArray {
41*c8dee2aaSAndroid Build Coastguard Worker public:
42*c8dee2aaSAndroid Build Coastguard Worker     using value_type = T;
43*c8dee2aaSAndroid Build Coastguard Worker 
44*c8dee2aaSAndroid Build Coastguard Worker     /**
45*c8dee2aaSAndroid Build Coastguard Worker      * Creates an empty array with no initial storage
46*c8dee2aaSAndroid Build Coastguard Worker      */
TArray()47*c8dee2aaSAndroid Build Coastguard Worker     TArray() : fOwnMemory(true), fCapacity{0} {}
48*c8dee2aaSAndroid Build Coastguard Worker 
49*c8dee2aaSAndroid Build Coastguard Worker     /**
50*c8dee2aaSAndroid Build Coastguard Worker      * Creates an empty array that will preallocate space for reserveCount elements.
51*c8dee2aaSAndroid Build Coastguard Worker      */
TArray(int reserveCount)52*c8dee2aaSAndroid Build Coastguard Worker     explicit TArray(int reserveCount) : TArray() { this->reserve_exact(reserveCount); }
53*c8dee2aaSAndroid Build Coastguard Worker 
54*c8dee2aaSAndroid Build Coastguard Worker     /**
55*c8dee2aaSAndroid Build Coastguard Worker      * Copies one array to another. The new array will be heap allocated.
56*c8dee2aaSAndroid Build Coastguard Worker      */
TArray(const TArray & that)57*c8dee2aaSAndroid Build Coastguard Worker     TArray(const TArray& that) : TArray(that.fData, that.fSize) {}
58*c8dee2aaSAndroid Build Coastguard Worker 
TArray(TArray && that)59*c8dee2aaSAndroid Build Coastguard Worker     TArray(TArray&& that) {
60*c8dee2aaSAndroid Build Coastguard Worker         if (that.fOwnMemory) {
61*c8dee2aaSAndroid Build Coastguard Worker             this->setData(that);
62*c8dee2aaSAndroid Build Coastguard Worker             that.setData({});
63*c8dee2aaSAndroid Build Coastguard Worker         } else {
64*c8dee2aaSAndroid Build Coastguard Worker             this->initData(that.fSize);
65*c8dee2aaSAndroid Build Coastguard Worker             that.move(fData);
66*c8dee2aaSAndroid Build Coastguard Worker         }
67*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(that.fSize);
68*c8dee2aaSAndroid Build Coastguard Worker         that.changeSize(0);
69*c8dee2aaSAndroid Build Coastguard Worker     }
70*c8dee2aaSAndroid Build Coastguard Worker 
71*c8dee2aaSAndroid Build Coastguard Worker     /**
72*c8dee2aaSAndroid Build Coastguard Worker      * Creates a TArray by copying contents of a standard C array. The new
73*c8dee2aaSAndroid Build Coastguard Worker      * array will be heap allocated. Be careful not to use this constructor
74*c8dee2aaSAndroid Build Coastguard Worker      * when you really want the (void*, int) version.
75*c8dee2aaSAndroid Build Coastguard Worker      */
TArray(const T * array,int count)76*c8dee2aaSAndroid Build Coastguard Worker     TArray(const T* array, int count) {
77*c8dee2aaSAndroid Build Coastguard Worker         this->initData(count);
78*c8dee2aaSAndroid Build Coastguard Worker         this->copy(array);
79*c8dee2aaSAndroid Build Coastguard Worker     }
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker     /**
82*c8dee2aaSAndroid Build Coastguard Worker      * Creates a TArray by copying contents from an SkSpan. The new array will be heap allocated.
83*c8dee2aaSAndroid Build Coastguard Worker      */
TArray(SkSpan<const T> data)84*c8dee2aaSAndroid Build Coastguard Worker     TArray(SkSpan<const T> data) : TArray(data.begin(), static_cast<int>(data.size())) {}
85*c8dee2aaSAndroid Build Coastguard Worker 
86*c8dee2aaSAndroid Build Coastguard Worker     /**
87*c8dee2aaSAndroid Build Coastguard Worker      * Creates a TArray by copying contents of an initializer list.
88*c8dee2aaSAndroid Build Coastguard Worker      */
TArray(std::initializer_list<T> data)89*c8dee2aaSAndroid Build Coastguard Worker     TArray(std::initializer_list<T> data) : TArray(data.begin(), data.size()) {}
90*c8dee2aaSAndroid Build Coastguard Worker 
91*c8dee2aaSAndroid Build Coastguard Worker     TArray& operator=(const TArray& that) {
92*c8dee2aaSAndroid Build Coastguard Worker         if (this == &that) {
93*c8dee2aaSAndroid Build Coastguard Worker             return *this;
94*c8dee2aaSAndroid Build Coastguard Worker         }
95*c8dee2aaSAndroid Build Coastguard Worker         this->clear();
96*c8dee2aaSAndroid Build Coastguard Worker         this->checkRealloc(that.size(), kExactFit);
97*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(that.fSize);
98*c8dee2aaSAndroid Build Coastguard Worker         this->copy(that.fData);
99*c8dee2aaSAndroid Build Coastguard Worker         return *this;
100*c8dee2aaSAndroid Build Coastguard Worker     }
101*c8dee2aaSAndroid Build Coastguard Worker 
102*c8dee2aaSAndroid Build Coastguard Worker     TArray& operator=(TArray&& that) {
103*c8dee2aaSAndroid Build Coastguard Worker         if (this != &that) {
104*c8dee2aaSAndroid Build Coastguard Worker             this->clear();
105*c8dee2aaSAndroid Build Coastguard Worker             this->unpoison();
106*c8dee2aaSAndroid Build Coastguard Worker             that.unpoison();
107*c8dee2aaSAndroid Build Coastguard Worker             if (that.fOwnMemory) {
108*c8dee2aaSAndroid Build Coastguard Worker                 // The storage is on the heap, so move the data pointer.
109*c8dee2aaSAndroid Build Coastguard Worker                 if (fOwnMemory) {
110*c8dee2aaSAndroid Build Coastguard Worker                     sk_free(fData);
111*c8dee2aaSAndroid Build Coastguard Worker                 }
112*c8dee2aaSAndroid Build Coastguard Worker 
113*c8dee2aaSAndroid Build Coastguard Worker                 fData = std::exchange(that.fData, nullptr);
114*c8dee2aaSAndroid Build Coastguard Worker 
115*c8dee2aaSAndroid Build Coastguard Worker                 // Can't use exchange with bitfields.
116*c8dee2aaSAndroid Build Coastguard Worker                 fCapacity = that.fCapacity;
117*c8dee2aaSAndroid Build Coastguard Worker                 that.fCapacity = 0;
118*c8dee2aaSAndroid Build Coastguard Worker 
119*c8dee2aaSAndroid Build Coastguard Worker                 fOwnMemory = true;
120*c8dee2aaSAndroid Build Coastguard Worker 
121*c8dee2aaSAndroid Build Coastguard Worker                 this->changeSize(that.fSize);
122*c8dee2aaSAndroid Build Coastguard Worker             } else {
123*c8dee2aaSAndroid Build Coastguard Worker                 // The data is stored inline in that, so move it element-by-element.
124*c8dee2aaSAndroid Build Coastguard Worker                 this->checkRealloc(that.size(), kExactFit);
125*c8dee2aaSAndroid Build Coastguard Worker                 this->changeSize(that.fSize);
126*c8dee2aaSAndroid Build Coastguard Worker                 that.move(fData);
127*c8dee2aaSAndroid Build Coastguard Worker             }
128*c8dee2aaSAndroid Build Coastguard Worker             that.changeSize(0);
129*c8dee2aaSAndroid Build Coastguard Worker         }
130*c8dee2aaSAndroid Build Coastguard Worker         return *this;
131*c8dee2aaSAndroid Build Coastguard Worker     }
132*c8dee2aaSAndroid Build Coastguard Worker 
~TArray()133*c8dee2aaSAndroid Build Coastguard Worker     ~TArray() {
134*c8dee2aaSAndroid Build Coastguard Worker         this->destroyAll();
135*c8dee2aaSAndroid Build Coastguard Worker         this->unpoison();
136*c8dee2aaSAndroid Build Coastguard Worker         if (fOwnMemory) {
137*c8dee2aaSAndroid Build Coastguard Worker             sk_free(fData);
138*c8dee2aaSAndroid Build Coastguard Worker         }
139*c8dee2aaSAndroid Build Coastguard Worker     }
140*c8dee2aaSAndroid Build Coastguard Worker 
141*c8dee2aaSAndroid Build Coastguard Worker     /**
142*c8dee2aaSAndroid Build Coastguard Worker      * Resets to size() = n newly constructed T objects and resets any reserve count.
143*c8dee2aaSAndroid Build Coastguard Worker      */
reset(int n)144*c8dee2aaSAndroid Build Coastguard Worker     void reset(int n) {
145*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(n >= 0);
146*c8dee2aaSAndroid Build Coastguard Worker         this->clear();
147*c8dee2aaSAndroid Build Coastguard Worker         this->checkRealloc(n, kExactFit);
148*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(n);
149*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < this->size(); ++i) {
150*c8dee2aaSAndroid Build Coastguard Worker             new (fData + i) T;
151*c8dee2aaSAndroid Build Coastguard Worker         }
152*c8dee2aaSAndroid Build Coastguard Worker     }
153*c8dee2aaSAndroid Build Coastguard Worker 
154*c8dee2aaSAndroid Build Coastguard Worker     /**
155*c8dee2aaSAndroid Build Coastguard Worker      * Resets to a copy of a C array and resets any reserve count.
156*c8dee2aaSAndroid Build Coastguard Worker      */
reset(const T * array,int count)157*c8dee2aaSAndroid Build Coastguard Worker     void reset(const T* array, int count) {
158*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(count >= 0);
159*c8dee2aaSAndroid Build Coastguard Worker         this->clear();
160*c8dee2aaSAndroid Build Coastguard Worker         this->checkRealloc(count, kExactFit);
161*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(count);
162*c8dee2aaSAndroid Build Coastguard Worker         this->copy(array);
163*c8dee2aaSAndroid Build Coastguard Worker     }
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker     /**
166*c8dee2aaSAndroid Build Coastguard Worker      * Ensures there is enough reserved space for at least n elements. This is guaranteed at least
167*c8dee2aaSAndroid Build Coastguard Worker      * until the array size grows above n and subsequently shrinks below n, any version of reset()
168*c8dee2aaSAndroid Build Coastguard Worker      * is called, or reserve() is called again.
169*c8dee2aaSAndroid Build Coastguard Worker      */
reserve(int n)170*c8dee2aaSAndroid Build Coastguard Worker     void reserve(int n) {
171*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(n >= 0);
172*c8dee2aaSAndroid Build Coastguard Worker         if (n > this->size()) {
173*c8dee2aaSAndroid Build Coastguard Worker             this->checkRealloc(n - this->size(), kGrowing);
174*c8dee2aaSAndroid Build Coastguard Worker         }
175*c8dee2aaSAndroid Build Coastguard Worker     }
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker     /**
178*c8dee2aaSAndroid Build Coastguard Worker      * Ensures there is enough reserved space for exactly n elements. The same capacity guarantees
179*c8dee2aaSAndroid Build Coastguard Worker      * as above apply.
180*c8dee2aaSAndroid Build Coastguard Worker      */
reserve_exact(int n)181*c8dee2aaSAndroid Build Coastguard Worker     void reserve_exact(int n) {
182*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(n >= 0);
183*c8dee2aaSAndroid Build Coastguard Worker         if (n > this->size()) {
184*c8dee2aaSAndroid Build Coastguard Worker             this->checkRealloc(n - this->size(), kExactFit);
185*c8dee2aaSAndroid Build Coastguard Worker         }
186*c8dee2aaSAndroid Build Coastguard Worker     }
187*c8dee2aaSAndroid Build Coastguard Worker 
removeShuffle(int n)188*c8dee2aaSAndroid Build Coastguard Worker     void removeShuffle(int n) {
189*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(n < this->size());
190*c8dee2aaSAndroid Build Coastguard Worker         int newCount = fSize - 1;
191*c8dee2aaSAndroid Build Coastguard Worker         fData[n].~T();
192*c8dee2aaSAndroid Build Coastguard Worker         if (n != newCount) {
193*c8dee2aaSAndroid Build Coastguard Worker             this->move(n, newCount);
194*c8dee2aaSAndroid Build Coastguard Worker         }
195*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(newCount);
196*c8dee2aaSAndroid Build Coastguard Worker     }
197*c8dee2aaSAndroid Build Coastguard Worker 
198*c8dee2aaSAndroid Build Coastguard Worker     // Is the array empty.
empty()199*c8dee2aaSAndroid Build Coastguard Worker     bool empty() const { return fSize == 0; }
200*c8dee2aaSAndroid Build Coastguard Worker 
201*c8dee2aaSAndroid Build Coastguard Worker     /**
202*c8dee2aaSAndroid Build Coastguard Worker      * Adds one new default-initialized T value and returns it by reference. Note that the reference
203*c8dee2aaSAndroid Build Coastguard Worker      * only remains valid until the next call that adds or removes elements.
204*c8dee2aaSAndroid Build Coastguard Worker      */
push_back()205*c8dee2aaSAndroid Build Coastguard Worker     T& push_back() {
206*c8dee2aaSAndroid Build Coastguard Worker         void* newT = this->push_back_raw(1);
207*c8dee2aaSAndroid Build Coastguard Worker         return *new (newT) T;
208*c8dee2aaSAndroid Build Coastguard Worker     }
209*c8dee2aaSAndroid Build Coastguard Worker 
210*c8dee2aaSAndroid Build Coastguard Worker     /**
211*c8dee2aaSAndroid Build Coastguard Worker      * Adds one new T value which is copy-constructed, returning it by reference. As always,
212*c8dee2aaSAndroid Build Coastguard Worker      * the reference only remains valid until the next call that adds or removes elements.
213*c8dee2aaSAndroid Build Coastguard Worker      */
push_back(const T & t)214*c8dee2aaSAndroid Build Coastguard Worker     T& push_back(const T& t) {
215*c8dee2aaSAndroid Build Coastguard Worker         this->unpoison();
216*c8dee2aaSAndroid Build Coastguard Worker         T* newT;
217*c8dee2aaSAndroid Build Coastguard Worker         if (this->capacity() > fSize) SK_LIKELY {
218*c8dee2aaSAndroid Build Coastguard Worker             // Copy over the element directly.
219*c8dee2aaSAndroid Build Coastguard Worker             newT = new (fData + fSize) T(t);
220*c8dee2aaSAndroid Build Coastguard Worker         } else {
221*c8dee2aaSAndroid Build Coastguard Worker             newT = this->growAndConstructAtEnd(t);
222*c8dee2aaSAndroid Build Coastguard Worker         }
223*c8dee2aaSAndroid Build Coastguard Worker 
224*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(fSize + 1);
225*c8dee2aaSAndroid Build Coastguard Worker         return *newT;
226*c8dee2aaSAndroid Build Coastguard Worker     }
227*c8dee2aaSAndroid Build Coastguard Worker 
228*c8dee2aaSAndroid Build Coastguard Worker     /**
229*c8dee2aaSAndroid Build Coastguard Worker      * Adds one new T value which is copy-constructed, returning it by reference.
230*c8dee2aaSAndroid Build Coastguard Worker      */
push_back(T && t)231*c8dee2aaSAndroid Build Coastguard Worker     T& push_back(T&& t) {
232*c8dee2aaSAndroid Build Coastguard Worker         this->unpoison();
233*c8dee2aaSAndroid Build Coastguard Worker         T* newT;
234*c8dee2aaSAndroid Build Coastguard Worker         if (this->capacity() > fSize) SK_LIKELY {
235*c8dee2aaSAndroid Build Coastguard Worker             // Move over the element directly.
236*c8dee2aaSAndroid Build Coastguard Worker             newT = new (fData + fSize) T(std::move(t));
237*c8dee2aaSAndroid Build Coastguard Worker         } else {
238*c8dee2aaSAndroid Build Coastguard Worker             newT = this->growAndConstructAtEnd(std::move(t));
239*c8dee2aaSAndroid Build Coastguard Worker         }
240*c8dee2aaSAndroid Build Coastguard Worker 
241*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(fSize + 1);
242*c8dee2aaSAndroid Build Coastguard Worker         return *newT;
243*c8dee2aaSAndroid Build Coastguard Worker     }
244*c8dee2aaSAndroid Build Coastguard Worker 
245*c8dee2aaSAndroid Build Coastguard Worker     /**
246*c8dee2aaSAndroid Build Coastguard Worker      *  Constructs a new T at the back of this array, returning it by reference.
247*c8dee2aaSAndroid Build Coastguard Worker      */
emplace_back(Args &&...args)248*c8dee2aaSAndroid Build Coastguard Worker     template <typename... Args> T& emplace_back(Args&&... args) {
249*c8dee2aaSAndroid Build Coastguard Worker         this->unpoison();
250*c8dee2aaSAndroid Build Coastguard Worker         T* newT;
251*c8dee2aaSAndroid Build Coastguard Worker         if (this->capacity() > fSize) SK_LIKELY {
252*c8dee2aaSAndroid Build Coastguard Worker             // Emplace the new element in directly.
253*c8dee2aaSAndroid Build Coastguard Worker             newT = new (fData + fSize) T(std::forward<Args>(args)...);
254*c8dee2aaSAndroid Build Coastguard Worker         } else {
255*c8dee2aaSAndroid Build Coastguard Worker             newT = this->growAndConstructAtEnd(std::forward<Args>(args)...);
256*c8dee2aaSAndroid Build Coastguard Worker         }
257*c8dee2aaSAndroid Build Coastguard Worker 
258*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(fSize + 1);
259*c8dee2aaSAndroid Build Coastguard Worker         return *newT;
260*c8dee2aaSAndroid Build Coastguard Worker     }
261*c8dee2aaSAndroid Build Coastguard Worker 
262*c8dee2aaSAndroid Build Coastguard Worker     /**
263*c8dee2aaSAndroid Build Coastguard Worker      * Allocates n more default-initialized T values, and returns the address of
264*c8dee2aaSAndroid Build Coastguard Worker      * the start of that new range. Note: this address is only valid until the
265*c8dee2aaSAndroid Build Coastguard Worker      * next API call made on the array that might add or remove elements.
266*c8dee2aaSAndroid Build Coastguard Worker      */
push_back_n(int n)267*c8dee2aaSAndroid Build Coastguard Worker     T* push_back_n(int n) {
268*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(n >= 0);
269*c8dee2aaSAndroid Build Coastguard Worker         T* newTs = TCast(this->push_back_raw(n));
270*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < n; ++i) {
271*c8dee2aaSAndroid Build Coastguard Worker             new (&newTs[i]) T;
272*c8dee2aaSAndroid Build Coastguard Worker         }
273*c8dee2aaSAndroid Build Coastguard Worker         return newTs;
274*c8dee2aaSAndroid Build Coastguard Worker     }
275*c8dee2aaSAndroid Build Coastguard Worker 
276*c8dee2aaSAndroid Build Coastguard Worker     /**
277*c8dee2aaSAndroid Build Coastguard Worker      * Version of above that uses a copy constructor to initialize all n items
278*c8dee2aaSAndroid Build Coastguard Worker      * to the same T.
279*c8dee2aaSAndroid Build Coastguard Worker      */
push_back_n(int n,const T & t)280*c8dee2aaSAndroid Build Coastguard Worker     T* push_back_n(int n, const T& t) {
281*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(n >= 0);
282*c8dee2aaSAndroid Build Coastguard Worker         T* newTs = TCast(this->push_back_raw(n));
283*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < n; ++i) {
284*c8dee2aaSAndroid Build Coastguard Worker             new (&newTs[i]) T(t);
285*c8dee2aaSAndroid Build Coastguard Worker         }
286*c8dee2aaSAndroid Build Coastguard Worker         return static_cast<T*>(newTs);
287*c8dee2aaSAndroid Build Coastguard Worker     }
288*c8dee2aaSAndroid Build Coastguard Worker 
289*c8dee2aaSAndroid Build Coastguard Worker     /**
290*c8dee2aaSAndroid Build Coastguard Worker      * Version of above that uses a copy constructor to initialize the n items
291*c8dee2aaSAndroid Build Coastguard Worker      * to separate T values.
292*c8dee2aaSAndroid Build Coastguard Worker      */
push_back_n(int n,const T t[])293*c8dee2aaSAndroid Build Coastguard Worker     T* push_back_n(int n, const T t[]) {
294*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(n >= 0);
295*c8dee2aaSAndroid Build Coastguard Worker         this->checkRealloc(n, kGrowing);
296*c8dee2aaSAndroid Build Coastguard Worker         T* end = this->end();
297*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(fSize + n);
298*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < n; ++i) {
299*c8dee2aaSAndroid Build Coastguard Worker             new (end + i) T(t[i]);
300*c8dee2aaSAndroid Build Coastguard Worker         }
301*c8dee2aaSAndroid Build Coastguard Worker         return end;
302*c8dee2aaSAndroid Build Coastguard Worker     }
303*c8dee2aaSAndroid Build Coastguard Worker 
304*c8dee2aaSAndroid Build Coastguard Worker     /**
305*c8dee2aaSAndroid Build Coastguard Worker      * Version of above that uses the move constructor to set n items.
306*c8dee2aaSAndroid Build Coastguard Worker      */
move_back_n(int n,T * t)307*c8dee2aaSAndroid Build Coastguard Worker     T* move_back_n(int n, T* t) {
308*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(n >= 0);
309*c8dee2aaSAndroid Build Coastguard Worker         this->checkRealloc(n, kGrowing);
310*c8dee2aaSAndroid Build Coastguard Worker         T* end = this->end();
311*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(fSize + n);
312*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < n; ++i) {
313*c8dee2aaSAndroid Build Coastguard Worker             new (end + i) T(std::move(t[i]));
314*c8dee2aaSAndroid Build Coastguard Worker         }
315*c8dee2aaSAndroid Build Coastguard Worker         return end;
316*c8dee2aaSAndroid Build Coastguard Worker     }
317*c8dee2aaSAndroid Build Coastguard Worker 
318*c8dee2aaSAndroid Build Coastguard Worker     /**
319*c8dee2aaSAndroid Build Coastguard Worker      * Removes the last element. Not safe to call when size() == 0.
320*c8dee2aaSAndroid Build Coastguard Worker      */
pop_back()321*c8dee2aaSAndroid Build Coastguard Worker     void pop_back() {
322*c8dee2aaSAndroid Build Coastguard Worker         sk_collection_not_empty(this->empty());
323*c8dee2aaSAndroid Build Coastguard Worker         fData[fSize - 1].~T();
324*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(fSize - 1);
325*c8dee2aaSAndroid Build Coastguard Worker     }
326*c8dee2aaSAndroid Build Coastguard Worker 
327*c8dee2aaSAndroid Build Coastguard Worker     /**
328*c8dee2aaSAndroid Build Coastguard Worker      * Removes the last n elements. Not safe to call when size() < n.
329*c8dee2aaSAndroid Build Coastguard Worker      */
pop_back_n(int n)330*c8dee2aaSAndroid Build Coastguard Worker     void pop_back_n(int n) {
331*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(n >= 0);
332*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(this->size() >= n);
333*c8dee2aaSAndroid Build Coastguard Worker         int i = fSize;
334*c8dee2aaSAndroid Build Coastguard Worker         while (i-- > fSize - n) {
335*c8dee2aaSAndroid Build Coastguard Worker             (*this)[i].~T();
336*c8dee2aaSAndroid Build Coastguard Worker         }
337*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(fSize - n);
338*c8dee2aaSAndroid Build Coastguard Worker     }
339*c8dee2aaSAndroid Build Coastguard Worker 
340*c8dee2aaSAndroid Build Coastguard Worker     /**
341*c8dee2aaSAndroid Build Coastguard Worker      * Pushes or pops from the back to resize. Pushes will be default initialized.
342*c8dee2aaSAndroid Build Coastguard Worker      */
resize_back(int newCount)343*c8dee2aaSAndroid Build Coastguard Worker     void resize_back(int newCount) {
344*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(newCount >= 0);
345*c8dee2aaSAndroid Build Coastguard Worker         if (newCount > this->size()) {
346*c8dee2aaSAndroid Build Coastguard Worker             if (this->empty()) {
347*c8dee2aaSAndroid Build Coastguard Worker                 // When the container is completely empty, grow to exactly the requested size.
348*c8dee2aaSAndroid Build Coastguard Worker                 this->checkRealloc(newCount, kExactFit);
349*c8dee2aaSAndroid Build Coastguard Worker             }
350*c8dee2aaSAndroid Build Coastguard Worker             this->push_back_n(newCount - fSize);
351*c8dee2aaSAndroid Build Coastguard Worker         } else if (newCount < this->size()) {
352*c8dee2aaSAndroid Build Coastguard Worker             this->pop_back_n(fSize - newCount);
353*c8dee2aaSAndroid Build Coastguard Worker         }
354*c8dee2aaSAndroid Build Coastguard Worker     }
355*c8dee2aaSAndroid Build Coastguard Worker 
356*c8dee2aaSAndroid Build Coastguard Worker     /** Swaps the contents of this array with that array. Does a pointer swap if possible,
357*c8dee2aaSAndroid Build Coastguard Worker         otherwise copies the T values. */
swap(TArray & that)358*c8dee2aaSAndroid Build Coastguard Worker     void swap(TArray& that) {
359*c8dee2aaSAndroid Build Coastguard Worker         using std::swap;
360*c8dee2aaSAndroid Build Coastguard Worker         if (this == &that) {
361*c8dee2aaSAndroid Build Coastguard Worker             return;
362*c8dee2aaSAndroid Build Coastguard Worker         }
363*c8dee2aaSAndroid Build Coastguard Worker         if (fOwnMemory && that.fOwnMemory) {
364*c8dee2aaSAndroid Build Coastguard Worker             swap(fData, that.fData);
365*c8dee2aaSAndroid Build Coastguard Worker             swap(fSize, that.fSize);
366*c8dee2aaSAndroid Build Coastguard Worker 
367*c8dee2aaSAndroid Build Coastguard Worker             // Can't use swap because fCapacity is a bit field.
368*c8dee2aaSAndroid Build Coastguard Worker             auto allocCount = fCapacity;
369*c8dee2aaSAndroid Build Coastguard Worker             fCapacity = that.fCapacity;
370*c8dee2aaSAndroid Build Coastguard Worker             that.fCapacity = allocCount;
371*c8dee2aaSAndroid Build Coastguard Worker         } else {
372*c8dee2aaSAndroid Build Coastguard Worker             // This could be more optimal...
373*c8dee2aaSAndroid Build Coastguard Worker             TArray copy(std::move(that));
374*c8dee2aaSAndroid Build Coastguard Worker             that = std::move(*this);
375*c8dee2aaSAndroid Build Coastguard Worker             *this = std::move(copy);
376*c8dee2aaSAndroid Build Coastguard Worker         }
377*c8dee2aaSAndroid Build Coastguard Worker     }
378*c8dee2aaSAndroid Build Coastguard Worker 
379*c8dee2aaSAndroid Build Coastguard Worker     /**
380*c8dee2aaSAndroid Build Coastguard Worker      * Moves all elements of `that` to the end of this array, leaving `that` empty.
381*c8dee2aaSAndroid Build Coastguard Worker      * This is a no-op if `that` is empty or equal to this array.
382*c8dee2aaSAndroid Build Coastguard Worker      */
move_back(TArray & that)383*c8dee2aaSAndroid Build Coastguard Worker     void move_back(TArray& that) {
384*c8dee2aaSAndroid Build Coastguard Worker         if (that.empty() || &that == this) {
385*c8dee2aaSAndroid Build Coastguard Worker             return;
386*c8dee2aaSAndroid Build Coastguard Worker         }
387*c8dee2aaSAndroid Build Coastguard Worker         void* dst = this->push_back_raw(that.size());
388*c8dee2aaSAndroid Build Coastguard Worker         // After move() returns, the contents of `dst` will have either been in-place initialized
389*c8dee2aaSAndroid Build Coastguard Worker         // using a the move constructor (per-item from `that`'s elements), or will have been
390*c8dee2aaSAndroid Build Coastguard Worker         // mem-copied into when MEM_MOVE is true (now valid objects).
391*c8dee2aaSAndroid Build Coastguard Worker         that.move(dst);
392*c8dee2aaSAndroid Build Coastguard Worker         // All items in `that` have either been destroyed (when MEM_MOVE is false) or should be
393*c8dee2aaSAndroid Build Coastguard Worker         // considered invalid (when MEM_MOVE is true). Reset fSize to 0 directly to skip any further
394*c8dee2aaSAndroid Build Coastguard Worker         // per-item destruction.
395*c8dee2aaSAndroid Build Coastguard Worker         that.changeSize(0);
396*c8dee2aaSAndroid Build Coastguard Worker     }
397*c8dee2aaSAndroid Build Coastguard Worker 
begin()398*c8dee2aaSAndroid Build Coastguard Worker     T* begin() {
399*c8dee2aaSAndroid Build Coastguard Worker         return fData;
400*c8dee2aaSAndroid Build Coastguard Worker     }
begin()401*c8dee2aaSAndroid Build Coastguard Worker     const T* begin() const {
402*c8dee2aaSAndroid Build Coastguard Worker         return fData;
403*c8dee2aaSAndroid Build Coastguard Worker     }
404*c8dee2aaSAndroid Build Coastguard Worker 
405*c8dee2aaSAndroid Build Coastguard Worker     // It's safe to use fItemArray + fSize because if fItemArray is nullptr then adding 0 is
406*c8dee2aaSAndroid Build Coastguard Worker     // valid and returns nullptr. See [expr.add] in the C++ standard.
end()407*c8dee2aaSAndroid Build Coastguard Worker     T* end() {
408*c8dee2aaSAndroid Build Coastguard Worker         if (fData == nullptr) {
409*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fSize == 0);
410*c8dee2aaSAndroid Build Coastguard Worker         }
411*c8dee2aaSAndroid Build Coastguard Worker         return fData + fSize;
412*c8dee2aaSAndroid Build Coastguard Worker     }
end()413*c8dee2aaSAndroid Build Coastguard Worker     const T* end() const {
414*c8dee2aaSAndroid Build Coastguard Worker         if (fData == nullptr) {
415*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fSize == 0);
416*c8dee2aaSAndroid Build Coastguard Worker         }
417*c8dee2aaSAndroid Build Coastguard Worker         return fData + fSize;
418*c8dee2aaSAndroid Build Coastguard Worker     }
data()419*c8dee2aaSAndroid Build Coastguard Worker     T* data() { return fData; }
data()420*c8dee2aaSAndroid Build Coastguard Worker     const T* data() const { return fData; }
size()421*c8dee2aaSAndroid Build Coastguard Worker     int size() const { return fSize; }
size_bytes()422*c8dee2aaSAndroid Build Coastguard Worker     size_t size_bytes() const { return Bytes(fSize); }
resize(size_t count)423*c8dee2aaSAndroid Build Coastguard Worker     void resize(size_t count) { this->resize_back((int)count); }
424*c8dee2aaSAndroid Build Coastguard Worker 
clear()425*c8dee2aaSAndroid Build Coastguard Worker     void clear() {
426*c8dee2aaSAndroid Build Coastguard Worker         this->destroyAll();
427*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(0);
428*c8dee2aaSAndroid Build Coastguard Worker     }
429*c8dee2aaSAndroid Build Coastguard Worker 
shrink_to_fit()430*c8dee2aaSAndroid Build Coastguard Worker     void shrink_to_fit() {
431*c8dee2aaSAndroid Build Coastguard Worker         if (!fOwnMemory || fSize == fCapacity) {
432*c8dee2aaSAndroid Build Coastguard Worker             return;
433*c8dee2aaSAndroid Build Coastguard Worker         }
434*c8dee2aaSAndroid Build Coastguard Worker         this->unpoison();
435*c8dee2aaSAndroid Build Coastguard Worker         if (fSize == 0) {
436*c8dee2aaSAndroid Build Coastguard Worker             sk_free(fData);
437*c8dee2aaSAndroid Build Coastguard Worker             fData = nullptr;
438*c8dee2aaSAndroid Build Coastguard Worker             fCapacity = 0;
439*c8dee2aaSAndroid Build Coastguard Worker         } else {
440*c8dee2aaSAndroid Build Coastguard Worker             SkSpan<std::byte> allocation = Allocate(fSize);
441*c8dee2aaSAndroid Build Coastguard Worker             this->move(TCast(allocation.data()));
442*c8dee2aaSAndroid Build Coastguard Worker             if (fOwnMemory) {
443*c8dee2aaSAndroid Build Coastguard Worker                 sk_free(fData);
444*c8dee2aaSAndroid Build Coastguard Worker             }
445*c8dee2aaSAndroid Build Coastguard Worker             // Poison is applied in `setDataFromBytes`.
446*c8dee2aaSAndroid Build Coastguard Worker             this->setDataFromBytes(allocation);
447*c8dee2aaSAndroid Build Coastguard Worker         }
448*c8dee2aaSAndroid Build Coastguard Worker     }
449*c8dee2aaSAndroid Build Coastguard Worker 
450*c8dee2aaSAndroid Build Coastguard Worker     /**
451*c8dee2aaSAndroid Build Coastguard Worker      * Get the i^th element.
452*c8dee2aaSAndroid Build Coastguard Worker      */
453*c8dee2aaSAndroid Build Coastguard Worker     T& operator[] (int i) {
454*c8dee2aaSAndroid Build Coastguard Worker         return fData[sk_collection_check_bounds(i, this->size())];
455*c8dee2aaSAndroid Build Coastguard Worker     }
456*c8dee2aaSAndroid Build Coastguard Worker 
457*c8dee2aaSAndroid Build Coastguard Worker     const T& operator[] (int i) const {
458*c8dee2aaSAndroid Build Coastguard Worker         return fData[sk_collection_check_bounds(i, this->size())];
459*c8dee2aaSAndroid Build Coastguard Worker     }
460*c8dee2aaSAndroid Build Coastguard Worker 
at(int i)461*c8dee2aaSAndroid Build Coastguard Worker     T& at(int i) { return (*this)[i]; }
at(int i)462*c8dee2aaSAndroid Build Coastguard Worker     const T& at(int i) const { return (*this)[i]; }
463*c8dee2aaSAndroid Build Coastguard Worker 
464*c8dee2aaSAndroid Build Coastguard Worker     /**
465*c8dee2aaSAndroid Build Coastguard Worker      * equivalent to operator[](0)
466*c8dee2aaSAndroid Build Coastguard Worker      */
front()467*c8dee2aaSAndroid Build Coastguard Worker     T& front() {
468*c8dee2aaSAndroid Build Coastguard Worker         sk_collection_not_empty(this->empty());
469*c8dee2aaSAndroid Build Coastguard Worker         return fData[0];
470*c8dee2aaSAndroid Build Coastguard Worker     }
471*c8dee2aaSAndroid Build Coastguard Worker 
front()472*c8dee2aaSAndroid Build Coastguard Worker     const T& front() const {
473*c8dee2aaSAndroid Build Coastguard Worker         sk_collection_not_empty(this->empty());
474*c8dee2aaSAndroid Build Coastguard Worker         return fData[0];
475*c8dee2aaSAndroid Build Coastguard Worker     }
476*c8dee2aaSAndroid Build Coastguard Worker 
477*c8dee2aaSAndroid Build Coastguard Worker     /**
478*c8dee2aaSAndroid Build Coastguard Worker      * equivalent to operator[](size() - 1)
479*c8dee2aaSAndroid Build Coastguard Worker      */
back()480*c8dee2aaSAndroid Build Coastguard Worker     T& back() {
481*c8dee2aaSAndroid Build Coastguard Worker         sk_collection_not_empty(this->empty());
482*c8dee2aaSAndroid Build Coastguard Worker         return fData[fSize - 1];
483*c8dee2aaSAndroid Build Coastguard Worker     }
484*c8dee2aaSAndroid Build Coastguard Worker 
back()485*c8dee2aaSAndroid Build Coastguard Worker     const T& back() const {
486*c8dee2aaSAndroid Build Coastguard Worker         sk_collection_not_empty(this->empty());
487*c8dee2aaSAndroid Build Coastguard Worker         return fData[fSize - 1];
488*c8dee2aaSAndroid Build Coastguard Worker     }
489*c8dee2aaSAndroid Build Coastguard Worker 
490*c8dee2aaSAndroid Build Coastguard Worker     /**
491*c8dee2aaSAndroid Build Coastguard Worker      * equivalent to operator[](size()-1-i)
492*c8dee2aaSAndroid Build Coastguard Worker      */
fromBack(int i)493*c8dee2aaSAndroid Build Coastguard Worker     T& fromBack(int i) {
494*c8dee2aaSAndroid Build Coastguard Worker         return (*this)[fSize - i - 1];
495*c8dee2aaSAndroid Build Coastguard Worker     }
496*c8dee2aaSAndroid Build Coastguard Worker 
fromBack(int i)497*c8dee2aaSAndroid Build Coastguard Worker     const T& fromBack(int i) const {
498*c8dee2aaSAndroid Build Coastguard Worker         return (*this)[fSize - i - 1];
499*c8dee2aaSAndroid Build Coastguard Worker     }
500*c8dee2aaSAndroid Build Coastguard Worker 
501*c8dee2aaSAndroid Build Coastguard Worker     bool operator==(const TArray<T, MEM_MOVE>& right) const {
502*c8dee2aaSAndroid Build Coastguard Worker         int leftCount = this->size();
503*c8dee2aaSAndroid Build Coastguard Worker         if (leftCount != right.size()) {
504*c8dee2aaSAndroid Build Coastguard Worker             return false;
505*c8dee2aaSAndroid Build Coastguard Worker         }
506*c8dee2aaSAndroid Build Coastguard Worker         for (int index = 0; index < leftCount; ++index) {
507*c8dee2aaSAndroid Build Coastguard Worker             if (fData[index] != right.fData[index]) {
508*c8dee2aaSAndroid Build Coastguard Worker                 return false;
509*c8dee2aaSAndroid Build Coastguard Worker             }
510*c8dee2aaSAndroid Build Coastguard Worker         }
511*c8dee2aaSAndroid Build Coastguard Worker         return true;
512*c8dee2aaSAndroid Build Coastguard Worker     }
513*c8dee2aaSAndroid Build Coastguard Worker 
514*c8dee2aaSAndroid Build Coastguard Worker     bool operator!=(const TArray<T, MEM_MOVE>& right) const {
515*c8dee2aaSAndroid Build Coastguard Worker         return !(*this == right);
516*c8dee2aaSAndroid Build Coastguard Worker     }
517*c8dee2aaSAndroid Build Coastguard Worker 
capacity()518*c8dee2aaSAndroid Build Coastguard Worker     int capacity() const {
519*c8dee2aaSAndroid Build Coastguard Worker         return fCapacity;
520*c8dee2aaSAndroid Build Coastguard Worker     }
521*c8dee2aaSAndroid Build Coastguard Worker 
522*c8dee2aaSAndroid Build Coastguard Worker protected:
523*c8dee2aaSAndroid Build Coastguard Worker     // Creates an empty array that will use the passed storage block until it is insufficiently
524*c8dee2aaSAndroid Build Coastguard Worker     // large to hold the entire array.
525*c8dee2aaSAndroid Build Coastguard Worker     template <int InitialCapacity>
526*c8dee2aaSAndroid Build Coastguard Worker     TArray(SkAlignedSTStorage<InitialCapacity, T>* storage, int size = 0) {
527*c8dee2aaSAndroid Build Coastguard Worker         static_assert(InitialCapacity >= 0);
528*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(size >= 0);
529*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(storage->get() != nullptr);
530*c8dee2aaSAndroid Build Coastguard Worker         if (size > InitialCapacity) {
531*c8dee2aaSAndroid Build Coastguard Worker             this->initData(size);
532*c8dee2aaSAndroid Build Coastguard Worker         } else {
533*c8dee2aaSAndroid Build Coastguard Worker             this->setDataFromBytes(*storage);
534*c8dee2aaSAndroid Build Coastguard Worker             this->changeSize(size);
535*c8dee2aaSAndroid Build Coastguard Worker 
536*c8dee2aaSAndroid Build Coastguard Worker             // setDataFromBytes always sets fOwnMemory to true, but we are actually using static
537*c8dee2aaSAndroid Build Coastguard Worker             // storage here, which shouldn't ever be freed.
538*c8dee2aaSAndroid Build Coastguard Worker             fOwnMemory = false;
539*c8dee2aaSAndroid Build Coastguard Worker         }
540*c8dee2aaSAndroid Build Coastguard Worker     }
541*c8dee2aaSAndroid Build Coastguard Worker 
542*c8dee2aaSAndroid Build Coastguard Worker     // Copy a C array, using pre-allocated storage if preAllocCount >= count. Otherwise, storage
543*c8dee2aaSAndroid Build Coastguard Worker     // will only be used when array shrinks to fit.
544*c8dee2aaSAndroid Build Coastguard Worker     template <int InitialCapacity>
TArray(const T * array,int size,SkAlignedSTStorage<InitialCapacity,T> * storage)545*c8dee2aaSAndroid Build Coastguard Worker     TArray(const T* array, int size, SkAlignedSTStorage<InitialCapacity, T>* storage)
546*c8dee2aaSAndroid Build Coastguard Worker             : TArray{storage, size} {
547*c8dee2aaSAndroid Build Coastguard Worker         this->copy(array);
548*c8dee2aaSAndroid Build Coastguard Worker     }
549*c8dee2aaSAndroid Build Coastguard Worker     template <int InitialCapacity>
TArray(SkSpan<const T> data,SkAlignedSTStorage<InitialCapacity,T> * storage)550*c8dee2aaSAndroid Build Coastguard Worker     TArray(SkSpan<const T> data, SkAlignedSTStorage<InitialCapacity, T>* storage)
551*c8dee2aaSAndroid Build Coastguard Worker             : TArray{storage, static_cast<int>(data.size())} {
552*c8dee2aaSAndroid Build Coastguard Worker         this->copy(data.begin());
553*c8dee2aaSAndroid Build Coastguard Worker     }
554*c8dee2aaSAndroid Build Coastguard Worker 
555*c8dee2aaSAndroid Build Coastguard Worker private:
556*c8dee2aaSAndroid Build Coastguard Worker     // Growth factors for checkRealloc.
557*c8dee2aaSAndroid Build Coastguard Worker     static constexpr double kExactFit = 1.0;
558*c8dee2aaSAndroid Build Coastguard Worker     static constexpr double kGrowing = 1.5;
559*c8dee2aaSAndroid Build Coastguard Worker 
560*c8dee2aaSAndroid Build Coastguard Worker     static constexpr int kMinHeapAllocCount = 8;
561*c8dee2aaSAndroid Build Coastguard Worker     static_assert(SkIsPow2(kMinHeapAllocCount), "min alloc count not power of two.");
562*c8dee2aaSAndroid Build Coastguard Worker 
563*c8dee2aaSAndroid Build Coastguard Worker     // Note for 32-bit machines kMaxCapacity will be <= SIZE_MAX. For 64-bit machines it will
564*c8dee2aaSAndroid Build Coastguard Worker     // just be INT_MAX if the sizeof(T) < 2^32.
565*c8dee2aaSAndroid Build Coastguard Worker     static constexpr int kMaxCapacity = SkToInt(std::min(SIZE_MAX / sizeof(T), (size_t)INT_MAX));
566*c8dee2aaSAndroid Build Coastguard Worker 
setDataFromBytes(SkSpan<std::byte> allocation)567*c8dee2aaSAndroid Build Coastguard Worker     void setDataFromBytes(SkSpan<std::byte> allocation) {
568*c8dee2aaSAndroid Build Coastguard Worker         T* data = TCast(allocation.data());
569*c8dee2aaSAndroid Build Coastguard Worker         // We have gotten extra bytes back from the allocation limit, pin to kMaxCapacity. It
570*c8dee2aaSAndroid Build Coastguard Worker         // would seem like the SkContainerAllocator should handle the divide, but it would have
571*c8dee2aaSAndroid Build Coastguard Worker         // to a full divide instruction. If done here the size is known at compile, and usually
572*c8dee2aaSAndroid Build Coastguard Worker         // can be implemented by a right shift. The full divide takes ~50X longer than the shift.
573*c8dee2aaSAndroid Build Coastguard Worker         size_t size = std::min(allocation.size() / sizeof(T), SkToSizeT(kMaxCapacity));
574*c8dee2aaSAndroid Build Coastguard Worker         this->setData(SkSpan<T>(data, size));
575*c8dee2aaSAndroid Build Coastguard Worker     }
576*c8dee2aaSAndroid Build Coastguard Worker 
setData(SkSpan<T> array)577*c8dee2aaSAndroid Build Coastguard Worker     void setData(SkSpan<T> array) {
578*c8dee2aaSAndroid Build Coastguard Worker         this->unpoison();
579*c8dee2aaSAndroid Build Coastguard Worker 
580*c8dee2aaSAndroid Build Coastguard Worker         fData = array.data();
581*c8dee2aaSAndroid Build Coastguard Worker         fCapacity = SkToU32(array.size());
582*c8dee2aaSAndroid Build Coastguard Worker         fOwnMemory = true;
583*c8dee2aaSAndroid Build Coastguard Worker 
584*c8dee2aaSAndroid Build Coastguard Worker         this->poison();
585*c8dee2aaSAndroid Build Coastguard Worker     }
586*c8dee2aaSAndroid Build Coastguard Worker 
unpoison()587*c8dee2aaSAndroid Build Coastguard Worker     void unpoison() {
588*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_SANITIZE_ADDRESS
589*c8dee2aaSAndroid Build Coastguard Worker         if (fData && fPoisoned) {
590*c8dee2aaSAndroid Build Coastguard Worker             // SkDebugf("UNPOISONING %p : 0 -> %zu\n", fData, Bytes(fCapacity));
591*c8dee2aaSAndroid Build Coastguard Worker             sk_asan_unpoison_memory_region(this->begin(), Bytes(fCapacity));
592*c8dee2aaSAndroid Build Coastguard Worker             fPoisoned = false;
593*c8dee2aaSAndroid Build Coastguard Worker         }
594*c8dee2aaSAndroid Build Coastguard Worker #endif
595*c8dee2aaSAndroid Build Coastguard Worker     }
596*c8dee2aaSAndroid Build Coastguard Worker 
poison()597*c8dee2aaSAndroid Build Coastguard Worker     void poison() {
598*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_SANITIZE_ADDRESS
599*c8dee2aaSAndroid Build Coastguard Worker         if (fData && fCapacity > fSize) {
600*c8dee2aaSAndroid Build Coastguard Worker             // SkDebugf("  POISONING %p : %zu -> %zu\n", fData, Bytes(fSize), Bytes(fCapacity));
601*c8dee2aaSAndroid Build Coastguard Worker             sk_asan_poison_memory_region(this->end(), Bytes(fCapacity - fSize));
602*c8dee2aaSAndroid Build Coastguard Worker             fPoisoned = true;
603*c8dee2aaSAndroid Build Coastguard Worker         }
604*c8dee2aaSAndroid Build Coastguard Worker #endif
605*c8dee2aaSAndroid Build Coastguard Worker     }
606*c8dee2aaSAndroid Build Coastguard Worker 
changeSize(int n)607*c8dee2aaSAndroid Build Coastguard Worker     void changeSize(int n) {
608*c8dee2aaSAndroid Build Coastguard Worker         this->unpoison();
609*c8dee2aaSAndroid Build Coastguard Worker         fSize = n;
610*c8dee2aaSAndroid Build Coastguard Worker         this->poison();
611*c8dee2aaSAndroid Build Coastguard Worker     }
612*c8dee2aaSAndroid Build Coastguard Worker 
613*c8dee2aaSAndroid Build Coastguard Worker     // We disable Control-Flow Integrity sanitization (go/cfi) when casting item-array buffers.
614*c8dee2aaSAndroid Build Coastguard Worker     // CFI flags this code as dangerous because we are casting `buffer` to a T* while the buffer's
615*c8dee2aaSAndroid Build Coastguard Worker     // contents might still be uninitialized memory. When T has a vtable, this is especially risky
616*c8dee2aaSAndroid Build Coastguard Worker     // because we could hypothetically access a virtual method on fItemArray and jump to an
617*c8dee2aaSAndroid Build Coastguard Worker     // unpredictable location in memory. Of course, TArray won't actually use fItemArray in this
618*c8dee2aaSAndroid Build Coastguard Worker     // way, and we don't want to construct a T before the user requests one. There's no real risk
619*c8dee2aaSAndroid Build Coastguard Worker     // here, so disable CFI when doing these casts.
620*c8dee2aaSAndroid Build Coastguard Worker     SK_NO_SANITIZE("cfi")
TCast(void * buffer)621*c8dee2aaSAndroid Build Coastguard Worker     static T* TCast(void* buffer) {
622*c8dee2aaSAndroid Build Coastguard Worker         return (T*)buffer;
623*c8dee2aaSAndroid Build Coastguard Worker     }
624*c8dee2aaSAndroid Build Coastguard Worker 
Bytes(int n)625*c8dee2aaSAndroid Build Coastguard Worker     static size_t Bytes(int n) {
626*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(n <= kMaxCapacity);
627*c8dee2aaSAndroid Build Coastguard Worker         return SkToSizeT(n) * sizeof(T);
628*c8dee2aaSAndroid Build Coastguard Worker     }
629*c8dee2aaSAndroid Build Coastguard Worker 
630*c8dee2aaSAndroid Build Coastguard Worker     static SkSpan<std::byte> Allocate(int capacity, double growthFactor = 1.0) {
631*c8dee2aaSAndroid Build Coastguard Worker         return SkContainerAllocator{sizeof(T), kMaxCapacity}.allocate(capacity, growthFactor);
632*c8dee2aaSAndroid Build Coastguard Worker     }
633*c8dee2aaSAndroid Build Coastguard Worker 
initData(int count)634*c8dee2aaSAndroid Build Coastguard Worker     void initData(int count) {
635*c8dee2aaSAndroid Build Coastguard Worker         this->setDataFromBytes(Allocate(count));
636*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(count);
637*c8dee2aaSAndroid Build Coastguard Worker     }
638*c8dee2aaSAndroid Build Coastguard Worker 
destroyAll()639*c8dee2aaSAndroid Build Coastguard Worker     void destroyAll() {
640*c8dee2aaSAndroid Build Coastguard Worker         if (!this->empty()) {
641*c8dee2aaSAndroid Build Coastguard Worker             T* cursor = this->begin();
642*c8dee2aaSAndroid Build Coastguard Worker             T* const end = this->end();
643*c8dee2aaSAndroid Build Coastguard Worker             do {
644*c8dee2aaSAndroid Build Coastguard Worker                 cursor->~T();
645*c8dee2aaSAndroid Build Coastguard Worker                 cursor++;
646*c8dee2aaSAndroid Build Coastguard Worker             } while (cursor < end);
647*c8dee2aaSAndroid Build Coastguard Worker         }
648*c8dee2aaSAndroid Build Coastguard Worker     }
649*c8dee2aaSAndroid Build Coastguard Worker 
650*c8dee2aaSAndroid Build Coastguard Worker     /** In the following move and copy methods, 'dst' is assumed to be uninitialized raw storage.
651*c8dee2aaSAndroid Build Coastguard Worker      *  In the following move methods, 'src' is destroyed leaving behind uninitialized raw storage.
652*c8dee2aaSAndroid Build Coastguard Worker      */
copy(const T * src)653*c8dee2aaSAndroid Build Coastguard Worker     void copy(const T* src) {
654*c8dee2aaSAndroid Build Coastguard Worker         if constexpr (std::is_trivially_copyable_v<T>) {
655*c8dee2aaSAndroid Build Coastguard Worker             if (!this->empty() && src != nullptr) {
656*c8dee2aaSAndroid Build Coastguard Worker                 sk_careful_memcpy(fData, src, this->size_bytes());
657*c8dee2aaSAndroid Build Coastguard Worker             }
658*c8dee2aaSAndroid Build Coastguard Worker         } else {
659*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < this->size(); ++i) {
660*c8dee2aaSAndroid Build Coastguard Worker                 new (fData + i) T(src[i]);
661*c8dee2aaSAndroid Build Coastguard Worker             }
662*c8dee2aaSAndroid Build Coastguard Worker         }
663*c8dee2aaSAndroid Build Coastguard Worker     }
664*c8dee2aaSAndroid Build Coastguard Worker 
move(int dst,int src)665*c8dee2aaSAndroid Build Coastguard Worker     void move(int dst, int src) {
666*c8dee2aaSAndroid Build Coastguard Worker         if constexpr (MEM_MOVE) {
667*c8dee2aaSAndroid Build Coastguard Worker             memcpy(static_cast<void*>(&fData[dst]),
668*c8dee2aaSAndroid Build Coastguard Worker                    static_cast<const void*>(&fData[src]),
669*c8dee2aaSAndroid Build Coastguard Worker                    sizeof(T));
670*c8dee2aaSAndroid Build Coastguard Worker         } else {
671*c8dee2aaSAndroid Build Coastguard Worker             new (&fData[dst]) T(std::move(fData[src]));
672*c8dee2aaSAndroid Build Coastguard Worker             fData[src].~T();
673*c8dee2aaSAndroid Build Coastguard Worker         }
674*c8dee2aaSAndroid Build Coastguard Worker     }
675*c8dee2aaSAndroid Build Coastguard Worker 
move(void * dst)676*c8dee2aaSAndroid Build Coastguard Worker     void move(void* dst) {
677*c8dee2aaSAndroid Build Coastguard Worker         if constexpr (MEM_MOVE) {
678*c8dee2aaSAndroid Build Coastguard Worker             sk_careful_memcpy(dst, fData, Bytes(fSize));
679*c8dee2aaSAndroid Build Coastguard Worker         } else {
680*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < this->size(); ++i) {
681*c8dee2aaSAndroid Build Coastguard Worker                 new (static_cast<char*>(dst) + Bytes(i)) T(std::move(fData[i]));
682*c8dee2aaSAndroid Build Coastguard Worker                 fData[i].~T();
683*c8dee2aaSAndroid Build Coastguard Worker             }
684*c8dee2aaSAndroid Build Coastguard Worker         }
685*c8dee2aaSAndroid Build Coastguard Worker     }
686*c8dee2aaSAndroid Build Coastguard Worker 
687*c8dee2aaSAndroid Build Coastguard Worker     // Helper function that makes space for n objects, adjusts the count, but does not initialize
688*c8dee2aaSAndroid Build Coastguard Worker     // the new objects.
push_back_raw(int n)689*c8dee2aaSAndroid Build Coastguard Worker     void* push_back_raw(int n) {
690*c8dee2aaSAndroid Build Coastguard Worker         this->checkRealloc(n, kGrowing);
691*c8dee2aaSAndroid Build Coastguard Worker         void* ptr = fData + fSize;
692*c8dee2aaSAndroid Build Coastguard Worker         this->changeSize(fSize + n);
693*c8dee2aaSAndroid Build Coastguard Worker         return ptr;
694*c8dee2aaSAndroid Build Coastguard Worker     }
695*c8dee2aaSAndroid Build Coastguard Worker 
696*c8dee2aaSAndroid Build Coastguard Worker     template <typename... Args>
growAndConstructAtEnd(Args &&...args)697*c8dee2aaSAndroid Build Coastguard Worker     SK_ALWAYS_INLINE T* growAndConstructAtEnd(Args&&... args) {
698*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<std::byte> buffer = this->preallocateNewData(/*delta=*/1, kGrowing);
699*c8dee2aaSAndroid Build Coastguard Worker         T* newT = new (TCast(buffer.data()) + fSize) T(std::forward<Args>(args)...);
700*c8dee2aaSAndroid Build Coastguard Worker         this->installDataAndUpdateCapacity(buffer);
701*c8dee2aaSAndroid Build Coastguard Worker 
702*c8dee2aaSAndroid Build Coastguard Worker         return newT;
703*c8dee2aaSAndroid Build Coastguard Worker     }
704*c8dee2aaSAndroid Build Coastguard Worker 
checkRealloc(int delta,double growthFactor)705*c8dee2aaSAndroid Build Coastguard Worker     void checkRealloc(int delta, double growthFactor) {
706*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(delta >= 0);
707*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fSize >= 0);
708*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fCapacity >= 0);
709*c8dee2aaSAndroid Build Coastguard Worker 
710*c8dee2aaSAndroid Build Coastguard Worker         // Check if there are enough remaining allocated elements to satisfy the request.
711*c8dee2aaSAndroid Build Coastguard Worker         if (this->capacity() - fSize < delta) {
712*c8dee2aaSAndroid Build Coastguard Worker             // Looks like we need to reallocate.
713*c8dee2aaSAndroid Build Coastguard Worker             this->installDataAndUpdateCapacity(this->preallocateNewData(delta, growthFactor));
714*c8dee2aaSAndroid Build Coastguard Worker         }
715*c8dee2aaSAndroid Build Coastguard Worker     }
716*c8dee2aaSAndroid Build Coastguard Worker 
preallocateNewData(int delta,double growthFactor)717*c8dee2aaSAndroid Build Coastguard Worker     SkSpan<std::byte> preallocateNewData(int delta, double growthFactor) {
718*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(delta >= 0);
719*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fSize >= 0);
720*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fCapacity >= 0);
721*c8dee2aaSAndroid Build Coastguard Worker 
722*c8dee2aaSAndroid Build Coastguard Worker         // Don't overflow fSize or size_t later in the memory allocation. Overflowing memory
723*c8dee2aaSAndroid Build Coastguard Worker         // allocation really only applies to fSizes on 32-bit machines; on 64-bit machines this
724*c8dee2aaSAndroid Build Coastguard Worker         // will probably never produce a check. Since kMaxCapacity is bounded above by INT_MAX,
725*c8dee2aaSAndroid Build Coastguard Worker         // this also checks the bounds of fSize.
726*c8dee2aaSAndroid Build Coastguard Worker         if (delta > kMaxCapacity - fSize) {
727*c8dee2aaSAndroid Build Coastguard Worker             sk_report_container_overflow_and_die();
728*c8dee2aaSAndroid Build Coastguard Worker         }
729*c8dee2aaSAndroid Build Coastguard Worker         const int newCount = fSize + delta;
730*c8dee2aaSAndroid Build Coastguard Worker 
731*c8dee2aaSAndroid Build Coastguard Worker         return Allocate(newCount, growthFactor);
732*c8dee2aaSAndroid Build Coastguard Worker     }
733*c8dee2aaSAndroid Build Coastguard Worker 
installDataAndUpdateCapacity(SkSpan<std::byte> allocation)734*c8dee2aaSAndroid Build Coastguard Worker     void installDataAndUpdateCapacity(SkSpan<std::byte> allocation) {
735*c8dee2aaSAndroid Build Coastguard Worker         this->move(TCast(allocation.data()));
736*c8dee2aaSAndroid Build Coastguard Worker         if (fOwnMemory) {
737*c8dee2aaSAndroid Build Coastguard Worker             sk_free(fData);
738*c8dee2aaSAndroid Build Coastguard Worker         }
739*c8dee2aaSAndroid Build Coastguard Worker         this->setDataFromBytes(allocation);
740*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fData != nullptr);
741*c8dee2aaSAndroid Build Coastguard Worker     }
742*c8dee2aaSAndroid Build Coastguard Worker 
743*c8dee2aaSAndroid Build Coastguard Worker     T* fData{nullptr};
744*c8dee2aaSAndroid Build Coastguard Worker     int fSize{0};
745*c8dee2aaSAndroid Build Coastguard Worker     uint32_t fOwnMemory : 1;
746*c8dee2aaSAndroid Build Coastguard Worker     uint32_t fCapacity : 31;
747*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_SANITIZE_ADDRESS
748*c8dee2aaSAndroid Build Coastguard Worker     bool fPoisoned = false;
749*c8dee2aaSAndroid Build Coastguard Worker #endif
750*c8dee2aaSAndroid Build Coastguard Worker };
751*c8dee2aaSAndroid Build Coastguard Worker 
swap(TArray<T,M> & a,TArray<T,M> & b)752*c8dee2aaSAndroid Build Coastguard Worker template <typename T, bool M> static inline void swap(TArray<T, M>& a, TArray<T, M>& b) {
753*c8dee2aaSAndroid Build Coastguard Worker     a.swap(b);
754*c8dee2aaSAndroid Build Coastguard Worker }
755*c8dee2aaSAndroid Build Coastguard Worker 
756*c8dee2aaSAndroid Build Coastguard Worker // Subclass of TArray that contains a pre-allocated memory block for the array.
757*c8dee2aaSAndroid Build Coastguard Worker template <int Nreq, typename T, bool MEM_MOVE = sk_is_trivially_relocatable_v<T>>
758*c8dee2aaSAndroid Build Coastguard Worker class STArray : private SkAlignedSTStorage<SkContainerAllocator::RoundUp<T>(Nreq), T>,
759*c8dee2aaSAndroid Build Coastguard Worker                 public TArray<T, MEM_MOVE> {
760*c8dee2aaSAndroid Build Coastguard Worker     // We round up the requested array size to the next capacity multiple.
761*c8dee2aaSAndroid Build Coastguard Worker     // This space would likely otherwise go to waste.
762*c8dee2aaSAndroid Build Coastguard Worker     static constexpr int N = SkContainerAllocator::RoundUp<T>(Nreq);
763*c8dee2aaSAndroid Build Coastguard Worker     static_assert(Nreq > 0);
764*c8dee2aaSAndroid Build Coastguard Worker     static_assert(N >= Nreq);
765*c8dee2aaSAndroid Build Coastguard Worker 
766*c8dee2aaSAndroid Build Coastguard Worker     using Storage = SkAlignedSTStorage<N,T>;
767*c8dee2aaSAndroid Build Coastguard Worker 
768*c8dee2aaSAndroid Build Coastguard Worker public:
STArray()769*c8dee2aaSAndroid Build Coastguard Worker     STArray()
770*c8dee2aaSAndroid Build Coastguard Worker         : Storage{}
771*c8dee2aaSAndroid Build Coastguard Worker         , TArray<T, MEM_MOVE>(this) {}  // Must use () to avoid confusion with initializer_list
772*c8dee2aaSAndroid Build Coastguard Worker                                         // when T=bool because * are convertable to bool.
773*c8dee2aaSAndroid Build Coastguard Worker 
STArray(const T * array,int count)774*c8dee2aaSAndroid Build Coastguard Worker     STArray(const T* array, int count)
775*c8dee2aaSAndroid Build Coastguard Worker         : Storage{}
776*c8dee2aaSAndroid Build Coastguard Worker         , TArray<T, MEM_MOVE>{array, count, this} {}
777*c8dee2aaSAndroid Build Coastguard Worker 
STArray(SkSpan<const T> data)778*c8dee2aaSAndroid Build Coastguard Worker     STArray(SkSpan<const T> data)
779*c8dee2aaSAndroid Build Coastguard Worker         : Storage{}
780*c8dee2aaSAndroid Build Coastguard Worker         , TArray<T, MEM_MOVE>{data, this} {}
781*c8dee2aaSAndroid Build Coastguard Worker 
STArray(std::initializer_list<T> data)782*c8dee2aaSAndroid Build Coastguard Worker     STArray(std::initializer_list<T> data)
783*c8dee2aaSAndroid Build Coastguard Worker         : STArray{data.begin(), SkToInt(data.size())} {}
784*c8dee2aaSAndroid Build Coastguard Worker 
STArray(int reserveCount)785*c8dee2aaSAndroid Build Coastguard Worker     explicit STArray(int reserveCount)
786*c8dee2aaSAndroid Build Coastguard Worker         : STArray() { this->reserve_exact(reserveCount); }
787*c8dee2aaSAndroid Build Coastguard Worker 
STArray(const STArray & that)788*c8dee2aaSAndroid Build Coastguard Worker     STArray(const STArray& that)
789*c8dee2aaSAndroid Build Coastguard Worker         : STArray() { *this = that; }
790*c8dee2aaSAndroid Build Coastguard Worker 
STArray(const TArray<T,MEM_MOVE> & that)791*c8dee2aaSAndroid Build Coastguard Worker     explicit STArray(const TArray<T, MEM_MOVE>& that)
792*c8dee2aaSAndroid Build Coastguard Worker         : STArray() { *this = that; }
793*c8dee2aaSAndroid Build Coastguard Worker 
STArray(STArray && that)794*c8dee2aaSAndroid Build Coastguard Worker     STArray(STArray&& that)
795*c8dee2aaSAndroid Build Coastguard Worker         : STArray() { *this = std::move(that); }
796*c8dee2aaSAndroid Build Coastguard Worker 
STArray(TArray<T,MEM_MOVE> && that)797*c8dee2aaSAndroid Build Coastguard Worker     explicit STArray(TArray<T, MEM_MOVE>&& that)
798*c8dee2aaSAndroid Build Coastguard Worker         : STArray() { *this = std::move(that); }
799*c8dee2aaSAndroid Build Coastguard Worker 
800*c8dee2aaSAndroid Build Coastguard Worker     STArray& operator=(const STArray& that) {
801*c8dee2aaSAndroid Build Coastguard Worker         TArray<T, MEM_MOVE>::operator=(that);
802*c8dee2aaSAndroid Build Coastguard Worker         return *this;
803*c8dee2aaSAndroid Build Coastguard Worker     }
804*c8dee2aaSAndroid Build Coastguard Worker 
805*c8dee2aaSAndroid Build Coastguard Worker     STArray& operator=(const TArray<T, MEM_MOVE>& that) {
806*c8dee2aaSAndroid Build Coastguard Worker         TArray<T, MEM_MOVE>::operator=(that);
807*c8dee2aaSAndroid Build Coastguard Worker         return *this;
808*c8dee2aaSAndroid Build Coastguard Worker     }
809*c8dee2aaSAndroid Build Coastguard Worker 
810*c8dee2aaSAndroid Build Coastguard Worker     STArray& operator=(STArray&& that) {
811*c8dee2aaSAndroid Build Coastguard Worker         TArray<T, MEM_MOVE>::operator=(std::move(that));
812*c8dee2aaSAndroid Build Coastguard Worker         return *this;
813*c8dee2aaSAndroid Build Coastguard Worker     }
814*c8dee2aaSAndroid Build Coastguard Worker 
815*c8dee2aaSAndroid Build Coastguard Worker     STArray& operator=(TArray<T, MEM_MOVE>&& that) {
816*c8dee2aaSAndroid Build Coastguard Worker         TArray<T, MEM_MOVE>::operator=(std::move(that));
817*c8dee2aaSAndroid Build Coastguard Worker         return *this;
818*c8dee2aaSAndroid Build Coastguard Worker     }
819*c8dee2aaSAndroid Build Coastguard Worker 
820*c8dee2aaSAndroid Build Coastguard Worker     // Force the use of TArray for data() and size().
821*c8dee2aaSAndroid Build Coastguard Worker     using TArray<T, MEM_MOVE>::data;
822*c8dee2aaSAndroid Build Coastguard Worker     using TArray<T, MEM_MOVE>::size;
823*c8dee2aaSAndroid Build Coastguard Worker };
824*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skia_private
825*c8dee2aaSAndroid Build Coastguard Worker #endif  // SkTArray_DEFINED
826