This commit is contained in:
2021-08-19 13:28:15 +02:00
parent ecf7c90840
commit fd7edc9b05
3 changed files with 265 additions and 185 deletions

View File

@@ -38,6 +38,7 @@ set(SRC
intern/multi_function_network_optimization.cc
intern/multi_function_network_to_procedure.cc
intern/multi_function_procedure.cc
intern/multi_function_procedure_builder.cc
intern/multi_function_procedure_executor.cc
FN_cpp_type.hh

View File

@@ -35,60 +35,13 @@ class MFInstructionCursor {
public:
MFInstructionCursor() = default;
MFInstructionCursor(MFCallInstruction &instruction) : instruction_(&instruction)
{
}
MFInstructionCursor(MFCallInstruction &instruction);
MFInstructionCursor(MFDestructInstruction &instruction);
MFInstructionCursor(MFBranchInstruction &instruction, bool branch_output);
MFInstructionCursor(MFDestructInstruction &instruction) : instruction_(&instruction)
{
}
static MFInstructionCursor Entry();
MFInstructionCursor(MFBranchInstruction &instruction, bool branch_output)
: instruction_(&instruction), branch_output_(branch_output)
{
}
static MFInstructionCursor Entry()
{
MFInstructionCursor cursor;
cursor.is_entry_ = true;
return cursor;
}
void insert(MFProcedure &procedure, MFInstruction *new_instruction)
{
if (instruction_ == nullptr) {
if (is_entry_) {
procedure.set_entry(*new_instruction);
}
else {
/* The cursors points at nothing, nothing to do. */
}
}
else {
switch (instruction_->type()) {
case MFInstructionType::Call: {
static_cast<MFCallInstruction *>(instruction_)->set_next(new_instruction);
break;
}
case MFInstructionType::Branch: {
MFBranchInstruction &branch_instruction = *static_cast<MFBranchInstruction *>(
instruction_);
if (branch_output_) {
branch_instruction.set_branch_true(new_instruction);
}
else {
branch_instruction.set_branch_false(new_instruction);
}
break;
}
case MFInstructionType::Destruct: {
static_cast<MFDestructInstruction *>(instruction_)->set_next(new_instruction);
break;
}
}
}
}
void insert(MFProcedure &procedure, MFInstruction *new_instruction);
};
struct MFProcedureBuilderBranch;
@@ -100,151 +53,46 @@ class MFProcedureBuilder {
public:
MFProcedureBuilder(MFProcedure &procedure,
MFInstructionCursor initial_cursor = MFInstructionCursor::Entry())
: procedure_(&procedure), cursors_({initial_cursor})
{
}
MFInstructionCursor initial_cursor = MFInstructionCursor::Entry());
MFProcedureBuilder(Span<MFProcedureBuilder *> builders)
: MFProcedureBuilder(*builders[0]->procedure_)
{
this->set_cursor(builders);
}
MFProcedureBuilder(Span<MFProcedureBuilder *> builders);
MFProcedureBuilder(MFProcedureBuilderBranch &branch);
void set_cursor(const MFInstructionCursor &cursor)
{
cursors_ = {cursor};
}
void set_cursor(Span<MFInstructionCursor> cursors)
{
cursors_ = cursors;
}
void set_cursor(const MFInstructionCursor &cursor);
void set_cursor(Span<MFInstructionCursor> cursors);
void set_cursor(Span<MFProcedureBuilder *> builders);
void set_cursor_after_branch(MFProcedureBuilderBranch &branch);
void set_cursor(Span<MFProcedureBuilder *> builders)
{
cursors_.clear();
for (MFProcedureBuilder *builder : builders) {
cursors_.extend(builder->cursors_);
}
}
void insert_destruct(MFVariable &variable)
{
MFDestructInstruction &instruction = procedure_->new_destruct_instruction();
instruction.set_variable(&variable);
this->insert_at_cursors(&instruction);
cursors_ = {MFInstructionCursor{instruction}};
}
void insert_destruct(Span<MFVariable *> variables)
{
for (MFVariable *variable : variables) {
this->insert_destruct(*variable);
}
}
void insert_destruct(MFVariable &variable);
void insert_destruct(Span<MFVariable *> variables);
MFProcedureBuilderBranch insert_branch(MFVariable &condition);
MFCallInstruction &insert_call(const MultiFunction &fn)
{
MFCallInstruction &instruction = procedure_->new_call_instruction(fn);
this->insert_at_cursors(&instruction);
cursors_ = {MFInstructionCursor{instruction}};
return instruction;
}
MFCallInstruction &insert_call(const MultiFunction &fn, Span<MFVariable *> variables)
{
MFCallInstruction &instruction = this->insert_call(fn);
instruction.set_params(variables);
return instruction;
}
MFCallInstruction &insert_call(const MultiFunction &fn);
MFCallInstruction &insert_call(const MultiFunction &fn, Span<MFVariable *> variables);
Vector<MFVariable *> insert_call_with_new_variables(
const MultiFunction &fn, Span<MFVariable *> input_and_mutable_variables = {})
{
Vector<MFVariable *> output_variables;
MFCallInstruction &instruction = this->insert_call(fn);
for (const int param_index : fn.param_indices()) {
const MFParamType param_type = fn.param_type(param_index);
switch (param_type.interface_type()) {
case MFParamType::Input:
case MFParamType::Mutable: {
MFVariable *variable = input_and_mutable_variables.first();
instruction.set_param_variable(param_index, variable);
input_and_mutable_variables = input_and_mutable_variables.drop_front(1);
break;
}
case MFParamType::Output: {
MFVariable &variable = procedure_->new_variable(param_type.data_type());
instruction.set_param_variable(param_index, &variable);
output_variables.append(&variable);
break;
}
}
}
/* All passed in variables should have been dropped in the loop above. */
BLI_assert(input_and_mutable_variables.is_empty());
return output_variables;
}
const MultiFunction &fn, Span<MFVariable *> input_and_mutable_variables = {});
template<int OutputN>
std::array<MFVariable *, OutputN> insert_call_with_new_variables(
const MultiFunction &fn, Span<MFVariable *> input_and_mutable_variables = {})
{
Vector<MFVariable *> output_variables = this->insert_call_with_new_variables(
fn, input_and_mutable_variables);
BLI_assert(output_variables.size() == OutputN);
const MultiFunction &fn, Span<MFVariable *> input_and_mutable_variables = {});
std::array<MFVariable *, OutputN> output_array;
initialized_copy_n(output_variables.data(), OutputN, output_array.data());
return output_array;
}
void add_parameter(MFParamType::InterfaceType interface_type, MFVariable &variable);
void add_parameter(MFParamType::InterfaceType interface_type, MFVariable &variable)
{
procedure_->add_parameter(interface_type, variable);
}
MFVariable &add_parameter(MFParamType param_type, std::string name = "");
MFVariable &add_parameter(MFParamType param_type, std::string name = "")
{
MFVariable &variable = procedure_->new_variable(param_type.data_type(), std::move(name));
this->add_parameter(param_type.interface_type(), variable);
return variable;
}
MFVariable &add_input_parameter(MFDataType data_type, std::string name = "");
MFVariable &add_input_parameter(MFDataType data_type, std::string name = "")
{
return this->add_parameter(MFParamType(MFParamType::Input, data_type), std::move(name));
}
template<typename T> MFVariable &add_single_input_parameter(std::string name = "");
template<typename T> MFVariable &add_single_input_parameter(std::string name = "")
{
return this->add_parameter(MFParamType::ForSingleInput(CPPType::get<T>()), std::move(name));
}
template<typename T> MFVariable &add_single_mutable_parameter(std::string name = "");
template<typename T> MFVariable &add_single_mutable_parameter(std::string name = "")
{
return this->add_parameter(MFParamType::ForMutableSingle(CPPType::get<T>()), std::move(name));
}
void add_output_parameter(MFVariable &variable)
{
this->add_parameter(MFParamType::Output, variable);
}
void add_output_parameter(MFVariable &variable);
private:
void insert_at_cursors(MFInstruction *instruction)
{
for (MFInstructionCursor &cursor : cursors_) {
cursor.insert(*procedure_, instruction);
}
}
void insert_at_cursors(MFInstruction *instruction);
};
struct MFProcedureBuilderBranch {
@@ -252,27 +100,131 @@ struct MFProcedureBuilderBranch {
MFProcedureBuilder branch_false;
};
MFProcedureBuilder::MFProcedureBuilder(MFProcedureBuilderBranch &branch)
/* --------------------------------------------------------------------
* MFInstructionCursor inline methods.
*/
inline MFInstructionCursor::MFInstructionCursor(MFCallInstruction &instruction)
: instruction_(&instruction)
{
}
inline MFInstructionCursor::MFInstructionCursor(MFDestructInstruction &instruction)
: instruction_(&instruction)
{
}
inline MFInstructionCursor::MFInstructionCursor(MFBranchInstruction &instruction,
bool branch_output)
: instruction_(&instruction), branch_output_(branch_output)
{
}
inline MFInstructionCursor MFInstructionCursor::Entry()
{
MFInstructionCursor cursor;
cursor.is_entry_ = true;
return cursor;
}
/* --------------------------------------------------------------------
* MFProcedureBuilder inline methods.
*/
inline MFProcedureBuilder::MFProcedureBuilder(MFProcedureBuilderBranch &branch)
: MFProcedureBuilder(*branch.branch_true.procedure_)
{
this->set_cursor_after_branch(branch);
}
void MFProcedureBuilder::set_cursor_after_branch(MFProcedureBuilderBranch &branch)
inline MFProcedureBuilder::MFProcedureBuilder(MFProcedure &procedure,
MFInstructionCursor initial_cursor)
: procedure_(&procedure), cursors_({initial_cursor})
{
}
inline MFProcedureBuilder::MFProcedureBuilder(Span<MFProcedureBuilder *> builders)
: MFProcedureBuilder(*builders[0]->procedure_)
{
this->set_cursor(builders);
}
inline void MFProcedureBuilder::set_cursor(const MFInstructionCursor &cursor)
{
cursors_ = {cursor};
}
inline void MFProcedureBuilder::set_cursor(Span<MFInstructionCursor> cursors)
{
cursors_ = cursors;
}
inline void MFProcedureBuilder::set_cursor_after_branch(MFProcedureBuilderBranch &branch)
{
this->set_cursor({&branch.branch_false, &branch.branch_true});
}
MFProcedureBuilderBranch MFProcedureBuilder::insert_branch(MFVariable &condition)
inline void MFProcedureBuilder::set_cursor(Span<MFProcedureBuilder *> builders)
{
MFBranchInstruction &instruction = procedure_->new_branch_instruction();
instruction.set_condition(&condition);
this->insert_at_cursors(&instruction);
cursors_.clear();
for (MFProcedureBuilder *builder : builders) {
cursors_.extend(builder->cursors_);
}
}
MFProcedureBuilderBranch branch{*procedure_, *procedure_};
branch.branch_true.set_cursor(MFInstructionCursor{instruction, true});
branch.branch_false.set_cursor(MFInstructionCursor{instruction, false});
return branch;
template<int OutputN>
inline std::array<MFVariable *, OutputN> MFProcedureBuilder::insert_call_with_new_variables(
const MultiFunction &fn, Span<MFVariable *> input_and_mutable_variables)
{
Vector<MFVariable *> output_variables = this->insert_call_with_new_variables(
fn, input_and_mutable_variables);
BLI_assert(output_variables.size() == OutputN);
std::array<MFVariable *, OutputN> output_array;
initialized_copy_n(output_variables.data(), OutputN, output_array.data());
return output_array;
}
inline void MFProcedureBuilder::add_parameter(MFParamType::InterfaceType interface_type,
MFVariable &variable)
{
procedure_->add_parameter(interface_type, variable);
}
inline MFVariable &MFProcedureBuilder::add_parameter(MFParamType param_type, std::string name)
{
MFVariable &variable = procedure_->new_variable(param_type.data_type(), std::move(name));
this->add_parameter(param_type.interface_type(), variable);
return variable;
}
inline MFVariable &MFProcedureBuilder::add_input_parameter(MFDataType data_type, std::string name)
{
return this->add_parameter(MFParamType(MFParamType::Input, data_type), std::move(name));
}
template<typename T>
inline MFVariable &MFProcedureBuilder::add_single_input_parameter(std::string name)
{
return this->add_parameter(MFParamType::ForSingleInput(CPPType::get<T>()), std::move(name));
}
template<typename T>
inline MFVariable &MFProcedureBuilder::add_single_mutable_parameter(std::string name)
{
return this->add_parameter(MFParamType::ForMutableSingle(CPPType::get<T>()), std::move(name));
}
inline void MFProcedureBuilder::add_output_parameter(MFVariable &variable)
{
this->add_parameter(MFParamType::Output, variable);
}
inline void MFProcedureBuilder::insert_at_cursors(MFInstruction *instruction)
{
for (MFInstructionCursor &cursor : cursors_) {
cursor.insert(*procedure_, instruction);
}
}
} // namespace blender::fn

