1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2020 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 "include/core/SkBitmap.h"
9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
10cb93a386Sopenharmony_ci#include "include/core/SkSurface.h"
11cb93a386Sopenharmony_ci#include "include/core/SkTextBlob.h"
12cb93a386Sopenharmony_ci#include "src/core/SkSurfacePriv.h"
13cb93a386Sopenharmony_ci#include "src/gpu/text/GrTextBlob.h"
14cb93a386Sopenharmony_ci#include "tests/Test.h"
15cb93a386Sopenharmony_ci#include "tools/ToolUtils.h"
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ciSkBitmap rasterize_blob(SkTextBlob* blob,
18cb93a386Sopenharmony_ci                        const SkPaint& paint,
19cb93a386Sopenharmony_ci                        GrRecordingContext* rContext,
20cb93a386Sopenharmony_ci                        const SkMatrix& matrix) {
21cb93a386Sopenharmony_ci    const SkImageInfo info =
22cb93a386Sopenharmony_ci            SkImageInfo::Make(500, 500, kN32_SkColorType, kPremul_SkAlphaType);
23cb93a386Sopenharmony_ci    auto surface = SkSurface::MakeRenderTarget(rContext, SkBudgeted::kNo, info);
24cb93a386Sopenharmony_ci    auto canvas = surface->getCanvas();
25cb93a386Sopenharmony_ci    canvas->drawColor(SK_ColorWHITE);
26cb93a386Sopenharmony_ci    canvas->concat(matrix);
27cb93a386Sopenharmony_ci    canvas->drawTextBlob(blob, 10, 250, paint);
28cb93a386Sopenharmony_ci    SkBitmap bitmap;
29cb93a386Sopenharmony_ci    bitmap.allocN32Pixels(500, 500);
30cb93a386Sopenharmony_ci    surface->readPixels(bitmap, 0, 0);
31cb93a386Sopenharmony_ci    return bitmap;
32cb93a386Sopenharmony_ci}
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_cibool check_for_black(const SkBitmap& bm) {
35cb93a386Sopenharmony_ci    for (int y = 0; y < bm.height(); y++) {
36cb93a386Sopenharmony_ci        for (int x = 0; x < bm.width(); x++) {
37cb93a386Sopenharmony_ci            if (bm.getColor(x, y) == SK_ColorBLACK) {
38cb93a386Sopenharmony_ci                return true;
39cb93a386Sopenharmony_ci            }
40cb93a386Sopenharmony_ci        }
41cb93a386Sopenharmony_ci    }
42cb93a386Sopenharmony_ci    return false;
43cb93a386Sopenharmony_ci}
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrTextBlobScaleAnimation, reporter, ctxInfo) {
46cb93a386Sopenharmony_ci    auto tf = ToolUtils::create_portable_typeface("Mono", SkFontStyle());
47cb93a386Sopenharmony_ci    SkFont font{tf};
48cb93a386Sopenharmony_ci    font.setHinting(SkFontHinting::kNormal);
49cb93a386Sopenharmony_ci    font.setSize(12);
50cb93a386Sopenharmony_ci    font.setEdging(SkFont::Edging::kAntiAlias);
51cb93a386Sopenharmony_ci    font.setSubpixel(true);
52cb93a386Sopenharmony_ci
53cb93a386Sopenharmony_ci    SkTextBlobBuilder builder;
54cb93a386Sopenharmony_ci    const auto& runBuffer = builder.allocRunPosH(font, 30, 0, nullptr);
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci    for (int i = 0; i < 30; i++) {
57cb93a386Sopenharmony_ci        runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
58cb93a386Sopenharmony_ci        runBuffer.pos[i] = SkIntToScalar(i);
59cb93a386Sopenharmony_ci    }
60cb93a386Sopenharmony_ci    auto blob = builder.make();
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ci    auto dContext = ctxInfo.directContext();
63cb93a386Sopenharmony_ci    bool anyBlack = false;
64cb93a386Sopenharmony_ci    for (int n = -13; n < 5; n++) {
65cb93a386Sopenharmony_ci        SkMatrix m = SkMatrix::Scale(std::exp2(n), std::exp2(n));
66cb93a386Sopenharmony_ci        auto bm = rasterize_blob(blob.get(), SkPaint(), dContext, m);
67cb93a386Sopenharmony_ci        anyBlack |= check_for_black(bm);
68cb93a386Sopenharmony_ci    }
69cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, anyBlack);
70cb93a386Sopenharmony_ci}
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_ci// Test extreme positions for all combinations of positions, origins, and translation matrices.
73cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrTextBlobMoveAround, reporter, ctxInfo) {
74cb93a386Sopenharmony_ci    auto tf = ToolUtils::create_portable_typeface("Mono", SkFontStyle());
75cb93a386Sopenharmony_ci    SkFont font{tf};
76cb93a386Sopenharmony_ci    font.setHinting(SkFontHinting::kNormal);
77cb93a386Sopenharmony_ci    font.setSize(12);
78cb93a386Sopenharmony_ci    font.setEdging(SkFont::Edging::kAntiAlias);
79cb93a386Sopenharmony_ci    font.setSubpixel(true);
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_ci    auto makeBlob = [&](SkPoint delta) {
82cb93a386Sopenharmony_ci        SkTextBlobBuilder builder;
83cb93a386Sopenharmony_ci        const auto& runBuffer = builder.allocRunPos(font, 30, nullptr);
84cb93a386Sopenharmony_ci
85cb93a386Sopenharmony_ci        for (int i = 0; i < 30; i++) {
86cb93a386Sopenharmony_ci            runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
87cb93a386Sopenharmony_ci            runBuffer.points()[i] = SkPoint::Make(SkIntToScalar(i*10) + delta.x(), 50 + delta.y());
88cb93a386Sopenharmony_ci        }
89cb93a386Sopenharmony_ci        return builder.make();
90cb93a386Sopenharmony_ci    };
91cb93a386Sopenharmony_ci
92cb93a386Sopenharmony_ci    auto dContext = ctxInfo.directContext();
93cb93a386Sopenharmony_ci    auto rasterizeBlob = [&](SkTextBlob* blob, SkPoint origin, const SkMatrix& matrix) {
94cb93a386Sopenharmony_ci        SkPaint paint;
95cb93a386Sopenharmony_ci        const SkImageInfo info =
96cb93a386Sopenharmony_ci                SkImageInfo::Make(350, 80, kN32_SkColorType, kPremul_SkAlphaType);
97cb93a386Sopenharmony_ci        auto surface = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, info);
98cb93a386Sopenharmony_ci        auto canvas = surface->getCanvas();
99cb93a386Sopenharmony_ci        canvas->drawColor(SK_ColorWHITE);
100cb93a386Sopenharmony_ci        canvas->concat(matrix);
101cb93a386Sopenharmony_ci        canvas->drawTextBlob(blob, 10 + origin.x(), 40 + origin.y(), paint);
102cb93a386Sopenharmony_ci        SkBitmap bitmap;
103cb93a386Sopenharmony_ci        bitmap.allocN32Pixels(350, 80);
104cb93a386Sopenharmony_ci        surface->readPixels(bitmap, 0, 0);
105cb93a386Sopenharmony_ci        return bitmap;
106cb93a386Sopenharmony_ci    };
107cb93a386Sopenharmony_ci
108cb93a386Sopenharmony_ci    SkBitmap benchMark;
109cb93a386Sopenharmony_ci    {
110cb93a386Sopenharmony_ci        auto blob = makeBlob({0, 0});
111cb93a386Sopenharmony_ci        benchMark = rasterizeBlob(blob.get(), {0,0}, SkMatrix::I());
112cb93a386Sopenharmony_ci    }
113cb93a386Sopenharmony_ci
114cb93a386Sopenharmony_ci    auto checkBitmap = [&](const SkBitmap& bitmap) {
115cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, benchMark.width() == bitmap.width());
116cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, benchMark.width() == bitmap.width());
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ci        for (int y = 0; y < benchMark.height(); y++) {
119cb93a386Sopenharmony_ci            for (int x = 0; x < benchMark.width(); x++) {
120cb93a386Sopenharmony_ci                if (benchMark.getColor(x, y) != bitmap.getColor(x, y)) {
121cb93a386Sopenharmony_ci                    return false;
122cb93a386Sopenharmony_ci                }
123cb93a386Sopenharmony_ci            }
124cb93a386Sopenharmony_ci        }
125cb93a386Sopenharmony_ci        return true;
126cb93a386Sopenharmony_ci    };
127cb93a386Sopenharmony_ci
128cb93a386Sopenharmony_ci    SkScalar interestingNumbers[] = {-10'000'000, -1'000'000, -1, 0, +1, +1'000'000, +10'000'000};
129cb93a386Sopenharmony_ci    for (auto originX : interestingNumbers) {
130cb93a386Sopenharmony_ci        for (auto originY : interestingNumbers) {
131cb93a386Sopenharmony_ci            for (auto translateX : interestingNumbers) {
132cb93a386Sopenharmony_ci                for (auto translateY : interestingNumbers) {
133cb93a386Sopenharmony_ci                    // Make sure everything adds to zero.
134cb93a386Sopenharmony_ci                    SkScalar deltaPosX = -(originX + translateX);
135cb93a386Sopenharmony_ci                    SkScalar deltaPosY = -(originY + translateY);
136cb93a386Sopenharmony_ci                    auto blob = makeBlob({deltaPosX, deltaPosY});
137cb93a386Sopenharmony_ci                    SkMatrix t = SkMatrix::Translate(translateX, translateY);
138cb93a386Sopenharmony_ci                    auto bitmap = rasterizeBlob(blob.get(), {originX, originY}, t);
139cb93a386Sopenharmony_ci                    REPORTER_ASSERT(reporter, checkBitmap(bitmap));
140cb93a386Sopenharmony_ci                }
141cb93a386Sopenharmony_ci            }
142cb93a386Sopenharmony_ci        }
143cb93a386Sopenharmony_ci    }
144cb93a386Sopenharmony_ci}
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ciDEF_TEST(GrBagOfBytesBasic, r) {
147cb93a386Sopenharmony_ci    const int k4K = 1 << 12;
148cb93a386Sopenharmony_ci    {
149cb93a386Sopenharmony_ci        // GrBagOfBytes::MinimumSizeWithOverhead(-1); // This should fail
150cb93a386Sopenharmony_ci        GrBagOfBytes::PlatformMinimumSizeWithOverhead(0, 16);
151cb93a386Sopenharmony_ci        GrBagOfBytes::PlatformMinimumSizeWithOverhead(
152cb93a386Sopenharmony_ci                std::numeric_limits<int>::max() - k4K - 1, 16);
153cb93a386Sopenharmony_ci        // GrBagOfBytes::MinimumSizeWithOverhead(std::numeric_limits<int>::max() - k4K);  // Fail
154cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(0, 1, 16, 16) == 31);
155cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(1, 1, 16, 16) == 32);
156cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(63, 1, 16, 16) == 94);
157cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(0, 8, 16, 16) == 24);
158cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(1, 8, 16, 16) == 32);
159cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(63, 8, 16, 16) == 88);
160cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(0, 16, 16, 16) == 16);
161cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(1, 16, 16, 16) == 32);
162cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(63, 16, 16, 16) == 80);
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(0, 1, 8, 16) == 23);
165cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(1, 1, 8, 16) == 24);
166cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(63, 1, 8, 16) == 86);
167cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(0, 8, 8, 16) == 16);
168cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(1, 8, 8, 16) == 24);
169cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, GrBagOfBytes::MinimumSizeWithOverhead(63, 8, 8, 16) == 80);
170cb93a386Sopenharmony_ci    }
171cb93a386Sopenharmony_ci
172cb93a386Sopenharmony_ci    {
173cb93a386Sopenharmony_ci        GrBagOfBytes bob;
174cb93a386Sopenharmony_ci        // bob.alignedBytes(0, 1);  // This should fail
175cb93a386Sopenharmony_ci        // bob.alignedBytes(1, 0);  // This should fail
176cb93a386Sopenharmony_ci        // bob.alignedBytes(1, 3);  // This should fail
177cb93a386Sopenharmony_ci
178cb93a386Sopenharmony_ci        struct Big {
179cb93a386Sopenharmony_ci            char stuff[std::numeric_limits<int>::max()];
180cb93a386Sopenharmony_ci        };
181cb93a386Sopenharmony_ci        // bob.alignedBytes(sizeof(Big), 1);  // this should fail
182cb93a386Sopenharmony_ci        // bob.allocateBytesFor<Big>();  // this should not compile
183cb93a386Sopenharmony_ci        // The following should run, but should not be regularly tested.
184cb93a386Sopenharmony_ci        // bob.allocateBytesFor<int>((std::numeric_limits<int>::max() - (1<<12)) / sizeof(int) - 1);
185cb93a386Sopenharmony_ci        // The following should fail
186cb93a386Sopenharmony_ci        // bob.allocateBytesFor<int>((std::numeric_limits<int>::max() - (1<<12)) / sizeof(int));
187cb93a386Sopenharmony_ci        bob.alignedBytes(1, 1);  // To avoid unused variable problems.
188cb93a386Sopenharmony_ci    }
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_ci    // Force multiple block allocation
191cb93a386Sopenharmony_ci    {
192cb93a386Sopenharmony_ci        GrBagOfBytes bob;
193cb93a386Sopenharmony_ci        const int k64K = 1 << 16;
194cb93a386Sopenharmony_ci        // By default allocation block sizes start at 1K and go up with fib. This should allocate
195cb93a386Sopenharmony_ci        // 10 individual blocks.
196cb93a386Sopenharmony_ci        for (int i = 0; i < 10; i++) {
197cb93a386Sopenharmony_ci            bob.alignedBytes(k64K, 1);
198cb93a386Sopenharmony_ci        }
199cb93a386Sopenharmony_ci    }
200cb93a386Sopenharmony_ci}
201cb93a386Sopenharmony_ci
202cb93a386Sopenharmony_ci// Helper for defining allocators with inline/reserved storage.
203cb93a386Sopenharmony_ci// For argument declarations, stick to the base type (GrSubRunAllocator).
204cb93a386Sopenharmony_ci// Note: Inheriting from the storage first means the storage will outlive the
205cb93a386Sopenharmony_ci// GrSubRunAllocator, letting ~GrSubRunAllocator read it as it calls destructors.
206cb93a386Sopenharmony_ci// (This is mostly only relevant for strict tools like MSAN.)
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_citemplate <size_t inlineSize>
209cb93a386Sopenharmony_ciclass GrSTSubRunAllocator : private GrBagOfBytes::Storage<inlineSize>, public GrSubRunAllocator {
210cb93a386Sopenharmony_cipublic:
211cb93a386Sopenharmony_ci    explicit GrSTSubRunAllocator(int firstHeapAllocation =
212cb93a386Sopenharmony_ci                                    GrBagOfBytes::PlatformMinimumSizeWithOverhead(inlineSize, 1))
213cb93a386Sopenharmony_ci            : GrSubRunAllocator{this->data(), SkTo<int>(this->size()), firstHeapAllocation} {}
214cb93a386Sopenharmony_ci};
215cb93a386Sopenharmony_ci
216cb93a386Sopenharmony_ciDEF_TEST(GrSubRunAllocator, r) {
217cb93a386Sopenharmony_ci    static int created = 0;
218cb93a386Sopenharmony_ci    static int destroyed = 0;
219cb93a386Sopenharmony_ci    struct Foo {
220cb93a386Sopenharmony_ci        Foo() : fI{-2}, fX{-3} { created++; }
221cb93a386Sopenharmony_ci        Foo(int i, float x) : fI{i}, fX{x} { created++; }
222cb93a386Sopenharmony_ci        ~Foo() { destroyed++; }
223cb93a386Sopenharmony_ci        int fI;
224cb93a386Sopenharmony_ci        float fX;
225cb93a386Sopenharmony_ci    };
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ci    struct alignas(8) OddAlignment {
228cb93a386Sopenharmony_ci        char buf[10];
229cb93a386Sopenharmony_ci    };
230cb93a386Sopenharmony_ci
231cb93a386Sopenharmony_ci    auto exercise = [&](GrSubRunAllocator* alloc) {
232cb93a386Sopenharmony_ci        created = 0;
233cb93a386Sopenharmony_ci        destroyed = 0;
234cb93a386Sopenharmony_ci        {
235cb93a386Sopenharmony_ci            int* p = alloc->makePOD<int>(3);
236cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, *p == 3);
237cb93a386Sopenharmony_ci            int* q = alloc->makePOD<int>(7);
238cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, *q == 7);
239cb93a386Sopenharmony_ci
240cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, *alloc->makePOD<int>(3) == 3);
241cb93a386Sopenharmony_ci            auto foo = alloc->makeUnique<Foo>(3, 4.0f);
242cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, foo->fI == 3);
243cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, foo->fX == 4.0f);
244cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, created == 1);
245cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, destroyed == 0);
246cb93a386Sopenharmony_ci
247cb93a386Sopenharmony_ci            alloc->makePODArray<int>(10);
248cb93a386Sopenharmony_ci
249cb93a386Sopenharmony_ci            auto fooArray = alloc->makeUniqueArray<Foo>(10);
250cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, fooArray[3].fI == -2);
251cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, fooArray[4].fX == -3.0f);
252cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, created == 11);
253cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, destroyed == 0);
254cb93a386Sopenharmony_ci            alloc->makePOD<OddAlignment>();
255cb93a386Sopenharmony_ci        }
256cb93a386Sopenharmony_ci
257cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, created == 11);
258cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, destroyed == 11);
259cb93a386Sopenharmony_ci    };
260cb93a386Sopenharmony_ci
261cb93a386Sopenharmony_ci    // Exercise default arena
262cb93a386Sopenharmony_ci    {
263cb93a386Sopenharmony_ci        GrSubRunAllocator arena{0};
264cb93a386Sopenharmony_ci        exercise(&arena);
265cb93a386Sopenharmony_ci    }
266cb93a386Sopenharmony_ci
267cb93a386Sopenharmony_ci    // Exercise on stack arena
268cb93a386Sopenharmony_ci    {
269cb93a386Sopenharmony_ci        GrSTSubRunAllocator<64> arena;
270cb93a386Sopenharmony_ci        exercise(&arena);
271cb93a386Sopenharmony_ci    }
272cb93a386Sopenharmony_ci
273cb93a386Sopenharmony_ci    // Exercise arena with a heap allocated starting block
274cb93a386Sopenharmony_ci    {
275cb93a386Sopenharmony_ci        std::unique_ptr<char[]> block{new char[1024]};
276cb93a386Sopenharmony_ci        GrSubRunAllocator arena{block.get(), 1024, 0};
277cb93a386Sopenharmony_ci        exercise(&arena);
278cb93a386Sopenharmony_ci    }
279cb93a386Sopenharmony_ci
280cb93a386Sopenharmony_ci    // Exercise the singly-link list of unique_ptrs use case
281cb93a386Sopenharmony_ci    {
282cb93a386Sopenharmony_ci        created = 0;
283cb93a386Sopenharmony_ci        destroyed = 0;
284cb93a386Sopenharmony_ci        GrSubRunAllocator arena;
285cb93a386Sopenharmony_ci
286cb93a386Sopenharmony_ci        struct Node {
287cb93a386Sopenharmony_ci            Node(std::unique_ptr<Node, GrSubRunAllocator::Destroyer> next)
288cb93a386Sopenharmony_ci                    : fNext{std::move(next)} { created++; }
289cb93a386Sopenharmony_ci            ~Node() { destroyed++; }
290cb93a386Sopenharmony_ci            std::unique_ptr<Node, GrSubRunAllocator::Destroyer> fNext;
291cb93a386Sopenharmony_ci        };
292cb93a386Sopenharmony_ci
293cb93a386Sopenharmony_ci        std::unique_ptr<Node, GrSubRunAllocator::Destroyer> current = nullptr;
294cb93a386Sopenharmony_ci        for (int i = 0; i < 128; i++) {
295cb93a386Sopenharmony_ci            current = arena.makeUnique<Node>(std::move(current));
296cb93a386Sopenharmony_ci        }
297cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, created == 128);
298cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, destroyed == 0);
299cb93a386Sopenharmony_ci    }
300cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, created == 128);
301cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, destroyed == 128);
302cb93a386Sopenharmony_ci
303cb93a386Sopenharmony_ci    // Exercise the array ctor w/ a mapping function
304cb93a386Sopenharmony_ci    {
305cb93a386Sopenharmony_ci        struct I {
306cb93a386Sopenharmony_ci            I(int v) : i{v} {}
307cb93a386Sopenharmony_ci            ~I() {}
308cb93a386Sopenharmony_ci            int i;
309cb93a386Sopenharmony_ci        };
310cb93a386Sopenharmony_ci        GrSTSubRunAllocator<64> arena;
311cb93a386Sopenharmony_ci        auto a = arena.makeUniqueArray<I>(8, [](size_t i) { return i; });
312cb93a386Sopenharmony_ci        for (size_t i = 0; i < 8; i++) {
313cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, a[i].i == (int)i);
314cb93a386Sopenharmony_ci        }
315cb93a386Sopenharmony_ci    }
316cb93a386Sopenharmony_ci
317cb93a386Sopenharmony_ci    {
318cb93a386Sopenharmony_ci        GrSubRunAllocator arena(4096);
319cb93a386Sopenharmony_ci        void* ptr = arena.alignedBytes(4081, 8);
320cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, ((intptr_t)ptr & 7) == 0);
321cb93a386Sopenharmony_ci    }
322cb93a386Sopenharmony_ci}
323