[Bf-blender-cvs] [10f2ad1556b] temp-multi-function-procedure: add return instruction and initial procedure validation

Jacques Lucke noreply at git.blender.org
Sun Aug 22 22:36:29 CEST 2021


Commit: 10f2ad1556bd9b79d28c4b5d642ed2d6aafb488a
Author: Jacques Lucke
Date:   Sun Aug 22 20:16:27 2021 +0200
Branches: temp-multi-function-procedure
https://developer.blender.org/rB10f2ad1556bd9b79d28c4b5d642ed2d6aafb488a

add return instruction and initial procedure validation

===================================================================

M	source/blender/functions/FN_multi_function_procedure.hh
M	source/blender/functions/FN_multi_function_procedure_builder.hh
M	source/blender/functions/intern/multi_function_procedure.cc
M	source/blender/functions/intern/multi_function_procedure_builder.cc
M	source/blender/functions/intern/multi_function_procedure_executor.cc
M	source/blender/functions/tests/FN_multi_function_procedure_test.cc

===================================================================

diff --git a/source/blender/functions/FN_multi_function_procedure.hh b/source/blender/functions/FN_multi_function_procedure.hh
index b9540540992..aacc3f9331f 100644
--- a/source/blender/functions/FN_multi_function_procedure.hh
+++ b/source/blender/functions/FN_multi_function_procedure.hh
@@ -30,6 +30,7 @@ class MFCallInstruction;
 class MFBranchInstruction;
 class MFDestructInstruction;
 class MFDummyInstruction;
