• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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