1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/Assertions.h"
8 #include "mozilla/LinkedList.h"
10 using mozilla::LinkedList
;
11 using mozilla::LinkedListElement
;
13 struct SomeClass
: public LinkedListElement
<SomeClass
> {
15 explicit SomeClass(int aValue
= 0) : mValue(aValue
) {}
16 void incr() { ++mValue
; }
20 static void CheckListValues(LinkedList
<SomeClass
>& list
,
21 unsigned int (&values
)[N
]) {
23 for (SomeClass
* x
: list
) {
24 MOZ_RELEASE_ASSERT(x
->mValue
== values
[count
]);
27 MOZ_RELEASE_ASSERT(count
== N
);
30 static void TestList() {
31 LinkedList
<SomeClass
> list
;
33 SomeClass
one(1), two(2), three(3);
35 MOZ_RELEASE_ASSERT(list
.isEmpty());
36 MOZ_RELEASE_ASSERT(list
.length() == 0);
37 MOZ_RELEASE_ASSERT(!list
.getFirst());
38 MOZ_RELEASE_ASSERT(!list
.getLast());
39 MOZ_RELEASE_ASSERT(!list
.popFirst());
40 MOZ_RELEASE_ASSERT(!list
.popLast());
42 for (SomeClass
* x
: list
) {
43 MOZ_RELEASE_ASSERT(x
);
44 MOZ_RELEASE_ASSERT(false);
47 list
.insertFront(&one
);
49 unsigned int check
[]{1};
50 CheckListValues(list
, check
);
53 MOZ_RELEASE_ASSERT(one
.isInList());
54 MOZ_RELEASE_ASSERT(!two
.isInList());
55 MOZ_RELEASE_ASSERT(!three
.isInList());
57 MOZ_RELEASE_ASSERT(list
.contains(&one
));
58 MOZ_RELEASE_ASSERT(!list
.contains(&two
));
59 MOZ_RELEASE_ASSERT(!list
.contains(&three
));
61 MOZ_RELEASE_ASSERT(!list
.isEmpty());
62 MOZ_RELEASE_ASSERT(list
.length() == 1);
63 MOZ_RELEASE_ASSERT(list
.getFirst()->mValue
== 1);
64 MOZ_RELEASE_ASSERT(list
.getLast()->mValue
== 1);
66 list
.insertFront(&two
);
68 unsigned int check
[]{2, 1};
69 CheckListValues(list
, check
);
72 MOZ_RELEASE_ASSERT(list
.length() == 2);
73 MOZ_RELEASE_ASSERT(list
.getFirst()->mValue
== 2);
74 MOZ_RELEASE_ASSERT(list
.getLast()->mValue
== 1);
76 list
.insertBack(&three
);
78 unsigned int check
[]{2, 1, 3};
79 CheckListValues(list
, check
);
82 MOZ_RELEASE_ASSERT(list
.length() == 3);
83 MOZ_RELEASE_ASSERT(list
.getFirst()->mValue
== 2);
84 MOZ_RELEASE_ASSERT(list
.getLast()->mValue
== 3);
88 unsigned int check
[]{2, 3};
89 CheckListValues(list
, check
);
92 three
.setPrevious(&one
);
94 unsigned int check
[]{2, 1, 3};
95 CheckListValues(list
, check
);
98 three
.removeFrom(list
);
100 unsigned int check
[]{2, 1};
101 CheckListValues(list
, check
);
104 two
.setPrevious(&three
);
106 unsigned int check
[]{3, 2, 1};
107 CheckListValues(list
, check
);
110 three
.removeFrom(list
);
112 unsigned int check
[]{2, 1};
113 CheckListValues(list
, check
);
118 unsigned int check
[]{2, 3, 1};
119 CheckListValues(list
, check
);
124 unsigned int check
[]{2, 3};
125 CheckListValues(list
, check
);
130 unsigned int check
[]{3};
131 CheckListValues(list
, check
);
134 three
.setPrevious(&two
);
136 unsigned int check
[]{2, 3};
137 CheckListValues(list
, check
);
142 unsigned int check
[]{2};
143 CheckListValues(list
, check
);
148 list
.insertBack(&three
);
150 unsigned int check
[]{3};
151 CheckListValues(list
, check
);
154 list
.insertFront(&two
);
156 unsigned int check
[]{2, 3};
157 CheckListValues(list
, check
);
160 for (SomeClass
* x
: list
) {
164 MOZ_RELEASE_ASSERT(list
.length() == 2);
165 MOZ_RELEASE_ASSERT(list
.getFirst() == &two
);
166 MOZ_RELEASE_ASSERT(list
.getLast() == &three
);
167 MOZ_RELEASE_ASSERT(list
.getFirst()->mValue
== 3);
168 MOZ_RELEASE_ASSERT(list
.getLast()->mValue
== 4);
170 const LinkedList
<SomeClass
>& constList
= list
;
171 for (const SomeClass
* x
: constList
) {
172 MOZ_RELEASE_ASSERT(x
);
176 static void TestMove() {
177 auto MakeSomeClass
= [](unsigned int aValue
) -> SomeClass
{
178 return SomeClass(aValue
);
181 LinkedList
<SomeClass
> list1
;
183 // Test move constructor for LinkedListElement.
184 SomeClass
c1(MakeSomeClass(1));
185 list1
.insertBack(&c1
);
187 // Test move assignment for LinkedListElement from an element not in a
190 c2
= MakeSomeClass(2);
191 list1
.insertBack(&c2
);
193 // Test move assignment of LinkedListElement from an element already in a
197 MOZ_RELEASE_ASSERT(!c2
.isInList());
198 MOZ_RELEASE_ASSERT(c3
.isInList());
200 // Test move constructor for LinkedList.
201 LinkedList
<SomeClass
> list2(std::move(list1
));
203 unsigned int check
[]{1, 2};
204 CheckListValues(list2
, check
);
206 MOZ_RELEASE_ASSERT(list1
.isEmpty());
208 // Test move assignment for LinkedList.
209 LinkedList
<SomeClass
> list3
;
210 list3
= std::move(list2
);
212 unsigned int check
[]{1, 2};
213 CheckListValues(list3
, check
);
215 MOZ_RELEASE_ASSERT(list2
.isEmpty());
220 static void TestRemoveAndGet() {
221 LinkedList
<SomeClass
> list
;
223 SomeClass
one(1), two(2), three(3);
224 list
.insertBack(&one
);
225 list
.insertBack(&two
);
226 list
.insertBack(&three
);
228 unsigned int check
[]{1, 2, 3};
229 CheckListValues(list
, check
);
232 MOZ_RELEASE_ASSERT(two
.removeAndGetNext() == &three
);
234 unsigned int check
[]{1, 3};
235 CheckListValues(list
, check
);
238 MOZ_RELEASE_ASSERT(three
.removeAndGetPrevious() == &one
);
240 unsigned int check
[]{1};
241 CheckListValues(list
, check
);
245 struct PrivateClass
: private LinkedListElement
<PrivateClass
> {
246 friend class mozilla::LinkedList
<PrivateClass
>;
247 friend class mozilla::LinkedListElement
<PrivateClass
>;
250 static void TestPrivate() {
251 LinkedList
<PrivateClass
> list
;
252 PrivateClass one
, two
;
253 list
.insertBack(&one
);
254 list
.insertBack(&two
);
257 for (PrivateClass
* p
: list
) {
258 MOZ_RELEASE_ASSERT(p
, "cannot have null elements in list");
261 MOZ_RELEASE_ASSERT(count
== 2);
264 struct CountedClass
: public LinkedListElement
<RefPtr
<CountedClass
>> {
266 void AddRef() { mCount
++; }
267 void Release() { mCount
--; }
269 CountedClass() : mCount(0) {}
270 ~CountedClass() { MOZ_RELEASE_ASSERT(mCount
== 0); }
273 static void TestRefPtrList() {
274 LinkedList
<RefPtr
<CountedClass
>> list
;
275 CountedClass
* elt1
= new CountedClass
;
276 CountedClass
* elt2
= new CountedClass
;
278 list
.insertBack(elt1
);
279 list
.insertBack(elt2
);
281 MOZ_RELEASE_ASSERT(elt1
->mCount
== 1);
282 MOZ_RELEASE_ASSERT(elt2
->mCount
== 1);
284 for (RefPtr
<CountedClass
> p
: list
) {
285 MOZ_RELEASE_ASSERT(p
->mCount
== 2);
288 RefPtr
<CountedClass
> ptr
= list
.getFirst();
290 MOZ_RELEASE_ASSERT(ptr
->mCount
== 2);
291 RefPtr
<CountedClass
> next
= ptr
->getNext();
293 ptr
= std::move(next
);
297 MOZ_RELEASE_ASSERT(elt1
->mCount
== 0);
298 MOZ_RELEASE_ASSERT(elt2
->mCount
== 0);
300 list
.insertBack(elt1
);
303 MOZ_RELEASE_ASSERT(elt1
->mCount
== 1);
304 MOZ_RELEASE_ASSERT(elt2
->mCount
== 1);
306 RefPtr
<CountedClass
> first
= list
.popFirst();
308 MOZ_RELEASE_ASSERT(elt1
->mCount
== 1);
309 MOZ_RELEASE_ASSERT(elt2
->mCount
== 1);
311 RefPtr
<CountedClass
> second
= list
.popFirst();
313 MOZ_RELEASE_ASSERT(elt1
->mCount
== 1);
314 MOZ_RELEASE_ASSERT(elt2
->mCount
== 1);
316 first
= second
= nullptr;