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