Chromium Code Reviews| Index: src/core/SkTDPQueue.h |
| diff --git a/src/core/SkTDPQueue.h b/src/core/SkTDPQueue.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..96fc8627bf66871f75b607ecb78b003be2a8b1fe |
| --- /dev/null |
| +++ b/src/core/SkTDPQueue.h |
| @@ -0,0 +1,190 @@ |
| +/* |
| + * 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&) = 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]; } |
|
egdaniel
2015/02/11 18:58:27
we assert the count > 0 on pop, but not here. Obvi
bsalomon
2015/02/11 19:14:51
nope, fair point. Will remove the redundant assert
|
| + T& peek() { return fArray[0]; } |
| + |
| + /** Removes the next item. */ |
| + void pop() { |
| + SkASSERT(fArray.count()); |
| + this->validate(); |
| + SkDEBUGCODE(if (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()); |
|
egdaniel
2015/02/11 18:58:27
should we assert the entry == fArray[index]? The o
bsalomon
2015/02/11 19:14:52
validate() does that.
|
| + this->validate(); |
| + SkDEBUGCODE(if (INDEX) { *INDEX(fArray[index]) = -1; }) |
|
egdaniel
2015/02/11 18:58:27
We don't need to checkout INDEX here, since we ass
bsalomon
2015/02/11 19:14:52
Done.
|
| + 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) { |
| + return false; |
| + } |
| + int p = ParentOf(index); |
| + if (LESS(fArray[index], fArray[p])) { |
| + SkTSwap(fArray[index], fArray[p]); |
| + this->setIndex(index); |
| + this->setIndex(p); |
| + index = p; |
| + percolated = true; |
| + } else { |
| + 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. |
| + 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(index); |
| + this->setIndex(child); |
| + 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); |
| + this->setIndex(child); |
| + index = child; |
| + } else { |
| + // We're less than both our children. |
| + return; |
| + } |
| + this->validate(index); |
| + } while (true); |
| + } |
| + |
| + void setIndex(int index) { |
| + SkASSERT(index < fArray.count()); |
| + if (INDEX) { |
| + *INDEX(fArray[index]) = index; |
| + } |
| + } |
| + |
| +#ifdef SK_DEBUG |
| + void validate(int excludedIndex = -1) const { |
| + 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 |