blob: 65470aeb55cfa05be4d0e184179fc758e91d18f2 [file] [log] [blame]
bsalomon@google.combbe52902012-12-03 18:01:45 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "Test.h"
9#include "SkRandom.h"
10#include "SkTInternalLList.h"
11#include "SkTLList.h"
12
13class ListElement {
14public:
15 ListElement(int id) : fID(id) {
16 }
17 bool operator== (const ListElement& other) { return fID == other.fID; }
18
19#ifdef SK_ENABLE_INST_COUNT
20 // Make the instance count available publicly.
21 static int InstanceCount() { return GetInstanceCount(); }
22#endif
23
24 int fID;
25
26private:
27 SK_DECLARE_INST_COUNT_ROOT(ListElement);
28 SK_DECLARE_INTERNAL_LLIST_INTERFACE(ListElement);
29};
30
31SK_DEFINE_INST_COUNT(ListElement);
32
33static void check_list(const SkTInternalLList<ListElement>& list,
34 skiatest::Reporter* reporter,
35 bool empty,
36 int numElements,
37 bool in0, bool in1, bool in2, bool in3,
38 ListElement elements[4]) {
39
40 REPORTER_ASSERT(reporter, empty == list.isEmpty());
41#if SK_DEBUG
42 REPORTER_ASSERT(reporter, numElements == list.countEntries());
43 REPORTER_ASSERT(reporter, in0 == list.isInList(&elements[0]));
44 REPORTER_ASSERT(reporter, in1 == list.isInList(&elements[1]));
45 REPORTER_ASSERT(reporter, in2 == list.isInList(&elements[2]));
46 REPORTER_ASSERT(reporter, in3 == list.isInList(&elements[3]));
47#endif
48}
49
50static void TestTInternalLList(skiatest::Reporter* reporter) {
51 SkTInternalLList<ListElement> list;
52 ListElement elements[4] = {
53 ListElement(0),
54 ListElement(1),
55 ListElement(2),
56 ListElement(3),
57 };
58
59 // list should be empty to start with
60 check_list(list, reporter, true, 0, false, false, false, false, elements);
61
62 list.addToHead(&elements[0]);
63
64 check_list(list, reporter, false, 1, true, false, false, false, elements);
65
66 list.addToHead(&elements[1]);
67 list.addToHead(&elements[2]);
68 list.addToHead(&elements[3]);
69
70 check_list(list, reporter, false, 4, true, true, true, true, elements);
71
72 // test out iterators
73 typedef SkTInternalLList<ListElement>::Iter Iter;
74 Iter iter;
75
76 ListElement* cur = iter.init(list, Iter::kHead_IterStart);
77 for (int i = 0; NULL != cur; ++i, cur = iter.next()) {
78 REPORTER_ASSERT(reporter, cur->fID == 3-i);
79 }
80
81 cur = iter.init(list, Iter::kTail_IterStart);
82 for (int i = 0; NULL != cur; ++i, cur = iter.prev()) {
83 REPORTER_ASSERT(reporter, cur->fID == i);
84 }
85
86 // remove middle, frontmost then backmost
87 list.remove(&elements[1]);
88 list.remove(&elements[3]);
89 list.remove(&elements[0]);
90
91 check_list(list, reporter, false, 1, false, false, true, false, elements);
92
93 // remove last element
94 list.remove(&elements[2]);
95
96 // list should be empty again
97 check_list(list, reporter, true, 0, false, false, false, false, elements);
98}
99
100static void TestTLList(skiatest::Reporter* reporter) {
101 typedef SkTLList<ListElement> ElList;
102 typedef ElList::Iter Iter;
103 SkRandom random;
104
105 for (int i = 1; i <= 16; i *= 2) {
106
107 ElList list1(i);
108 ElList list2(i);
109 Iter iter1;
110 Iter iter2;
111 Iter iter3;
112 Iter iter4;
113
114#ifdef SK_ENABLE_INST_COUNT
115 SkASSERT(0 == ListElement::InstanceCount());
116#endif
117
118 REPORTER_ASSERT(reporter, list1.isEmpty());
119 REPORTER_ASSERT(reporter, NULL == iter1.init(list1, Iter::kHead_IterStart));
120 REPORTER_ASSERT(reporter, NULL == iter1.init(list1, Iter::kTail_IterStart));
121 // Try popping an empty list
122 list1.popHead();
123 list1.popTail();
124 REPORTER_ASSERT(reporter, list1.isEmpty());
125 REPORTER_ASSERT(reporter, list1 == list2);
126
127 // Create two identical lists, one by appending to head and the other to the tail.
128 list1.addToHead(ListElement(1));
129 list2.addToTail(ListElement(1));
130#ifdef SK_ENABLE_INST_COUNT
131 SkASSERT(2 == ListElement::InstanceCount());
132#endif
133 iter1.init(list1, Iter::kHead_IterStart);
134 iter2.init(list1, Iter::kTail_IterStart);
135 REPORTER_ASSERT(reporter, iter1.get()->fID == iter2.get()->fID);
136 iter3.init(list2, Iter::kHead_IterStart);
137 iter4.init(list2, Iter::kTail_IterStart);
138 REPORTER_ASSERT(reporter, iter3.get()->fID == iter1.get()->fID);
139 REPORTER_ASSERT(reporter, iter4.get()->fID == iter1.get()->fID);
140 REPORTER_ASSERT(reporter, list1 == list2);
141
142 // add an element to the second list, check that iters are still valid
143 list2.addToHead(ListElement(2));
144#ifdef SK_ENABLE_INST_COUNT
145 SkASSERT(3 == ListElement::InstanceCount());
146#endif
147 REPORTER_ASSERT(reporter, iter3.get()->fID == iter1.get()->fID);
148 REPORTER_ASSERT(reporter, iter4.get()->fID == iter1.get()->fID);
149 REPORTER_ASSERT(reporter, 1 == Iter(list2, Iter::kTail_IterStart).get()->fID);
150 REPORTER_ASSERT(reporter, 2 == Iter(list2, Iter::kHead_IterStart).get()->fID);
151 REPORTER_ASSERT(reporter, list1 != list2);
152 list1.addToHead(ListElement(2));
153 REPORTER_ASSERT(reporter, list1 == list2);
154#ifdef SK_ENABLE_INST_COUNT
155 SkASSERT(4 == ListElement::InstanceCount());
156#endif
157 REPORTER_ASSERT(reporter, !list1.isEmpty());
158
159 list1.reset();
160 list2.reset();
161#ifdef SK_ENABLE_INST_COUNT
162 SkASSERT(0 == ListElement::InstanceCount());
163#endif
164 REPORTER_ASSERT(reporter, list1.isEmpty() && list2.isEmpty());
165
166 int count = 0;
167 for (int j = 0; j < 100; ++j) {
168 if (list1.isEmpty() || random.nextBiasedBool(3 * SK_Scalar1 / 4)) {
169 int id = static_cast<int>(random.nextU());
170 if (random.nextBool()) {
171 list1.addToHead(ListElement(id));
172 } else {
173 list1.addToTail(ListElement(id));
174 }
175 ++count;
176 } else {
177 // walk to a random place either forward or backwards and remove.
178 int n = random.nextULessThan(list1.count());
179 Iter::IterStart start;
180 ListElement* (Iter::*incrFunc)();
181
182 if (random.nextBool()) {
183 start = Iter::kHead_IterStart;
184 incrFunc = &Iter::next;
185 } else {
186 start = Iter::kTail_IterStart;
187 incrFunc = &Iter::prev;
188 }
189
190 // find the element
191 Iter iter(list1, start);
192 while (n--) {
193 REPORTER_ASSERT(reporter, NULL != iter.get());
194 (iter.*incrFunc)();
195 }
196 REPORTER_ASSERT(reporter, NULL != iter.get());
197
198 // remember the prev and next elements from the element to be removed
199 Iter prev = iter;
200 Iter next = iter;
201 prev.prev();
202 next.next();
203 list1.remove(iter.get());
204
205 // make sure the remembered next/prev iters still work
206 Iter pn = prev; pn.next();
207 Iter np = next; np.prev();
208 // pn should match next unless the target node was the head, in which case prev
209 // walked off the list.
210 REPORTER_ASSERT(reporter, pn.get() == next.get() || NULL == prev.get());
211 // Similarly, np should match prev unless next originally walked off the tail.
212 REPORTER_ASSERT(reporter, np.get() == prev.get() || NULL == next.get());
213 --count;
214 }
215 REPORTER_ASSERT(reporter, count == list1.count());
216#ifdef SK_ENABLE_INST_COUNT
217 SkASSERT(count == ListElement::InstanceCount());
218#endif
219 }
220 list1.reset();
221#ifdef SK_ENABLE_INST_COUNT
222 SkASSERT(0 == ListElement::InstanceCount());
223#endif
224 }
225}
226
227static void test_llists(skiatest::Reporter* reporter) {
228 TestTInternalLList(reporter);
229 TestTLList(reporter);
230}
231
232#include "TestClassDef.h"
233DEFINE_TESTCLASS("LList", TestLListClass, test_llists)