diff options
author | rtk0c <[email protected]> | 2021-04-18 22:29:10 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2021-04-18 22:29:10 -0700 |
commit | b00b306de1140cb7b759ed0f639e8210fd7dffa6 (patch) | |
tree | 601a7d5d457cad99a565a55ff318f6af4be07bc5 /core/src/Model/Workflow.cpp | |
parent | b3dfa12eee1cbca6be7a155e9e506d5a080071e2 (diff) |
Initial work on evaluation
Diffstat (limited to 'core/src/Model/Workflow.cpp')
-rw-r--r-- | core/src/Model/Workflow.cpp | 150 |
1 files changed, 135 insertions, 15 deletions
diff --git a/core/src/Model/Workflow.cpp b/core/src/Model/Workflow.cpp index 588081d..7ca1b9e 100644 --- a/core/src/Model/Workflow.cpp +++ b/core/src/Model/Workflow.cpp @@ -2,6 +2,7 @@ #include <algorithm> #include <cassert> +#include <queue> #include <utility> WorkflowConnection::WorkflowConnection() @@ -243,7 +244,10 @@ bool Workflow::Connect(WorkflowNode& sourceNode, int sourcePin, WorkflowNode& de // Would be same as `dst.GetSupportedDirection()` because we validated that they are the same above auto direction = src.GetSupportedDirection(); - // TODO check type + // TODO report error to user? + if (src.GetMatchingType() != dst.GetMatchingType()) { + return false; + } using Pt = WorkflowConnection::ConnectionPoint; Pt* srcConnPt; @@ -391,33 +395,37 @@ std::pair<std::unique_ptr<WorkflowNode>&, size_t> Workflow::AllocWorkflowStep() return { mNodes.emplace_back(std::unique_ptr<WorkflowNode>()), id }; } +namespace { +enum class EvaluationStatus { + Unevaluated, + Success, + Failed, +}; +} // namespace + struct WorkflowEvaluationContext::RuntimeNode { - WorkflowNode* Node; + EvaluationStatus Status = EvaluationStatus::Unevaluated; }; struct WorkflowEvaluationContext::RuntimeConnection { - WorkflowConnection* Connection; std::unique_ptr<BaseValue> Value; + + bool IsAvailableValue() const { + return Value != nullptr; + } }; 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]; - } + mRuntimeNodes.resize(workflow.mNodes.size()); + mRuntimeConnections.resize(workflow.mConnections.size()); } BaseValue* WorkflowEvaluationContext::GetConnectionValue(size_t id, bool constant) { if (constant) { return mWorkflow->GetConstantById(id); } else { - return mConnections[id].Value.get(); + return mRuntimeConnections[id].Value.get(); } } @@ -430,7 +438,7 @@ BaseValue* WorkflowEvaluationContext::GetConnectionValue(const WorkflowNode::Inp } void WorkflowEvaluationContext::SetConnectionValue(size_t id, std::unique_ptr<BaseValue> value) { - mConnections[id].Value = std::move(value); + mRuntimeConnections[id].Value = std::move(value); } void WorkflowEvaluationContext::SetConnectionValue(const WorkflowNode::OutputPin& outputPin, std::unique_ptr<BaseValue> value) { @@ -440,17 +448,129 @@ void WorkflowEvaluationContext::SetConnectionValue(const WorkflowNode::OutputPin } void WorkflowEvaluationContext::Run() { - // TODO + std::queue<size_t> candidates; // Stores index to nodes + int evaluatedCount = 0; + int erroredCount = 0; + + // Evaluate all the input nodes first + for (size_t i = 0; i < mRuntimeNodes.size(); ++i) { + if (mWorkflow->mNodes[i]->GetType() == WorkflowNode::InputType) { + candidates.push(i); + } + } + + auto AddOutputsToCandidates = [&](size_t idx) { + auto& node = *mWorkflow->mNodes[idx]; + auto& rNode = mRuntimeNodes[idx]; + for (auto& pin : node.mOutputs) { + if (!pin.IsConnected()) continue; + // TODO support the other variant + if (pin.GetSupportedDirection() != WorkflowConnection::OneToMany) continue; + + auto& rConn = mRuntimeConnections[pin.Connection]; + auto& conn = mWorkflow->mConnections[pin.Connection]; + if (rConn.IsAvailableValue()) { + for (WorkflowConnection::ConnectionPoint& cp : conn.MultiConnections) { + if (rNode.Status != EvaluationStatus::Unevaluated) { + candidates.push(cp.Node); + } + } + } + } + }; + auto FindCandidates = [&]() { + for (size_t i = 0; i < mWorkflow->mNodes.size(); ++i) { + auto& node = mWorkflow->mNodes[i]; + auto& rNode = mRuntimeNodes[i]; + + if (rNode.Status != EvaluationStatus::Unevaluated) { + continue; + } + + for (auto& pin : node->mInputs) { + if (!pin.IsConnected()) continue; + + auto& rConn = mRuntimeConnections[pin.Connection]; + if (!rConn.IsAvailableValue()) { + goto skip; + } + } + + candidates.push(i); + + skip: + continue; + } + }; + + while (true) { + while (!candidates.empty()) { + auto idx = candidates.front(); + auto& node = *mWorkflow->mNodes[idx]; + auto& rNode = mRuntimeNodes[idx]; + candidates.pop(); + + int preEvalErrors = mErrors.size(); + node.Evaluate(*this); + if (preEvalErrors != mErrors.size()) { + erroredCount++; + } else { + evaluatedCount++; + AddOutputsToCandidates(idx); + } + } + + if (evaluatedCount + erroredCount >= mRuntimeNodes.size()) { + break; + } + + // Candidates empty, but there are still possibly-evaluable nodes + FindCandidates(); + } + + for (size_t i = 0; i < mRuntimeNodes.size(); ++i) { + if (mWorkflow->mNodes[i]->GetType() == WorkflowNode::OutputType) { + // TODO + } + } } void WorkflowEvaluationContext::ReportError(std::string message, const WorkflowNode& node, int pinId, bool inputPin) { + mErrors.push_back(WorkflowEvaluationError{ + .Message = std::move(message), + .NodeId = node.GetId(), + .PinId = pinId, + .PinType = inputPin ? WorkflowEvaluationError::InputPin : WorkflowEvaluationError::OutputPin, + .Type = WorkflowEvaluationError::Error, + }); } void WorkflowEvaluationContext::ReportError(std::string message, const WorkflowNode& node) { + mErrors.push_back(WorkflowEvaluationError{ + .Message = std::move(message), + .NodeId = node.GetId(), + .PinId = -1, + .PinType = WorkflowEvaluationError::NoPin, + .Type = WorkflowEvaluationError::Error, + }); } void WorkflowEvaluationContext::ReportWarning(std::string message, const WorkflowNode& node, int pinId, bool inputPin) { + mErrors.push_back(WorkflowEvaluationError{ + .Message = std::move(message), + .NodeId = node.GetId(), + .PinId = pinId, + .PinType = inputPin ? WorkflowEvaluationError::InputPin : WorkflowEvaluationError::OutputPin, + .Type = WorkflowEvaluationError::Warning, + }); } void WorkflowEvaluationContext::ReportWarning(std::string message, const WorkflowNode& node) { + mErrors.push_back(WorkflowEvaluationError{ + .Message = std::move(message), + .NodeId = node.GetId(), + .PinId = -1, + .PinType = WorkflowEvaluationError::NoPin, + .Type = WorkflowEvaluationError::Warning, + }); } |