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 <cstdint>
16
17 #include "pw_compilation_testing/negative_compilation.h"
18 #include "pw_containers/intrusive_forward_list.h"
19 #include "pw_containers/intrusive_list.h"
20 #include "pw_containers/intrusive_map.h"
21 #include "pw_containers/intrusive_multimap.h"
22 #include "pw_containers/intrusive_multiset.h"
23 #include "pw_containers/intrusive_set.h"
24 #include "pw_unit_test/framework.h"
25
26 namespace {
27
28 using pw::IntrusiveForwardList;
29 using pw::IntrusiveMap;
30 using pw::IntrusiveMultiMap;
31 using pw::IntrusiveMultiSet;
32 using pw::IntrusiveSet;
33 using pw::containers::future::IntrusiveList;
34
35 struct ForwardListItem1 : public IntrusiveForwardList<ForwardListItem1>::Item {
36 };
37 struct ForwardListItem2 : public IntrusiveForwardList<ForwardListItem2>::Item {
38 };
39 struct ListItem1 : public IntrusiveList<ListItem1>::Item {};
40 struct ListItem2 : public IntrusiveList<ListItem2>::Item {};
41
42 struct MapPair1 : public IntrusiveMap<uint32_t, MapPair1>::Pair {
MapPair1__anon2a4d2c500111::MapPair143 explicit MapPair1(uint32_t id) : IntrusiveMap<uint32_t, MapPair1>::Pair(id) {}
44 };
45 struct MapPair2 : public IntrusiveMap<uint32_t, MapPair2>::Pair {
MapPair2__anon2a4d2c500111::MapPair246 explicit MapPair2(uint32_t id) : IntrusiveMap<uint32_t, MapPair2>::Pair(id) {}
47 };
48 struct MultiMapPair1 : public IntrusiveMultiMap<uint32_t, MultiMapPair1>::Pair {
MultiMapPair1__anon2a4d2c500111::MultiMapPair149 explicit MultiMapPair1(uint32_t id)
50 : IntrusiveMultiMap<uint32_t, MultiMapPair1>::Pair(id) {}
51 };
52 struct MultiMapPair2 : public IntrusiveMultiMap<uint32_t, MultiMapPair2>::Pair {
MultiMapPair2__anon2a4d2c500111::MultiMapPair253 explicit MultiMapPair2(uint32_t id)
54 : IntrusiveMultiMap<uint32_t, MultiMapPair2>::Pair(id) {}
55 };
56
57 struct SetItem1 : public IntrusiveSet<SetItem1>::Item {
operator <__anon2a4d2c500111::SetItem158 bool operator<(const SetItem1& rhs) const { return this < &rhs; }
59 };
60 struct SetItem2 : public IntrusiveSet<SetItem2>::Item {
operator <__anon2a4d2c500111::SetItem261 bool operator<(const SetItem2& rhs) const { return this < &rhs; }
62 };
63 struct MultiSetItem1 : public IntrusiveMultiSet<MultiSetItem1>::Item {
operator <__anon2a4d2c500111::MultiSetItem164 bool operator<(const MultiSetItem1& rhs) const { return this < &rhs; }
65 };
66 struct MultiSetItem2 : public IntrusiveMultiSet<MultiSetItem2>::Item {
operator <__anon2a4d2c500111::MultiSetItem267 bool operator<(const MultiSetItem2& rhs) const { return this < &rhs; }
68 };
69
70 class Base {
71 public:
Base(const char * name)72 explicit constexpr Base(const char* name) : name_(name) {}
name() const73 constexpr const char* name() const { return name_; }
74
75 private:
76 const char* name_;
77 };
78
79 class Derived : public Base,
80 public ForwardListItem1,
81 public ForwardListItem2,
82 public ListItem1,
83 public ListItem2,
84 public MapPair1,
85 public MapPair2,
86 public MultiMapPair1,
87 public MultiMapPair2,
88 public SetItem1,
89 public SetItem2,
90 public MultiSetItem1,
91 public MultiSetItem2 {
92 public:
Derived(const char * name,uint32_t id)93 Derived(const char* name, uint32_t id)
94 : Base(name),
95 MapPair1(id),
96 MapPair2(id),
97 MultiMapPair1(id),
98 MultiMapPair2(id) {}
99 };
100
TEST(IntrusiveItemTest,AddToEachContainerSequentially)101 TEST(IntrusiveItemTest, AddToEachContainerSequentially) {
102 Derived item("a", 1);
103
104 IntrusiveForwardList<ForwardListItem1> forward_list1;
105 IntrusiveForwardList<ForwardListItem2> forward_list2;
106 IntrusiveList<ListItem1> list1;
107 IntrusiveList<ListItem2> list2;
108 IntrusiveMap<uint32_t, MapPair1> map1;
109 IntrusiveMap<uint32_t, MapPair2> map2;
110 IntrusiveMultiMap<uint32_t, MultiMapPair1> multimap1;
111 IntrusiveMultiMap<uint32_t, MultiMapPair2> multimap2;
112 IntrusiveSet<SetItem1> set1;
113 IntrusiveSet<SetItem2> set2;
114 IntrusiveMultiSet<MultiSetItem1> multiset1;
115 IntrusiveMultiSet<MultiSetItem2> multiset2;
116
117 forward_list1.push_front(item);
118 forward_list1.clear();
119
120 forward_list2.push_front(item);
121 forward_list2.clear();
122
123 list1.push_back(item);
124 list1.clear();
125
126 list2.push_back(item);
127 list2.clear();
128
129 map1.insert(item);
130 map1.clear();
131
132 map2.insert(item);
133 map2.clear();
134
135 multimap1.insert(item);
136 multimap1.clear();
137
138 multimap2.insert(item);
139 multimap2.clear();
140
141 set1.insert(item);
142 set1.clear();
143
144 set2.insert(item);
145 set2.clear();
146
147 multiset1.insert(item);
148 multiset1.clear();
149
150 multiset2.insert(item);
151 multiset2.clear();
152 }
153
TEST(IntrusiveItemTest,AddToEachContainerSimultaneousy)154 TEST(IntrusiveItemTest, AddToEachContainerSimultaneousy) {
155 Derived item("a", 1);
156
157 IntrusiveForwardList<ForwardListItem1> forward_list1;
158 IntrusiveForwardList<ForwardListItem2> forward_list2;
159 IntrusiveList<ListItem1> list1;
160 IntrusiveList<ListItem2> list2;
161 IntrusiveMap<uint32_t, MapPair1> map1;
162 IntrusiveMap<uint32_t, MapPair2> map2;
163 IntrusiveMultiMap<uint32_t, MultiMapPair1> multimap1;
164 IntrusiveMultiMap<uint32_t, MultiMapPair2> multimap2;
165 IntrusiveSet<SetItem1> set1;
166 IntrusiveSet<SetItem2> set2;
167 IntrusiveMultiSet<MultiSetItem1> multiset1;
168 IntrusiveMultiSet<MultiSetItem2> multiset2;
169
170 forward_list1.push_front(item);
171 list1.push_back(item);
172 map1.insert(item);
173 multimap1.insert(item);
174 set1.insert(item);
175 multiset1.insert(item);
176
177 forward_list1.clear();
178 list1.clear();
179 map1.clear();
180 multimap1.clear();
181 set1.clear();
182 multiset1.clear();
183
184 forward_list2.push_front(item);
185 list2.push_back(item);
186 map2.insert(item);
187 multimap2.insert(item);
188 set2.insert(item);
189 multiset2.insert(item);
190
191 forward_list2.clear();
192 list2.clear();
193 map2.clear();
194 multimap2.clear();
195 set2.clear();
196 multiset2.clear();
197 }
198
199 #if PW_NC_TEST(ForwardListValueTypeHasMultipleBases)
200 PW_NC_EXPECT_CLANG(
201 "member 'ItemType' found in multiple base classes of different types");
202 PW_NC_EXPECT_GCC("lookup of 'ItemType' in '{anonymous}::Derived' is ambiguous");
203 [[maybe_unused]] IntrusiveForwardList<Derived> bad_fwd_list;
204
205 #elif PW_NC_TEST(ListValueTypeHasMultipleBases)
206 PW_NC_EXPECT_CLANG(
207 "member 'ItemType' found in multiple base classes of different types");
208 PW_NC_EXPECT_GCC("lookup of 'ItemType' in '{anonymous}::Derived' is ambiguous");
209 [[maybe_unused]] IntrusiveList<Derived> bad_list;
210
211 #elif PW_NC_TEST(MapValueTypeHasMultipleBases)
212 PW_NC_EXPECT_CLANG(
213 "member 'key' found in multiple base classes of different types");
214 PW_NC_EXPECT_GCC("request for member 'key' is ambiguous");
215 [[maybe_unused]] IntrusiveMap<uint32_t, Derived> bad_map;
216
217 #elif PW_NC_TEST(MultiMapValueTypeHasMultipleBases)
218 PW_NC_EXPECT_CLANG(
219 "member 'key' found in multiple base classes of different types");
220 PW_NC_EXPECT_GCC("request for member 'key' is ambiguous");
221 [[maybe_unused]] IntrusiveMultiMap<uint32_t, Derived> bad_multimap;
222
223 #elif PW_NC_TEST(SetValueTypeHasMultipleBases)
224 PW_NC_EXPECT_CLANG(
225 "member 'ItemType' found in multiple base classes of different types");
226 PW_NC_EXPECT_GCC("lookup of 'ItemType' in '{anonymous}::Derived' is ambiguous");
227 [[maybe_unused]] IntrusiveSet<Derived> bad_set([](const Derived& lhs,
__anon2a4d2c500202(const Derived& lhs, const Derived& rhs) 228 const Derived& rhs) {
229 return &lhs < &rhs;
230 });
231
232 #elif PW_NC_TEST(MultiSetValueTypeHasMultipleBases)
233 PW_NC_EXPECT_CLANG(
234 "member 'ItemType' found in multiple base classes of different types");
235 PW_NC_EXPECT_GCC("lookup of 'ItemType' in '{anonymous}::Derived' is ambiguous");
236 [[maybe_unused]] IntrusiveMultiSet<Derived> bad_multiset(
__anon2a4d2c500302(const Derived& lhs, const Derived& rhs) 237 [](const Derived& lhs, const Derived& rhs) { return &lhs < &rhs; });
238
239 #endif // PW_NC_TEST
240
241 } // namespace
242