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 "SkSmallAllocator.h"
9 #include "SkTypes.h"
10 #include "Test.h"
11 
12 class CountingClass {
13 public:
CountingClass()14     CountingClass() {
15         kCount++;
16     }
17 
~CountingClass()18     ~CountingClass() {
19         kCount--;
20     }
21 
GetCount()22     static int GetCount() { return kCount; }
23 
24 private:
25     static int kCount;
26 };
27 
28 int CountingClass::kCount;
29 
test_allocator(skiatest::Reporter * reporter)30 template<uint32_t kMaxObjects, size_t kBytes> void test_allocator(skiatest::Reporter* reporter) {
31     {
32         SkSmallAllocator<kMaxObjects, kBytes> alloc;
33         for (uint32_t i = 0; i < kMaxObjects; ++i) {
34             CountingClass* c = alloc.template createT<CountingClass>();
35             REPORTER_ASSERT(reporter, c != nullptr);
36             REPORTER_ASSERT(reporter, CountingClass::GetCount() == static_cast<int>(i+1));
37         }
38     }
39     REPORTER_ASSERT(reporter, CountingClass::GetCount() == 0);
40 }
41 
42 // Tests that ensure that the destructor is called, whether the objects
43 // were created in fStorage or on the heap.
DEF_TEST(SmallAllocator_destructor,reporter)44 DEF_TEST(SmallAllocator_destructor, reporter) {
45     // Four times as many bytes as objects will never require any heap
46     // allocations (since SkAlign4(sizeof(CountingClass)) == 4 and the allocator
47     // will stop once it reaches kMaxObjects).
48     test_allocator<5, 20>(reporter);
49     test_allocator<10, 40>(reporter);
50     test_allocator<20, 80>(reporter);
51 
52 #ifndef SK_DEBUG
53     // Allowing less bytes than objects means some will be allocated on the
54     // heap. Don't run these in debug where we assert.
55     test_allocator<50, 20>(reporter);
56     test_allocator<100, 20>(reporter);
57 #endif
58 }
59 
60 class Dummy {
61 };
62 
63 class DummyContainer {
64 public:
DummyContainer(Dummy * d)65     explicit DummyContainer(Dummy* d)
66         :fDummy(d)
67     {}
68 
getDummy() const69     Dummy* getDummy() const { return fDummy; }
70 
71 private:
72     Dummy* fDummy;
73 };
74 
75 // Test that using a createT with a constructor taking a pointer as a
76 // parameter works as expected.
DEF_TEST(SmallAllocator_pointer,reporter)77 DEF_TEST(SmallAllocator_pointer, reporter) {
78     SkSmallAllocator<1, 8> alloc;
79     Dummy d;
80     DummyContainer* container = alloc.createT<DummyContainer>(&d);
81     REPORTER_ASSERT(reporter, container != nullptr);
82     REPORTER_ASSERT(reporter, container->getDummy() == &d);
83 }
84