View File

@@ -0,0 +1,127 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "FN_multi_function_procedure_builder.hh"
namespace blender::fn {
void MFInstructionCursor::insert(MFProcedure &procedure, MFInstruction *new_instruction)
{
if (instruction_ == nullptr) {
if (is_entry_) {
procedure.set_entry(*new_instruction);
}
else {
/* The cursors points at nothing, nothing to do. */
}
}
else {
switch (instruction_->type()) {
case MFInstructionType::Call: {
static_cast<MFCallInstruction *>(instruction_)->set_next(new_instruction);
break;
}
case MFInstructionType::Branch: {
MFBranchInstruction &branch_instruction = *static_cast<MFBranchInstruction *>(
instruction_);
if (branch_output_) {
branch_instruction.set_branch_true(new_instruction);
}
else {
branch_instruction.set_branch_false(new_instruction);
}
break;
}
case MFInstructionType::Destruct: {
static_cast<MFDestructInstruction *>(instruction_)->set_next(new_instruction);
break;
}
}
}
}
void MFProcedureBuilder::insert_destruct(MFVariable &variable)
{
MFDestructInstruction &instruction = procedure_->new_destruct_instruction();
instruction.set_variable(&variable);
this->insert_at_cursors(&instruction);
cursors_ = {MFInstructionCursor{instruction}};
}
void MFProcedureBuilder::insert_destruct(Span<MFVariable *> variables)
{
for (MFVariable *variable : variables) {
this->insert_destruct(*variable);
}
}
MFCallInstruction &MFProcedureBuilder::insert_call(const MultiFunction &fn)
{
MFCallInstruction &instruction = procedure_->new_call_instruction(fn);
this->insert_at_cursors(&instruction);
cursors_ = {MFInstructionCursor{instruction}};
return instruction;
}
MFCallInstruction &MFProcedureBuilder::insert_call(const MultiFunction &fn,
Span<MFVariable *> variables)
{
MFCallInstruction &instruction = this->insert_call(fn);
instruction.set_params(variables);
return instruction;
}
Vector<MFVariable *> MFProcedureBuilder::insert_call_with_new_variables(
const MultiFunction &fn, Span<MFVariable *> input_and_mutable_variables)
{
Vector<MFVariable *> output_variables;
MFCallInstruction &instruction = this->insert_call(fn);
for (const int param_index : fn.param_indices()) {
const MFParamType param_type = fn.param_type(param_index);
switch (param_type.interface_type()) {
case MFParamType::Input:
case MFParamType::Mutable: {
MFVariable *variable = input_and_mutable_variables.first();
instruction.set_param_variable(param_index, variable);
input_and_mutable_variables = input_and_mutable_variables.drop_front(1);
break;
}
case MFParamType::Output: {
MFVariable &variable = procedure_->new_variable(param_type.data_type());
instruction.set_param_variable(param_index, &variable);
output_variables.append(&variable);
break;
}
}
}
/* All passed in variables should have been dropped in the loop above. */
BLI_assert(input_and_mutable_variables.is_empty());
return output_variables;
}
MFProcedureBuilderBranch MFProcedureBuilder::insert_branch(MFVariable &condition)
{
MFBranchInstruction &instruction = procedure_->new_branch_instruction();
instruction.set_condition(&condition);
this->insert_at_cursors(&instruction);
MFProcedureBuilderBranch branch{*procedure_, *procedure_};
branch.branch_true.set_cursor(MFInstructionCursor{instruction, true});
branch.branch_false.set_cursor(MFInstructionCursor{instruction, false});
return branch;
}
} // namespace blender::fn