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 "lib/stdcompat/bit.h"
20 #include "pw_unit_test/framework.h"
21
22 namespace {
23
24 // Test fixtures.
25
26 using ::pw::allocator::BumpAllocator;
27 using ::pw::allocator::Layout;
28
29 class DestroyCounter final {
30 public:
DestroyCounter(size_t * counter)31 DestroyCounter(size_t* counter) : counter_(counter) {}
~DestroyCounter()32 ~DestroyCounter() { *counter_ += 1; }
33
34 private:
35 size_t* counter_;
36 };
37
38 // Unit tests.
39
TEST(BumpAllocatorTest,ExplicitlyInit)40 TEST(BumpAllocatorTest, ExplicitlyInit) {
41 alignas(16) std::array<std::byte, 256> buffer;
42 BumpAllocator allocator;
43 allocator.Init(buffer);
44 }
45
TEST(BumpAllocatorTest,AllocateValid)46 TEST(BumpAllocatorTest, AllocateValid) {
47 alignas(16) std::array<std::byte, 256> buffer;
48 BumpAllocator allocator(buffer);
49 void* ptr = allocator.Allocate(Layout(64, 16));
50 ASSERT_NE(ptr, nullptr);
51 }
52
TEST(BumpAllocatorTest,AllocateAligned)53 TEST(BumpAllocatorTest, AllocateAligned) {
54 alignas(16) std::array<std::byte, 256> buffer;
55 BumpAllocator allocator(buffer);
56 void* ptr = allocator.Allocate(Layout(1, 1));
57 ASSERT_NE(ptr, nullptr);
58
59 // Last pointer was aligned, so next won't automatically be.
60 ptr = allocator.Allocate(Layout(8, 32));
61 ASSERT_NE(ptr, nullptr);
62 EXPECT_EQ(cpp20::bit_cast<uintptr_t>(ptr) % 32, 0U);
63 }
64
TEST(BumpAllocatorTest,AllocateFailsWhenExhausted)65 TEST(BumpAllocatorTest, AllocateFailsWhenExhausted) {
66 alignas(16) std::array<std::byte, 256> buffer;
67 BumpAllocator allocator(buffer);
68 void* ptr = allocator.Allocate(Layout(256, 16));
69 ASSERT_NE(ptr, nullptr);
70 ptr = allocator.Allocate(Layout(1, 1));
71 EXPECT_EQ(ptr, nullptr);
72 }
73
TEST(BumpAllocatorTest,DeallocateDoesNothing)74 TEST(BumpAllocatorTest, DeallocateDoesNothing) {
75 alignas(16) std::array<std::byte, 256> buffer;
76 BumpAllocator allocator(buffer);
77 void* ptr = allocator.Allocate(Layout(256, 16));
78 ASSERT_NE(ptr, nullptr);
79 allocator.Deallocate(ptr);
80 ptr = allocator.Allocate(Layout(1, 1));
81 EXPECT_EQ(ptr, nullptr);
82 }
83
TEST(BumpAllocatorTest,NewDoesNotDestroy)84 TEST(BumpAllocatorTest, NewDoesNotDestroy) {
85 alignas(16) std::array<std::byte, 256> buffer;
86 size_t counter = 0;
87 {
88 BumpAllocator allocator(buffer);
89 DestroyCounter* dc1 = allocator.New<DestroyCounter>(&counter);
90 EXPECT_EQ(counter, 0U);
91 allocator.Delete(dc1);
92 }
93 EXPECT_EQ(counter, 0U);
94 }
95
TEST(BumpAllocatorTest,DeleteDoesNothing)96 TEST(BumpAllocatorTest, DeleteDoesNothing) {
97 alignas(16) std::array<std::byte, 256> buffer;
98 size_t counter = 0;
99 BumpAllocator allocator(buffer);
100 DestroyCounter* dc1 = allocator.New<DestroyCounter>(&counter);
101 EXPECT_EQ(counter, 0U);
102 allocator.Delete(dc1);
103 EXPECT_EQ(counter, 0U);
104 }
105
TEST(BumpAllocatorTest,NewOwnedDestroys)106 TEST(BumpAllocatorTest, NewOwnedDestroys) {
107 alignas(16) std::array<std::byte, 256> buffer;
108 size_t counter = 0;
109 {
110 BumpAllocator allocator(buffer);
111 allocator.NewOwned<DestroyCounter>(&counter);
112 EXPECT_EQ(counter, 0U);
113 }
114 EXPECT_EQ(counter, 1U);
115 }
116
TEST(BumpAllocatorTest,MakeUniqueDoesNotDestroy)117 TEST(BumpAllocatorTest, MakeUniqueDoesNotDestroy) {
118 alignas(16) std::array<std::byte, 256> buffer;
119 size_t counter = 0;
120 {
121 BumpAllocator allocator(buffer);
122 allocator.MakeUnique<DestroyCounter>(&counter).get();
123 EXPECT_EQ(counter, 0U);
124 }
125 EXPECT_EQ(counter, 0U);
126 }
127
TEST(BumpAllocatorTest,MakeUniqueOwnedDestroys)128 TEST(BumpAllocatorTest, MakeUniqueOwnedDestroys) {
129 alignas(16) std::array<std::byte, 256> buffer;
130 size_t counter = 0;
131 {
132 BumpAllocator allocator(buffer);
133 allocator.MakeUniqueOwned<DestroyCounter>(&counter).get();
134 EXPECT_EQ(counter, 0U);
135 }
136 EXPECT_EQ(counter, 1U);
137 }
138
139 } // namespace
140