1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/core/SkTBlockList.h" 9cb93a386Sopenharmony_ci#include "tests/Test.h" 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_cinamespace { 12cb93a386Sopenharmony_cistruct C { 13cb93a386Sopenharmony_ci C() : fID(-1) { ++gInstCnt; } 14cb93a386Sopenharmony_ci C(int id) : fID(id) { ++gInstCnt; } 15cb93a386Sopenharmony_ci C(C&& c) : C(c.fID) {} 16cb93a386Sopenharmony_ci C(const C& c) : C(c.fID) {} 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ci C& operator=(C&&) = default; 19cb93a386Sopenharmony_ci C& operator=(const C&) = default; 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci ~C() { --gInstCnt; } 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci int fID; 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ci // Under the hood, SkTBlockList and SkBlockAllocator round up to max_align_t. If 'C' was 26cb93a386Sopenharmony_ci // just 4 bytes, that often means the internal blocks can squeeze a few extra instances in. This 27cb93a386Sopenharmony_ci // is fine, but makes predicting a little trickier, so make sure C is a bit bigger. 28cb93a386Sopenharmony_ci int fPadding[4]; 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci static int gInstCnt; 31cb93a386Sopenharmony_ci}; 32cb93a386Sopenharmony_ciint C::gInstCnt = 0; 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_cistruct D { 35cb93a386Sopenharmony_ci int fID; 36cb93a386Sopenharmony_ci}; 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci} // namespace 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_ciclass TBlockListTestAccess { 41cb93a386Sopenharmony_cipublic: 42cb93a386Sopenharmony_ci template<int N> 43cb93a386Sopenharmony_ci static size_t ScratchBlockSize(SkTBlockList<C, N>& list) { 44cb93a386Sopenharmony_ci return (size_t) list.fAllocator->scratchBlockSize(); 45cb93a386Sopenharmony_ci } 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci template<int N> 48cb93a386Sopenharmony_ci static size_t TotalSize(SkTBlockList<C, N>& list) { 49cb93a386Sopenharmony_ci return list.fAllocator->totalSize(); 50cb93a386Sopenharmony_ci } 51cb93a386Sopenharmony_ci}; 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci// Checks that the allocator has the correct count, etc and that the element IDs are correct. 54cb93a386Sopenharmony_ci// Then pops popCnt items and checks again. 55cb93a386Sopenharmony_citemplate<int N> 56cb93a386Sopenharmony_cistatic void check_allocator_helper(SkTBlockList<C, N>* allocator, int cnt, int popCnt, 57cb93a386Sopenharmony_ci skiatest::Reporter* reporter) { 58cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (0 == cnt) == allocator->empty()); 59cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cnt == allocator->count()); 60cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cnt == C::gInstCnt); 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ci int i = 0; 63cb93a386Sopenharmony_ci for (const C& c : allocator->items()) { 64cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, i == c.fID); 65cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, allocator->item(i).fID == i); 66cb93a386Sopenharmony_ci ++i; 67cb93a386Sopenharmony_ci } 68cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, i == cnt); 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci if (cnt > 0) { 71cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cnt-1 == allocator->back().fID); 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ci if (popCnt > 0) { 75cb93a386Sopenharmony_ci for (i = 0; i < popCnt; ++i) { 76cb93a386Sopenharmony_ci allocator->pop_back(); 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci check_allocator_helper(allocator, cnt - popCnt, 0, reporter); 79cb93a386Sopenharmony_ci } 80cb93a386Sopenharmony_ci} 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_citemplate<int N> 83cb93a386Sopenharmony_cistatic void check_iterator_helper(SkTBlockList<C, N>* allocator, 84cb93a386Sopenharmony_ci const std::vector<C*>& expected, 85cb93a386Sopenharmony_ci skiatest::Reporter* reporter) { 86cb93a386Sopenharmony_ci const SkTBlockList<C, N>* cAlloc = allocator; 87cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (size_t) allocator->count() == expected.size()); 88cb93a386Sopenharmony_ci // Forward+const 89cb93a386Sopenharmony_ci int i = 0; 90cb93a386Sopenharmony_ci for (const C& c : cAlloc->items()) { 91cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (uintptr_t) &c == (uintptr_t) expected[i]); 92cb93a386Sopenharmony_ci ++i; 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (size_t) i == expected.size()); 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci // Forward+non-const 97cb93a386Sopenharmony_ci i = 0; 98cb93a386Sopenharmony_ci for (C& c : allocator->items()) { 99cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (uintptr_t) &c == (uintptr_t) expected[i]); 100cb93a386Sopenharmony_ci ++i; 101cb93a386Sopenharmony_ci } 102cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (size_t) i == expected.size()); 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci // Reverse+const 105cb93a386Sopenharmony_ci i = (int) expected.size() - 1; 106cb93a386Sopenharmony_ci for (const C& c : cAlloc->ritems()) { 107cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (uintptr_t) &c == (uintptr_t) expected[i]); 108cb93a386Sopenharmony_ci --i; 109cb93a386Sopenharmony_ci } 110cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, i == -1); 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci // Reverse+non-const 113cb93a386Sopenharmony_ci i = (int) expected.size() - 1; 114cb93a386Sopenharmony_ci for (C& c : allocator->ritems()) { 115cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (uintptr_t) &c == (uintptr_t) expected[i]); 116cb93a386Sopenharmony_ci --i; 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, i == -1); 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ci // Also test random access 121cb93a386Sopenharmony_ci for (i = 0; i < allocator->count(); ++i) { 122cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (uintptr_t) &allocator->item(i) == (uintptr_t) expected[i]); 123cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (uintptr_t) &cAlloc->item(i) == (uintptr_t) expected[i]); 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci} 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_ci// Adds cnt items to the allocator, tests the cnts and iterators, pops popCnt items and checks 128cb93a386Sopenharmony_ci// again. Finally it resets the allocator and checks again. 129cb93a386Sopenharmony_citemplate<int N> 130cb93a386Sopenharmony_cistatic void check_allocator(SkTBlockList<C, N>* allocator, int cnt, int popCnt, 131cb93a386Sopenharmony_ci skiatest::Reporter* reporter) { 132cb93a386Sopenharmony_ci enum ItemInitializer : int { 133cb93a386Sopenharmony_ci kCopyCtor, 134cb93a386Sopenharmony_ci kMoveCtor, 135cb93a386Sopenharmony_ci kCopyAssign, 136cb93a386Sopenharmony_ci kMoveAssign, 137cb93a386Sopenharmony_ci kEmplace, 138cb93a386Sopenharmony_ci }; 139cb93a386Sopenharmony_ci static constexpr int kInitCount = (int) kEmplace + 1; 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci SkASSERT(allocator); 142cb93a386Sopenharmony_ci SkASSERT(allocator->empty()); 143cb93a386Sopenharmony_ci std::vector<C*> items; 144cb93a386Sopenharmony_ci for (int i = 0; i < cnt; ++i) { 145cb93a386Sopenharmony_ci switch((ItemInitializer) (i % kInitCount)) { 146cb93a386Sopenharmony_ci case kCopyCtor: 147cb93a386Sopenharmony_ci allocator->push_back(C(i)); 148cb93a386Sopenharmony_ci break; 149cb93a386Sopenharmony_ci case kMoveCtor: 150cb93a386Sopenharmony_ci allocator->push_back(std::move(C(i))); 151cb93a386Sopenharmony_ci break; 152cb93a386Sopenharmony_ci case kCopyAssign: 153cb93a386Sopenharmony_ci allocator->push_back() = C(i); 154cb93a386Sopenharmony_ci break; 155cb93a386Sopenharmony_ci case kMoveAssign: 156cb93a386Sopenharmony_ci allocator->push_back() = std::move(C(i)); 157cb93a386Sopenharmony_ci break; 158cb93a386Sopenharmony_ci case kEmplace: 159cb93a386Sopenharmony_ci allocator->emplace_back(i); 160cb93a386Sopenharmony_ci break; 161cb93a386Sopenharmony_ci } 162cb93a386Sopenharmony_ci items.push_back(&allocator->back()); 163cb93a386Sopenharmony_ci } 164cb93a386Sopenharmony_ci check_iterator_helper(allocator, items, reporter); 165cb93a386Sopenharmony_ci check_allocator_helper(allocator, cnt, popCnt, reporter); 166cb93a386Sopenharmony_ci allocator->reset(); 167cb93a386Sopenharmony_ci check_iterator_helper(allocator, {}, reporter); 168cb93a386Sopenharmony_ci check_allocator_helper(allocator, 0, 0, reporter); 169cb93a386Sopenharmony_ci} 170cb93a386Sopenharmony_ci 171cb93a386Sopenharmony_citemplate<int N> 172cb93a386Sopenharmony_cistatic void run_allocator_test(SkTBlockList<C, N>* allocator, skiatest::Reporter* reporter) { 173cb93a386Sopenharmony_ci check_allocator(allocator, 0, 0, reporter); 174cb93a386Sopenharmony_ci check_allocator(allocator, 1, 1, reporter); 175cb93a386Sopenharmony_ci check_allocator(allocator, 2, 2, reporter); 176cb93a386Sopenharmony_ci check_allocator(allocator, 10, 1, reporter); 177cb93a386Sopenharmony_ci check_allocator(allocator, 10, 5, reporter); 178cb93a386Sopenharmony_ci check_allocator(allocator, 10, 10, reporter); 179cb93a386Sopenharmony_ci check_allocator(allocator, 100, 10, reporter); 180cb93a386Sopenharmony_ci} 181cb93a386Sopenharmony_ci 182cb93a386Sopenharmony_citemplate<int N1, int N2> 183cb93a386Sopenharmony_cistatic void run_concat_test(skiatest::Reporter* reporter, int aCount, int bCount) { 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci SkTBlockList<C, N1> listA; 186cb93a386Sopenharmony_ci SkTBlockList<C, N2> listB; 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci for (int i = 0; i < aCount; ++i) { 189cb93a386Sopenharmony_ci listA.emplace_back(i); 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci for (int i = 0; i < bCount; ++i) { 192cb93a386Sopenharmony_ci listB.emplace_back(aCount + i); 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, listA.count() == aCount && listB.count() == bCount); 196cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, C::gInstCnt == aCount + bCount); 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci // Concatenate B into A and verify. 199cb93a386Sopenharmony_ci listA.concat(std::move(listB)); 200cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, listA.count() == aCount + bCount); 201cb93a386Sopenharmony_ci // SkTBlockList guarantees the moved list is empty, but clang-tidy doesn't know about it; 202cb93a386Sopenharmony_ci // in practice we won't really be using moved lists so this won't pollute our main code base 203cb93a386Sopenharmony_ci // with lots of warning disables. 204cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, listB.count() == 0); // NOLINT(bugprone-use-after-move) 205cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, C::gInstCnt == aCount + bCount); 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_ci int i = 0; 208cb93a386Sopenharmony_ci for (const C& item : listA.items()) { 209cb93a386Sopenharmony_ci // By construction of A and B originally, the concatenated id sequence is continuous 210cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, i == item.fID); 211cb93a386Sopenharmony_ci i++; 212cb93a386Sopenharmony_ci } 213cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, i == (aCount + bCount)); 214cb93a386Sopenharmony_ci} 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_citemplate<int N1, int N2> 217cb93a386Sopenharmony_cistatic void run_concat_trivial_test(skiatest::Reporter* reporter, int aCount, int bCount) { 218cb93a386Sopenharmony_ci static_assert(std::is_trivially_copyable<D>::value); 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci // This is similar to run_concat_test(), except since D is trivial we can't verify the instant 221cb93a386Sopenharmony_ci // counts that are tracked via ctor/dtor. 222cb93a386Sopenharmony_ci SkTBlockList<D, N1> listA; 223cb93a386Sopenharmony_ci SkTBlockList<D, N2> listB; 224cb93a386Sopenharmony_ci 225cb93a386Sopenharmony_ci for (int i = 0; i < aCount; ++i) { 226cb93a386Sopenharmony_ci listA.push_back({i}); 227cb93a386Sopenharmony_ci } 228cb93a386Sopenharmony_ci for (int i = 0; i < bCount; ++i) { 229cb93a386Sopenharmony_ci listB.push_back({aCount + i}); 230cb93a386Sopenharmony_ci } 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, listA.count() == aCount && listB.count() == bCount); 233cb93a386Sopenharmony_ci // Concatenate B into A and verify. 234cb93a386Sopenharmony_ci listA.concat(std::move(listB)); 235cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, listA.count() == aCount + bCount); 236cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, listB.count() == 0); // NOLINT(bugprone-use-after-move): see above 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ci int i = 0; 239cb93a386Sopenharmony_ci for (const D& item : listA.items()) { 240cb93a386Sopenharmony_ci // By construction of A and B originally, the concatenated id sequence is continuous 241cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, i == item.fID); 242cb93a386Sopenharmony_ci i++; 243cb93a386Sopenharmony_ci } 244cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, i == (aCount + bCount)); 245cb93a386Sopenharmony_ci} 246cb93a386Sopenharmony_ci 247cb93a386Sopenharmony_citemplate<int N> 248cb93a386Sopenharmony_cistatic void run_reserve_test(skiatest::Reporter* reporter) { 249cb93a386Sopenharmony_ci constexpr int kItemsPerBlock = N + 4; // Make this a number > 1, even if N starting items == 1 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_ci SkTBlockList<C, N> list(kItemsPerBlock); 252cb93a386Sopenharmony_ci size_t initialSize = TBlockListTestAccess::TotalSize(list); 253cb93a386Sopenharmony_ci // Should be able to add N instances of T w/o changing size from initialSize 254cb93a386Sopenharmony_ci for (int i = 0; i < N; ++i) { 255cb93a386Sopenharmony_ci list.push_back(C(i)); 256cb93a386Sopenharmony_ci } 257cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, initialSize == TBlockListTestAccess::TotalSize(list)); 258cb93a386Sopenharmony_ci 259cb93a386Sopenharmony_ci // Reserve room for 2*kItemsPerBlock items 260cb93a386Sopenharmony_ci list.reserve(2 * kItemsPerBlock); 261cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, list.count() == N); // count shouldn't change though 262cb93a386Sopenharmony_ci 263cb93a386Sopenharmony_ci size_t reservedSize = TBlockListTestAccess::TotalSize(list); 264cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, reservedSize >= initialSize + 2 * kItemsPerBlock * sizeof(C)); 265cb93a386Sopenharmony_ci for (int i = 0; i < 2 * kItemsPerBlock; ++i) { 266cb93a386Sopenharmony_ci list.push_back(C(i)); 267cb93a386Sopenharmony_ci } 268cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, reservedSize == TBlockListTestAccess::TotalSize(list)); 269cb93a386Sopenharmony_ci 270cb93a386Sopenharmony_ci // Make the next block partially fully (N > 0 but < kItemsPerBlock) 271cb93a386Sopenharmony_ci for (int i = 0; i < N; ++i) { 272cb93a386Sopenharmony_ci list.push_back(C(i)); 273cb93a386Sopenharmony_ci } 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_ci // Reserve room again for 2*kItemsPerBlock, but reserve should automatically take account of the 276cb93a386Sopenharmony_ci // (kItemsPerBlock-N) that are still available in the active block 277cb93a386Sopenharmony_ci list.reserve(2 * kItemsPerBlock); 278cb93a386Sopenharmony_ci int extraReservedCount = kItemsPerBlock + N; 279cb93a386Sopenharmony_ci // Because SkTBlockList normally allocates blocks in fixed sizes, and extraReservedCount > 280cb93a386Sopenharmony_ci // items-per-block, it will always use that size and not that of the growth policy. 281cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, TBlockListTestAccess::ScratchBlockSize(list) >= 282cb93a386Sopenharmony_ci extraReservedCount * sizeof(C)); 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_ci reservedSize = TBlockListTestAccess::TotalSize(list); 285cb93a386Sopenharmony_ci for (int i = 0; i < 2 * kItemsPerBlock; ++i) { 286cb93a386Sopenharmony_ci list.push_back(C(i)); 287cb93a386Sopenharmony_ci } 288cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, reservedSize == TBlockListTestAccess::TotalSize(list)); 289cb93a386Sopenharmony_ci 290cb93a386Sopenharmony_ci // If we reserve a count < items-per-block, it will use the fixed size from the growth policy. 291cb93a386Sopenharmony_ci list.reserve(2); 292cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, TBlockListTestAccess::ScratchBlockSize(list) >= 293cb93a386Sopenharmony_ci kItemsPerBlock * sizeof(C)); 294cb93a386Sopenharmony_ci 295cb93a386Sopenharmony_ci // Ensure the reservations didn't initialize any more D's than anticipated 296cb93a386Sopenharmony_ci int expectedInstanceCount = 2 * (N + 2 * kItemsPerBlock); 297cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, expectedInstanceCount == C::gInstCnt); 298cb93a386Sopenharmony_ci 299cb93a386Sopenharmony_ci list.reset(); 300cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == C::gInstCnt); 301cb93a386Sopenharmony_ci} 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ciDEF_TEST(SkTBlockList, reporter) { 304cb93a386Sopenharmony_ci // Test combinations of allocators with and without stack storage and with different block sizes 305cb93a386Sopenharmony_ci SkTBlockList<C> a1(1); 306cb93a386Sopenharmony_ci run_allocator_test(&a1, reporter); 307cb93a386Sopenharmony_ci 308cb93a386Sopenharmony_ci SkTBlockList<C> a2(2); 309cb93a386Sopenharmony_ci run_allocator_test(&a2, reporter); 310cb93a386Sopenharmony_ci 311cb93a386Sopenharmony_ci SkTBlockList<C> a5(5); 312cb93a386Sopenharmony_ci run_allocator_test(&a5, reporter); 313cb93a386Sopenharmony_ci 314cb93a386Sopenharmony_ci SkTBlockList<C, 1> sa1; 315cb93a386Sopenharmony_ci run_allocator_test(&sa1, reporter); 316cb93a386Sopenharmony_ci 317cb93a386Sopenharmony_ci SkTBlockList<C, 3> sa3; 318cb93a386Sopenharmony_ci run_allocator_test(&sa3, reporter); 319cb93a386Sopenharmony_ci 320cb93a386Sopenharmony_ci SkTBlockList<C, 4> sa4; 321cb93a386Sopenharmony_ci run_allocator_test(&sa4, reporter); 322cb93a386Sopenharmony_ci 323cb93a386Sopenharmony_ci run_reserve_test<1>(reporter); 324cb93a386Sopenharmony_ci run_reserve_test<2>(reporter); 325cb93a386Sopenharmony_ci run_reserve_test<3>(reporter); 326cb93a386Sopenharmony_ci run_reserve_test<4>(reporter); 327cb93a386Sopenharmony_ci run_reserve_test<5>(reporter); 328cb93a386Sopenharmony_ci 329cb93a386Sopenharmony_ci run_concat_test<1, 1>(reporter, 10, 10); 330cb93a386Sopenharmony_ci run_concat_test<5, 1>(reporter, 50, 10); 331cb93a386Sopenharmony_ci run_concat_test<1, 5>(reporter, 10, 50); 332cb93a386Sopenharmony_ci run_concat_test<5, 5>(reporter, 100, 100); 333cb93a386Sopenharmony_ci 334cb93a386Sopenharmony_ci run_concat_trivial_test<1, 1>(reporter, 10, 10); 335cb93a386Sopenharmony_ci run_concat_trivial_test<5, 1>(reporter, 50, 10); 336cb93a386Sopenharmony_ci run_concat_trivial_test<1, 5>(reporter, 10, 50); 337cb93a386Sopenharmony_ci run_concat_trivial_test<5, 5>(reporter, 100, 100); 338cb93a386Sopenharmony_ci} 339