Chromium Code Reviews| Index: src/core/SkTTopoSort.h |
| diff --git a/src/core/SkTTopoSort.h b/src/core/SkTTopoSort.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..57387035194d97f9ad10ad1aeb7ac385088cb59d |
| --- /dev/null |
| +++ b/src/core/SkTTopoSort.h |
| @@ -0,0 +1,96 @@ |
| +/* |
| + * 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 SkTTopoSort_DEFINED |
| +#define SkTTopoSort_DEFINED |
| + |
| +#include "SkTDArray.h" |
| + |
| +#ifdef SK_DEBUG |
| +template <typename T, typename Traits = T> |
| +void SkTTopoSort_CheckAllUnmarked(const SkTDArray<T*>& graph) { |
| + for (int i = 0; i < graph.count(); ++i) { |
| + SkASSERT(!Traits::IsTempMarked(graph[i])); |
| + SkASSERT(!Traits::WasOutput(graph[i])); |
| + } |
| +} |
| + |
| +template <typename T, typename Traits = T> |
| +void SkTTopoSort_CleanExit(const SkTDArray<T*>& graph) { |
| + for (int i = 0; i < graph.count(); ++i) { |
| + SkASSERT(!Traits::IsTempMarked(graph[i])); |
| + SkASSERT(Traits::WasOutput(graph[i])); |
| + } |
| +} |
| +#endif |
| + |
| +// Recursively visit a node and all the other nodes it depends on. |
| +// Return false if there is a loop. |
| +template <typename T, typename Traits = T> |
| +bool SkTTopoSort_Visit(T* node, SkTDArray<T*>* result) { |
| + if (Traits::IsTempMarked(node)) { |
| + // There is a loop. |
| + return false; |
| + } |
| + |
| + // If the node under consideration has been already been output it means it |
| + // (and all the nodes it depends on) are already in 'result'. |
| + if (!Traits::WasOutput(node)) { |
| + // This node hasn't been output yet. Recursively assess all the |
| + // nodes it depends on outputing them first. |
| + Traits::SetTempMark(node); |
| + for (int i = 0; i < Traits::NumDependencies(node); ++i) { |
| + if (!SkTTopoSort_Visit<T, Traits>(Traits::Dependency(node, i), result)) { |
| + return false; |
| + } |
| + } |
| + Traits::Output(node, result->count()); // mark this node as output |
| + Traits::ResetTempMark(node); |
| + |
| + *result->append() = node; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +// Topologically sort the nodes in 'graph'. For this sort, when node 'i' depends |
| +// on node 'j' it means node 'j' must appear in the result before node 'i'. |
| +// A false return value means there was a loop and the contents of 'graph' will |
| +// be in some arbitrary state. |
| +template <typename T, typename Traits = T> |
|
bsalomon
2015/10/19 14:19:13
Maybe comment about what signatures are required o
robertphillips
2015/10/19 16:21:07
Done.
|
| +bool SkTTopoSort(SkTDArray<T*>* graph) { |
|
bsalomon
2015/10/19 14:19:13
Wondering in consideration of GrDT graph if the gr
robertphillips
2015/10/19 16:21:07
Interesting. I think we could just call SkTTopoSor
|
| + SkTDArray<T*> result; |
| + |
| +#ifdef SK_DEBUG |
| + SkTTopoSort_CheckAllUnmarked<T, Traits>(*graph); |
| +#endif |
| + |
| + result.setReserve(graph->count()); |
| + |
| + for (int i = 0; i < graph->count(); ++i) { |
| + if (Traits::WasOutput((*graph)[i])) { |
| + // This node was depended on by some earlier node and has already |
| + // been output |
| + continue; |
| + } |
| + |
| + // Output this node after all the nodes it depends on have been output. |
| + if (!SkTTopoSort_Visit<T, Traits>((*graph)[i], &result)) { |
| + return false; |
| + } |
| + } |
| + |
| + SkASSERT(graph->count() == result.count()); |
| + graph->swap(result); |
| + |
| +#ifdef SK_DEBUG |
| + SkTTopoSort_CleanExit<T, Traits>(*graph); |
| +#endif |
| + return true; |
| +} |
| + |
| +#endif |