+class MFReturnInstruction;
 class MFProcedure;
 
 enum class MFInstructionType {
@@ -37,6 +38,7 @@ enum class MFInstructionType {
   Branch,
   Destruct,
   Dummy,
+  Return,
 };
 
 class MFVariable : NonCopyable, NonMovable {
@@ -71,6 +73,7 @@ class MFInstruction : NonCopyable, NonMovable {
   friend MFBranchInstruction;
   friend MFDestructInstruction;
   friend MFDummyInstruction;
+  friend MFReturnInstruction;
 
  public:
   MFInstructionType type() const;
@@ -104,6 +107,8 @@ class MFBranchInstruction : public MFInstruction {
   MFInstruction *branch_true_ = nullptr;
   MFInstruction *branch_false_ = nullptr;
 
+  friend MFProcedure;
+
  public:
   MFVariable *condition();
   const MFVariable *condition() const;
@@ -123,6 +128,8 @@ class MFDestructInstruction : public MFInstruction {
   MFVariable *variable_ = nullptr;
   MFInstruction *next_ = nullptr;
 
+  friend MFProcedure;
+
  public:
   MFVariable *variable();
   const MFVariable *variable() const;
@@ -137,12 +144,27 @@ class MFDummyInstruction : public MFInstruction {
  private:
   MFInstruction *next_ = nullptr;
 
+  friend MFProcedure;
+
  public:
   MFInstruction *next();
   const MFInstruction *next() const;
   void set_next(MFInstruction *instruction);
 };
 
+class MFReturnInstruction : public MFInstruction {
+};
+
+struct MFParameter {
+  MFParamType::InterfaceType type;
+  MFVariable *variable;
+};
+
+struct ConstMFParameter {
+  MFParamType::InterfaceType type;
+  const MFVariable *variable;
+};
+
 class MFProcedure : NonCopyable, NonMovable {
  private:
   LinearAllocator<> allocator_;
@@ -150,8 +172,9 @@ class MFProcedure : NonCopyable, NonMovable {
   Vector<MFBranchInstruction *> branch_instructions_;
   Vector<MFDestructInstruction *> destruct_instructions_;
   Vector<MFDummyInstruction *> dummy_instructions_;
+  Vector<MFReturnInstruction *> return_instructions_;
   Vector<MFVariable *> variables_;
-  Vector<std::pair<MFParamType::InterfaceType, MFVariable *>> params_;
+  Vector<MFParameter> params_;
   MFInstruction *entry_ = nullptr;
 
  public:
@@ -163,10 +186,11 @@ class MFProcedure : NonCopyable, NonMovable {
   MFBranchInstruction &new_branch_instruction();
   MFDestructInstruction &new_destruct_instruction();
   MFDummyInstruction &new_dummy_instruction();
+  MFReturnInstruction &new_return_instruction();
 
   void add_parameter(MFParamType::InterfaceType interface_type, MFVariable &variable);
 
-  Span<std::pair<MFParamType::InterfaceType, const MFVariable *>> params() const;
+  Span<ConstMFParameter> params() const;
 
   MFInstruction *entry();
   const MFInstruction *entry() const;
@@ -178,6 +202,23 @@ class MFProcedure : NonCopyable, NonMovable {
   void assert_valid() const;
 
   std::string to_dot() const;
+
+  bool validate() const;
+
+ private:
+  bool validate_all_instruction_pointers_set() const;
+  bool validate_all_params_provided() const;
+  bool validate_same_variables_in_one_call() const;
+  bool validate_parameters() const;
+  bool validate_initialization() const;
+
+  struct InitState {
+    bool can_be_initialized = false;
+    bool can_be_uninitialized = false;
+  };
+
+  InitState find_initialization_state_before_instruction(const MFInstruction &target_instruction,
+                                                         const MFVariable &variable) const;
 };
 
 namespace multi_function_procedure_types {
@@ -332,9 +373,10 @@ inline const MFInstruction *MFDummyInstruction::next() const
  * MFProcedure inline methods.
  */
 
-inline Span<std::pair<MFParamType::InterfaceType, const MFVariable *>> MFProcedure::params() const
+inline Span<ConstMFParameter> MFProcedure::params() const
 {
-  return params_.as_span().cast<std::pair<MFParamType::InterfaceType, const MFVariable *>>();
+  static_assert(sizeof(MFParameter) == sizeof(ConstMFParameter));
+  return params_.as_span().cast<ConstMFParameter>();
 }
 
 inline MFInstruction *MFProcedure::entry()
diff --git a/source/blender/functions/FN_multi_function_procedure_builder.hh b/source/blender/functions/FN_multi_function_procedure_builder.hh
index 1088c18a8b9..397a9b08beb 100644
--- a/source/blender/functions/FN_multi_function_procedure_builder.hh
+++ b/source/blender/functions/FN_multi_function_procedure_builder.hh
@@ -70,6 +70,8 @@ class MFProcedureBuilder {
   void add_destruct(MFVariable &variable);
   void add_destruct(Span<MFVariable *> variables);
 
+  MFReturnInstruction &add_return();
+
   Branch add_branch(MFVariable &condition);
 
   Loop add_loop();
diff --git a/source/blender/functions/intern/multi_function_procedure.cc b/source/blender/functions/intern/multi_function_procedure.cc
index d9bf611fa34..bb7c2a98e32 100644
--- a/source/blender/functions/intern/multi_function_procedure.cc
+++ b/source/blender/functions/intern/multi_function_procedure.cc
@@ -17,6 +17,7 @@
 #include "FN_multi_function_procedure.hh"
 
 #include "BLI_dot_export.hh"
+#include "BLI_stack.hh"
 
 namespace blender::fn {
 
@@ -167,6 +168,14 @@ MFDummyInstruction &MFProcedure::new_dummy_instruction()
   return instruction;
 }
 
+MFReturnInstruction &MFProcedure::new_return_instruction()
+{
+  MFReturnInstruction &instruction = *allocator_.construct<MFReturnInstruction>().release();
+  instruction.type_ = MFInstructionType::Return;
+  return_instructions_.append(&instruction);
+  return instruction;
+}
+
 void MFProcedure::add_parameter(MFParamType::InterfaceType interface_type, MFVariable &variable)
 {
   params_.append({interface_type, &variable});
@@ -205,6 +214,9 @@ MFProcedure::~MFProcedure()
   for (MFDummyInstruction *instruction : dummy_instructions_) {
     instruction->~MFDummyInstruction();
   }
+  for (MFReturnInstruction *instruction : return_instructions_) {
+    instruction->~MFReturnInstruction();
+  }
   for (MFVariable *variable : variables_) {
     variable->~MFVariable();
   }
@@ -220,6 +232,269 @@ static std::string optional_variable_to_string(const MFVariable *variable)
   return ss.str();
 }
 
+bool MFProcedure::validate() const
+{
+  if (!this->validate_all_instruction_pointers_set()) {
+    return false;
+  }
+  if (!this->validate_all_params_provided()) {
+    return false;
+  }
+  if (!this->validate_same_variables_in_one_call()) {
+    return false;
+  }
+  if (!this->validate_parameters()) {
+    return false;
+  }
+  if (!this->validate_initialization()) {
+    return false;
+  }
+  return true;
+}
+
+bool MFProcedure::validate_all_instruction_pointers_set() const
+{
+  for (const MFCallInstruction *instruction : call_instructions_) {
+    if (instruction->next_ == nullptr) {
+      return false;
+    }
+  }
+  for (const MFDestructInstruction *instruction : destruct_instructions_) {
+    if (instruction->next_ == nullptr) {
+      return false;
+    }
+  }
+  for (const MFBranchInstruction *instruction : branch_instructions_) {
+    if (instruction->branch_true_ == nullptr) {
+      return false;
+    }
+    if (instruction->branch_false_ == nullptr) {
+      return false;
+    }
+  }
+  for (const MFDummyInstruction *instruction : dummy_instructions_) {
+    if (instruction->next_ == nullptr) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool MFProcedure::validate_all_params_provided() const
+{
+  for (const MFCallInstruction *instruction : call_instructions_) {
+    for (const MFVariable *variable : instruction->params_) {
+      if (variable == nullptr) {
+        return false;
+      }
+    }
+  }
+  for (const MFBranchInstruction *instruction : branch_instructions_) {
+    if (instruction->condition_ == nullptr) {
+      return false;
+    }
+  }
+  for (const MFDestructInstruction *instruction : destruct_instructions_) {
+    if (instruction->variable_ == nullptr) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool MFProcedure::validate_same_variables_in_one_call() const
+{
+  for (const MFCallInstruction *instruction : call_instructions_) {
+    const MultiFunction &fn = *instruction->fn_;
+    for (const int param_index : fn.param_indices()) {
+      const MFParamType param_type = fn.param_type(param_index);
+      const MFVariable *variable = instruction->params_[param_index];
+      for (const int other_param_index : fn.param_indices()) {
+        if (other_param_index == param_index) {
+          continue;
+        }
+        const MFVariable *other_variable = instruction->params_[other_param_index];
+        if (other_variable != variable) {
+          continue;
+        }
+        if (ELEM(param_type.interface_type(), MFParamType::Mutable, MFParamType::Output)) {
+          /* When a variable is used as mutable or output parameter, it can only be used once. */
+          return false;
+        }
+        const MFParamType other_param_type = fn.param_type(other_param_index);
+        /* A variable is allowed to be used as input more than once. */
+        if (other_param_type.interface_type() != MFParamType::Input) {
+          return false;
+        }
+      }
+    }
+  }
+  return true;
+}
+
+bool MFProcedure::validate_parameters() const
+{
+  Set<const MFVariable *> variables;
+  for (const MFParameter &param : params_) {
+    /* One variable cannot be used as multiple parameters. */
+    if (!variables.add(param.variable)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool MFProcedure::validate_initialization() const
+{
+  /* TODO: Issue warning when it maybe wrongly initialized. */
+  for (const MFDestructInstruction *instruction : destruct_instructions_) {
+    const MFVariable &variable = *instruction->variable_;
+    const InitState state = this->find_initialization_state_before_instruction(*instruction,
+                                                                               variable);
+    if (!state.can_be_initialized) {
+      return false;
+    }
+  }
+  for (const MFBranchInstruction *instruction : branch_instructions_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list