xref: /aosp_15_r20/external/skia/tests/TArrayTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2014 Google Inc.
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 #include "include/private/base/SkASAN.h"  // IWYU pragma: keep
9 #include "include/private/base/SkTArray.h"
10 #include "src/base/SkFixedArray.h"
11 #include "src/base/SkRandom.h"
12 #include "tests/Test.h"
13 
14 #include <array>
15 #include <cstdint>
16 #include <initializer_list>
17 #include <utility>
18 
19 using namespace skia_private;
20 
21 // This class is used to test TArray's behavior with classes containing a vtable.
22 
23 namespace {
24 
25 class TestClass {
26 public:
27     TestClass() = default;
28     TestClass(const TestClass&) = default;
29     TestClass& operator=(const TestClass&) = default;
TestClass(int v)30     TestClass(int v) : value(v) {}
~TestClass()31     virtual ~TestClass() {}
32 
operator ==(const TestClass & c) const33     bool operator==(const TestClass& c) const { return value == c.value; }
operator !=(const TestClass & c) const34     bool operator!=(const TestClass& c) const { return value != c.value; }
35 
36     int value = 0;
37 };
38 
39 }  // namespace
40 
41 // Tests the TArray<T> class template.
42 
43 template <typename ArrayType>
TestTSet_basic(skiatest::Reporter * reporter)44 static void TestTSet_basic(skiatest::Reporter* reporter) {
45     using T = typename ArrayType::value_type;
46     ArrayType a;
47 
48     // Starts empty.
49     REPORTER_ASSERT(reporter, a.empty());
50     REPORTER_ASSERT(reporter, a.size() == 0);
51 
52     // { }, add a default constructed element
53     a.push_back() = T{0};
54     REPORTER_ASSERT(reporter, !a.empty());
55     REPORTER_ASSERT(reporter, a.size() == 1);
56 
57     // { 0 }, removeShuffle the only element.
58     a.removeShuffle(0);
59     REPORTER_ASSERT(reporter, a.empty());
60     REPORTER_ASSERT(reporter, a.size() == 0);
61 
62     // { }, add a default, add a 1, remove first
63     a.push_back() = T{0};
64     a.push_back() = T{1};
65     a.removeShuffle(0);
66     REPORTER_ASSERT(reporter, !a.empty());
67     REPORTER_ASSERT(reporter, a.size() == 1);
68     REPORTER_ASSERT(reporter, a[0] == T{1});
69 
70     // { 1 }, replace with new array
71     T b[5] = {T{0}, T{1}, T{2}, T{3}, T{4}};
72     a.reset(b, std::size(b));
73     REPORTER_ASSERT(reporter, a.size() == std::size(b));
74     REPORTER_ASSERT(reporter, a[2] == T{2});
75     REPORTER_ASSERT(reporter, a[4] == T{4});
76 
77     // { 0, 1, 2, 3, 4 }, removeShuffle the last
78     a.removeShuffle(4);
79     REPORTER_ASSERT(reporter, a.size() == std::size(b) - 1);
80     REPORTER_ASSERT(reporter, a[3] == T{3});
81 
82     // { 0, 1, 2, 3 }, remove a middle, note shuffle
83     a.removeShuffle(1);
84     REPORTER_ASSERT(reporter, a.size() == std::size(b) - 2);
85     REPORTER_ASSERT(reporter, a[0] == T{0});
86     REPORTER_ASSERT(reporter, a[1] == T{3});
87     REPORTER_ASSERT(reporter, a[2] == T{2});
88 
89     // { 0, 3, 2 }... remove the last element.
90     a.pop_back();
91     REPORTER_ASSERT(reporter, a.size() == std::size(b) - 3);
92 
93     // { 0, 3, 5, 5, 5 }... add three elements.
94     a.push_back_n(3, 5);
95     REPORTER_ASSERT(reporter, a.size() == std::size(b));
96     REPORTER_ASSERT(reporter, a[2] == T{5});
97     REPORTER_ASSERT(reporter, a[3] == T{5});
98     REPORTER_ASSERT(reporter, a[4] == T{5});
99 
100     // { 0 }... pop four elements.
101     a.pop_back_n(4);
102     REPORTER_ASSERT(reporter, a.size() == std::size(b) - 4);
103     REPORTER_ASSERT(reporter, a[0] == 0);
104 }
105 
106 template <typename T>
test_construction(skiatest::Reporter * reporter,bool hasMoveSemantics=true)107 static void test_construction(skiatest::Reporter* reporter, bool hasMoveSemantics = true) {
108     using ValueType = typename T::value_type;
109 
110     // No arguments: Creates an empty array with no initial storage.
111     T arrayNoArgs;
112     REPORTER_ASSERT(reporter, arrayNoArgs.empty());
113 
114     // Single integer: Creates an empty array that will preallocate space for reserveCount elements.
115     T arrayReserve(15);
116     REPORTER_ASSERT(reporter, arrayReserve.empty());
117     // May get some extra elements for free because sk_allocate_* can round up.
118     REPORTER_ASSERT(reporter, arrayReserve.capacity() >= 15 && arrayReserve.capacity() < 50);
119 
120     // Another array, const&: Copies one array to another.
121     T arrayInitial;
122     arrayInitial.push_back(ValueType{1});
123     arrayInitial.push_back(ValueType{2});
124     arrayInitial.push_back(ValueType{3});
125 
126     T arrayCopy(arrayInitial);
127     REPORTER_ASSERT(reporter, arrayInitial.size() == 3);
128     REPORTER_ASSERT(reporter, arrayInitial[0] == ValueType{1});
129     REPORTER_ASSERT(reporter, arrayInitial[1] == ValueType{2});
130     REPORTER_ASSERT(reporter, arrayInitial[2] == ValueType{3});
131     REPORTER_ASSERT(reporter, arrayCopy.size() == 3);
132     REPORTER_ASSERT(reporter, arrayCopy[0] == ValueType{1});
133     REPORTER_ASSERT(reporter, arrayCopy[1] == ValueType{2});
134     REPORTER_ASSERT(reporter, arrayCopy[2] == ValueType{3});
135 
136     // Another array, &&: Moves one array to another.
137     T arrayMove(std::move(arrayInitial));
138     if (hasMoveSemantics) {
139         REPORTER_ASSERT(reporter, arrayInitial.empty()); // NOLINT(bugprone-use-after-move)
140     }
141     REPORTER_ASSERT(reporter, arrayMove.size() == 3);
142     REPORTER_ASSERT(reporter, arrayMove[0] == ValueType{1});
143     REPORTER_ASSERT(reporter, arrayMove[1] == ValueType{2});
144     REPORTER_ASSERT(reporter, arrayMove[2] == ValueType{3});
145 
146     // Pointer and count: Copies contents of a standard C array.
147     typename T::value_type data[3] = { 7, 8, 9 };
148     T arrayPtrCount(data, 3);
149     REPORTER_ASSERT(reporter, arrayPtrCount.size() == 3);
150     REPORTER_ASSERT(reporter, arrayPtrCount[0] == ValueType{7});
151     REPORTER_ASSERT(reporter, arrayPtrCount[1] == ValueType{8});
152     REPORTER_ASSERT(reporter, arrayPtrCount[2] == ValueType{9});
153 
154     // Initializer list.
155     T arrayInitializer{8, 6, 7, 5, 3, 0, 9};
156     REPORTER_ASSERT(reporter, arrayInitializer.size() == 7);
157     REPORTER_ASSERT(reporter, arrayInitializer[0] == ValueType{8});
158     REPORTER_ASSERT(reporter, arrayInitializer[1] == ValueType{6});
159     REPORTER_ASSERT(reporter, arrayInitializer[2] == ValueType{7});
160     REPORTER_ASSERT(reporter, arrayInitializer[3] == ValueType{5});
161     REPORTER_ASSERT(reporter, arrayInitializer[4] == ValueType{3});
162     REPORTER_ASSERT(reporter, arrayInitializer[5] == ValueType{0});
163     REPORTER_ASSERT(reporter, arrayInitializer[6] == ValueType{9});
164 }
165 
166 template <typename T, typename U>
test_starray_compatibility(skiatest::Reporter * reporter)167 static void test_starray_compatibility(skiatest::Reporter* reporter) {
168     // We expect TArrays of the same type to be copyable and movable, even when:
169     // - one side is an TArray, and the other side is an STArray
170     // - both sides are STArray, but each side has a different internal capacity
171     T tArray;
172     tArray.push_back(1);
173     tArray.push_back(2);
174     tArray.push_back(3);
175     T tArray2 = tArray;
176 
177     // Copy construction from other-type array.
178     U arrayCopy(tArray);
179     REPORTER_ASSERT(reporter, tArray.size() == 3);
180     REPORTER_ASSERT(reporter, tArray[0] == 1);
181     REPORTER_ASSERT(reporter, tArray[1] == 2);
182     REPORTER_ASSERT(reporter, tArray[2] == 3);
183     REPORTER_ASSERT(reporter, arrayCopy.size() == 3);
184     REPORTER_ASSERT(reporter, arrayCopy[0] == 1);
185     REPORTER_ASSERT(reporter, arrayCopy[1] == 2);
186     REPORTER_ASSERT(reporter, arrayCopy[2] == 3);
187 
188     // Assignment from other-type array.
189     U arrayAssignment;
190     arrayAssignment = tArray;
191     REPORTER_ASSERT(reporter, tArray.size() == 3);
192     REPORTER_ASSERT(reporter, tArray[0] == 1);
193     REPORTER_ASSERT(reporter, tArray[1] == 2);
194     REPORTER_ASSERT(reporter, tArray[2] == 3);
195     REPORTER_ASSERT(reporter, arrayAssignment.size() == 3);
196     REPORTER_ASSERT(reporter, arrayAssignment[0] == 1);
197     REPORTER_ASSERT(reporter, arrayAssignment[1] == 2);
198     REPORTER_ASSERT(reporter, arrayAssignment[2] == 3);
199 
200     // Move construction from other-type array.
201     U arrayMove(std::move(tArray));
202     REPORTER_ASSERT(reporter, tArray.empty()); // NOLINT(bugprone-use-after-move)
203     REPORTER_ASSERT(reporter, arrayMove.size() == 3);
204     REPORTER_ASSERT(reporter, arrayMove[0] == 1);
205     REPORTER_ASSERT(reporter, arrayMove[1] == 2);
206     REPORTER_ASSERT(reporter, arrayMove[2] == 3);
207 
208     // Move assignment from other-type array.
209     U arrayMoveAssign;
210     arrayMoveAssign = std::move(tArray2);
211     REPORTER_ASSERT(reporter, tArray2.empty()); // NOLINT(bugprone-use-after-move)
212     REPORTER_ASSERT(reporter, arrayMoveAssign.size() == 3);
213     REPORTER_ASSERT(reporter, arrayMoveAssign[0] == 1);
214     REPORTER_ASSERT(reporter, arrayMoveAssign[1] == 2);
215     REPORTER_ASSERT(reporter, arrayMoveAssign[2] == 3);
216 }
217 
218 // Move-only type used for testing swap and move_back() of TArray&&'s.
219 namespace {
220 struct MoveOnlyInt {
MoveOnlyInt__anon21639d440211::MoveOnlyInt221     MoveOnlyInt(int i) : fInt(i) {}
MoveOnlyInt__anon21639d440211::MoveOnlyInt222     MoveOnlyInt(MoveOnlyInt&& that) : fInt(that.fInt) {}
operator ==__anon21639d440211::MoveOnlyInt223     bool operator==(int i) const { return fInt == i; }
224     int fInt;
225 };
226 } // anonymous
227 
test_swap(skiatest::Reporter * reporter,SkSpan<TArray<T> * > arrays,SkSpan<const int> sizes)228 template <typename T> static void test_swap(skiatest::Reporter* reporter,
229                                             SkSpan<TArray<T>*> arrays,
230                                             SkSpan<const int> sizes) {
231     for (auto a : arrays) {
232     for (auto b : arrays) {
233         if (a == b) {
234             continue;
235         }
236 
237         for (auto sizeA : sizes) {
238         for (auto sizeB : sizes) {
239             a->clear();
240             b->clear();
241 
242             int curr = 0;
243             for (int i = 0; i < sizeA; i++) { a->push_back(curr++); }
244             for (int i = 0; i < sizeB; i++) { b->push_back(curr++); }
245 
246             a->swap(*b);
247             REPORTER_ASSERT(reporter, b->size() == sizeA);
248             REPORTER_ASSERT(reporter, a->size() == sizeB);
249 
250             curr = 0;
251             for (auto&& x : *b) { REPORTER_ASSERT(reporter, x == curr++); }
252             for (auto&& x : *a) { REPORTER_ASSERT(reporter, x == curr++); }
253 
254             a->swap(*a);
255             curr = sizeA;
256             for (auto&& x : *a) { REPORTER_ASSERT(reporter, x == curr++); }
257         }}
258     }}
259 }
260 
DEF_TEST(TArray_Swap,reporter)261 DEF_TEST(TArray_Swap, reporter) {
262     static constexpr int kSizes[] = {0, 1, 5, 10, 15, 20, 25};
263 
264     TArray<int> arr;
265     STArray< 5, int> arr5;
266     STArray<10, int> arr10;
267     STArray<20, int> arr20;
268     TArray<int>* arrays[] = { &arr, &arr5, &arr10, &arr20 };
269     test_swap<int>(reporter, arrays, kSizes);
270 
271     TArray<MoveOnlyInt> moi;
272     STArray< 5, MoveOnlyInt> moi5;
273     STArray<10, MoveOnlyInt> moi10;
274     STArray<20, MoveOnlyInt> moi20;
275     TArray<MoveOnlyInt>* arraysMoi[] = { &moi, &moi5, &moi10, &moi20 };
276     test_swap<MoveOnlyInt>(reporter, arraysMoi, kSizes);
277 }
278 
test_array_move(skiatest::Reporter * reporter,SkSpan<TArray<T> * > arrays,SkSpan<const int> sizes)279 template <typename T> static void test_array_move(skiatest::Reporter* reporter,
280                                                   SkSpan<TArray<T>*> arrays,
281                                                   SkSpan<const int> sizes) {
282     // self test is a no-op
283     for (auto a : arrays) {
284         for (auto sizeA : sizes) {
285             a->clear();
286             for (int i = 0; i < sizeA; i++) { a->push_back(i); }
287             a->move_back(*a);
288             REPORTER_ASSERT(reporter, a->size() == sizeA);
289             for (int i = 0; i < sizeA; i++) {
290                 REPORTER_ASSERT(reporter, (*a)[i] == i);
291             }
292         }
293     }
294 
295     for (auto a : arrays) {
296     for (auto b : arrays) {
297         if (a == b) {
298             continue;
299         }
300 
301         for (auto sizeA : sizes) {
302         for (auto sizeB : sizes) {
303             a->clear();
304             b->clear();
305 
306             int curr = 0;
307             for (int i = 0; i < sizeA; i++) { a->push_back(curr++); }
308             for (int i = 0; i < sizeB; i++) { b->push_back(curr++); }
309 
310             a->move_back(*b);
311             REPORTER_ASSERT(reporter, b->size() == 0);
312             REPORTER_ASSERT(reporter, a->size() == sizeA + sizeB);
313 
314             curr = 0;
315             for (auto&& x : *a) { REPORTER_ASSERT(reporter, x == curr++); }
316         }}
317     }}
318 }
319 
DEF_TEST(TArray_Move,reporter)320 DEF_TEST(TArray_Move, reporter) {
321     static constexpr int kSizes[] = {0, 1, 5, 10, 15, 20, 25};
322 
323     TArray<int> arr;
324     STArray< 5, int> arr5;
325     STArray<10, int> arr10;
326     STArray<20, int> arr20;
327     TArray<int>* arrays[] = { &arr, &arr5, &arr10, &arr20 };
328     test_array_move<int>(reporter, arrays, kSizes);
329 
330     TArray<MoveOnlyInt> moi;
331     STArray< 5, MoveOnlyInt> moi5;
332     STArray<10, MoveOnlyInt> moi10;
333     STArray<20, MoveOnlyInt> moi20;
334     TArray<MoveOnlyInt>* arraysMoi[] = { &moi, &moi5, &moi10, &moi20 };
335     test_array_move<MoveOnlyInt>(reporter, arraysMoi, kSizes);
336 }
337 
DEF_TEST(TArray_NoUnnecessaryAllocs,reporter)338 DEF_TEST(TArray_NoUnnecessaryAllocs, reporter) {
339     {
340         TArray<int> a;
341         REPORTER_ASSERT(reporter, a.capacity() == 0);
342     }
343     {
344         STArray<10, int> a;
345         REPORTER_ASSERT(reporter, a.capacity() == 10);
346     }
347     {
348         TArray<int> a(1);
349         REPORTER_ASSERT(reporter, a.capacity() >= 1);
350     }
351     {
352         TArray<int> a, b;
353         b = a;
354         REPORTER_ASSERT(reporter, b.capacity() == 0);
355     }
356     {
357         STArray<10, int> a;
358         TArray<int> b;
359         b = a;
360         REPORTER_ASSERT(reporter, b.capacity() == 0);
361     }
362     {
363         TArray<int> a;
364         TArray<int> b(a);  // NOLINT(performance-unnecessary-copy-initialization)
365         REPORTER_ASSERT(reporter, b.capacity() == 0);
366     }
367     {
368         STArray<10, int> a;
369         TArray<int> b(a);  // NOLINT(performance-unnecessary-copy-initialization)
370         REPORTER_ASSERT(reporter, b.capacity() == 0);
371     }
372     {
373         TArray<int> a;
374         TArray<int> b(std::move(a));
375         REPORTER_ASSERT(reporter, b.capacity() == 0);
376     }
377     {
378         STArray<10, int> a;
379         TArray<int> b(std::move(a));
380         REPORTER_ASSERT(reporter, b.capacity() == 0);
381     }
382     {
383         TArray<int> a;
384         TArray<int> b;
385         b = std::move(a);
386         REPORTER_ASSERT(reporter, b.capacity() == 0);
387     }
388     {
389         STArray<10, int> a;
390         TArray<int> b;
391         b = std::move(a);
392         REPORTER_ASSERT(reporter, b.capacity() == 0);
393     }
394 }
395 
396 template <typename ArrayType>
test_self_assignment(skiatest::Reporter * reporter)397 static void test_self_assignment(skiatest::Reporter* reporter) {
398     ArrayType a;
399     a.push_back(1);
400     REPORTER_ASSERT(reporter, !a.empty());
401     REPORTER_ASSERT(reporter, a.size() == 1);
402     REPORTER_ASSERT(reporter, a[0] == 1);
403 
404     a = static_cast<ArrayType&>(a);
405     REPORTER_ASSERT(reporter, !a.empty());
406     REPORTER_ASSERT(reporter, a.size() == 1);
407     REPORTER_ASSERT(reporter, a[0] == 1);
408 }
409 
DEF_TEST(TArray_SelfAssignment,reporter)410 DEF_TEST(TArray_SelfAssignment, reporter) {
411     test_self_assignment<TArray<int>>(reporter);
412     test_self_assignment<STArray<3, unsigned short>>(reporter);
413 }
414 
DEF_TEST(FixedArray_SelfAssignment,reporter)415 DEF_TEST(FixedArray_SelfAssignment, reporter) {
416     test_self_assignment<FixedArray<1, int>>(reporter);
417     test_self_assignment<FixedArray<4, unsigned short>>(reporter);
418 }
419 
420 template <typename ArrayType>
test_comparison(skiatest::Reporter * reporter)421 static void test_comparison(skiatest::Reporter* reporter) {
422     using T = typename ArrayType::value_type;
423     ArrayType a, b;
424 
425     // Empty arrays.
426     REPORTER_ASSERT(reporter, a == b);
427     REPORTER_ASSERT(reporter, !(a != b));
428 
429     // Arrays with identical contents.
430     for (int x = 0; x < 10; ++x) {
431         a.push_back(T(x));
432         b.push_back(T(x));
433         REPORTER_ASSERT(reporter, a == b);
434         REPORTER_ASSERT(reporter, !(a != b));
435     }
436 
437     // Arrays with differing sizes.
438     for (int x = 0; x < 10; ++x) {
439         a.pop_back();
440         REPORTER_ASSERT(reporter, a != b);
441         REPORTER_ASSERT(reporter, b != a);
442         REPORTER_ASSERT(reporter, !(a == b));
443         REPORTER_ASSERT(reporter, !(b == a));
444     }
445 
446     // Arrays with differing contents.
447     a = b;
448     for (int x = 0; x < 10; ++x) {
449         a[x] = T(x + 100);
450         REPORTER_ASSERT(reporter, a != b);
451         REPORTER_ASSERT(reporter, b != a);
452         REPORTER_ASSERT(reporter, !(a == b));
453         REPORTER_ASSERT(reporter, !(b == a));
454         a[x] = T(x);
455     }
456 }
457 
DEF_TEST(TArray_Comparison,reporter)458 DEF_TEST(TArray_Comparison, reporter) {
459     test_comparison<TArray<int>>(reporter);
460     test_comparison<TArray<double>>(reporter);
461     test_comparison<TArray<TestClass>>(reporter);
462     test_comparison<STArray<1, int>>(reporter);
463     test_comparison<STArray<5, char>>(reporter);
464     test_comparison<STArray<7, TestClass>>(reporter);
465     test_comparison<STArray<10, float>>(reporter);
466 }
467 
DEF_TEST(FixedArray_Comparison,reporter)468 DEF_TEST(FixedArray_Comparison, reporter) {
469     test_comparison<FixedArray<15, int>>(reporter);
470     test_comparison<FixedArray<20, char>>(reporter);
471     test_comparison<FixedArray<25, float>>(reporter);
472 }
473 
test_array_reserve(skiatest::Reporter * reporter,Array * array,int reserveCount)474 template <typename Array> static void test_array_reserve(skiatest::Reporter* reporter,
475                                                          Array* array, int reserveCount) {
476     SkRandom random;
477     REPORTER_ASSERT(reporter, array->capacity() >= reserveCount);
478     array->push_back();
479     REPORTER_ASSERT(reporter, array->capacity() >= reserveCount);
480     array->pop_back();
481     REPORTER_ASSERT(reporter, array->capacity() >= reserveCount);
482     while (array->size() < reserveCount) {
483         // Two steps forward, one step back
484         if (random.nextULessThan(3) < 2) {
485             array->push_back();
486         } else if (array->size() > 0) {
487             array->pop_back();
488         }
489         REPORTER_ASSERT(reporter, array->capacity() >= reserveCount);
490     }
491 }
492 
test_reserve(skiatest::Reporter * reporter)493 template<typename Array> static void test_reserve(skiatest::Reporter* reporter) {
494     // Test that our allocated space stays >= to the reserve count until the array is filled to
495     // the reserve count
496     for (int reserveCount : {1, 2, 10, 100}) {
497         // Test setting reserve in constructor.
498         Array array1(reserveCount);
499         test_array_reserve(reporter, &array1, reserveCount);
500 
501         // Test setting reserve after constructor.
502         Array array2;
503         array2.reserve(reserveCount);
504         test_array_reserve(reporter, &array2, reserveCount);
505 
506         // Test increasing reserve after constructor.
507         Array array3(reserveCount/2);
508         array3.reserve(reserveCount);
509         test_array_reserve(reporter, &array3, reserveCount);
510 
511         // Test setting reserve on non-empty array.
512         Array array4;
513         array4.push_back_n(reserveCount);
514         array4.reserve(2 * reserveCount);
515         array4.pop_back_n(reserveCount);
516         test_array_reserve(reporter, &array4, 2 * reserveCount);
517     }
518 }
519 
520 template <typename T>
test_inner_push(skiatest::Reporter * reporter)521 static void test_inner_push(skiatest::Reporter* reporter) {
522     T a;
523     a.push_back(12345);
524     for (int x=0; x<50; ++x) {
525         a.push_back(a.front());
526     }
527     for (int x=0; x<50; ++x) {
528         a.push_back(a.back());
529     }
530 
531     REPORTER_ASSERT(reporter, a.size() == 101);
532     REPORTER_ASSERT(reporter, std::count(a.begin(), a.end(), 12345) == a.size());
533 }
534 
535 struct EmplaceStruct {
EmplaceStructEmplaceStruct536     EmplaceStruct(int v) : fValue(v) {}
537     int fValue;
538 };
539 
540 template <typename T>
test_inner_emplace(skiatest::Reporter * reporter)541 static void test_inner_emplace(skiatest::Reporter* reporter) {
542     T a;
543     a.emplace_back(12345);
544     for (int x=0; x<50; ++x) {
545         a.emplace_back(a.front().fValue);
546     }
547     for (int x=0; x<50; ++x) {
548         a.emplace_back(a.back().fValue);
549     }
550 
551     REPORTER_ASSERT(reporter, a.size() == 101);
552     REPORTER_ASSERT(reporter, std::all_of(a.begin(), a.end(), [](const EmplaceStruct& s) {
553                         return s.fValue == 12345;
554                     }));
555 }
556 
DEF_TEST(TArray_Basic,reporter)557 DEF_TEST(TArray_Basic, reporter) {
558     // ints are POD types and can work with either MEM_MOVE=true or false.
559     TestTSet_basic<TArray<int, true>>(reporter);
560     TestTSet_basic<TArray<int, false>>(reporter);
561 
562     // TestClass has a vtable and can only work with MEM_MOVE=false.
563     TestTSet_basic<TArray<TestClass, false>>(reporter);
564 }
565 
DEF_TEST(FixedArray_Basic,reporter)566 DEF_TEST(FixedArray_Basic, reporter) {
567     TestTSet_basic<FixedArray<5, char>>(reporter);
568     TestTSet_basic<FixedArray<7, int>>(reporter);
569     TestTSet_basic<FixedArray<100, double>>(reporter);
570 }
571 
DEF_TEST(TArray_Reserve,reporter)572 DEF_TEST(TArray_Reserve, reporter) {
573     test_reserve<TArray<int>>(reporter);
574     test_reserve<STArray<1, int>>(reporter);
575     test_reserve<STArray<2, int>>(reporter);
576     test_reserve<STArray<16, int>>(reporter);
577 
578     test_reserve<TArray<TestClass>>(reporter);
579     test_reserve<STArray<1, TestClass>>(reporter);
580     test_reserve<STArray<2, TestClass>>(reporter);
581     test_reserve<STArray<16, TestClass>>(reporter);
582 }
583 
DEF_TEST(TArray_Construction,reporter)584 DEF_TEST(TArray_Construction, reporter) {
585     test_construction<TArray<int>>(reporter);
586     test_construction<TArray<double>>(reporter);
587     test_construction<TArray<TestClass>>(reporter);
588     test_construction<STArray<1, int>>(reporter);
589     test_construction<STArray<5, char>>(reporter);
590     test_construction<STArray<7, TestClass>>(reporter);
591     test_construction<STArray<10, float>>(reporter);
592 }
593 
DEF_TEST(FixedArray_Construction,reporter)594 DEF_TEST(FixedArray_Construction, reporter) {
595     test_construction<FixedArray<15, int>>(reporter, /*hasMoveSemantics=*/false);
596     test_construction<FixedArray<20, char>>(reporter, /*hasMoveSemantics=*/false);
597     test_construction<FixedArray<25, float>>(reporter, /*hasMoveSemantics=*/false);
598 }
599 
DEF_TEST(TArray_InnerPush,reporter)600 DEF_TEST(TArray_InnerPush, reporter) {
601     test_inner_push<TArray<int>>(reporter);
602     test_inner_push<STArray<1, int>>(reporter);
603     test_inner_push<STArray<99, int>>(reporter);
604     test_inner_push<STArray<200, int>>(reporter);
605 }
606 
DEF_TEST(FixedArray_InnerPush,reporter)607 DEF_TEST(FixedArray_InnerPush, reporter) {
608     test_inner_push<FixedArray<101, int>>(reporter);
609     test_inner_push<FixedArray<150, short>>(reporter);
610     test_inner_push<FixedArray<250, double>>(reporter);
611 }
612 
DEF_TEST(TArray_InnerEmplace,reporter)613 DEF_TEST(TArray_InnerEmplace, reporter) {
614     test_inner_emplace<TArray<EmplaceStruct>>(reporter);
615     test_inner_emplace<STArray<1, EmplaceStruct>>(reporter);
616     test_inner_emplace<STArray<99, EmplaceStruct>>(reporter);
617     test_inner_emplace<STArray<200, EmplaceStruct>>(reporter);
618 }
619 
DEF_TEST(TArray_STArrayCompatibility,reporter)620 DEF_TEST(TArray_STArrayCompatibility, reporter) {
621     test_starray_compatibility<STArray<1, int>, TArray<int>>(reporter);
622     test_starray_compatibility<STArray<5, char>, TArray<char>>(reporter);
623     test_starray_compatibility<STArray<10, float>, TArray<float>>(reporter);
624     test_starray_compatibility<TArray<int>, STArray<1, int>>(reporter);
625     test_starray_compatibility<TArray<char>, STArray<5, char>>(reporter);
626     test_starray_compatibility<TArray<float>, STArray<10, float>>(reporter);
627     test_starray_compatibility<STArray<10, uint8_t>, STArray<1, uint8_t>>(reporter);
628     test_starray_compatibility<STArray<1, long>, STArray<10, long>>(reporter);
629     test_starray_compatibility<STArray<3, double>, STArray<4, double>>(reporter);
630     test_starray_compatibility<STArray<2, short>, STArray<1, short>>(reporter);
631 }
632 
DEF_TEST(TArray_BoundsCheck,reporter)633 DEF_TEST(TArray_BoundsCheck, reporter) {
634 #if 0  // The v[0] fails
635     TArray<int> v;
636     v[0];
637 #endif
638 }
639 
640 #if defined(SK_SANITIZE_ADDRESS)
641 
642 template <typename Array>
verify_poison(skiatest::Reporter * r,const Array & array)643 static void verify_poison(skiatest::Reporter* r, const Array& array) {
644     int allocated = array.size() * sizeof(typename Array::value_type);
645     int capacity = array.capacity() * sizeof(typename Array::value_type);
646     const std::byte* data = reinterpret_cast<const std::byte*>(array.data());
647 
648     for (int index = 0; index < allocated; ++index) {
649         REPORTER_ASSERT(r, !sk_asan_address_is_poisoned(data + index));
650     }
651 
652     // ASAN user poisoning is conservative for ranges that are smaller than eight bytes long.
653     // We guarantee this alignment via SkContainerAllocator (because kCapacityMultiple == 8).
654     // https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm#mapping
655     REPORTER_ASSERT(r, capacity >= 8);
656     for (int index = allocated; index < capacity; ++index) {
657         REPORTER_ASSERT(r, sk_asan_address_is_poisoned(data + index));
658     }
659 }
660 
661 template <typename Array>
test_poison(skiatest::Reporter * reporter)662 static void test_poison(skiatest::Reporter* reporter) {
663     Array array;
664 
665     for (int index = 0; index < 20; ++index) {
666         array.emplace_back();
667         verify_poison(reporter, array);
668     }
669 
670     for (int index = 0; index < 20; ++index) {
671         array.pop_back();
672         verify_poison(reporter, array);
673     }
674 
675     for (int index = 0; index < 20; ++index) {
676         array.reserve(array.capacity() + 3);
677         verify_poison(reporter, array);
678     }
679 
680     array.clear();
681     verify_poison(reporter, array);
682 }
683 
DEF_TEST(TArray_ASANPoisoning,reporter)684 DEF_TEST(TArray_ASANPoisoning, reporter) {
685     test_poison<TArray<int>>(reporter);
686     test_poison<STArray<1, double>>(reporter);
687     test_poison<STArray<2, char>>(reporter);
688     test_poison<STArray<16, TestClass>>(reporter);
689 }
690 
691 #endif
692