aboutsummaryrefslogtreecommitdiff
path: root/core/src/Model/Workflow.cpp
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2021-04-18 22:29:10 -0700
committerrtk0c <[email protected]>2021-04-18 22:29:10 -0700
commitb00b306de1140cb7b759ed0f639e8210fd7dffa6 (patch)
tree601a7d5d457cad99a565a55ff318f6af4be07bc5 /core/src/Model/Workflow.cpp
parentb3dfa12eee1cbca6be7a155e9e506d5a080071e2 (diff)
Initial work on evaluation
Diffstat (limited to 'core/src/Model/Workflow.cpp')
-rw-r--r--core/src/Model/Workflow.cpp150
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,
+ });
}