| 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 |