2 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
6 * You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "mozilla/Assertions.h"
9 #include "mozilla/LinkedList.h"
11 using mozilla::AutoCleanLinkedList
;
12 using mozilla::LinkedList
;
13 using mozilla::LinkedListElement
;
15 struct SomeClass
: public LinkedListElement
<SomeClass
> {
17 explicit SomeClass(int aValue
= 0) : mValue(aValue
) {}
18 SomeClass(SomeClass
&&) = default;
19 SomeClass
& operator=(SomeClass
&&) = default;
20 void incr() { ++mValue
; }
24 static void CheckListValues(LinkedList
<SomeClass
>& list
,
25 unsigned int (&values
)[N
]) {
27 for (SomeClass
* x
: list
) {
28 MOZ_RELEASE_ASSERT(x
->mValue
== values
[count
]);
31 MOZ_RELEASE_ASSERT(count
== N
);
34 static void TestList() {
35 LinkedList
<SomeClass
> list
;
37 SomeClass
one(1), two(2), three(3);
39 MOZ_RELEASE_ASSERT(list
.isEmpty());
40 MOZ_RELEASE_ASSERT(list
.length() == 0);
41 MOZ_RELEASE_ASSERT(!list
.getFirst());
42 MOZ_RELEASE_ASSERT(!list
.getLast());
43 MOZ_RELEASE_ASSERT(!list
.popFirst());
44 MOZ_RELEASE_ASSERT(!list
.popLast());
46 for (SomeClass
* x
: list
) {
47 MOZ_RELEASE_ASSERT(x
);
48 MOZ_RELEASE_ASSERT(false);
51 list
.insertFront(&one
);
53 unsigned int check
[]{1};
54 CheckListValues(list
, check
);
57 MOZ_RELEASE_ASSERT(one
.isInList());
58 MOZ_RELEASE_ASSERT(!two
.isInList());
59 MOZ_RELEASE_ASSERT(!three
.isInList());
61 MOZ_RELEASE_ASSERT(list
.contains(&one
));
62 MOZ_RELEASE_ASSERT(!list
.contains(&two
));
63 MOZ_RELEASE_ASSERT(!list
.contains(&three
));
65 MOZ_RELEASE_ASSERT(!list
.isEmpty());
66 MOZ_RELEASE_ASSERT(list
.length() == 1);
67 MOZ_RELEASE_ASSERT(list
.getFirst()->mValue
== 1);
68 MOZ_RELEASE_ASSERT(list
.getLast()->mValue
== 1);
70 list
.insertFront(&two
);
72 unsigned int check
[]{2, 1};
73 CheckListValues(list
, check
);
76 MOZ_RELEASE_ASSERT(list
.length() == 2);
77 MOZ_RELEASE_ASSERT(list
.getFirst()->mValue
== 2);
78 MOZ_RELEASE_ASSERT(list
.getLast()->mValue
== 1);
80 list
.insertBack(&three
);
82 unsigned int check
[]{2, 1, 3};
83 CheckListValues(list
, check
);
86 MOZ_RELEASE_ASSERT(list
.length() == 3);
87 MOZ_RELEASE_ASSERT(list
.getFirst()->mValue
== 2);
88 MOZ_RELEASE_ASSERT(list
.getLast()->mValue
== 3);
92 unsigned int check
[]{2, 3};
93 CheckListValues(list
, check
);
96 three
.setPrevious(&one
);
98 unsigned int check
[]{2, 1, 3};
99 CheckListValues(list
, check
);
102 three
.removeFrom(list
);
104 unsigned int check
[]{2, 1};
105 CheckListValues(list
, check
);
108 two
.setPrevious(&three
);
110 unsigned int check
[]{3, 2, 1};
111 CheckListValues(list
, check
);
114 three
.removeFrom(list
);
116 unsigned int check
[]{2, 1};
117 CheckListValues(list
, check
);
122 unsigned int check
[]{2, 3, 1};
123 CheckListValues(list
, check
);
128 unsigned int check
[]{2, 3};
129 CheckListValues(list
, check
);
134 unsigned int check
[]{3};
135 CheckListValues(list
, check
);
138 three
.setPrevious(&two
);
140 unsigned int check
[]{2, 3};
141 CheckListValues(list
, check
);
146 unsigned int check
[]{2};
147 CheckListValues(list
, check
);
152 list
.insertBack(&three
);
154 unsigned int check
[]{3};
155 CheckListValues(list
, check
);
158 list
.insertFront(&two
);
160 unsigned int check
[]{2, 3};
161 CheckListValues(list
, check
);
164 for (SomeClass
* x
: list
) {
168 MOZ_RELEASE_ASSERT(list
.length() == 2);
169 MOZ_RELEASE_ASSERT(list
.getFirst() == &two
);
170 MOZ_RELEASE_ASSERT(list
.getLast() == &three
);
171 MOZ_RELEASE_ASSERT(list
.getFirst()->mValue
== 3);
172 MOZ_RELEASE_ASSERT(list
.getLast()->mValue
== 4);
174 const LinkedList
<SomeClass
>& constList
= list
;
175 for (const SomeClass
* x
: constList
) {
176 MOZ_RELEASE_ASSERT(x
);
180 static void TestExtendLists() {
181 AutoCleanLinkedList
<SomeClass
> list1
, list2
;
183 constexpr unsigned int N
= 5;
184 for (unsigned int i
= 0; i
< N
; ++i
) {
185 list1
.insertBack(new SomeClass(static_cast<int>(i
)));
187 AutoCleanLinkedList
<SomeClass
> singleItemList
;
188 singleItemList
.insertFront(new SomeClass(static_cast<int>(i
+ N
)));
189 list2
.extendBack(std::move(singleItemList
));
191 // list1 = { 0, 1, 2, 3, 4 }
192 // list2 = { 5, 6, 7, 8, 9 }
194 list1
.extendBack(AutoCleanLinkedList
<SomeClass
>());
195 list1
.extendBack(std::move(list2
));
197 // Make sure the line above has properly emptied |list2|.
198 MOZ_RELEASE_ASSERT(list2
.isEmpty()); // NOLINT(bugprone-use-after-move)
201 for (SomeClass
* x
: list1
) {
202 MOZ_RELEASE_ASSERT(x
->mValue
== i
++);
204 MOZ_RELEASE_ASSERT(i
== N
* 2);
208 AutoCleanLinkedList
<SomeClass
> list1
, list2
;
209 for (unsigned int i
= 1; i
<= 5; ++i
) {
210 list1
.insertBack(new SomeClass(static_cast<int>(i
)));
212 AutoCleanLinkedList
<SomeClass
> singleItemList
;
213 singleItemList
.insertFront(new SomeClass(static_cast<int>(i
* 10)));
214 list2
.extendBack(std::move(singleItemList
));
216 // list1 = { 1, 2, 3, 4, 5 }
217 // list2 = { 10, 20, 30, 40, 50 }
219 list1
.splice(2, list2
, 0, 5);
221 MOZ_RELEASE_ASSERT(list2
.isEmpty());
222 unsigned int kExpected1
[]{1, 2, 10, 20, 30, 40, 50, 3, 4, 5};
223 CheckListValues(list1
, kExpected1
);
225 // Since aSourceLen=100 exceeds list1's end, the function transfers
226 // three items [3, 4, 5].
227 list2
.splice(0, list1
, 7, 100);
229 unsigned int kExpected2
[]{1, 2, 10, 20, 30, 40, 50};
230 unsigned int kExpected3
[]{3, 4, 5};
231 CheckListValues(list1
, kExpected2
);
232 CheckListValues(list2
, kExpected3
);
234 // Since aDestinationPos=100 exceeds list2's end, the function transfers
235 // items to list2's end.
236 list2
.splice(100, list1
, 1, 1);
238 unsigned int kExpected4
[]{1, 10, 20, 30, 40, 50};
239 unsigned int kExpected5
[]{3, 4, 5, 2};
240 CheckListValues(list1
, kExpected4
);
241 CheckListValues(list2
, kExpected5
);
244 static void TestMove() {
245 auto MakeSomeClass
= [](unsigned int aValue
) -> SomeClass
{
246 return SomeClass(aValue
);
249 LinkedList
<SomeClass
> list1
;
251 // Test move constructor for LinkedListElement.
252 SomeClass
c1(MakeSomeClass(1));
253 list1
.insertBack(&c1
);
255 // Test move assignment for LinkedListElement from an element not in a
258 c2
= MakeSomeClass(2);
259 list1
.insertBack(&c2
);
261 // Test move assignment of LinkedListElement from an element already in a
265 MOZ_RELEASE_ASSERT(!c2
.isInList());
266 MOZ_RELEASE_ASSERT(c3
.isInList());
268 // Test move constructor for LinkedList.
269 LinkedList
<SomeClass
> list2(std::move(list1
));
271 unsigned int check
[]{1, 2};
272 CheckListValues(list2
, check
);
274 MOZ_RELEASE_ASSERT(list1
.isEmpty());
276 // Test move assignment for LinkedList.
277 LinkedList
<SomeClass
> list3
;
278 list3
= std::move(list2
);
280 unsigned int check
[]{1, 2};
281 CheckListValues(list3
, check
);
283 MOZ_RELEASE_ASSERT(list2
.isEmpty());
288 static void TestRemoveAndGet() {
289 LinkedList
<SomeClass
> list
;
291 SomeClass
one(1), two(2), three(3);
292 list
.insertBack(&one
);
293 list
.insertBack(&two
);
294 list
.insertBack(&three
);
296 unsigned int check
[]{1, 2, 3};
297 CheckListValues(list
, check
);
300 MOZ_RELEASE_ASSERT(two
.removeAndGetNext() == &three
);
302 unsigned int check
[]{1, 3};
303 CheckListValues(list
, check
);
306 MOZ_RELEASE_ASSERT(three
.removeAndGetPrevious() == &one
);
308 unsigned int check
[]{1};
309 CheckListValues(list
, check
);
313 struct PrivateClass
: private LinkedListElement
<PrivateClass
> {
314 friend class mozilla::LinkedList
<PrivateClass
>;
315 friend class mozilla::LinkedListElement
<PrivateClass
>;
318 static void TestPrivate() {
319 LinkedList
<PrivateClass
> list
;
320 PrivateClass one
, two
;
321 list
.insertBack(&one
);
322 list
.insertBack(&two
);
325 for (PrivateClass
* p
: list
) {
326 MOZ_RELEASE_ASSERT(p
, "cannot have null elements in list");
329 MOZ_RELEASE_ASSERT(count
== 2);
332 struct CountedClass
: public LinkedListElement
<RefPtr
<CountedClass
>> {
334 void AddRef() { mCount
++; }
335 void Release() { mCount
--; }
337 CountedClass() : mCount(0) {}
338 ~CountedClass() { MOZ_RELEASE_ASSERT(mCount
== 0); }
341 static void TestRefPtrList() {
342 LinkedList
<RefPtr
<CountedClass
>> list
;
343 CountedClass
* elt1
= new CountedClass
;
344 CountedClass
* elt2
= new CountedClass
;
346 list
.insertBack(elt1
);
347 list
.insertBack(elt2
);
349 MOZ_RELEASE_ASSERT(elt1
->mCount
== 1);
350 MOZ_RELEASE_ASSERT(elt2
->mCount
== 1);
352 for (RefPtr
<CountedClass
> p
: list
) {
353 MOZ_RELEASE_ASSERT(p
->mCount
== 2);
356 RefPtr
<CountedClass
> ptr
= list
.getFirst();
358 MOZ_RELEASE_ASSERT(ptr
->mCount
== 2);
359 RefPtr
<CountedClass
> next
= ptr
->getNext();
361 ptr
= std::move(next
);
365 MOZ_RELEASE_ASSERT(elt1
->mCount
== 0);
366 MOZ_RELEASE_ASSERT(elt2
->mCount
== 0);
368 list
.insertBack(elt1
);
371 MOZ_RELEASE_ASSERT(elt1
->mCount
== 1);
372 MOZ_RELEASE_ASSERT(elt2
->mCount
== 1);
374 RefPtr
<CountedClass
> first
= list
.popFirst();
376 MOZ_RELEASE_ASSERT(elt1
->mCount
== 1);
377 MOZ_RELEASE_ASSERT(elt2
->mCount
== 1);
379 RefPtr
<CountedClass
> second
= list
.popFirst();
381 MOZ_RELEASE_ASSERT(elt1
->mCount
== 1);
382 MOZ_RELEASE_ASSERT(elt2
->mCount
== 1);
384 first
= second
= nullptr;