Move stop/is_running implementation to Action base class

Try to fix issue #1105.  Until now if an UpdateComponentAction, a
LambdaAction, or any action that can contain those inside their
"else" or "then" action lists, resulted in a call to script.stop on
the script that contains them, the script would continue running,
because they didn't implement a stop() method.  Basically only
the asynchronous ones did: DelayAction, WaitUntilAction and
ScriptWaitAction.

With this change num_running_ in Action replaces
DelayAction::num_running_ and WaitUntilAction::triggered_ to provide
the same is_running logic to other actions.
This commit is contained in:
Andrew Zaborowski 2020-05-01 00:11:26 +02:00 committed by Andrew Zaborowski
parent 8b92456ded
commit da390d32f8
3 changed files with 34 additions and 45 deletions

View file

@ -53,41 +53,34 @@ template<typename... Ts> class ScriptWaitAction : public Action<Ts...>, public C
public: public:
ScriptWaitAction(Script *script) : script_(script) {} ScriptWaitAction(Script *script) : script_(script) {}
void play(Ts... x) { /* ignore - see play_complex */ void play(Ts... x) override { /* ignore - see play_complex */
} }
void play_complex(Ts... x) override { void play_complex(Ts... x) override {
this->num_running_++;
// Check if we can continue immediately. // Check if we can continue immediately.
if (!this->script_->is_running()) { if (!this->script_->is_running()) {
this->triggered_ = false;
this->play_next(x...); this->play_next(x...);
return; return;
} }
this->var_ = std::make_tuple(x...); this->var_ = std::make_tuple(x...);
this->triggered_ = true;
this->loop(); this->loop();
} }
void stop() override { this->triggered_ = false; }
void loop() override { void loop() override {
if (!this->triggered_) if (this->num_running_ == 0)
return; return;
if (this->script_->is_running()) if (this->script_->is_running())
return; return;
this->triggered_ = false;
this->play_next_tuple(this->var_); this->play_next_tuple(this->var_);
} }
float get_setup_priority() const override { return setup_priority::DATA; } float get_setup_priority() const override { return setup_priority::DATA; }
bool is_running() override { return this->triggered_ || this->is_running_next(); }
protected: protected:
Script *script_; Script *script_;
bool triggered_{false};
std::tuple<Ts...> var_{}; std::tuple<Ts...> var_{};
}; };

View file

