Flutter Engine
The Flutter Engine
GrTTopoSort.h
Go to the documentation of this file.
1/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrTTopoSort_DEFINED
9#define GrTTopoSort_DEFINED
10
12#include "include/core/SkSpan.h"
13
14#ifdef SK_DEBUG
15template <typename T, typename Traits = T>
16void GrTTopoSort_CheckAllUnmarked(SkSpan<const sk_sp<T>> graph) {
17 for (const auto& node : graph) {
18 SkASSERT(!Traits::IsTempMarked(node.get()));
19 SkASSERT(!Traits::WasOutput(node.get()));
20 }
21}
22
23template <typename T, typename Traits = T>
24void GrTTopoSort_CleanExit(SkSpan<const sk_sp<T>> graph, uint32_t offset) {
25 for (size_t i = 0; i < graph.size(); ++i) {
26 SkASSERT(!Traits::IsTempMarked(graph[i].get()));
27 SkASSERT(Traits::WasOutput(graph[i].get()));
28 SkASSERT(Traits::GetIndex(graph[i].get()) - offset == (uint32_t) i);
29 }
30}
31#endif
32
33// Recursively visit a node and all the other nodes it depends on.
34// Return false if there is a loop.
35template <typename T, typename Traits = T>
36bool GrTTopoSort_Visit(T* node, uint32_t* counter) {
37 if (Traits::IsTempMarked(node)) {
38 // There is a loop.
39 return false;
40 }
41
42 // If the node under consideration has been already been output it means it
43 // (and all the nodes it depends on) are already in 'result'.
44 if (Traits::WasOutput(node)) {
45 return true;
46 }
47
48 bool succeeded = true;
49 // This node hasn't been output yet. Recursively assess all the
50 // nodes it depends on outputing them first.
51 Traits::SetTempMark(node);
52 for (int i = 0; i < Traits::NumDependencies(node); ++i) {
53 if (!GrTTopoSort_Visit<T, Traits>(Traits::Dependency(node, i), counter)) {
54 succeeded = false;
55 }
56 }
57
58 Traits::Output(node, *counter); // mark this node as output
59 ++(*counter);
60 Traits::ResetTempMark(node);
61
62 return succeeded;
63}
64
65// Topologically sort the nodes in 'graph'. For this sort, when node 'i' depends
66// on node 'j' it means node 'j' must appear in the result before node 'i'. Note that all
67// dependencies of a node in the Span must also be in the Span or already have WasOutput() = true.
68//
69// A false return value means there was a loop and the contents of 'graph' will
70// be in some arbitrary state.
71//
72// Traits requires:
73// static void Output(T* t, uint32_t index) { ... } // 'index' is 't's position in the result
74// static bool WasOutput(const T* t) { ... }
75// static uint32_t GetIndex() { ... }
76//
77// static void SetTempMark(T* t) { ... } // transiently used during toposort
78// static void ResetTempMark(T* t) { ... }
79// static bool IsTempMarked(const T* t) { ... }
80//
81// static int NumDependencies(const T* t) { ... } // 't' will be output after all the other -
82// static T* Dependency(T* t, int index) { ... } // nodes on which it depends
83// We'll look on T for these by default, or you can pass a custom Traits type.
84//
85// The offset parameter is useful if you are sorting ranges of a larger graph and when Output()
86// is called on a T it must know it's position in the full graph array.
87//
88// TODO: potentially add a version that takes a seed node and just outputs that
89// node and all the nodes on which it depends. This could be used to partially
90// flush a GrRenderTask DAG.
91template <typename T, typename Traits = T>
92bool GrTTopoSort(SkSpan<sk_sp<T>> graph, uint32_t offset = 0) {
93 uint32_t counter = offset;
94
95#ifdef SK_DEBUG
96 GrTTopoSort_CheckAllUnmarked<T, Traits>(graph);
97#endif
98
99 bool succeeded = true;
100
101 for (size_t i = 0; i < graph.size(); ++i) {
102 if (Traits::WasOutput(graph[i].get())) {
103 // This node was depended on by some earlier node and has already
104 // been output
105 continue;
106 }
107
108 // Output this node after all the nodes it depends on have been output.
109 if (!GrTTopoSort_Visit<T, Traits>(graph[i].get(), &counter)) {
110 succeeded = false;
111 }
112 }
113
114 SkASSERT(counter - offset == (uint32_t) graph.size());
115
116 // Reorder the array given the output order
117 for (uint32_t i = 0; i < (uint32_t) graph.size(); ++i) {
118 for (uint32_t correctIndex = Traits::GetIndex(graph[i].get()) - offset;
119 correctIndex != i;
120 correctIndex = Traits::GetIndex(graph[i].get()) - offset) {
121 graph[i].swap(graph[correctIndex]);
122 }
123 }
124
125#ifdef SK_DEBUG
126 GrTTopoSort_CleanExit<T, Traits>(graph, offset);
127#endif
128 return succeeded;
129}
130
131#endif
bool GrTTopoSort(SkSpan< sk_sp< T > > graph, uint32_t offset=0)
Definition: GrTTopoSort.h:92
bool GrTTopoSort_Visit(T *node, uint32_t *counter)
Definition: GrTTopoSort.h:36
#define SkASSERT(cond)
Definition: SkAssert.h:116
Output
Definition: SkSLBench.cpp:61
const myers::Point & get(const myers::Segment &)
#define T
Definition: precompiler.cc:65
SeparatedVector2 offset