[Bf-blender-cvs] [35bf6b9790f] temp-geometry-nodes-fields: move dot graph generation into utility class
Jacques Lucke
noreply at git.blender.org
Sun Aug 29 12:57:01 CEST 2021
Commit: 35bf6b9790fd3ca1a62216860765d9faa2f71fa1
Author: Jacques Lucke
Date: Sun Aug 29 12:27:39 2021 +0200
Branches: temp-geometry-nodes-fields
https://developer.blender.org/rB35bf6b9790fd3ca1a62216860765d9faa2f71fa1
move dot graph generation into utility class
===================================================================
M source/blender/functions/FN_multi_function_procedure.hh
M source/blender/functions/intern/multi_function_procedure.cc
===================================================================
diff --git a/source/blender/functions/FN_multi_function_procedure.hh b/source/blender/functions/FN_multi_function_procedure.hh
index 07aa84e0f94..88053808c24 100644
--- a/source/blender/functions/FN_multi_function_procedure.hh
+++ b/source/blender/functions/FN_multi_function_procedure.hh
@@ -178,6 +178,8 @@ class MFProcedure : NonCopyable, NonMovable {
Vector<MFParameter> params_;
MFInstruction *entry_ = nullptr;
+ friend class MFProcedureDotExport;
+
public:
MFProcedure() = default;
~MFProcedure();
diff --git a/source/blender/functions/intern/multi_function_procedure.cc b/source/blender/functions/intern/multi_function_procedure.cc
index d98664712bf..1782d50371f 100644
--- a/source/blender/functions/intern/multi_function_procedure.cc
+++ b/source/blender/functions/intern/multi_function_procedure.cc
@@ -488,264 +488,285 @@ MFProcedure::InitState MFProcedure::find_initialization_state_before_instruction
return state;
}
-static bool has_to_be_block_begin(const MFProcedure &procedure, const MFInstruction &instruction)
-{
- if (procedure.entry() == &instruction) {
- return true;
- }
- if (instruction.prev().size() != 1) {
- return true;
- }
- if (instruction.prev()[0]->type() == MFInstructionType::Branch) {
- return true;
- }
- return false;
-}
-
-static const MFInstruction &get_first_instruction_in_block(const MFProcedure &procedure,
- const MFInstruction &representative)
-{
- const MFInstruction *current = &representative;
- while (!has_to_be_block_begin(procedure, *current)) {
- current = current->prev()[0];
- if (current == &representative) {
- /* There is a loop without entry or exit, just break it up here. */
- break;
- }
- }
- return *current;
-}
-
-static const MFInstruction *get_next_instruction_in_block(const MFProcedure &procedure,
- const MFInstruction &instruction,
- const MFInstruction &block_begin)
-{
- const MFInstruction *next = nullptr;
- switch (instruction.type()) {
- case MFInstructionType::Call: {
- next = static_cast<const MFCallInstruction &>(instruction).next();
- break;
- }
- case MFInstructionType::Destruct: {
- next = static_cast<const MFDestructInstruction &>(instruction).next();
- break;
- }
- case MFInstructionType::Dummy: {
- next = static_cast<const MFDummyInstruction &>(instruction).next();
- break;
- }
- case MFInstructionType::Return:
- case MFInstructionType::Branch: {
- break;
- }
- }
- if (next == nullptr) {
- return nullptr;
- }
- if (next == &block_begin) {
- return nullptr;
- }
- if (has_to_be_block_begin(procedure, *next)) {
- return nullptr;
- }
- return next;
-}
-
-static Vector<const MFInstruction *> get_instructions_in_block(const MFProcedure &procedure,
- const MFInstruction &representative)
-{
- Vector<const MFInstruction *> instructions;
- const MFInstruction &begin = get_first_instruction_in_block(procedure, representative);
- for (const MFInstruction *current = &begin; current != nullptr;
- current = get_next_instruction_in_block(procedure, *current, begin)) {
- instructions.append(current);
- }
- return instructions;
-}
-
-static void variable_to_string(const MFVariable *variable, std::stringstream &ss)
-{
- if (variable == nullptr) {
- ss << "null";
- }
- else {
- ss << "$" << variable->id();
- if (!variable->name().is_empty()) {
- ss << "(" << variable->name() << ")";
- }
- }
-}
-
-static void instruction_name_format(StringRef name, std::stringstream &ss)
-{
- ss << name;
-}
-
-static void instruction_to_string(const MFCallInstruction &instruction, std::stringstream &ss)
-{
- const MultiFunction &fn = instruction.fn();
- instruction_name_format(fn.name() + ": ", ss);
- for (const int param_index : fn.param_indices()) {
- const MFParamType param_type = fn.param_type(param_index);
- const MFVariable *variable = instruction.params()[param_index];
- ss << R"(<font color="grey30">)";
- switch (param_type.interface_type()) {
- case MFParamType::Input: {
- ss << "in";
- break;
- }
- case MFParamType::Mutable: {
- ss << "mut";
- break;
+class MFProcedureDotExport {
+ private:
+ const MFProcedure &procedure_;
+ dot::DirectedGraph digraph_;
+ Map<const MFInstruction *, dot::Node *> dot_nodes_by_begin_;
+ Map<const MFInstruction *, dot::Node *> dot_nodes_by_end_;
+
+ public:
+ MFProcedureDotExport(const MFProcedure &procedure) : procedure_(procedure)
+ {
+ }
+
+ std::string generate()
+ {
+ this->create_nodes();
+ this->create_edges();
+ return digraph_.to_dot_string();
+ }
+
+ void create_nodes()
+ {
+ Vector<const MFInstruction *> all_instructions;
+ auto add_instructions = [&](auto instructions) {
+ all_instructions.extend(instructions.begin(), instructions.end());
+ };
+ add_instructions(procedure_.call_instructions_);
+ add_instructions(procedure_.branch_instructions_);
+ add_instructions(procedure_.destruct_instructions_);
+ add_instructions(procedure_.dummy_instructions_);
+ add_instructions(procedure_.return_instructions_);
+
+ Set<const MFInstruction *> handled_instructions;
+
+ for (const MFInstruction *representative : all_instructions) {
+ if (handled_instructions.contains(representative)) {
+ continue;
}
- case MFParamType::Output: {
- ss << "out";
- break;
+ Vector<const MFInstruction *> block_instructions = this->get_instructions_in_block(
+ *representative);
+ std::stringstream ss;
+ ss << "<";
+
+ for (const MFInstruction *current : block_instructions) {
+ handled_instructions.add_new(current);
+ switch (current->type()) {
+ case MFInstructionType::Call: {
+ this->instruction_to_string(*static_cast<const MFCallInstruction *>(current), ss);
+ break;
+ }
+ case MFInstructionType::Destruct: {
+ this->instruction_to_string(*static_cast<const MFDestructInstruction *>(current), ss);
+ break;
+ }
+ case MFInstructionType::Dummy: {
+ this->instruction_to_string(*static_cast<const MFDummyInstruction *>(current), ss);
+ break;
+ }
+ case MFInstructionType::Return: {
+ this->instruction_to_string(*static_cast<const MFReturnInstruction *>(current), ss);
+ break;
+ }
+ case MFInstructionType::Branch: {
+ this->instruction_to_string(*static_cast<const MFBranchInstruction *>(current), ss);
+ break;
+ }
+ }
+ ss << R"(<br align="left" />)";
}
- }
- ss << " </font> ";
- variable_to_string(variable, ss);
- if (param_index < fn.param_amount() - 1) {
- ss << ", ";
- }
- }
-}
-
-static void instruction_to_string(const MFDestructInstruction &instruction, std::stringstream &ss)
-{
- instruction_name_format("Destruct ", ss);
- variable_to_string(instruction.variable(), ss);
-}
-
-static void instruction_to_string(const MFDummyInstruction &UNUSED(instruction),
- std::stringstream &ss)
-{
- instruction_name_format("Dummy ", ss);
-}
-
-static void instruction_to_string(const MFReturnInstruction &UNUSED(instruction),
- std::stringstream &ss)
-{
- instruction_name_format("Return ", ss);
-}
-
-static void instruction_to_string(const MFBranchInstruction &instruction, std::stringstream &ss)
-{
- instruction_name_format("Branch ", ss);
- variable_to_string(instruction.condition(), ss);
-}
-
-std::string MFProcedure::to_dot() const
-{
- Vector<const MFInstruction *> all_instructions;
- all_instructions.extend(call_instructions_.begin(), call_instructions_.end());
- all_instructions.extend(branch_instructions_.begin(), branch_instructions_.end());
- all_instructions.extend(destruct_instructions_.begin(), destruct_instructions_.end());
- all_instructions.extend(dummy_instructions_.begin(), dummy_instructions_.end());
- all_instructions.extend(return_instructions_.begin(), return_instructions_.end());
+ ss << ">";
- Set<const MFInstruction *> handled_instructions;
-
- dot::DirectedGraph digraph;
- Map<const MFInstruction *, dot::Node *> dot_nodes_by_begin;
- Map<const MFInstruction *, dot::Node *> dot_nodes_by_end;
-
- for (const MFInstruction *representative : all_instructions) {
- if (handled_instructions.contains(representative)) {
- continue;
+ dot::Node &dot_node = digraph_.new_node(ss.str());
+ dot_node.set_shape(dot::Attr_shape::Rectangle);
+ dot_nodes_by_begin_.add_new(block_instructions.first(), &dot_node);
+ dot_nodes_by_end_.add_new(block_instructions.last(), &dot_node);
}
- Vector<const MFInstruction *> block_instructions = get_instructions_in_block(*this,
- *representative);
- std::stringstream ss;
- ss << "<";
+ }
- for (const MFInstruction *current : block_instructions) {
- handled_instructions.add_new(current);
- switch (current->type()) {
+ void create_edges()
+ {
+ auto create_edge = [&](dot::Node &from_node,
+ const MFInstruction *to_instruction) -> dot::DirectedEdge & {
+ if (to_instruction == nullptr) {
+ dot::Node &to_node = digraph_.new_node("missing");
+ to_node.set_shape(dot::Attr_shape::Diamond);
+ return digraph_.new_edge(from_node, to_node);
+ }
+ dot::Node &to_node = *dot_nodes_by_begin_.lookup(to_instruction);
+ return digraph_.new_edge(from_node, to_node);
+ };
+
+ for (auto item : dot_nodes_by_end_.items()) {
+ const MFInstruction &from_instruction = *item.key;
+ dot::Node &from_node = *item.value;
+ switch (from_instruction.type()) {
case MFInstructionType::Call: {
- instruction_to_string(*static_cast<const MFCallInstruction *>
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list