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