OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkRandom.h" | 8 #include "SkRandom.h" |
9 #include "SkTInternalLList.h" | 9 #include "SkTInternalLList.h" |
10 #include "SkTLList.h" | 10 #include "SkTLList.h" |
(...skipping 23 matching lines...) Expand all Loading... |
34 #ifdef SK_DEBUG | 34 #ifdef SK_DEBUG |
35 list.validate(); | 35 list.validate(); |
36 REPORTER_ASSERT(reporter, numElements == list.countEntries()); | 36 REPORTER_ASSERT(reporter, numElements == list.countEntries()); |
37 REPORTER_ASSERT(reporter, in0 == list.isInList(&elements[0])); | 37 REPORTER_ASSERT(reporter, in0 == list.isInList(&elements[0])); |
38 REPORTER_ASSERT(reporter, in1 == list.isInList(&elements[1])); | 38 REPORTER_ASSERT(reporter, in1 == list.isInList(&elements[1])); |
39 REPORTER_ASSERT(reporter, in2 == list.isInList(&elements[2])); | 39 REPORTER_ASSERT(reporter, in2 == list.isInList(&elements[2])); |
40 REPORTER_ASSERT(reporter, in3 == list.isInList(&elements[3])); | 40 REPORTER_ASSERT(reporter, in3 == list.isInList(&elements[3])); |
41 #endif | 41 #endif |
42 } | 42 } |
43 | 43 |
44 static void TestTInternalLList(skiatest::Reporter* reporter) { | 44 static void test_tinternallist(skiatest::Reporter* reporter) { |
45 SkTInternalLList<ListElement> list; | 45 SkTInternalLList<ListElement> list; |
46 ListElement elements[4] = { | 46 ListElement elements[4] = { |
47 ListElement(0), | 47 ListElement(0), |
48 ListElement(1), | 48 ListElement(1), |
49 ListElement(2), | 49 ListElement(2), |
50 ListElement(3), | 50 ListElement(3), |
51 }; | 51 }; |
52 | 52 |
53 // list should be empty to start with | 53 // list should be empty to start with |
54 check_list(list, reporter, true, 0, false, false, false, false, elements); | 54 check_list(list, reporter, true, 0, false, false, false, false, elements); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 | 107 |
108 list.addBefore(&elements[2], &elements[3]); | 108 list.addBefore(&elements[2], &elements[3]); |
109 check_list(list, reporter, false, 4, true, true, true, true, elements); | 109 check_list(list, reporter, false, 4, true, true, true, true, elements); |
110 | 110 |
111 cur = iter.init(list, Iter::kHead_IterStart); | 111 cur = iter.init(list, Iter::kHead_IterStart); |
112 for (int i = 0; cur; ++i, cur = iter.next()) { | 112 for (int i = 0; cur; ++i, cur = iter.next()) { |
113 REPORTER_ASSERT(reporter, cur->fID == i); | 113 REPORTER_ASSERT(reporter, cur->fID == i); |
114 } | 114 } |
115 } | 115 } |
116 | 116 |
117 static void TestTLList(skiatest::Reporter* reporter) { | 117 template <unsigned int N> static void test_tllist(skiatest::Reporter* reporter)
{ |
118 typedef SkTLList<ListElement> ElList; | 118 typedef SkTLList<ListElement, N> ElList; |
119 typedef ElList::Iter Iter; | 119 typedef typename ElList::Iter Iter; |
120 SkRandom random; | 120 SkRandom random; |
121 | 121 |
122 for (int i = 1; i <= 16; i *= 2) { | 122 ElList list1; |
| 123 ElList list2; |
| 124 Iter iter1; |
| 125 Iter iter2; |
| 126 Iter iter3; |
| 127 Iter iter4; |
123 | 128 |
124 ElList list1(i); | 129 REPORTER_ASSERT(reporter, list1.isEmpty()); |
125 ElList list2(i); | 130 REPORTER_ASSERT(reporter, nullptr == iter1.init(list1, Iter::kHead_IterStart
)); |
126 Iter iter1; | 131 REPORTER_ASSERT(reporter, nullptr == iter1.init(list1, Iter::kTail_IterStart
)); |
127 Iter iter2; | 132 // Try popping an empty list |
128 Iter iter3; | 133 list1.popHead(); |
129 Iter iter4; | 134 list1.popTail(); |
| 135 REPORTER_ASSERT(reporter, list1.isEmpty()); |
| 136 REPORTER_ASSERT(reporter, list1 == list2); |
130 | 137 |
131 REPORTER_ASSERT(reporter, list1.isEmpty()); | 138 // Create two identical lists, one by appending to head and the other to the
tail. |
132 REPORTER_ASSERT(reporter, nullptr == iter1.init(list1, Iter::kHead_IterS
tart)); | 139 list1.addToHead(ListElement(1)); |
133 REPORTER_ASSERT(reporter, nullptr == iter1.init(list1, Iter::kTail_IterS
tart)); | 140 list2.addToTail(ListElement(1)); |
134 // Try popping an empty list | 141 iter1.init(list1, Iter::kHead_IterStart); |
135 list1.popHead(); | 142 iter2.init(list1, Iter::kTail_IterStart); |
136 list1.popTail(); | 143 REPORTER_ASSERT(reporter, iter1.get()->fID == iter2.get()->fID); |
137 REPORTER_ASSERT(reporter, list1.isEmpty()); | 144 iter3.init(list2, Iter::kHead_IterStart); |
138 REPORTER_ASSERT(reporter, list1 == list2); | 145 iter4.init(list2, Iter::kTail_IterStart); |
| 146 REPORTER_ASSERT(reporter, iter3.get()->fID == iter1.get()->fID); |
| 147 REPORTER_ASSERT(reporter, iter4.get()->fID == iter1.get()->fID); |
| 148 REPORTER_ASSERT(reporter, list1 == list2); |
139 | 149 |
140 // Create two identical lists, one by appending to head and the other to
the tail. | 150 list2.reset(); |
141 list1.addToHead(ListElement(1)); | |
142 list2.addToTail(ListElement(1)); | |
143 iter1.init(list1, Iter::kHead_IterStart); | |
144 iter2.init(list1, Iter::kTail_IterStart); | |
145 REPORTER_ASSERT(reporter, iter1.get()->fID == iter2.get()->fID); | |
146 iter3.init(list2, Iter::kHead_IterStart); | |
147 iter4.init(list2, Iter::kTail_IterStart); | |
148 REPORTER_ASSERT(reporter, iter3.get()->fID == iter1.get()->fID); | |
149 REPORTER_ASSERT(reporter, iter4.get()->fID == iter1.get()->fID); | |
150 REPORTER_ASSERT(reporter, list1 == list2); | |
151 | 151 |
152 list2.reset(); | 152 // use both before/after in-place construction on an empty list |
| 153 list2.addBefore(list2.headIter(), 1); |
| 154 REPORTER_ASSERT(reporter, list2 == list1); |
| 155 list2.reset(); |
153 | 156 |
154 // use both before/after in-place construction on an empty list | 157 list2.addAfter(list2.tailIter(), 1); |
155 list2.addBefore(list2.headIter(), 1); | 158 REPORTER_ASSERT(reporter, list2 == list1); |
156 REPORTER_ASSERT(reporter, list2 == list1); | |
157 list2.reset(); | |
158 | 159 |
159 list2.addAfter(list2.tailIter(), 1); | 160 // add an element to the second list, check that iters are still valid |
160 REPORTER_ASSERT(reporter, list2 == list1); | 161 iter3.init(list2, Iter::kHead_IterStart); |
| 162 iter4.init(list2, Iter::kTail_IterStart); |
| 163 list2.addToHead(ListElement(2)); |
161 | 164 |
162 // add an element to the second list, check that iters are still valid | 165 REPORTER_ASSERT(reporter, iter3.get()->fID == iter1.get()->fID); |
163 iter3.init(list2, Iter::kHead_IterStart); | 166 REPORTER_ASSERT(reporter, iter4.get()->fID == iter1.get()->fID); |
164 iter4.init(list2, Iter::kTail_IterStart); | 167 REPORTER_ASSERT(reporter, 1 == Iter(list2, Iter::kTail_IterStart).get()->fID
); |
165 list2.addToHead(ListElement(2)); | 168 REPORTER_ASSERT(reporter, 2 == Iter(list2, Iter::kHead_IterStart).get()->fID
); |
| 169 REPORTER_ASSERT(reporter, list1 != list2); |
| 170 list1.addToHead(ListElement(2)); |
| 171 REPORTER_ASSERT(reporter, list1 == list2); |
| 172 REPORTER_ASSERT(reporter, !list1.isEmpty()); |
166 | 173 |
167 REPORTER_ASSERT(reporter, iter3.get()->fID == iter1.get()->fID); | 174 list1.reset(); |
168 REPORTER_ASSERT(reporter, iter4.get()->fID == iter1.get()->fID); | 175 list2.reset(); |
169 REPORTER_ASSERT(reporter, 1 == Iter(list2, Iter::kTail_IterStart).get()-
>fID); | 176 REPORTER_ASSERT(reporter, list1.isEmpty() && list2.isEmpty()); |
170 REPORTER_ASSERT(reporter, 2 == Iter(list2, Iter::kHead_IterStart).get()-
>fID); | |
171 REPORTER_ASSERT(reporter, list1 != list2); | |
172 list1.addToHead(ListElement(2)); | |
173 REPORTER_ASSERT(reporter, list1 == list2); | |
174 REPORTER_ASSERT(reporter, !list1.isEmpty()); | |
175 | 177 |
176 list1.reset(); | 178 // randomly perform insertions and deletions on a list and perform tests |
177 list2.reset(); | 179 int count = 0; |
178 REPORTER_ASSERT(reporter, list1.isEmpty() && list2.isEmpty()); | 180 for (int j = 0; j < 100; ++j) { |
| 181 if (list1.isEmpty() || random.nextBiasedBool(3 * SK_Scalar1 / 4)) { |
| 182 int id = j; |
| 183 // Choose one of three ways to insert a new element: at the head, at
the tail, |
| 184 // before a random element, after a random element |
| 185 int numValidMethods = 0 == count ? 2 : 4; |
| 186 int insertionMethod = random.nextULessThan(numValidMethods); |
| 187 switch (insertionMethod) { |
| 188 case 0: |
| 189 list1.addToHead(ListElement(id)); |
| 190 break; |
| 191 case 1: |
| 192 list1.addToTail(ListElement(id)); |
| 193 break; |
| 194 case 2: // fallthru to share code that picks random element. |
| 195 case 3: { |
| 196 int n = random.nextULessThan(list1.count()); |
| 197 Iter iter = list1.headIter(); |
| 198 // remember the elements before/after the insertion point. |
| 199 while (n--) { |
| 200 iter.next(); |
| 201 } |
| 202 Iter prev(iter); |
| 203 Iter next(iter); |
| 204 next.next(); |
| 205 prev.prev(); |
179 | 206 |
180 // randomly perform insertions and deletions on a list and perform tests | 207 SkASSERT(iter.get()); |
181 int count = 0; | 208 // insert either before or after the iterator, then check th
at the |
182 for (int j = 0; j < 100; ++j) { | 209 // surrounding sequence is correct. |
183 if (list1.isEmpty() || random.nextBiasedBool(3 * SK_Scalar1 / 4)) { | 210 if (2 == insertionMethod) { |
184 int id = j; | 211 list1.addBefore(iter, id); |
185 // Choose one of three ways to insert a new element: at the head
, at the tail, | 212 Iter newItem(iter); |
186 // before a random element, after a random element | 213 newItem.prev(); |
187 int numValidMethods = 0 == count ? 2 : 4; | 214 REPORTER_ASSERT(reporter, newItem.get()->fID == id); |
188 int insertionMethod = random.nextULessThan(numValidMethods); | 215 |
189 switch (insertionMethod) { | 216 if (next.get()) { |
190 case 0: | 217 REPORTER_ASSERT(reporter, next.prev()->fID == iter.g
et()->fID); |
191 list1.addToHead(ListElement(id)); | |
192 break; | |
193 case 1: | |
194 list1.addToTail(ListElement(id)); | |
195 break; | |
196 case 2: // fallthru to share code that picks random element. | |
197 case 3: { | |
198 int n = random.nextULessThan(list1.count()); | |
199 Iter iter = list1.headIter(); | |
200 // remember the elements before/after the insertion poin
t. | |
201 while (n--) { | |
202 iter.next(); | |
203 } | 218 } |
204 Iter prev(iter); | 219 if (prev.get()) { |
205 Iter next(iter); | 220 REPORTER_ASSERT(reporter, prev.next()->fID == id); |
206 next.next(); | 221 } |
207 prev.prev(); | 222 } else { |
| 223 list1.addAfter(iter, id); |
| 224 Iter newItem(iter); |
| 225 newItem.next(); |
| 226 REPORTER_ASSERT(reporter, newItem.get()->fID == id); |
208 | 227 |
209 SkASSERT(iter.get()); | 228 if (next.get()) { |
210 // insert either before or after the iterator, then chec
k that the | 229 REPORTER_ASSERT(reporter, next.prev()->fID == id); |
211 // surrounding sequence is correct. | 230 } |
212 if (2 == insertionMethod) { | 231 if (prev.get()) { |
213 list1.addBefore(iter, id); | 232 REPORTER_ASSERT(reporter, prev.next()->fID == iter.g
et()->fID); |
214 Iter newItem(iter); | |
215 newItem.prev(); | |
216 REPORTER_ASSERT(reporter, newItem.get()->fID == id); | |
217 | |
218 if (next.get()) { | |
219 REPORTER_ASSERT(reporter, next.prev()->fID == it
er.get()->fID); | |
220 } | |
221 if (prev.get()) { | |
222 REPORTER_ASSERT(reporter, prev.next()->fID == id
); | |
223 } | |
224 } else { | |
225 list1.addAfter(iter, id); | |
226 Iter newItem(iter); | |
227 newItem.next(); | |
228 REPORTER_ASSERT(reporter, newItem.get()->fID == id); | |
229 | |
230 if (next.get()) { | |
231 REPORTER_ASSERT(reporter, next.prev()->fID == id
); | |
232 } | |
233 if (prev.get()) { | |
234 REPORTER_ASSERT(reporter, prev.next()->fID == it
er.get()->fID); | |
235 } | |
236 } | 233 } |
237 } | 234 } |
238 } | 235 } |
239 ++count; | 236 } |
| 237 ++count; |
| 238 } else { |
| 239 // walk to a random place either forward or backwards and remove. |
| 240 int n = random.nextULessThan(list1.count()); |
| 241 typename Iter::IterStart start; |
| 242 ListElement* (Iter::*incrFunc)(); |
| 243 |
| 244 if (random.nextBool()) { |
| 245 start = Iter::kHead_IterStart; |
| 246 incrFunc = &Iter::next; |
240 } else { | 247 } else { |
241 // walk to a random place either forward or backwards and remove
. | 248 start = Iter::kTail_IterStart; |
242 int n = random.nextULessThan(list1.count()); | 249 incrFunc = &Iter::prev; |
243 Iter::IterStart start; | 250 } |
244 ListElement* (Iter::*incrFunc)(); | |
245 | 251 |
246 if (random.nextBool()) { | 252 // find the element |
247 start = Iter::kHead_IterStart; | 253 Iter iter(list1, start); |
248 incrFunc = &Iter::next; | 254 while (n--) { |
249 } else { | 255 REPORTER_ASSERT(reporter, iter.get()); |
250 start = Iter::kTail_IterStart; | 256 (iter.*incrFunc)(); |
251 incrFunc = &Iter::prev; | 257 } |
252 } | 258 REPORTER_ASSERT(reporter, iter.get()); |
253 | 259 |
254 // find the element | 260 // remember the prev and next elements from the element to be remove
d |
255 Iter iter(list1, start); | 261 Iter prev = iter; |
256 while (n--) { | 262 Iter next = iter; |
257 REPORTER_ASSERT(reporter, iter.get()); | 263 prev.prev(); |
258 (iter.*incrFunc)(); | 264 next.next(); |
259 } | 265 list1.remove(iter.get()); |
260 REPORTER_ASSERT(reporter, iter.get()); | |
261 | 266 |
262 // remember the prev and next elements from the element to be re
moved | 267 // make sure the remembered next/prev iters still work |
263 Iter prev = iter; | 268 Iter pn = prev; pn.next(); |
264 Iter next = iter; | 269 Iter np = next; np.prev(); |
265 prev.prev(); | 270 // pn should match next unless the target node was the head, in whic
h case prev |
266 next.next(); | 271 // walked off the list. |
267 list1.remove(iter.get()); | 272 REPORTER_ASSERT(reporter, pn.get() == next.get() || nullptr == prev.
get()); |
268 | 273 // Similarly, np should match prev unless next originally walked off
the tail. |
269 // make sure the remembered next/prev iters still work | 274 REPORTER_ASSERT(reporter, np.get() == prev.get() || nullptr == next.
get()); |
270 Iter pn = prev; pn.next(); | 275 --count; |
271 Iter np = next; np.prev(); | |
272 // pn should match next unless the target node was the head, in
which case prev | |
273 // walked off the list. | |
274 REPORTER_ASSERT(reporter, pn.get() == next.get() || nullptr == p
rev.get()); | |
275 // Similarly, np should match prev unless next originally walked
off the tail. | |
276 REPORTER_ASSERT(reporter, np.get() == prev.get() || nullptr == n
ext.get()); | |
277 --count; | |
278 } | |
279 REPORTER_ASSERT(reporter, count == list1.count()); | |
280 } | 276 } |
281 list1.reset(); | 277 REPORTER_ASSERT(reporter, count == list1.count()); |
282 } | 278 } |
283 } | 279 } |
284 | 280 |
285 DEF_TEST(LList, reporter) { | 281 DEF_TEST(LList, reporter) { |
286 TestTInternalLList(reporter); | 282 test_tinternallist(reporter); |
287 TestTLList(reporter); | 283 test_tllist<1>(reporter); |
| 284 test_tllist<3>(reporter); |
| 285 test_tllist<8>(reporter); |
| 286 test_tllist<10>(reporter); |
| 287 test_tllist<16>(reporter); |
288 } | 288 } |
OLD | NEW |