2015-02-13 19:08:21 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2015 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/utils/SkRandom.h"
|
|
|
|
#include "src/core/SkTDPQueue.h"
|
|
|
|
#include "tests/Test.h"
|
2015-02-13 19:08:21 +00:00
|
|
|
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2020-07-31 17:47:50 +00:00
|
|
|
struct Mock {
|
2015-02-13 19:08:21 +00:00
|
|
|
int fValue;
|
|
|
|
int fPriority;
|
|
|
|
mutable int fIndex;
|
|
|
|
|
2020-07-31 17:47:50 +00:00
|
|
|
static bool LessP(Mock* const& a, Mock* const& b) { return a->fPriority < b->fPriority; }
|
|
|
|
static int* PQIndex(Mock* const& mock) { return &mock->fIndex; }
|
2015-02-13 19:08:21 +00:00
|
|
|
|
2020-07-31 17:47:50 +00:00
|
|
|
bool operator== (const Mock& that) const {
|
2015-02-13 19:08:21 +00:00
|
|
|
return fValue == that.fValue && fPriority == that.fPriority;
|
|
|
|
}
|
2020-07-31 17:47:50 +00:00
|
|
|
bool operator!= (const Mock& that) const { return !(*this == that); }
|
2015-02-13 19:08:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void random_test(skiatest::Reporter* reporter) {
|
|
|
|
SkRandom random;
|
2020-07-31 17:47:50 +00:00
|
|
|
static const Mock kSentinel = {-1, -1, -1};
|
2015-02-13 19:08:21 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < 100; ++i) {
|
2020-07-31 17:47:50 +00:00
|
|
|
// Create a random set of Mock objects.
|
2015-02-13 19:08:21 +00:00
|
|
|
int count = random.nextULessThan(100);
|
2020-07-31 17:47:50 +00:00
|
|
|
SkTDArray<Mock> array;
|
2015-02-13 19:08:21 +00:00
|
|
|
array.setReserve(count);
|
|
|
|
for (int j = 0; j < count; ++j) {
|
2020-07-31 17:47:50 +00:00
|
|
|
Mock* mock = array.append();
|
|
|
|
mock->fPriority = random.nextS();
|
|
|
|
mock->fValue = random.nextS();
|
|
|
|
mock->fIndex = -1;
|
|
|
|
if (*mock == kSentinel) {
|
2015-02-13 19:08:21 +00:00
|
|
|
array.pop();
|
|
|
|
--j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-31 17:47:50 +00:00
|
|
|
// Stick the mock objects in the pqueue.
|
|
|
|
SkTDPQueue<Mock*, Mock::LessP, Mock::PQIndex> pq;
|
2015-02-13 19:08:21 +00:00
|
|
|
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.
|
2020-07-31 17:47:50 +00:00
|
|
|
Mock* top = pq.peek();
|
2015-02-13 19:08:21 +00:00
|
|
|
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,
|
2021-08-12 14:48:09 +00:00
|
|
|
top = pq.peek();
|
2015-02-13 19:08:21 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-25 20:43:59 +00:00
|
|
|
void sort_test(skiatest::Reporter* reporter) {
|
|
|
|
SkRandom random;
|
|
|
|
|
2020-07-31 17:47:50 +00:00
|
|
|
SkTDPQueue<Mock *, Mock::LessP, Mock::PQIndex> pqTest;
|
|
|
|
SkTDPQueue<Mock *, Mock::LessP, Mock::PQIndex> pqControl;
|
2017-05-25 20:43:59 +00:00
|
|
|
|
2020-07-31 17:47:50 +00:00
|
|
|
// Create a random set of Mock objects and populate the test queue.
|
2017-05-25 20:43:59 +00:00
|
|
|
int count = random.nextULessThan(100);
|
2020-07-31 17:47:50 +00:00
|
|
|
SkTDArray<Mock> testArray;
|
2017-05-25 20:43:59 +00:00
|
|
|
testArray.setReserve(count);
|
|
|
|
for (int i = 0; i < count; i++) {
|
2020-07-31 17:47:50 +00:00
|
|
|
Mock *mock = testArray.append();
|
|
|
|
mock->fPriority = random.nextS();
|
|
|
|
mock->fValue = random.nextS();
|
|
|
|
mock->fIndex = -1;
|
2017-05-25 20:43:59 +00:00
|
|
|
pqTest.insert(&testArray[i]);
|
|
|
|
}
|
|
|
|
|
2020-07-31 17:47:50 +00:00
|
|
|
// Stick equivalent mock objects into the control queue.
|
|
|
|
SkTDArray<Mock> controlArray;
|
2017-05-25 20:43:59 +00:00
|
|
|
controlArray.setReserve(count);
|
|
|
|
for (int i = 0; i < count; i++) {
|
2020-07-31 17:47:50 +00:00
|
|
|
Mock *mock = controlArray.append();
|
|
|
|
mock->fPriority = testArray[i].fPriority;
|
|
|
|
mock->fValue = testArray[i].fValue;
|
|
|
|
mock->fIndex = -1;
|
2017-05-25 20:43:59 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-13 19:08:21 +00:00
|
|
|
DEF_TEST(TDPQueueTest, reporter) {
|
|
|
|
simple_test(reporter);
|
|
|
|
random_test(reporter);
|
2017-05-25 20:43:59 +00:00
|
|
|
sort_test(reporter);
|
2015-02-13 19:08:21 +00:00
|
|
|
}
|