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:
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 {
this->num_running_++;
// Check if we can continue immediately.
if (!this->script_->is_running()) {
this->triggered_ = false;
this->play_next(x...);
return;
}
this->var_ = std::make_tuple(x...);
this->triggered_ = true;
this->loop();
}
void stop() override { this->triggered_ = false; }
void loop() override {
if (!this->triggered_)
if (this->num_running_ == 0)
return;
if (this->script_->is_running())
return;
this->triggered_ = false;
this->play_next_tuple(this->var_);
}
float get_setup_priority() const override { return setup_priority::DATA; }
bool is_running() override { return this->triggered_ || this->is_running_next(); }
protected:
Script *script_;
bool triggered_{false};
std::tuple<Ts...> var_{};
};

View file

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

View file

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