[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