[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 ¶m : 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