| Index: src/core/SkTDPQueue.h
|
| diff --git a/src/core/SkTDPQueue.h b/src/core/SkTDPQueue.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9efde01b669ed34358d31cf8d29788fa52c4e30a
|
| --- /dev/null
|
| +++ b/src/core/SkTDPQueue.h
|
| @@ -0,0 +1,191 @@
|
| +/*
|
| + * Copyright 2015 Google Inc.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| + */
|
| +
|
| +#ifndef SkTDPQueue_DEFINED
|
| +#define SkTDPQueue_DEFINED
|
| +
|
| +#include "SkTDArray.h"
|
| +
|
| +/**
|
| + * This class implements a priority queue. T is the type of the elements in the queue. LESS is a
|
| + * function that compares two Ts and returns true if the first is higher priority than the second.
|
| + *
|
| + * Optionally objects may know their index into the priority queue. The queue will update the index
|
| + * as the objects move through the queue. This is enabled by using a non-NULL function for INDEX.
|
| + * When an INDEX function is provided random deletes from the queue are allowed using remove().
|
| + * Additionally, the * priority is allowed to change as long as priorityDidChange() is called
|
| + * afterwards. In debug builds the index will be set to -1 before an element is removed from the
|
| + * queue.
|
| + */
|
| +template <typename T,
|
| + bool (*LESS)(const T&, const T&),
|
| + int* (*INDEX)(const T&) = (int* (*)(const T&))NULL>
|
| +class SkTDPQueue : public SkNoncopyable {
|
| +public:
|
| + SkTDPQueue() {}
|
| +
|
| + /** Number of items in the queue. */
|
| + int count() const { return fArray.count(); }
|
| +
|
| + /** Gets the next item in the queue without popping it. */
|
| + const T& peek() const { return fArray[0]; }
|
| + T& peek() { return fArray[0]; }
|
| +
|
| + /** Removes the next item. */
|
| + void pop() {
|
| + this->validate();
|
| + SkDEBUGCODE(if (SkToBool(INDEX)) { *INDEX(fArray[0]) = -1; })
|
| + if (1 == fArray.count()) {
|
| + fArray.pop();
|
| + return;
|
| + }
|
| +
|
| + fArray[0] = fArray[fArray.count() - 1];
|
| + this->setIndex(0);
|
| + fArray.pop();
|
| + this->percolateDownIfNecessary(0);
|
| +
|
| + this->validate();
|
| + }
|
| +
|
| + /** Inserts a new item in the queue based on its priority. */
|
| + void insert(T entry) {
|
| + this->validate();
|
| + int index = fArray.count();
|
| + *fArray.append() = entry;
|
| + this->setIndex(fArray.count() - 1);
|
| + this->percolateUpIfNecessary(index);
|
| + this->validate();
|
| + }
|
| +
|
| + /** Random access removal. This requires that the INDEX function is non-NULL. */
|
| + void remove(T entry) {
|
| + SkASSERT(NULL != INDEX);
|
| + int index = *INDEX(entry);
|
| + SkASSERT(index >= 0 && index < fArray.count());
|
| + this->validate();
|
| + SkDEBUGCODE(*INDEX(fArray[index]) = -1;)
|
| + if (index == fArray.count() - 1) {
|
| + fArray.pop();
|
| + return;
|
| + }
|
| + fArray[index] = fArray[fArray.count() - 1];
|
| + fArray.pop();
|
| + this->setIndex(index);
|
| + this->percolateUpOrDown(index);
|
| + this->validate();
|
| + }
|
| +
|
| + /** Notification that the priority of an entry has changed. This must be called after an
|
| + item's priority is changed to maintain correct ordering. Changing the priority is only
|
| + allowed if an INDEX function is provided. */
|
| + void priorityDidChange(T entry) {
|
| + SkASSERT(NULL != INDEX);
|
| + int index = *INDEX(entry);
|
| + SkASSERT(index >= 0 && index < fArray.count());
|
| + this->validate(index);
|
| + this->percolateUpOrDown(index);
|
| + this->validate();
|
| + }
|
| +
|
| +private:
|
| + static int LeftOf(int x) { SkASSERT(x >= 0); return 2 * x + 1; }
|
| + static int ParentOf(int x) { SkASSERT(x > 0); return (x - 1) >> 1; }
|
| +
|
| + void percolateUpOrDown(int index) {
|
| + SkASSERT(index >= 0);
|
| + if (!percolateUpIfNecessary(index)) {
|
| + this->validate(index);
|
| + this->percolateDownIfNecessary(index);
|
| + }
|
| + }
|
| +
|
| + bool percolateUpIfNecessary(int index) {
|
| + SkASSERT(index >= 0);
|
| + bool percolated = false;
|
| + do {
|
| + if (0 == index) {
|
| + this->setIndex(index);
|
| + return percolated;
|
| + }
|
| + int p = ParentOf(index);
|
| + if (LESS(fArray[index], fArray[p])) {
|
| + SkTSwap(fArray[index], fArray[p]);
|
| + this->setIndex(index);
|
| + index = p;
|
| + percolated = true;
|
| + } else {
|
| + this->setIndex(index);
|
| + return percolated;
|
| + }
|
| + this->validate(index);
|
| + } while (true);
|
| + }
|
| +
|
| + void percolateDownIfNecessary(int index) {
|
| + SkASSERT(index >= 0);
|
| + do {
|
| + int child = LeftOf(index);
|
| +
|
| + if (child >= fArray.count()) {
|
| + // We're a leaf.
|
| + this->setIndex(index);
|
| + return;
|
| + }
|
| +
|
| + if (child + 1 >= fArray.count()) {
|
| + // We only have a left child.
|
| + if (LESS(fArray[child], fArray[index])) {
|
| + SkTSwap(fArray[child], fArray[index]);
|
| + this->setIndex(child);
|
| + this->setIndex(index);
|
| + return;
|
| + }
|
| + } else if (LESS(fArray[child + 1], fArray[child])) {
|
| + // The right child is the one we should swap with, if we swap.
|
| + child++;
|
| + }
|
| +
|
| + // Check if we need to swap.
|
| + if (LESS(fArray[child], fArray[index])) {
|
| + SkTSwap(fArray[child], fArray[index]);
|
| + this->setIndex(index);
|
| + index = child;
|
| + } else {
|
| + // We're less than both our children.
|
| + this->setIndex(index);
|
| + return;
|
| + }
|
| + this->validate(index);
|
| + } while (true);
|
| + }
|
| +
|
| + void setIndex(int index) {
|
| + SkASSERT(index < fArray.count());
|
| + if (SkToBool(INDEX)) {
|
| + *INDEX(fArray[index]) = index;
|
| + }
|
| + }
|
| +
|
| + void validate(int excludedIndex = -1) const {
|
| +#ifdef SK_DEBUG
|
| + for (int i = 1; i < fArray.count(); ++i) {
|
| + int p = ParentOf(i);
|
| + if (excludedIndex != p && excludedIndex != i) {
|
| + SkASSERT(!(LESS(fArray[i], fArray[p])));
|
| + SkASSERT(!SkToBool(INDEX) || *INDEX(fArray[i]) == i);
|
| + }
|
| + }
|
| +#endif
|
| + }
|
| +
|
| + SkTDArray<T> fArray;
|
| +
|
| + typedef SkNoncopyable INHERITED;
|
| +};
|
| +
|
| +#endif
|
|
|