@ -77,17 +77,24 @@ template<typename... Ts> class Action {
public: public:
virtual void play(Ts... x) = 0; virtual void play(Ts... x) = 0;
virtual void play_complex(Ts... x) { virtual void play_complex(Ts... x) {
this->num_running_++;
this->play(x...); this->play(x...);
this->play_next(x...); this->play_next(x...);
} }
void play_next(Ts... x) { void play_next(Ts... x) {
if (this->next_ != nullptr) { if (this->num_running_ > 0) {
this->next_->play_complex(x...); this->num_running_--;
if (this->next_ != nullptr) {
this->next_->play_complex(x...);
}
} }
} }
virtual void stop() {} virtual void stop() {}
virtual void stop_complex() { virtual void stop_complex() {
this->stop(); if (num_running_) {
this->stop();
this->num_running_ = 0;
}
this->stop_next(); this->stop_next();
} }
void stop_next() { void stop_next() {
@ -95,7 +102,7 @@ template<typename... Ts> class Action {
this->next_->stop_complex(); this->next_->stop_complex();
} }
} }
virtual bool is_running() { return this->is_running_next(); } virtual bool is_running() { return this->num_running_ > 0 || this->is_running_next(); }
bool is_running_next() { bool is_running_next() {
if (this->next_ == nullptr) if (this->next_ == nullptr)
return false; return false;
@ -114,6 +121,8 @@ template<typename... Ts> class Action {
} }
Action<Ts...> *next_ = nullptr; Action<Ts...> *next_ = nullptr;
int num_running_{0};
}; };
template<typename... Ts> class ActionList { template<typename... Ts> class ActionList {

View file

@ -110,27 +110,17 @@ template<typename... Ts> class DelayAction : public Action<Ts...>, public Compon
void stop() override { void stop() override {
this->cancel_timeout(""); this->cancel_timeout("");
this->num_running_ = 0;
} }
void play(Ts... x) override { /* ignore - see play_complex */ void play(Ts... x) override { /* ignore - see play_complex */
} }
void play_complex(Ts... x) override { void play_complex(Ts... x) override {
auto f = std::bind(&DelayAction<Ts...>::delay_end_, this, x...); auto f = std::bind(&Action<Ts...>::play_next, this, x...);
this->num_running_++; this->num_running_++;
this->set_timeout(this->delay_.value(x...), f); this->set_timeout(this->delay_.value(x...), f);
} }
float get_setup_priority() const override { return setup_priority::HARDWARE; } float get_setup_priority() const override { return setup_priority::HARDWARE; }
bool is_running() override { return this->num_running_ > 0 || this->is_running_next(); }
protected:
void delay_end_(Ts... x) {
this->num_running_--;
this->play_next(x...);
}
int num_running_{0};
}; };
template<typename... Ts> class LambdaAction : public Action<Ts...> { template<typename... Ts> class LambdaAction : public Action<Ts...> {
@ -160,17 +150,18 @@ template<typename... Ts> class IfAction : public Action<Ts...> {
} }
void play_complex(Ts... x) override { void play_complex(Ts... x) override {
this->num_running_++;
bool res = this->condition_->check(x...); bool res = this->condition_->check(x...);
if (res) { if (res) {
if (this->then_.empty()) { if (this->then_.empty()) {
this->play_next(x...); this->play_next(x...);
} else { } else if (this->num_running_ > 0) {
this->then_.play(x...); this->then_.play(x...);
} }
} else { } else {
if (this->else_.empty()) { if (this->else_.empty()) {
this->play_next(x...); this->play_next(x...);
} else { } else if (this->num_running_ > 0) {
this->else_.play(x...); this->else_.play(x...);
} }
} }
@ -181,8 +172,6 @@ template<typename... Ts> class IfAction : public Action<Ts...> {
this->else_.stop(); this->else_.stop();
} }
bool is_running() override { return this->then_.is_running() || this->else_.is_running() || this->is_running_next(); }
protected: protected:
Condition<Ts...> *condition_; Condition<Ts...> *condition_;
ActionList<Ts...> then_; ActionList<Ts...> then_;
@ -196,9 +185,11 @@ template<typename... Ts> class WhileAction : public Action<Ts...> {
void add_then(const std::vector<Action<Ts...> *> &actions) { void add_then(const std::vector<Action<Ts...> *> &actions) {
this->then_.add_actions(actions); this->then_.add_actions(actions);
this->then_.add_action(new LambdaAction<Ts...>([this](Ts... x) { this->then_.add_action(new LambdaAction<Ts...>([this](Ts... x) {
if (this->condition_->check_tuple(this->var_)) { if (this->num_running_ > 0 && this->condition_->check_tuple(this->var_)) {
// play again // play again
this->then_.play_tuple(this->var_); if (this->num_running_ > 0) {
this->then_.play_tuple(this->var_);
}
} else { } else {
// condition false, play next // condition false, play next
this->play_next_tuple(this->var_); this->play_next_tuple(this->var_);
@ -210,6 +201,7 @@ template<typename... Ts> class WhileAction : public Action<Ts...> {
} }
void play_complex(Ts... x) override { void play_complex(Ts... x) override {
this->num_running_++;
// Store loop parameters // Store loop parameters
this->var_ = std::make_tuple(x...); this->var_ = std::make_tuple(x...);
// Initial condition check // Initial condition check
@ -220,13 +212,13 @@ template<typename... Ts> class WhileAction : public Action<Ts...> {
return; return;
} }
this->then_.play_tuple(this->var_); if (this->num_running_ > 0) {
this->then_.play_tuple(this->var_);
}
} }
void stop() override { this->then_.stop(); } void stop() override { this->then_.stop(); }
bool is_running() override { return this->then_.is_running() || this->is_running_next(); }
protected: protected:
Condition<Ts...> *condition_; Condition<Ts...> *condition_;
ActionList<Ts...> then_; ActionList<Ts...> then_;
@ -237,42 +229,37 @@ template<typename... Ts> class WaitUntilAction : public Action<Ts...>, public Co
public: public:
WaitUntilAction(Condition<Ts...> *condition) : condition_(condition) {} WaitUntilAction(Condition<Ts...> *condition) : condition_(condition) {}
void play(Ts... x) { /* ignore - see play_complex */ void play(Ts... x) override { /* ignore - see play_complex */
} }
void play_complex(Ts... x) override { void play_complex(Ts... x) override {
this->num_running_++;
// Check if we can continue immediately. // Check if we can continue immediately.
if (this->condition_->check(x...)) { if (this->condition_->check(x...)) {
this->triggered_ = false; if (this->num_running_ > 0) {
this->play_next(x...); this->play_next(x...);
}
return; return;
} }
this->var_ = std::make_tuple(x...); this->var_ = std::make_tuple(x...);
this->triggered_ = true;
this->loop(); this->loop();
} }
void stop() override { this->triggered_ = false; }
void loop() override { void loop() override {
if (!this->triggered_) if (this->num_running_ == 0)
return; return;
if (!this->condition_->check_tuple(this->var_)) { if (!this->condition_->check_tuple(this->var_)) {
return; return;
} }
this->triggered_ = false;
this->play_next_tuple(this->var_); this->play_next_tuple(this->var_);
} }
float get_setup_priority() const override { return setup_priority::DATA; } float get_setup_priority() const override { return setup_priority::DATA; }
bool is_running() override { return this->triggered_ || this->is_running_next(); }
protected: protected:
Condition<Ts...> *condition_; Condition<Ts...> *condition_;
bool triggered_{false};
std::tuple<Ts...> var_{}; std::tuple<Ts...> var_{};
}; };