44 enum eCyclicCheckVisitedState {
59 struct CyclesSolverState {
71 printf(
"Detected %d dependency cycles\n",
num_cycles);
79 inline void set_node_visited_state(
Node *
node, eCyclicCheckVisitedState
state)
84 inline eCyclicCheckVisitedState get_node_visited_state(
Node *
node)
89 inline void set_node_num_visited_children(
Node *
node,
int num_children)
94 inline int get_node_num_visited_children(
Node *
node)
99 void schedule_node_to_stack(CyclesSolverState *
state, OperationNode *
node)
103 entry.from =
nullptr;
104 entry.via_relation =
nullptr;
106 set_node_visited_state(
node, NODE_IN_STACK);
110 void schedule_leaf_nodes(CyclesSolverState *
state)
112 for (OperationNode *
node :
state->graph->operations) {
113 bool has_inlinks =
false;
120 if (has_inlinks ==
false) {
124 set_node_visited_state(
node, NODE_NOT_VISITED);
132 bool schedule_non_checked_node(CyclesSolverState *
state)
134 for (OperationNode *
node :
state->graph->operations) {
135 if (get_node_visited_state(
node) == NODE_NOT_VISITED) {
143 bool check_relation_can_murder(Relation *relation)
151 Relation *select_relation_to_murder(Relation *relation, StackEntry *cycle_start_entry)
157 if (check_relation_can_murder(relation)) {
160 StackEntry *current = cycle_start_entry;
161 OperationNode *to_node = (OperationNode *)relation->to;
162 while (current->node != to_node) {
163 if (check_relation_can_murder(current->via_relation)) {
164 return current->via_relation;
166 current = current->from;
172 void solve_cycles(CyclesSolverState *
state)
177 OperationNode *
node = entry->node;
178 bool all_child_traversed =
true;
179 const int num_visited = get_node_num_visited_children(
node);
183 OperationNode *to = (OperationNode *)rel->to;
184 eCyclicCheckVisitedState to_state = get_node_visited_state(to);
185 if (to_state == NODE_IN_STACK) {
186 string cycle_str =
" " + to->full_identifier() +
" depends on\n " +
188 StackEntry *current = entry;
189 while (current->node != to) {
191 cycle_str +=
" " + current->from->node->full_identifier() +
" via '" +
192 current->via_relation->name +
"'\n";
193 current = current->from;
195 printf(
"Dependency cycle detected:\n%s", cycle_str.c_str());
196 Relation *sacrificial_relation = select_relation_to_murder(rel, entry);
200 else if (to_state == NODE_NOT_VISITED) {
201 StackEntry new_entry;
203 new_entry.from = entry;
204 new_entry.via_relation = rel;
206 set_node_visited_state(
node, NODE_IN_STACK);
207 all_child_traversed =
false;
208 set_node_num_visited_children(
node, i);
213 if (all_child_traversed) {
214 set_node_visited_state(
node, NODE_VISITED);
226 schedule_leaf_nodes(&
state);
227 solve_cycles(&
state);
232 while (schedule_non_checked_node(&
state)) {
233 solve_cycles(&
state);
void * BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL()
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL()
#define BLI_stack_new(esize, descr)
struct Depsgraph Depsgraph
BLI_Stack * traversal_stack
void deg_graph_detect_cycles(Depsgraph *graph)
string full_identifier() const