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