1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_allocator/bump_allocator.h"
16
17 #include <cstring>
18
19 #include "pw_unit_test/framework.h"
20
21 namespace {
22
23 // Test fixtures.
24
25 using ::pw::allocator::BumpAllocator;
26 using ::pw::allocator::Layout;
27
28 class DestroyCounter final {
29 public:
DestroyCounter(size_t * counter)30 DestroyCounter(size_t* counter) : counter_(counter) {}
~DestroyCounter()31 ~DestroyCounter() { *counter_ += 1; }
32
33 private:
34 size_t* counter_;
35 };
36
37 // Unit tests.
38
TEST(BumpAllocatorTest,ExplicitlyInit)39 TEST(BumpAllocatorTest, ExplicitlyInit) {
40 alignas(16) std::array<std::byte, 256> buffer;
41 BumpAllocator allocator;
42 allocator.Init(buffer);
43 }
44
TEST(BumpAllocatorTest,AllocateValid)45 TEST(BumpAllocatorTest, AllocateValid) {
46 alignas(16) std::array<std::byte, 256> buffer;
47 BumpAllocator allocator(buffer);
48 void* ptr = allocator.Allocate(Layout(64, 16));
49 ASSERT_NE(ptr, nullptr);
50 }
51
TEST(BumpAllocatorTest,AllocateAligned)52 TEST(BumpAllocatorTest, AllocateAligned) {
53 alignas(16) std::array<std::byte, 256> buffer;
54 BumpAllocator allocator(buffer);
55 void* ptr = allocator.Allocate(Layout(1, 1));
56 ASSERT_NE(ptr, nullptr);
57
58 // Last pointer was aligned, so next won't automatically be.
59 ptr = allocator.Allocate(Layout(8, 32));
60 ASSERT_NE(ptr, nullptr);
61 EXPECT_EQ(reinterpret_cast<uintptr_t>(ptr) % 32, 0U);
62 }
63
TEST(BumpAllocatorTest,AllocateFailsWhenExhausted)64 TEST(BumpAllocatorTest, AllocateFailsWhenExhausted) {
65 alignas(16) std::array<std::byte, 256> buffer;
66 BumpAllocator allocator(buffer);
67 void* ptr = allocator.Allocate(Layout(256, 16));
68 ASSERT_NE(ptr, nullptr);
69 ptr = allocator.Allocate(Layout(1, 1));
70 EXPECT_EQ(ptr, nullptr);
71 }
72
TEST(BumpAllocatorTest,DeallocateDoesNothing)73 TEST(BumpAllocatorTest, DeallocateDoesNothing) {
74 alignas(16) std::array<std::byte, 256> buffer;
75 BumpAllocator allocator(buffer);
76 void* ptr = allocator.Allocate(Layout(256, 16));
77 ASSERT_NE(ptr, nullptr);
78 allocator.Deallocate(ptr);
79 ptr = allocator.Allocate(Layout(1, 1));
80 EXPECT_EQ(ptr, nullptr);
81 }
82
TEST(BumpAllocatorTest,NewDoesNotDestroy)83 TEST(BumpAllocatorTest, NewDoesNotDestroy) {
84 alignas(16) std::array<std::byte, 256> buffer;
85 size_t counter = 0;
86 {
87 BumpAllocator allocator(buffer);
88 DestroyCounter* dc1 = allocator.New<DestroyCounter>(&counter);
89 EXPECT_EQ(counter, 0U);
90 allocator.Delete(dc1);
91 }
92 EXPECT_EQ(counter, 0U);
93 }
94
TEST(BumpAllocatorTest,DeleteDoesNothing)95 TEST(BumpAllocatorTest, DeleteDoesNothing) {
96 alignas(16) std::array<std::byte, 256> buffer;
97 size_t counter = 0;
98 BumpAllocator allocator(buffer);
99 DestroyCounter* dc1 = allocator.New<DestroyCounter>(&counter);
100 EXPECT_EQ(counter, 0U);
101 allocator.Delete(dc1);
102 EXPECT_EQ(counter, 0U);
103 }
104
TEST(BumpAllocatorTest,NewOwnedDestroys)105 TEST(BumpAllocatorTest, NewOwnedDestroys) {
106 alignas(16) std::array<std::byte, 256> buffer;
107 size_t counter = 0;
108 {
109 BumpAllocator allocator(buffer);
110 allocator.NewOwned<DestroyCounter>(&counter);
111 EXPECT_EQ(counter, 0U);
112 }
113 EXPECT_EQ(counter, 1U);
114 }
115
TEST(BumpAllocatorTest,MakeUniqueDoesNotDestroy)116 TEST(BumpAllocatorTest, MakeUniqueDoesNotDestroy) {
117 alignas(16) std::array<std::byte, 256> buffer;
118 size_t counter = 0;
119 {
120 BumpAllocator allocator(buffer);
121 allocator.MakeUnique<DestroyCounter>(&counter).get();
122 EXPECT_EQ(counter, 0U);
123 }
124 EXPECT_EQ(counter, 0U);
125 }
126
TEST(BumpAllocatorTest,MakeUniqueOwnedDestroys)127 TEST(BumpAllocatorTest, MakeUniqueOwnedDestroys) {
128 alignas(16) std::array<std::byte, 256> buffer;
129 size_t counter = 0;
130 {
131 BumpAllocator allocator(buffer);
132 allocator.MakeUniqueOwned<DestroyCounter>(&counter).get();
133 EXPECT_EQ(counter, 0U);
134 }
135 EXPECT_EQ(counter, 1U);
136 }
137
138 } // namespace
139