aboutsummaryrefslogtreecommitdiff
path: root/core/src/Model/Workflow/Evaluation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/Model/Workflow/Evaluation.cpp')
-rw-r--r--core/src/Model/Workflow/Evaluation.cpp183
1 files changed, 183 insertions, 0 deletions
diff --git a/core/src/Model/Workflow/Evaluation.cpp b/core/src/Model/Workflow/Evaluation.cpp
new file mode 100644
index 0000000..111d34e
--- /dev/null
+++ b/core/src/Model/Workflow/Evaluation.cpp
@@ -0,0 +1,183 @@
+#include "Evaluation.hpp"
+
+#include <queue>
+
+namespace {
+enum class EvaluationStatus {
+ Unevaluated,
+ Success,
+ Failed,
+};
+} // namespace
+
+struct WorkflowEvaluationContext::RuntimeNode {
+ EvaluationStatus Status = EvaluationStatus::Unevaluated;
+};
+
+struct WorkflowEvaluationContext::RuntimeConnection {
+ std::unique_ptr<BaseValue> Value;
+
+ bool IsAvailableValue() const {
+ return Value != nullptr;
+ }
+};
+
+WorkflowEvaluationContext::WorkflowEvaluationContext(Workflow& workflow)
+ : mWorkflow{ &workflow } {
+ 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 mRuntimeConnections[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<BaseValue> value) {
+ mRuntimeConnections[id].Value = std::move(value);
+}
+
+void WorkflowEvaluationContext::SetConnectionValue(const WorkflowNode::OutputPin& outputPin, std::unique_ptr<BaseValue> value) {
+ if (outputPin.IsConnected()) {
+ SetConnectionValue(outputPin.Connection, std::move(value));
+ }
+}
+
+void WorkflowEvaluationContext::Run() {
+ 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,
+ });
+}