Commit 75546791 by Marcus Winter

dataflow_cpp: check for cycles in graph

parent 60383a1c
......@@ -35,6 +35,7 @@ class ClockListener {
public:
virtual ~ClockListener() {}
virtual void OnClock(int /*clock*/) = 0;
virtual bool OnHasCycle(ClockListener * /*node*/) { return false; }
};
} // namespace internal
......
......@@ -73,6 +73,10 @@ class In {
bool IsConnected() const { return connected_; }
void SetConnected() { connected_ = true; }
bool HasCycle(ClockListener * node) {
return listener_->OnHasCycle(node);
}
void SetSlices(int slices) {
slices_ = slices;
values_ = reinterpret_cast<SignalType*>(
......
......@@ -106,6 +106,9 @@ class Inputs<T1, embb::base::internal::Nil, embb::base::internal::Nil,
listener_->OnClock(clock);
}
}
virtual bool OnHasCycle(ClockListener * node) {
return listener_->OnHasCycle(node);
}
bool IsFullyConnected() {
return this->template Get<0>().IsConnected();
}
......@@ -164,6 +167,9 @@ class Inputs<T1, T2, embb::base::internal::Nil,
listener_->OnClock(clock);
}
}
virtual bool OnHasCycle(ClockListener * node) {
return listener_->OnHasCycle(node);
}
bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &
this->template Get<1>().IsConnected();
......@@ -228,6 +234,9 @@ class Inputs<T1, T2, T3, embb::base::internal::Nil,
listener_->OnClock(clock);
}
}
virtual bool OnHasCycle(ClockListener * node) {
return listener_->OnHasCycle(node);
}
bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &
this->template Get<1>().IsConnected() &
......@@ -297,6 +306,9 @@ class Inputs<T1, T2, T3, T4, embb::base::internal::Nil>
listener_->OnClock(clock);
}
}
virtual bool OnHasCycle(ClockListener * node) {
return listener_->OnHasCycle(node);
}
bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &
this->template Get<1>().IsConnected() &
......@@ -373,6 +385,9 @@ class Inputs
listener_->OnClock(clock);
}
}
virtual bool OnHasCycle(ClockListener * node) {
return listener_->OnHasCycle(node);
}
bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &&
this->template Get<1>().IsConnected() &
......
......@@ -44,6 +44,7 @@ class Node {
virtual bool HasOutputs() const { return false; }
virtual void Run(int clock) = 0;
virtual bool IsFullyConnected() = 0;
virtual bool HasCycle() { return false; }
virtual bool Start(int /*clock*/) {
EMBB_THROW(embb::base::ErrorException,
"Nodes are started implicitly.");
......
......@@ -36,6 +36,7 @@ namespace dataflow {
namespace internal {
class Scheduler;
class ClockListener;
template <typename Type>
class Out {
......@@ -70,6 +71,14 @@ class Out {
return targets_.size() > 0;
}
bool HasCycle(ClockListener * node) {
bool result = false;
for (size_t ii = 0; ii < targets_.size() && !result; ii++) {
result = result || targets_[ii]->HasCycle(node);
}
return result;
}
private:
std::vector< InType * > targets_;
};
......
......@@ -42,6 +42,8 @@ template <
typename = embb::base::internal::Nil >
class Outputs;
class ClockListener;
template <>
class Outputs<embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil,
......@@ -53,6 +55,9 @@ class Outputs<embb::base::internal::Nil, embb::base::internal::Nil,
bool IsFullyConnected() {
return true;
}
bool HasCycle(ClockListener * /*node*/) {
return false;
}
};
template <typename T1>
......@@ -65,6 +70,9 @@ class Outputs<T1, embb::base::internal::Nil, embb::base::internal::Nil,
bool IsFullyConnected() {
return this->template Get<0>().IsConnected();
}
bool HasCycle(ClockListener * node) {
return this->template Get<0>().HasCycle(node);
}
};
template <typename T1, typename T2>
......@@ -77,6 +85,10 @@ class Outputs<T1, T2, embb::base::internal::Nil,
return this->template Get<0>().IsConnected() &&
this->template Get<1>().IsConnected();
}
bool HasCycle(ClockListener * node) {
return this->template Get<0>().HasCycle(node) ||
this->template Get<1>().HasCycle(node);
}
};
template <typename T1, typename T2, typename T3>
......@@ -90,6 +102,11 @@ class Outputs<T1, T2, T3, embb::base::internal::Nil,
this->template Get<1>().IsConnected() &&
this->template Get<2>().IsConnected();
}
bool HasCycle(ClockListener * node) {
return this->template Get<0>().HasCycle(node) ||
this->template Get<1>().HasCycle(node) ||
this->template Get<2>().HasCycle(node);
}
};
template <typename T1, typename T2, typename T3, typename T4>
......@@ -103,6 +120,12 @@ class Outputs<T1, T2, T3, T4, embb::base::internal::Nil>
this->template Get<2>().IsConnected() &&
this->template Get<3>().IsConnected();
}
bool HasCycle(ClockListener * node) {
return this->template Get<0>().HasCycle(node) ||
this->template Get<1>().HasCycle(node) ||
this->template Get<2>().HasCycle(node) ||
this->template Get<3>().HasCycle(node);
}
};
template <typename T1, typename T2, typename T3, typename T4,
......@@ -118,6 +141,13 @@ class Outputs
this->template Get<3>().IsConnected() &&
this->template Get<4>().IsConnected();
}
bool HasCycle(ClockListener * node) {
return this->template Get<0>().HasCycle(node) ||
this->template Get<1>().HasCycle(node) ||
this->template Get<2>().HasCycle(node) ||
this->template Get<3>().HasCycle(node) ||
this->template Get<4>().HasCycle(node);
}
};
} // namespace internal
......
......@@ -98,6 +98,10 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>,
return inputs_.IsFullyConnected() && outputs_.IsFullyConnected();
}
virtual bool HasCycle() {
return outputs_.HasCycle(this);
}
InputsType & GetInputs() {
return inputs_;
}
......@@ -160,6 +164,15 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>,
}
}
virtual bool OnHasCycle(ClockListener * node) {
ClockListener * this_node = this;
if (this_node == node) {
return true;
} else {
return outputs_.HasCycle(node);
}
}
private:
InputsType inputs_;
OutputsType outputs_;
......
......@@ -85,6 +85,15 @@ class Select
return inputs_.IsFullyConnected() && outputs_.IsFullyConnected();
}
virtual bool OnHasCycle(ClockListener * node) {
ClockListener * this_node = this;
if (this_node == node) {
return true;
} else {
return outputs_.HasCycle(node);
}
}
InputsType & GetInputs() {
return inputs_;
}
......
......@@ -82,6 +82,15 @@ class Switch
return inputs_.IsFullyConnected() && outputs_.IsFullyConnected();
}
virtual bool OnHasCycle(ClockListener * node) {
ClockListener * this_node = this;
if (this_node == node) {
return true;
} else {
return outputs_.HasCycle(node);
}
}
InputsType & GetInputs() {
return inputs_;
}
......
......@@ -838,14 +838,19 @@ class Network : public internal::ClockListener {
bool IsValid() {
bool valid = true;
for (size_t ii = 0; ii < sources_.size(); ii++) {
valid = valid & sources_[ii]->IsFullyConnected();
// check connectivity
for (size_t ii = 0; ii < sources_.size() && valid; ii++) {
valid = valid && sources_[ii]->IsFullyConnected();
}
for (size_t ii = 0; ii < processes_.size(); ii++) {
valid = valid & processes_[ii]->IsFullyConnected();
for (size_t ii = 0; ii < processes_.size() && valid; ii++) {
valid = valid && processes_[ii]->IsFullyConnected();
}
for (size_t ii = 0; ii < sinks_.size(); ii++) {
valid = valid & sinks_[ii]->IsFullyConnected();
for (size_t ii = 0; ii < sinks_.size() && valid; ii++) {
valid = valid && sinks_[ii]->IsFullyConnected();
}
// check for cycles
for (size_t ii = 0; ii < processes_.size() && valid; ii++) {
valid = valid && !processes_[ii]->HasCycle();
}
return valid;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment