29enum eCyclicCheckVisitedState {
44struct CyclesSolverState {
45 CyclesSolverState(Depsgraph *graph)
53 if (num_cycles != 0) {
54 printf(
"Detected %d dependency cycles\n", num_cycles);
62inline void set_node_visited_state(
Node *node, eCyclicCheckVisitedState
state)
64 node->custom_flags = (node->custom_flags & ~0x3) |
int(
state);
67inline eCyclicCheckVisitedState get_node_visited_state(
Node *node)
69 return (eCyclicCheckVisitedState)(node->custom_flags & 0x3);
72inline void set_node_num_visited_children(
Node *node,
int num_children)
74 node->custom_flags = (node->custom_flags & 0x3) | (num_children << 2);
77inline int get_node_num_visited_children(
Node *node)
79 return node->custom_flags >> 2;
82void schedule_node_to_stack(CyclesSolverState *
state, OperationNode *node)
87 entry.via_relation =
nullptr;
89 set_node_visited_state(node, NODE_IN_STACK);
93void schedule_leaf_nodes(CyclesSolverState *
state)
95 for (OperationNode *node :
state->graph->operations) {
96 bool has_inlinks =
false;
97 for (Relation *rel : node->inlinks) {
102 node->custom_flags = 0;
103 if (has_inlinks ==
false) {
104 schedule_node_to_stack(
state, node);
107 set_node_visited_state(node, NODE_NOT_VISITED);
115bool schedule_non_checked_node(CyclesSolverState *
state)
117 for (OperationNode *node :
state->graph->operations) {
118 if (get_node_visited_state(node) == NODE_NOT_VISITED) {
119 schedule_node_to_stack(
state, node);
126bool check_relation_can_murder(Relation *relation)
134Relation *select_relation_to_murder(Relation *relation, StackEntry *cycle_start_entry)
140 if (check_relation_can_murder(relation)) {
143 StackEntry *current = cycle_start_entry;
144 OperationNode *to_node = (OperationNode *)relation->to;
145 while (current->node != to_node) {
146 if (check_relation_can_murder(current->via_relation)) {
147 return current->via_relation;
149 current = current->from;
155void solve_cycles(CyclesSolverState *
state)
160 OperationNode *node = entry->node;
161 bool all_child_traversed =
true;
162 const int num_visited = get_node_num_visited_children(node);
163 for (
int i = num_visited; i < node->outlinks.size(); i++) {
164 Relation *rel = node->outlinks[i];
166 OperationNode *to = (OperationNode *)rel->to;
167 eCyclicCheckVisitedState to_state = get_node_visited_state(to);
168 if (to_state == NODE_IN_STACK) {
169 string cycle_str =
" " + to->full_identifier() +
" depends on\n " +
170 node->full_identifier() +
" via '" + rel->name +
"'\n";
171 StackEntry *current = entry;
172 while (current->node != to) {
174 cycle_str +=
" " + current->from->node->full_identifier() +
" via '" +
175 current->via_relation->name +
"'\n";
176 current = current->from;
178 printf(
"Dependency cycle detected:\n%s", cycle_str.c_str());
179 Relation *sacrificial_relation = select_relation_to_murder(rel, entry);
183 else if (to_state == NODE_NOT_VISITED) {
184 StackEntry new_entry;
186 new_entry.from = entry;
187 new_entry.via_relation = rel;
189 set_node_visited_state(node, NODE_IN_STACK);
190 all_child_traversed =
false;
191 set_node_num_visited_children(node, i);
196 if (all_child_traversed) {
197 set_node_visited_state(node, NODE_VISITED);
207 CyclesSolverState
state(graph);
209 schedule_leaf_nodes(&
state);
210 solve_cycles(&
state);
215 while (schedule_non_checked_node(&
state)) {
216 solve_cycles(&
state);
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_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL()
#define BLI_stack_new(esize, descr)
BLI_Stack * traversal_stack
void deg_graph_detect_cycles(Depsgraph *graph)