1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <algorithm>
18 #include <forward_list>
19 #include <vector>
20
21 #include "gtest/gtest.h"
22 #include "intrusive_forward_list.h"
23
24 namespace art {
25
26 struct IFLTestValue : public IntrusiveForwardListNode<IFLTestValue> {
27 // Deliberately not explicit.
IFLTestValueart::IFLTestValue28 IFLTestValue(int v) : value(v) { } // NOLINT(runtime/explicit)
29
30 int value;
31 };
32 using IFLTestValueList = IntrusiveForwardList<IFLTestValue>;
33 using ConstIFLTestValueList = IntrusiveForwardList<const IFLTestValue>;
34
operator ==(const IFLTestValue & lhs,const IFLTestValue & rhs)35 bool operator==(const IFLTestValue& lhs, const IFLTestValue& rhs) {
36 return lhs.value == rhs.value;
37 }
38
operator <(const IFLTestValue & lhs,const IFLTestValue & rhs)39 bool operator<(const IFLTestValue& lhs, const IFLTestValue& rhs) {
40 return lhs.value < rhs.value;
41 }
42
43 struct IFLTestValue2 {
44 // Deliberately not explicit.
IFLTestValue2art::IFLTestValue245 IFLTestValue2(int v) : hook(), value(v) { } // NOLINT(runtime/explicit)
46
47 IntrusiveForwardListHook hook;
48 int value;
49 };
50 using IFLTestValue2List =
51 IntrusiveForwardList<IFLTestValue2, IntrusiveForwardListMemberHookTraits<IFLTestValue2>>;
52
operator ==(const IFLTestValue2 & lhs,const IFLTestValue2 & rhs)53 bool operator==(const IFLTestValue2& lhs, const IFLTestValue2& rhs) {
54 return lhs.value == rhs.value;
55 }
56
operator <(const IFLTestValue2 & lhs,const IFLTestValue2 & rhs)57 bool operator<(const IFLTestValue2& lhs, const IFLTestValue2& rhs) {
58 return lhs.value < rhs.value;
59 }
60
61 #define ASSERT_LISTS_EQUAL(expected, value) \
62 do { \
63 ASSERT_EQ((expected).empty(), (value).empty()); \
64 ASSERT_EQ(std::distance((expected).begin(), (expected).end()), \
65 std::distance((value).begin(), (value).end())); \
66 ASSERT_TRUE(std::equal((expected).begin(), (expected).end(), (value).begin())); \
67 } while (false)
68
69 class IntrusiveForwardListTest : public testing::Test {
70 public:
71 template <typename ListType>
72 void IteratorToConstIterator();
73
74 template <typename ListType>
75 void IteratorOperators();
76
77 template <typename ListType>
78 void ConstructRange();
79
80 template <typename ListType>
81 void Assign();
82
83 template <typename ListType>
84 void PushPop();
85
86 template <typename ListType>
87 void InsertAfter1();
88
89 template <typename ListType>
90 void InsertAfter2();
91
92 template <typename ListType>
93 void EraseAfter1();
94
95 template <typename ListType>
96 void EraseAfter2();
97
98 template <typename ListType>
99 void SwapClear();
100
101 template <typename ListType>
102 void SpliceAfter();
103
104 template <typename ListType>
105 void Remove();
106
107 template <typename ListType>
108 void Unique();
109
110 template <typename ListType>
111 void Merge();
112
113 template <typename ListType>
114 void Sort1();
115
116 template <typename ListType>
117 void Sort2();
118
119 template <typename ListType>
120 void Reverse();
121
122 template <typename ListType>
123 void ModifyValue();
124 };
125
126 template <typename ListType>
IteratorToConstIterator()127 void IntrusiveForwardListTest::IteratorToConstIterator() {
128 ListType ifl;
129 typename ListType::iterator begin = ifl.begin();
130 typename ListType::const_iterator cbegin = ifl.cbegin();
131 typename ListType::const_iterator converted_begin = begin;
132 ASSERT_TRUE(converted_begin == cbegin);
133 }
134
TEST_F(IntrusiveForwardListTest,IteratorToConstIterator)135 TEST_F(IntrusiveForwardListTest, IteratorToConstIterator) {
136 IteratorToConstIterator<IFLTestValueList>();
137 IteratorToConstIterator<ConstIFLTestValueList>();
138 IteratorToConstIterator<IFLTestValue2List>();
139 }
140
141 template <typename ListType>
IteratorOperators()142 void IntrusiveForwardListTest::IteratorOperators() {
143 using ValueType = typename ListType::value_type;
144 ListType ifl;
145 ASSERT_TRUE(ifl.begin() == ifl.cbegin());
146 ASSERT_FALSE(ifl.begin() != ifl.cbegin());
147 ASSERT_TRUE(ifl.end() == ifl.cend());
148 ASSERT_FALSE(ifl.end() != ifl.cend());
149
150 ASSERT_TRUE(ifl.begin() == ifl.end()); // Empty.
151 ASSERT_FALSE(ifl.begin() != ifl.end()); // Empty.
152
153 ValueType value(1);
154 ifl.insert_after(ifl.cbefore_begin(), value);
155
156 ASSERT_FALSE(ifl.begin() == ifl.end()); // Not empty.
157 ASSERT_TRUE(ifl.begin() != ifl.end()); // Not empty.
158 }
159
TEST_F(IntrusiveForwardListTest,IteratorOperators)160 TEST_F(IntrusiveForwardListTest, IteratorOperators) {
161 IteratorOperators<IFLTestValueList>();
162 IteratorOperators<ConstIFLTestValueList>();
163 IteratorOperators<IFLTestValue2List>();
164 }
165
166 template <typename ListType>
ConstructRange()167 void IntrusiveForwardListTest::ConstructRange() {
168 using ValueType = typename ListType::value_type;
169 std::forward_list<int> ref({ 1, 2, 7 });
170 std::vector<ValueType> storage(ref.begin(), ref.end());
171 ListType ifl(storage.begin(), storage.end());
172 ASSERT_LISTS_EQUAL(ref, ifl);
173 }
174
TEST_F(IntrusiveForwardListTest,ConstructRange)175 TEST_F(IntrusiveForwardListTest, ConstructRange) {
176 ConstructRange<IFLTestValueList>();
177 ConstructRange<ConstIFLTestValueList>();
178 ConstructRange<IFLTestValue2List>();
179 }
180
181 template <typename ListType>
Assign()182 void IntrusiveForwardListTest::Assign() {
183 using ValueType = typename ListType::value_type;
184 std::forward_list<int> ref1({ 2, 8, 5 });
185 std::vector<ValueType> storage1(ref1.begin(), ref1.end());
186 ListType ifl;
187 ifl.assign(storage1.begin(), storage1.end());
188 ASSERT_LISTS_EQUAL(ref1, ifl);
189 std::forward_list<int> ref2({ 7, 1, 3 });
190 std::vector<ValueType> storage2(ref2.begin(), ref2.end());
191 ifl.assign(storage2.begin(), storage2.end());
192 ASSERT_LISTS_EQUAL(ref2, ifl);
193 }
194
TEST_F(IntrusiveForwardListTest,Assign)195 TEST_F(IntrusiveForwardListTest, Assign) {
196 Assign<IFLTestValueList>();
197 Assign<ConstIFLTestValueList>();
198 Assign<IFLTestValue2List>();
199 }
200
201 template <typename ListType>
PushPop()202 void IntrusiveForwardListTest::PushPop() {
203 using ValueType = typename ListType::value_type;
204 ValueType value3(3);
205 ValueType value7(7);
206 std::forward_list<int> ref;
207 ListType ifl;
208 ASSERT_LISTS_EQUAL(ref, ifl);
209 ref.push_front(3);
210 ifl.push_front(value3);
211 ASSERT_LISTS_EQUAL(ref, ifl);
212 ASSERT_EQ(3, ifl.front());
213 ref.push_front(7);
214 ifl.push_front(value7);
215 ASSERT_LISTS_EQUAL(ref, ifl);
216 ASSERT_EQ(7, ifl.front());
217 ref.pop_front();
218 ifl.pop_front();
219 ASSERT_LISTS_EQUAL(ref, ifl);
220 ASSERT_EQ(3, ifl.front());
221 ref.pop_front();
222 ifl.pop_front();
223 ASSERT_LISTS_EQUAL(ref, ifl);
224 }
225
TEST_F(IntrusiveForwardListTest,PushPop)226 TEST_F(IntrusiveForwardListTest, PushPop) {
227 PushPop<IFLTestValueList>();
228 PushPop<ConstIFLTestValueList>();
229 PushPop<IFLTestValue2List>();
230 }
231
232 template <typename ListType>
InsertAfter1()233 void IntrusiveForwardListTest::InsertAfter1() {
234 using ValueType = typename ListType::value_type;
235 ValueType value4(4);
236 ValueType value8(8);
237 ValueType value5(5);
238 ValueType value3(3);
239 std::forward_list<int> ref;
240 ListType ifl;
241
242 auto ref_it = ref.insert_after(ref.before_begin(), 4);
243 auto ifl_it = ifl.insert_after(ifl.before_begin(), value4);
244 ASSERT_LISTS_EQUAL(ref, ifl);
245 ASSERT_EQ(*ref_it, *ifl_it);
246 CHECK(ref_it == ref.begin());
247 ASSERT_TRUE(ifl_it == ifl.begin());
248
249 ref_it = ref.insert_after(ref.begin(), 8);
250 ifl_it = ifl.insert_after(ifl.begin(), value8);
251 ASSERT_LISTS_EQUAL(ref, ifl);
252 ASSERT_EQ(*ref_it, *ifl_it);
253 CHECK(ref_it != ref.end());
254 ASSERT_TRUE(ifl_it != ifl.end());
255 CHECK(++ref_it == ref.end());
256 ASSERT_TRUE(++ifl_it == ifl.end());
257
258 ref_it = ref.insert_after(ref.begin(), 5);
259 ifl_it = ifl.insert_after(ifl.begin(), value5);
260 ASSERT_LISTS_EQUAL(ref, ifl);
261 ASSERT_EQ(*ref_it, *ifl_it);
262
263 ref_it = ref.insert_after(ref_it, 3);
264 ifl_it = ifl.insert_after(ifl_it, value3);
265 ASSERT_LISTS_EQUAL(ref, ifl);
266 ASSERT_EQ(*ref_it, *ifl_it);
267 }
268
TEST_F(IntrusiveForwardListTest,InsertAfter1)269 TEST_F(IntrusiveForwardListTest, InsertAfter1) {
270 InsertAfter1<IFLTestValueList>();
271 InsertAfter1<ConstIFLTestValueList>();
272 InsertAfter1<IFLTestValue2List>();
273 }
274
275 template <typename ListType>
InsertAfter2()276 void IntrusiveForwardListTest::InsertAfter2() {
277 using ValueType = typename ListType::value_type;
278 std::forward_list<int> ref;
279 ListType ifl;
280
281 auto ref_it = ref.insert_after(ref.before_begin(), { 2, 8, 5 });
282 std::vector<ValueType> storage1({ { 2 }, { 8 }, { 5 } });
283 auto ifl_it = ifl.insert_after(ifl.before_begin(), storage1.begin(), storage1.end());
284 ASSERT_LISTS_EQUAL(ref, ifl);
285 ASSERT_EQ(*ref_it, *ifl_it);
286
287 std::vector<ValueType> storage2({ { 7 }, { 2 } });
288 ref_it = ref.insert_after(ref.begin(), { 7, 2 });
289 ifl_it = ifl.insert_after(ifl.begin(), storage2.begin(), storage2.end());
290 ASSERT_LISTS_EQUAL(ref, ifl);
291 ASSERT_EQ(*ref_it, *ifl_it);
292
293 std::vector<ValueType> storage3({ { 1 }, { 3 }, { 4 }, { 9 } });
294 ref_it = ref.begin();
295 ifl_it = ifl.begin();
296 std::advance(ref_it, std::distance(ref.begin(), ref.end()) - 1);
297 std::advance(ifl_it, std::distance(ifl.begin(), ifl.end()) - 1);
298 ref_it = ref.insert_after(ref_it, { 1, 3, 4, 9 });
299 ifl_it = ifl.insert_after(ifl_it, storage3.begin(), storage3.end());
300 ASSERT_LISTS_EQUAL(ref, ifl);
301 }
302
TEST_F(IntrusiveForwardListTest,InsertAfter2)303 TEST_F(IntrusiveForwardListTest, InsertAfter2) {
304 InsertAfter2<IFLTestValueList>();
305 InsertAfter2<ConstIFLTestValueList>();
306 InsertAfter2<IFLTestValue2List>();
307 }
308
309 template <typename ListType>
EraseAfter1()310 void IntrusiveForwardListTest::EraseAfter1() {
311 using ValueType = typename ListType::value_type;
312 std::forward_list<int> ref({ 1, 2, 7, 4, 5 });
313 std::vector<ValueType> storage(ref.begin(), ref.end());
314 ListType ifl(storage.begin(), storage.end());
315 ASSERT_LISTS_EQUAL(ref, ifl);
316 CHECK_EQ(std::distance(ref.begin(), ref.end()), 5);
317
318 auto ref_it = ref.begin();
319 auto ifl_it = ifl.begin();
320 std::advance(ref_it, 2);
321 std::advance(ifl_it, 2);
322 ref_it = ref.erase_after(ref_it);
323 ifl_it = ifl.erase_after(ifl_it);
324 ASSERT_LISTS_EQUAL(ref, ifl);
325 CHECK_EQ(std::distance(ref.begin(), ref.end()), 4);
326 CHECK(ref_it != ref.end());
327 ASSERT_TRUE(ifl_it != ifl.end());
328 CHECK(++ref_it == ref.end());
329 ASSERT_TRUE(++ifl_it == ifl.end());
330
331 ref_it = ref.begin();
332 ifl_it = ifl.begin();
333 std::advance(ref_it, 2);
334 std::advance(ifl_it, 2);
335 ref_it = ref.erase_after(ref_it);
336 ifl_it = ifl.erase_after(ifl_it);
337 ASSERT_LISTS_EQUAL(ref, ifl);
338 CHECK_EQ(std::distance(ref.begin(), ref.end()), 3);
339 CHECK(ref_it == ref.end());
340 ASSERT_TRUE(ifl_it == ifl.end());
341
342 ref_it = ref.erase_after(ref.begin());
343 ifl_it = ifl.erase_after(ifl.begin());
344 ASSERT_LISTS_EQUAL(ref, ifl);
345 CHECK_EQ(std::distance(ref.begin(), ref.end()), 2);
346 CHECK(ref_it != ref.end());
347 ASSERT_TRUE(ifl_it != ifl.end());
348 CHECK(++ref_it == ref.end());
349 ASSERT_TRUE(++ifl_it == ifl.end());
350
351 ref_it = ref.erase_after(ref.before_begin());
352 ifl_it = ifl.erase_after(ifl.before_begin());
353 ASSERT_LISTS_EQUAL(ref, ifl);
354 CHECK_EQ(std::distance(ref.begin(), ref.end()), 1);
355 CHECK(ref_it == ref.begin());
356 ASSERT_TRUE(ifl_it == ifl.begin());
357
358 ref_it = ref.erase_after(ref.before_begin());
359 ifl_it = ifl.erase_after(ifl.before_begin());
360 ASSERT_LISTS_EQUAL(ref, ifl);
361 CHECK_EQ(std::distance(ref.begin(), ref.end()), 0);
362 CHECK(ref_it == ref.begin());
363 ASSERT_TRUE(ifl_it == ifl.begin());
364 }
365
TEST_F(IntrusiveForwardListTest,EraseAfter1)366 TEST_F(IntrusiveForwardListTest, EraseAfter1) {
367 EraseAfter1<IFLTestValueList>();
368 EraseAfter1<ConstIFLTestValueList>();
369 EraseAfter1<IFLTestValue2List>();
370 }
371
372 template <typename ListType>
EraseAfter2()373 void IntrusiveForwardListTest::EraseAfter2() {
374 using ValueType = typename ListType::value_type;
375 std::forward_list<int> ref({ 1, 2, 7, 4, 5, 3, 2, 8, 9 });
376 std::vector<ValueType> storage(ref.begin(), ref.end());
377 ListType ifl(storage.begin(), storage.end());
378 ASSERT_LISTS_EQUAL(ref, ifl);
379 CHECK_EQ(std::distance(ref.begin(), ref.end()), 9);
380
381 auto ref_it = ref.begin();
382 auto ifl_it = ifl.begin();
383 std::advance(ref_it, 3);
384 std::advance(ifl_it, 3);
385 ref_it = ref.erase_after(ref.begin(), ref_it);
386 ifl_it = ifl.erase_after(ifl.begin(), ifl_it);
387 ASSERT_LISTS_EQUAL(ref, ifl);
388 ASSERT_EQ(std::distance(ref.begin(), ref_it), std::distance(ifl.begin(), ifl_it));
389 CHECK_EQ(std::distance(ref.begin(), ref.end()), 7);
390
391 ref_it = ref.erase_after(ref_it, ref.end());
392 ifl_it = ifl.erase_after(ifl_it, ifl.end());
393 ASSERT_LISTS_EQUAL(ref, ifl);
394 CHECK(ref_it == ref.end());
395 ASSERT_TRUE(ifl_it == ifl.end());
396 CHECK_EQ(std::distance(ref.begin(), ref.end()), 2);
397
398 ref_it = ref.erase_after(ref.before_begin(), ref.end());
399 ifl_it = ifl.erase_after(ifl.before_begin(), ifl.end());
400 ASSERT_LISTS_EQUAL(ref, ifl);
401 CHECK(ref_it == ref.end());
402 ASSERT_TRUE(ifl_it == ifl.end());
403 CHECK_EQ(std::distance(ref.begin(), ref.end()), 0);
404 }
405
TEST_F(IntrusiveForwardListTest,EraseAfter2)406 TEST_F(IntrusiveForwardListTest, EraseAfter2) {
407 EraseAfter2<IFLTestValueList>();
408 EraseAfter2<ConstIFLTestValueList>();
409 EraseAfter2<IFLTestValue2List>();
410 }
411
412 template <typename ListType>
SwapClear()413 void IntrusiveForwardListTest::SwapClear() {
414 using ValueType = typename ListType::value_type;
415 std::forward_list<int> ref1({ 1, 2, 7 });
416 std::vector<ValueType> storage1(ref1.begin(), ref1.end());
417 ListType ifl1(storage1.begin(), storage1.end());
418 std::forward_list<int> ref2({ 3, 8, 6 });
419 std::vector<ValueType> storage2(ref2.begin(), ref2.end());
420 ListType ifl2(storage2.begin(), storage2.end());
421 ASSERT_LISTS_EQUAL(ref1, ifl1);
422 ASSERT_LISTS_EQUAL(ref2, ifl2);
423 ref1.swap(ref2);
424 ifl1.swap(ifl2);
425 ASSERT_LISTS_EQUAL(ref1, ifl1);
426 ASSERT_LISTS_EQUAL(ref2, ifl2);
427 ref1.clear();
428 ifl1.clear();
429 ASSERT_LISTS_EQUAL(ref1, ifl1);
430 ASSERT_LISTS_EQUAL(ref2, ifl2);
431 swap(ref1, ref2);
432 swap(ifl1, ifl2);
433 ASSERT_LISTS_EQUAL(ref1, ifl1);
434 ASSERT_LISTS_EQUAL(ref2, ifl2);
435 ref1.clear();
436 ifl1.clear();
437 ASSERT_LISTS_EQUAL(ref1, ifl1);
438 ASSERT_LISTS_EQUAL(ref2, ifl2);
439 }
440
TEST_F(IntrusiveForwardListTest,SwapClear)441 TEST_F(IntrusiveForwardListTest, SwapClear) {
442 SwapClear<IFLTestValueList>();
443 SwapClear<ConstIFLTestValueList>();
444 SwapClear<IFLTestValue2List>();
445 }
446
447 template <typename ListType>
SpliceAfter()448 void IntrusiveForwardListTest::SpliceAfter() {
449 using ValueType = typename ListType::value_type;
450 std::forward_list<int> ref1({ 3, 1, 2, 7, 4, 5, 4, 8, 7 });
451 std::forward_list<int> ref2;
452 std::vector<ValueType> storage(ref1.begin(), ref1.end());
453 ListType ifl1(storage.begin(), storage.end());
454 ListType ifl2;
455 ASSERT_LISTS_EQUAL(ref1, ifl1);
456 ASSERT_LISTS_EQUAL(ref2, ifl2);
457
458 // Move everything to ref2/ifl2.
459 ref2.splice_after(ref2.before_begin(), ref1);
460 ifl2.splice_after(ifl2.before_begin(), ifl1);
461 ASSERT_LISTS_EQUAL(ref1, ifl1);
462 ASSERT_LISTS_EQUAL(ref2, ifl2);
463
464 // Move first element (3) to ref1/ifl1.
465 ref1.splice_after(ref1.before_begin(), ref2, ref2.before_begin());
466 ifl1.splice_after(ifl1.before_begin(), ifl2, ifl2.before_begin());
467 ASSERT_LISTS_EQUAL(ref1, ifl1);
468 ASSERT_LISTS_EQUAL(ref2, ifl2);
469
470 // Move second element (2) to ref1/ifl1 after the first element (3).
471 ref1.splice_after(ref1.begin(), ref2, ref2.begin());
472 ifl1.splice_after(ifl1.begin(), ifl2, ifl2.begin());
473 ASSERT_LISTS_EQUAL(ref1, ifl1);
474 ASSERT_LISTS_EQUAL(ref2, ifl2);
475
476 // Move everything from ref2/ifl2 between the 2 elements now in ref1/ifl1.
477 ref1.splice_after(ref1.begin(), ref2);
478 ifl1.splice_after(ifl1.begin(), ifl2);
479 ASSERT_LISTS_EQUAL(ref1, ifl1);
480 ASSERT_LISTS_EQUAL(ref2, ifl2);
481
482 std::forward_list<int> check({ 3, 1, 7, 4, 5, 4, 8, 7, 2 });
483 ASSERT_LISTS_EQUAL(check, ifl1);
484 ASSERT_TRUE(ifl2.empty());
485
486 // Empty splice_after().
487 ref2.splice_after(
488 ref2.before_begin(), ref1, ref1.before_begin(), ref1.begin());
489 ifl2.splice_after(ifl2.before_begin(), ifl1, ifl1.before_begin(), ifl1.begin());
490 ASSERT_LISTS_EQUAL(ref1, ifl1);
491 ASSERT_LISTS_EQUAL(ref2, ifl2);
492
493 // Move { 1, 7 } to ref2/ifl2.
494 auto ref_it = ref1.begin();
495 auto ifl_it = ifl1.begin();
496 std::advance(ref_it, 3);
497 std::advance(ifl_it, 3);
498 ref2.splice_after(ref2.before_begin(), ref1, ref1.begin(), ref_it);
499 ifl2.splice_after(ifl2.before_begin(), ifl1, ifl1.begin(), ifl_it);
500 ASSERT_LISTS_EQUAL(ref1, ifl1);
501 ASSERT_LISTS_EQUAL(ref2, ifl2);
502
503 // Move { 8, 7, 2 } to the beginning of ref1/ifl1.
504 ref_it = ref1.begin();
505 ifl_it = ifl1.begin();
506 std::advance(ref_it, 3);
507 std::advance(ifl_it, 3);
508 ref1.splice_after(ref1.before_begin(), ref1, ref_it, ref1.end());
509 ifl1.splice_after(ifl1.before_begin(), ifl1, ifl_it, ifl1.end());
510 ASSERT_LISTS_EQUAL(ref1, ifl1);
511
512 check.assign({ 8, 7, 2, 3, 4, 5, 4 });
513 ASSERT_LISTS_EQUAL(check, ifl1);
514 check.assign({ 1, 7 });
515 ASSERT_LISTS_EQUAL(check, ifl2);
516
517 // Move all but the first element to ref2/ifl2.
518 ref_it = ref2.begin();
519 ifl_it = ifl2.begin();
520 std::advance(ref_it, 1);
521 std::advance(ifl_it, 1);
522 ref2.splice_after(ref_it, ref1, ref1.begin(), ref1.end());
523 ifl2.splice_after(ifl_it, ifl1, ifl1.begin(), ifl1.end());
524 ASSERT_LISTS_EQUAL(ref1, ifl1);
525 ASSERT_LISTS_EQUAL(ref2, ifl2);
526
527 check.assign({8});
528 ASSERT_LISTS_EQUAL(check, ifl1);
529
530 // Move the first element of ref1/ifl1 to the beginning of ref1/ifl1 (do nothing).
531 ref1.splice_after(ref1.before_begin(), ref1, ref1.before_begin());
532 ifl1.splice_after(ifl1.before_begin(), ifl1, ifl1.before_begin());
533 ASSERT_LISTS_EQUAL(ref1, ifl1);
534 ASSERT_LISTS_EQUAL(check, ifl1);
535
536 // Move the first element of ref2/ifl2 after itself (do nothing).
537 ref1.splice_after(ref1.begin(), ref1, ref1.before_begin());
538 ifl1.splice_after(ifl1.begin(), ifl1, ifl1.before_begin());
539 ASSERT_LISTS_EQUAL(ref1, ifl1);
540 ASSERT_LISTS_EQUAL(check, ifl1);
541
542 check.assign({ 1, 7, 7, 2, 3, 4, 5, 4 });
543 ASSERT_LISTS_EQUAL(check, ifl2);
544
545 // Move the first element of ref2/ifl2 to the beginning of ref2/ifl2 (do nothing).
546 ref2.splice_after(ref2.before_begin(), ref2, ref2.before_begin());
547 ifl2.splice_after(ifl2.before_begin(), ifl2, ifl2.before_begin());
548 ASSERT_LISTS_EQUAL(ref2, ifl2);
549 ASSERT_LISTS_EQUAL(check, ifl2);
550
551 // Move the first element of ref2/ifl2 after itself (do nothing).
552 ref2.splice_after(ref2.begin(), ref2, ref2.before_begin());
553 ifl2.splice_after(ifl2.begin(), ifl2, ifl2.before_begin());
554 ASSERT_LISTS_EQUAL(ref2, ifl2);
555 ASSERT_LISTS_EQUAL(check, ifl2);
556 }
557
TEST_F(IntrusiveForwardListTest,SpliceAfter)558 TEST_F(IntrusiveForwardListTest, SpliceAfter) {
559 SpliceAfter<IFLTestValueList>();
560 SpliceAfter<ConstIFLTestValueList>();
561 SpliceAfter<IFLTestValue2List>();
562 }
563
564 template <typename ListType>
Remove()565 void IntrusiveForwardListTest::Remove() {
566 using ValueType = typename ListType::value_type;
567 std::forward_list<int> ref({ 3, 1, 2, 7, 4, 5, 4, 8, 7 });
568 std::vector<ValueType> storage(ref.begin(), ref.end());
569 ListType ifl(storage.begin(), storage.end());
570 ASSERT_LISTS_EQUAL(ref, ifl);
571 ref.remove(1);
572 ifl.remove(1);
573 ASSERT_LISTS_EQUAL(ref, ifl);
574 ref.remove(4);
575 ifl.remove(4);
576 ASSERT_LISTS_EQUAL(ref, ifl);
577 auto odd = [](ValueType value) { return (value.value & 1) != 0; };
578 ref.remove_if(odd);
579 ifl.remove_if(odd);
580 ASSERT_LISTS_EQUAL(ref, ifl);
581 auto all = [](ValueType value ATTRIBUTE_UNUSED) { return true; };
582 ref.remove_if(all);
583 ifl.remove_if(all);
584 ASSERT_LISTS_EQUAL(ref, ifl);
585 }
586
TEST_F(IntrusiveForwardListTest,Remove)587 TEST_F(IntrusiveForwardListTest, Remove) {
588 Remove<IFLTestValueList>();
589 Remove<ConstIFLTestValueList>();
590 Remove<IFLTestValue2List>();
591 }
592
593 template <typename ListType>
Unique()594 void IntrusiveForwardListTest::Unique() {
595 using ValueType = typename ListType::value_type;
596 std::forward_list<int> ref({ 3, 1, 1, 2, 3, 3, 7, 7, 4, 4, 5, 7 });
597 std::vector<ValueType> storage(ref.begin(), ref.end());
598 ListType ifl(storage.begin(), storage.end());
599 ASSERT_LISTS_EQUAL(ref, ifl);
600 ref.unique();
601 ifl.unique();
602 ASSERT_LISTS_EQUAL(ref, ifl);
603 std::forward_list<int> check({ 3, 1, 2, 3, 7, 4, 5, 7 });
604 ASSERT_LISTS_EQUAL(check, ifl);
605
606 auto bin_pred = [](const ValueType& lhs, const ValueType& rhs) {
607 return (lhs.value & ~1) == (rhs.value & ~1);
608 };
609 ref.unique(bin_pred);
610 ifl.unique(bin_pred);
611 ASSERT_LISTS_EQUAL(ref, ifl);
612 check.assign({ 3, 1, 2, 7, 4, 7 });
613 ASSERT_LISTS_EQUAL(check, ifl);
614 }
615
TEST_F(IntrusiveForwardListTest,Unique)616 TEST_F(IntrusiveForwardListTest, Unique) {
617 Unique<IFLTestValueList>();
618 Unique<ConstIFLTestValueList>();
619 Unique<IFLTestValue2List>();
620 }
621
622 template <typename ListType>
Merge()623 void IntrusiveForwardListTest::Merge() {
624 using ValueType = typename ListType::value_type;
625 std::forward_list<int> ref1({ 1, 4, 8, 8, 12 });
626 std::vector<ValueType> storage1(ref1.begin(), ref1.end());
627 ListType ifl1(storage1.begin(), storage1.end());
628 std::forward_list<int> ref2({ 3, 5, 6, 7, 9 });
629 std::vector<ValueType> storage2(ref2.begin(), ref2.end());
630 ListType ifl2(storage2.begin(), storage2.end());
631 ASSERT_LISTS_EQUAL(ref1, ifl1);
632 ASSERT_LISTS_EQUAL(ref2, ifl2);
633 CHECK(std::is_sorted(ref1.begin(), ref1.end()));
634 CHECK(std::is_sorted(ref2.begin(), ref2.end()));
635 ref1.merge(ref2);
636 ifl1.merge(ifl2);
637 ASSERT_LISTS_EQUAL(ref1, ifl1);
638 ASSERT_LISTS_EQUAL(ref2, ifl2);
639 CHECK(ref2.empty());
640 std::forward_list<int> check({ 1, 3, 4, 5, 6, 7, 8, 8, 9, 12 });
641 ASSERT_LISTS_EQUAL(check, ifl1);
642 }
643
TEST_F(IntrusiveForwardListTest,Merge)644 TEST_F(IntrusiveForwardListTest, Merge) {
645 Merge<IFLTestValueList>();
646 Merge<ConstIFLTestValueList>();
647 Merge<IFLTestValue2List>();
648 }
649
650 template <typename ListType>
Sort1()651 void IntrusiveForwardListTest::Sort1() {
652 using ValueType = typename ListType::value_type;
653 std::forward_list<int> ref({ 2, 9, 8, 3, 7, 4, 1, 5, 3, 0 });
654 std::vector<ValueType> storage(ref.begin(), ref.end());
655 ListType ifl(storage.begin(), storage.end());
656 ASSERT_LISTS_EQUAL(ref, ifl);
657 CHECK(!std::is_sorted(ref.begin(), ref.end()));
658 ref.sort();
659 ifl.sort();
660 ASSERT_LISTS_EQUAL(ref, ifl);
661 std::forward_list<int> check({ 0, 1, 2, 3, 3, 4, 5, 7, 8, 9 });
662 ASSERT_LISTS_EQUAL(check, ifl);
663 }
664
TEST_F(IntrusiveForwardListTest,Sort1)665 TEST_F(IntrusiveForwardListTest, Sort1) {
666 Sort1<IFLTestValueList>();
667 Sort1<ConstIFLTestValueList>();
668 Sort1<IFLTestValue2List>();
669 }
670
671 template <typename ListType>
Sort2()672 void IntrusiveForwardListTest::Sort2() {
673 using ValueType = typename ListType::value_type;
674 std::forward_list<int> ref({ 2, 9, 8, 3, 7, 4, 1, 5, 3, 0 });
675 std::vector<ValueType> storage(ref.begin(), ref.end());
676 ListType ifl(storage.begin(), storage.end());
677 ASSERT_LISTS_EQUAL(ref, ifl);
678 auto cmp = [](const ValueType& lhs, const ValueType& rhs) {
679 return (lhs.value & ~1) < (rhs.value & ~1);
680 };
681 CHECK(!std::is_sorted(ref.begin(), ref.end(), cmp));
682 ref.sort(cmp);
683 ifl.sort(cmp);
684 ASSERT_LISTS_EQUAL(ref, ifl);
685 std::forward_list<int> check({ 1, 0, 2, 3, 3, 4, 5, 7, 9, 8 });
686 ASSERT_LISTS_EQUAL(check, ifl);
687 }
688
TEST_F(IntrusiveForwardListTest,Sort2)689 TEST_F(IntrusiveForwardListTest, Sort2) {
690 Sort2<IFLTestValueList>();
691 Sort2<ConstIFLTestValueList>();
692 Sort2<IFLTestValue2List>();
693 }
694
695 template <typename ListType>
Reverse()696 void IntrusiveForwardListTest::Reverse() {
697 using ValueType = typename ListType::value_type;
698 std::forward_list<int> ref({ 8, 3, 5, 4, 1, 3 });
699 std::vector<ValueType> storage(ref.begin(), ref.end());
700 ListType ifl(storage.begin(), storage.end());
701 ASSERT_LISTS_EQUAL(ref, ifl);
702 CHECK(!std::is_sorted(ref.begin(), ref.end()));
703 ref.reverse();
704 ifl.reverse();
705 ASSERT_LISTS_EQUAL(ref, ifl);
706 std::forward_list<int> check({ 3, 1, 4, 5, 3, 8 });
707 ASSERT_LISTS_EQUAL(check, ifl);
708 }
709
TEST_F(IntrusiveForwardListTest,Reverse)710 TEST_F(IntrusiveForwardListTest, Reverse) {
711 Reverse<IFLTestValueList>();
712 Reverse<ConstIFLTestValueList>();
713 Reverse<IFLTestValue2List>();
714 }
715
716 template <typename ListType>
ModifyValue()717 void IntrusiveForwardListTest::ModifyValue() {
718 using ValueType = typename ListType::value_type;
719 std::forward_list<int> ref({ 3, 7, 42 });
720 std::vector<ValueType> storage(ref.begin(), ref.end());
721 ListType ifl(storage.begin(), storage.end());
722 ASSERT_LISTS_EQUAL(ref, ifl);
723
724 auto add1 = [](const ValueType& value) { return value.value + 1; };
725 std::transform(ref.begin(), ref.end(), ref.begin(), add1);
726 std::transform(ifl.begin(), ifl.end(), ifl.begin(), add1);
727 ASSERT_LISTS_EQUAL(ref, ifl);
728 }
729
TEST_F(IntrusiveForwardListTest,ModifyValue)730 TEST_F(IntrusiveForwardListTest, ModifyValue) {
731 ModifyValue<IFLTestValueList>();
732 // Does not compile with ConstIFLTestValueList because LHS of the assignment is const.
733 // ModifyValue<ConstIFLTestValueList>();
734 static_assert(std::is_const<ConstIFLTestValueList::iterator::value_type>::value, "Const check.");
735 ModifyValue<IFLTestValue2List>();
736 }
737
738 struct Tag1;
739 struct Tag2;
740 struct TwoListsValue : public IntrusiveForwardListNode<TwoListsValue, Tag1>,
741 public IntrusiveForwardListNode<TwoListsValue, Tag2> {
742 // Deliberately not explicit.
TwoListsValueart::TwoListsValue743 TwoListsValue(int v) : value(v) { } // NOLINT(runtime/explicit)
744
745 int value;
746 };
747 using FirstList =
748 IntrusiveForwardList<TwoListsValue, IntrusiveForwardListBaseHookTraits<TwoListsValue, Tag1>>;
749 using SecondList =
750 IntrusiveForwardList<TwoListsValue, IntrusiveForwardListBaseHookTraits<TwoListsValue, Tag2>>;
751
operator ==(const TwoListsValue & lhs,const TwoListsValue & rhs)752 bool operator==(const TwoListsValue& lhs, const TwoListsValue& rhs) {
753 return lhs.value == rhs.value;
754 }
755
TEST_F(IntrusiveForwardListTest,TwoLists)756 TEST_F(IntrusiveForwardListTest, TwoLists) {
757 // Test that a value can be in two lists at the same time and the hooks do not interfere.
758 std::vector<TwoListsValue> storage({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); // storage[i] = i
759
760 std::vector<int> order1({ 3, 1, 7, 2, 8, 9, 4, 0, 6, 5 });
761 FirstList list1;
762 auto pos1 = list1.before_begin();
763 for (size_t idx : order1) {
764 pos1 = list1.insert_after(pos1, storage[idx]);
765 }
766
767 std::vector<int> order2({ 8, 5, 1, 6, 7, 2, 9, 3, 0, 4 });
768 SecondList list2;
769 auto pos2 = list2.before_begin();
770 for (size_t idx : order2) {
771 pos2 = list2.insert_after(pos2, storage[idx]);
772 }
773
774 // Using `storage[i] = i`, we can easily compare that nodes of each list are in the right order.
775 ASSERT_LISTS_EQUAL(order1, list1);
776 ASSERT_LISTS_EQUAL(order2, list2);
777 }
778
779 } // namespace art
780