| /* |
| * Copyright 2015 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "SkTDPQueue.h" |
| #include "SkRandom.h" |
| #include "Test.h" |
| |
| namespace { bool intless(const int& a, const int& b) { return a < b; } } |
| |
| static void simple_test(skiatest::Reporter* reporter) { |
| SkTDPQueue<int, intless> heap; |
| REPORTER_ASSERT(reporter, 0 == heap.count()); |
| |
| heap.insert(0); |
| REPORTER_ASSERT(reporter, 1 == heap.count()); |
| REPORTER_ASSERT(reporter, 0 == heap.peek()); |
| heap.pop(); |
| REPORTER_ASSERT(reporter, 0 == heap.count()); |
| |
| heap.insert(0); |
| heap.insert(1); |
| REPORTER_ASSERT(reporter, 2 == heap.count()); |
| REPORTER_ASSERT(reporter, 0 == heap.peek()); |
| heap.pop(); |
| REPORTER_ASSERT(reporter, 1 == heap.count()); |
| REPORTER_ASSERT(reporter, 1 == heap.peek()); |
| heap.pop(); |
| REPORTER_ASSERT(reporter, 0 == heap.count()); |
| |
| heap.insert(2); |
| heap.insert(1); |
| heap.insert(0); |
| REPORTER_ASSERT(reporter, 3 == heap.count()); |
| REPORTER_ASSERT(reporter, 0 == heap.peek()); |
| heap.pop(); |
| REPORTER_ASSERT(reporter, 2 == heap.count()); |
| REPORTER_ASSERT(reporter, 1 == heap.peek()); |
| heap.pop(); |
| REPORTER_ASSERT(reporter, 1 == heap.count()); |
| REPORTER_ASSERT(reporter, 2 == heap.peek()); |
| heap.pop(); |
| REPORTER_ASSERT(reporter, 0 == heap.count()); |
| |
| heap.insert(2); |
| heap.insert(3); |
| heap.insert(0); |
| heap.insert(1); |
| REPORTER_ASSERT(reporter, 4 == heap.count()); |
| REPORTER_ASSERT(reporter, 0 == heap.peek()); |
| heap.pop(); |
| REPORTER_ASSERT(reporter, 3 == heap.count()); |
| REPORTER_ASSERT(reporter, 1 == heap.peek()); |
| heap.pop(); |
| REPORTER_ASSERT(reporter, 2 == heap.count()); |
| REPORTER_ASSERT(reporter, 2 == heap.peek()); |
| heap.pop(); |
| REPORTER_ASSERT(reporter, 1 == heap.count()); |
| REPORTER_ASSERT(reporter, 3 == heap.peek()); |
| heap.pop(); |
| REPORTER_ASSERT(reporter, 0 == heap.count()); |
| } |
| |
| struct Dummy { |
| int fValue; |
| int fPriority; |
| mutable int fIndex; |
| |
| static bool LessP(Dummy* const& a, Dummy* const& b) { return a->fPriority < b->fPriority; } |
| static int* PQIndex(Dummy* const& dummy) { return &dummy->fIndex; } |
| |
| bool operator== (const Dummy& that) const { |
| return fValue == that.fValue && fPriority == that.fPriority; |
| } |
| bool operator!= (const Dummy& that) const { return !(*this == that); } |
| }; |
| |
| void random_test(skiatest::Reporter* reporter) { |
| SkRandom random; |
| static const Dummy kSentinel = {-1, -1, -1}; |
| |
| for (int i = 0; i < 100; ++i) { |
| // Create a random set of Dummy objects. |
| int count = random.nextULessThan(100); |
| SkTDArray<Dummy> array; |
| array.setReserve(count); |
| for (int j = 0; j < count; ++j) { |
| Dummy* dummy = array.append(); |
| dummy->fPriority = random.nextS(); |
| dummy->fValue = random.nextS(); |
| dummy->fIndex = -1; |
| if (*dummy == kSentinel) { |
| array.pop(); |
| --j; |
| } |
| } |
| |
| // Stick the dummy objects in the pqueue. |
| SkTDPQueue<Dummy*, Dummy::LessP, Dummy::PQIndex> pq; |
| for (int j = 0; j < count; ++j) { |
| pq.insert(&array[j]); |
| } |
| REPORTER_ASSERT(reporter, pq.count() == array.count()); |
| for (int j = 0; j < count; ++j) { |
| // every item should have an entry in the queue. |
| REPORTER_ASSERT(reporter, -1 != array[j].fIndex); |
| } |
| |
| // Begin the test. |
| while (pq.count()) { |
| // Make sure the top of the queue is really the highest priority. |
| Dummy* top = pq.peek(); |
| for (int k = 0; k < count; ++k) { |
| REPORTER_ASSERT(reporter, kSentinel == array[k] || |
| array[k].fPriority >= top->fPriority); |
| } |
| // Do one of three random actions: |
| unsigned action = random.nextULessThan(3); |
| switch (action) { |
| case 0: { // pop the top, |
| Dummy* top = pq.peek(); |
| REPORTER_ASSERT(reporter, array.begin() <= top && top < array.end()); |
| pq.pop(); |
| *top = kSentinel; |
| break; |
| } |
| case 1: { // remove a random element, |
| int item; |
| do { |
| item = random.nextULessThan(count); |
| } while (array[item] == kSentinel); |
| pq.remove(&array[item]); |
| array[item] = kSentinel; |
| break; |
| } |
| case 2: { // or change an element's priority. |
| int item; |
| do { |
| item = random.nextULessThan(count); |
| } while (array[item] == kSentinel); |
| array[item].fPriority = random.nextS(); |
| pq.priorityDidChange(&array[item]); |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| void sort_test(skiatest::Reporter* reporter) { |
| SkRandom random; |
| |
| SkTDPQueue<Dummy *, Dummy::LessP, Dummy::PQIndex> pqTest; |
| SkTDPQueue<Dummy *, Dummy::LessP, Dummy::PQIndex> pqControl; |
| |
| // Create a random set of Dummy objects and populate the test queue. |
| int count = random.nextULessThan(100); |
| SkTDArray<Dummy> testArray; |
| testArray.setReserve(count); |
| for (int i = 0; i < count; i++) { |
| Dummy *dummy = testArray.append(); |
| dummy->fPriority = random.nextS(); |
| dummy->fValue = random.nextS(); |
| dummy->fIndex = -1; |
| pqTest.insert(&testArray[i]); |
| } |
| |
| // Stick equivalent dummy objects into the control queue. |
| SkTDArray<Dummy> controlArray; |
| controlArray.setReserve(count); |
| for (int i = 0; i < count; i++) { |
| Dummy *dummy = controlArray.append(); |
| dummy->fPriority = testArray[i].fPriority; |
| dummy->fValue = testArray[i].fValue; |
| dummy->fIndex = -1; |
| pqControl.insert(&controlArray[i]); |
| } |
| |
| // Sort the queue |
| pqTest.sort(); |
| |
| // Compare elements in the queue to ensure they are in sorted order |
| int prevPriority = pqTest.peek()->fPriority; |
| for (int i = 0; i < count; i++) { |
| REPORTER_ASSERT(reporter, i <= pqTest.at(i)->fIndex); |
| REPORTER_ASSERT(reporter, prevPriority <= pqTest.at(i)->fPriority); |
| prevPriority = pqTest.at(i)->fPriority; |
| } |
| |
| // Verify that after sorting the queue still produces the same result as the control queue |
| for (int i = 0; i < count; i++) { |
| REPORTER_ASSERT(reporter, *pqControl.peek() == *pqTest.peek()); |
| pqControl.pop(); |
| pqTest.pop(); |
| } |
| } |
| |
| DEF_TEST(TDPQueueTest, reporter) { |
| simple_test(reporter); |
| random_test(reporter); |
| sort_test(reporter); |
| } |