1 // Copyright 2024 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/as_pmr_allocator.h"
16
17 #include <deque>
18 #include <forward_list>
19 #include <list>
20 #include <map>
21 #include <set>
22 #include <unordered_map>
23 #include <unordered_set>
24 #include <vector>
25
26 #include "pw_allocator/testing.h"
27 #include "pw_unit_test/framework.h"
28
29 namespace {
30
31 // Test fixtures.
32
33 using ::pw::allocator::AsPmrAllocator;
34 using ::pw::allocator::test::AllocatorForTest;
35
36 struct Foo {
37 uint32_t value;
38
Foo__anona599d5640111::Foo39 Foo(uint32_t value_) : value(value_) {}
40 };
41
operator ==(const Foo & lhs,const Foo & rhs)42 bool operator==(const Foo& lhs, const Foo& rhs) {
43 return lhs.value == rhs.value;
44 }
45
operator <(const Foo & lhs,const Foo & rhs)46 bool operator<(const Foo& lhs, const Foo& rhs) { return lhs.value < rhs.value; }
47
48 } // namespace
49
50 template <>
51 struct std::hash<Foo> {
operator ()std::hash52 size_t operator()(const Foo& foo) const {
53 return std::hash<uint32_t>()(foo.value);
54 }
55 };
56
57 namespace {
58
59 struct Bar {
60 std::array<std::byte, 16> buffer;
61
Bar__anona599d5640211::Bar62 Bar(int value) { std::memset(buffer.data(), value, buffer.size()); }
63 };
64
65 template <typename T, typename = void>
66 struct has_emplace_front : std::false_type {};
67
68 template <typename T>
69 struct has_emplace_front<
70 T,
71 std::void_t<decltype(std::declval<T>().emplace_front())>>
72 : std::true_type{};
73
74 template <typename T, typename = void>
75 struct has_emplace_back : std::false_type {};
76
77 template <typename T>
78 struct has_emplace_back<T,
79 std::void_t<decltype(std::declval<T>().emplace_back())>>
80 : std::true_type{};
81
82 template <typename T, typename = void>
83 struct has_key_type : std::false_type {};
84
85 template <typename T>
86 struct has_key_type<T, std::void_t<typename T::key_type>> : std::true_type{};
87
88 template <typename T, typename = void>
89 struct has_mapped_type : std::false_type {};
90
91 template <typename T>
92 struct has_mapped_type<T, std::void_t<typename T::mapped_type>>
93 : std::true_type{};
94
95 template <typename Container, size_t kCapacity = 256>
TestPmrAllocator()96 void TestPmrAllocator() {
97 AllocatorForTest<kCapacity> underlying;
98 auto& requested_bytes = underlying.metrics().requested_bytes;
99 EXPECT_EQ(requested_bytes.value(), 0U);
100
101 AsPmrAllocator allocator = underlying.as_pmr();
102 {
103 Container container(allocator);
104 size_t size = 0;
105 // Sequence containers.
106 if constexpr (has_emplace_front<Container>::value) {
107 container.emplace_front(1);
108 container.emplace_front(2);
109 size += sizeof(typename Container::value_type) * 2;
110 }
111 if constexpr (has_emplace_back<Container>::value) {
112 container.emplace_back(3);
113 container.emplace_back(4);
114 size += sizeof(typename Container::value_type) * 2;
115 }
116 // Associative containers.
117 if constexpr (has_mapped_type<Container>::value) {
118 container.insert({1, 10});
119 container.insert({2, 20});
120 size += sizeof(typename Container::key_type) * 2;
121 size += sizeof(typename Container::mapped_type) * 2;
122 } else if constexpr (has_key_type<Container>::value) {
123 container.insert(3);
124 container.insert(4);
125 size += sizeof(typename Container::key_type) * 2;
126 }
127 EXPECT_GE(requested_bytes.value(), size);
128 }
129 EXPECT_EQ(requested_bytes.value(), 0U);
130 }
131
132 // Unit tests.
133
TEST(AsPmrAllocatorTest,Vector)134 TEST(AsPmrAllocatorTest, Vector) { TestPmrAllocator<pw::pmr::vector<Foo>>(); }
135
TEST(AsPmrAllocatorTest,Deque)136 TEST(AsPmrAllocatorTest, Deque) {
137 // Some implementations preallocate a lot of memory.
138 TestPmrAllocator<pw::pmr::deque<Foo>, 8192>();
139 }
140
TEST(AsPmrAllocatorTest,ForwardList)141 TEST(AsPmrAllocatorTest, ForwardList) {
142 TestPmrAllocator<pw::pmr::forward_list<Foo>>();
143 }
144
TEST(AsPmrAllocatorTest,List)145 TEST(AsPmrAllocatorTest, List) { TestPmrAllocator<pw::pmr::list<Foo>>(); }
146
TEST(AsPmrAllocatorTest,Set)147 TEST(AsPmrAllocatorTest, Set) { TestPmrAllocator<pw::pmr::set<Foo>>(); }
148
TEST(AsPmrAllocatorTest,Map)149 TEST(AsPmrAllocatorTest, Map) { TestPmrAllocator<pw::pmr::map<Foo, Bar>>(); }
150
TEST(AsPmrAllocatorTest,MultiSet)151 TEST(AsPmrAllocatorTest, MultiSet) {
152 TestPmrAllocator<pw::pmr::multiset<Foo>>();
153 }
154
TEST(AsPmrAllocatorTest,MultiMap)155 TEST(AsPmrAllocatorTest, MultiMap) {
156 TestPmrAllocator<pw::pmr::multimap<Foo, Bar>>();
157 }
158
TEST(AsPmrAllocatorTest,UnorderedSet)159 TEST(AsPmrAllocatorTest, UnorderedSet) {
160 // Some implementations preallocate a lot of memory.
161 TestPmrAllocator<pw::pmr::unordered_set<Foo>, 1024>();
162 }
163
TEST(AsPmrAllocatorTest,UnorderedMap)164 TEST(AsPmrAllocatorTest, UnorderedMap) {
165 // Some implementations preallocate a lot of memory.
166 TestPmrAllocator<pw::pmr::unordered_map<Foo, Bar>, 1024>();
167 }
168
TEST(AsPmrAllocatorTest,UnorderedMultiSet)169 TEST(AsPmrAllocatorTest, UnorderedMultiSet) {
170 // Some implementations preallocate a lot of memory.
171 TestPmrAllocator<pw::pmr::unordered_multiset<Foo>, 1024>();
172 }
173
TEST(AsPmrAllocatorTest,UnorderedMultiMap)174 TEST(AsPmrAllocatorTest, UnorderedMultiMap) {
175 // Some implementations preallocate a lot of memory.
176 TestPmrAllocator<pw::pmr::unordered_multimap<Foo, Bar>, 1024>();
177 }
178
179 } // namespace
180