#include "Workflow.hpp" #include #include WorkflowConnection::WorkflowConnection() : Source{ WorkflowNode::kInvalidId } , Destination{ WorkflowNode::kInvalidId } , SourcePin{ -1 } , DestinationPin{ -1 } { } bool WorkflowConnection::IsValid() const { return Source != WorkflowNode::kInvalidId; } bool WorkflowNode::InputPin::IsConstantConnection() const { return ConnectionToConst; } bool WorkflowNode::InputPin::IsConnected() const { return Connection != WorkflowConnection::kInvalidId; } bool WorkflowNode::OutputPin::IsConnected() const { return Connection != WorkflowConnection::kInvalidId; } WorkflowNode::WorkflowNode(Type type, Kind kind) : mType{ type } , mKind{ kind } { } size_t WorkflowNode::GetId() const { return mId; } WorkflowNode::Type WorkflowNode::GetType() const { return mType; } WorkflowNode::Kind WorkflowNode::GetKind() const { return mKind; } void WorkflowNode::ConnectInput(int nodeId, WorkflowNode& output, int outputNodeId) { mWorkflow->Connect(*this, nodeId, output, outputNodeId); } void WorkflowNode::DisconnectInput(int nodeId) { mWorkflow->DisconnectByDestination(*this, nodeId); } bool WorkflowNode::IsInputConnected(int nodeId) const { return mInputs[nodeId].IsConnected(); } void WorkflowNode::ConnectOutput(int nodeId, WorkflowNode& input, int inputNodeId) { mWorkflow->Connect(input, inputNodeId, *this, nodeId); } void WorkflowNode::DisconnectOutput(int nodeId) { mWorkflow->DisconnectBySource(*this, nodeId); } bool WorkflowNode::IsOutputConnected(int nodeId) const { return mOutputs[nodeId].IsConnected(); } WorkflowNode::InputPin& WorkflowNode::InsertInputPin(int atIdx) { assert(atIdx >= 0 && atIdx < mInputs.size()); mInputs.push_back(InputPin{}); for (int i = (int)mInputs.size() - 1, end = atIdx + 1; i >= end; --i) { SwapInputPin(i, i + 1); } return mInputs[atIdx]; } void WorkflowNode::RemoveInputPin(int pin) { DisconnectInput(pin); for (int i = 0, end = (int)mInputs.size() - 1; i < end; ++i) { SwapInputPin(i, i + 1); } mInputs.resize(mInputs.size() - 1); } void WorkflowNode::SwapInputPin(int a, int b) { auto& pinA = mInputs[a]; auto& pinB = mInputs[b]; if (mWorkflow) { if (pinA.IsConnected() && !pinA.IsConstantConnection()) { auto& conn = *mWorkflow->GetConnectionById(pinA.Connection); conn.DestinationPin = b; } if (pinB.IsConnected() && !pinB.IsConstantConnection()) { auto& conn = *mWorkflow->GetConnectionById(pinB.Connection); conn.DestinationPin = a; } } std::swap(pinA, pinB); } WorkflowNode::OutputPin& WorkflowNode::InsertOutputPin(int atIdx) { assert(atIdx >= 0 && atIdx < mOutputs.size()); mOutputs.push_back(OutputPin{}); for (int i = (int)mOutputs.size() - 1, end = atIdx + 1; i >= end; --i) { SwapOutputPin(i, i + 1); } return mOutputs[atIdx]; } void WorkflowNode::RemoveOutputPin(int pin) { DisconnectOutput(pin); for (int i = 0, end = (int)mOutputs.size() - 1; i < end; ++i) { SwapInputPin(i, i + 1); } mOutputs.resize(mOutputs.size() - 1); } void WorkflowNode::SwapOutputPin(int a, int b) { auto& pinA = mOutputs[a]; auto& pinB = mOutputs[b]; if (mWorkflow) { if (pinA.IsConnected()) { auto& conn = *mWorkflow->GetConnectionById(pinA.Connection); conn.SourcePin = b; } if (pinB.IsConnected()) { auto& conn = *mWorkflow->GetConnectionById(pinB.Connection); conn.SourcePin = a; } } std::swap(pinA, pinB); } WorkflowConnection* Workflow::GetConnectionById(size_t id) { return &mConnections[id]; } WorkflowNode* Workflow::GetStepById(size_t id) { return mNodes[id].get(); } BaseValue* Workflow::GetConstantById(size_t id) { return mConstants[id].get(); } void Workflow::AddStep(std::unique_ptr step) { auto [storage, id] = AllocWorkflowStep(); storage = std::move(step); storage->OnAttach(*this, id); storage->mWorkflow = this; storage->mId = id; } void Workflow::RemoveStep(size_t id) { auto& step = mNodes[id]; if (step == nullptr) return; step->OnDetach(); step->mWorkflow = nullptr; step->mId = WorkflowNode::kInvalidId; } void Workflow::Connect(WorkflowNode& source, int sourceNode, WorkflowNode& destination, int destinationNode) { if (source.mInputs[sourceNode].IsConnected()) { DisconnectBySource(source, sourceNode); } auto [conn, id] = AllocWorkflowConnection(); conn.Source = source.GetId(); conn.SourcePin = sourceNode; conn.Destination = destination.GetId(); conn.DestinationPin = destinationNode; source.mInputs[sourceNode].Connection = id; destination.mInputs[destinationNode].Connection = id; } void Workflow::DisconnectBySource(WorkflowNode& source, int sourceNode) { auto& sn = source.mOutputs[sourceNode]; if (!sn.IsConnected()) return; auto& conn = mConnections[sn.Connection]; auto& dn = mNodes[conn.Destination]->mInputs[conn.DestinationPin]; sn.Connection = WorkflowConnection::kInvalidId; dn.Connection = WorkflowConnection::kInvalidId; conn = {}; } void Workflow::DisconnectByDestination(WorkflowNode& destination, int destinationNode) { auto& dn = destination.mOutputs[destinationNode]; if (!dn.IsConnected()) return; auto& conn = mConnections[dn.Connection]; auto& sn = mNodes[conn.Source]->mInputs[conn.SourcePin]; sn.Connection = WorkflowConnection::kInvalidId; dn.Connection = WorkflowConnection::kInvalidId; conn = {}; } std::pair Workflow::AllocWorkflowConnection() { for (size_t idx = 0; idx < mConnections.size(); ++idx) { auto& elm = mConnections[idx]; if (!elm.IsValid()) { return { elm, idx }; } } auto id = mConnections.size(); return { mConnections.emplace_back(WorkflowConnection{}), id }; } std::pair&, size_t> Workflow::AllocWorkflowStep() { for (size_t idx = 0; idx < mNodes.size(); ++idx) { auto& elm = mNodes[idx]; if (elm == nullptr) { return { elm, idx }; } } auto id = mNodes.size(); return { mNodes.emplace_back(std::unique_ptr()), id }; } struct WorkflowEvaluationContext::RuntimeNode { WorkflowNode* Node; }; struct WorkflowEvaluationContext::RuntimeConnection { WorkflowConnection* Connection; std::unique_ptr Value; }; WorkflowEvaluationContext::WorkflowEvaluationContext(Workflow& workflow) : mWorkflow{ &workflow } { mNodes.resize(workflow.mNodes.size()); for (size_t i = 0; i < workflow.mNodes.size(); ++i) { mNodes[i].Node = workflow.mNodes[i].get(); } mConnections.resize(workflow.mConnections.size()); for (size_t i = 0; i < workflow.mConnections.size(); ++i) { mConnections[i].Connection = &workflow.mConnections[i]; } } BaseValue* WorkflowEvaluationContext::GetConnectionValue(size_t id, bool constant) { if (constant) { return mWorkflow->GetConstantById(id); } else { return mConnections[id].Value.get(); } } BaseValue* WorkflowEvaluationContext::GetConnectionValue(const WorkflowNode::InputPin& inputPin) { if (inputPin.IsConnected()) { return GetConnectionValue(inputPin.Connection, inputPin.IsConstantConnection()); } else { return nullptr; } } void WorkflowEvaluationContext::SetConnectionValue(size_t id, std::unique_ptr value) { mConnections[id].Value = std::move(value); } void WorkflowEvaluationContext::SetConnectionValue(const WorkflowNode::OutputPin& outputPin, std::unique_ptr value) { if (outputPin.IsConnected()) { SetConnectionValue(outputPin.Connection, std::move(value)); } } void WorkflowEvaluationContext::Run() { // TODO } void WorkflowEvaluationContext::ReportError(std::string message, const WorkflowNode& node, int pinId, bool inputPin) { } void WorkflowEvaluationContext::ReportError(std::string message, const WorkflowNode& node) { } void WorkflowEvaluationContext::ReportWarning(std::string message, const WorkflowNode& node, int pinId, bool inputPin) { } void WorkflowEvaluationContext::ReportWarning(std::string message, const WorkflowNode& node) { }