diff --git a/modules/flow/Makefile b/modules/flow/Makefile index 1f4db056cf4f639717167d464e50412fe6e7f3ae..80f40614cdafda1d7fc5e13fe82d1f5fede0e383 100644 --- a/modules/flow/Makefile +++ b/modules/flow/Makefile @@ -14,7 +14,6 @@ HEAD_FILES = \ actions/nondelay_action.h \ actions/sleep_action.h \ actions/sequence_action.h \ - actions/fallback_action.h \ actions/parallel_action.h \ actions/invert_action.h \ actions/if_else_action.h \ @@ -30,7 +29,6 @@ CPP_SRC_FILES = \ actions/nondelay_action.cpp \ actions/sleep_action.cpp \ actions/sequence_action.cpp \ - actions/fallback_action.cpp \ actions/parallel_action.cpp \ actions/invert_action.cpp \ actions/if_else_action.cpp \ @@ -47,7 +45,6 @@ TEST_CPP_SRC_FILES = \ actions/sleep_action_test.cpp \ actions/nondelay_action_test.cpp \ actions/sequence_action_test.cpp \ - actions/fallback_action_test.cpp \ actions/parallel_action_test.cpp \ actions/invert_action_test.cpp \ actions/if_else_action_test.cpp \ diff --git a/modules/flow/actions/fallback_action.cpp b/modules/flow/actions/fallback_action.cpp deleted file mode 100644 index 33e67d234d17570f3958e1a7791bff41f931d661..0000000000000000000000000000000000000000 --- a/modules/flow/actions/fallback_action.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "fallback_action.h" - -#include -#include -#include -#include - -namespace tbox { -namespace flow { - -using namespace std::placeholders; - -FallbackAction::~FallbackAction() { - for (auto action : children_) - delete action; -} - -void FallbackAction::toJson(Json &js) const { - Action::toJson(js); - Json &js_children = js["children"]; - for (auto action : children_) { - Json js_child; - action->toJson(js_child); - js_children.push_back(std::move(js_child)); - } -} - -int FallbackAction::append(Action *action) { - TBOX_ASSERT(action != nullptr); - - if (std::find(children_.begin(), children_.end(), action) == children_.end()) { - int index = children_.size(); - children_.push_back(action); - action->setFinishCallback(std::bind(&FallbackAction::onChildFinished, this, _1)); - return index; - } else { - LogWarn("can't add child twice"); - return -1; - } -} - -bool FallbackAction::onStart() { - startOtheriseFinish(); - return true; -} - -bool FallbackAction::onStop() { - if (index_ < children_.size()) - return children_.at(index_)->stop(); - return false; -} - -bool FallbackAction::onPause() { - if (index_ < children_.size()) - return children_.at(index_)->pause(); - return false; -} - -bool FallbackAction::onResume() { - if (index_ < children_.size()) - return children_.at(index_)->resume(); - return false; -} - -void FallbackAction::onReset() { - for (auto child : children_) - child->reset(); - - index_ = 0; -} - -void FallbackAction::startOtheriseFinish() { - if (index_ < children_.size()) { - children_.at(index_)->start(); - } else { - finish(false); - } -} - -void FallbackAction::onChildFinished(bool is_succ) { - if (is_succ) { - finish(true); - } else { - ++index_; - startOtheriseFinish(); - } -} - -} -} diff --git a/modules/flow/actions/fallback_action.h b/modules/flow/actions/fallback_action.h deleted file mode 100644 index 331b1aab3e53048cda30580ddebdefef26833b64..0000000000000000000000000000000000000000 --- a/modules/flow/actions/fallback_action.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef TBOX_FLOW_FALLBACK_FLOW_H_20221031 -#define TBOX_FLOW_FALLBACK_FLOW_H_20221031 - -#include "../action.h" - -namespace tbox { -namespace flow { - -/** - * bool FallbackAction(acton_vec) { - * for (item : action_vec) - * if (item()) - * return true; - * return false; - * } - */ -class FallbackAction : public Action { - public: - using Action::Action; - virtual ~FallbackAction(); - - virtual std::string type() const override { return "Fallback"; } - - virtual void toJson(Json &js) const; - - int append(Action *action); - - int index() const { return index_; } - - protected: - virtual bool onStart() override; - virtual bool onStop() override; - virtual bool onPause() override; - virtual bool onResume() override; - virtual void onReset() override; - - private: - void startOtheriseFinish(); - void onChildFinished(bool is_succ); - - private: - size_t index_ = 0; - std::vector children_; -}; - -} -} - -#endif //TBOX_FLOW_FALLBACK_FLOW_H_20221031 diff --git a/modules/flow/actions/fallback_action_test.cpp b/modules/flow/actions/fallback_action_test.cpp deleted file mode 100644 index 2264c92e1f96911fdfaccb1eb1b29eee4f54b479..0000000000000000000000000000000000000000 --- a/modules/flow/actions/fallback_action_test.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include -#include -#include - -#include "fallback_action.h" -#include "nondelay_action.h" -#include "sleep_action.h" - -namespace tbox { -namespace flow { - -TEST(FallbackAction, AllFail) { - auto loop = event::Loop::New(); - SetScopeExitAction([loop] { delete loop; }); - - bool action_run_1 = false; - bool action_run_2 = false; - - auto *seq_action = new FallbackAction(*loop); - SetScopeExitAction([seq_action] { delete seq_action; }); - - seq_action->append(new NondelayAction(*loop, - [&] { - action_run_1 = true; - return false; - } - )); - seq_action->append(new NondelayAction(*loop, - [&] { - EXPECT_TRUE(action_run_1); - action_run_2 = true; - return false; - } - )); - seq_action->setFinishCallback( - [loop](bool is_succ) { - EXPECT_FALSE(is_succ); - loop->exitLoop(); - } - ); - seq_action->start(); - - loop->runLoop(); - EXPECT_TRUE(action_run_2); - EXPECT_EQ(seq_action->index(), 2); -} - -TEST(FallbackAction, SuccHead) { - auto loop = event::Loop::New(); - SetScopeExitAction([loop] { delete loop; }); - - bool action_run_1 = false; - bool action_run_2 = false; - - auto *seq_action = new FallbackAction(*loop); - SetScopeExitAction([seq_action] { delete seq_action; }); - - seq_action->append(new NondelayAction(*loop, - [&] { - action_run_1 = true; - return true; - } - )); - seq_action->append(new NondelayAction(*loop, - [&] { - action_run_2 = true; - return false; - } - )); - seq_action->setFinishCallback( - [loop](bool is_succ) { - EXPECT_TRUE(is_succ); - loop->exitLoop(); - } - ); - seq_action->start(); - - loop->runLoop(); - EXPECT_TRUE(action_run_1); - EXPECT_FALSE(action_run_2); - EXPECT_EQ(seq_action->index(), 0); -} - - -TEST(FallbackAction, SuccTail) { - auto loop = event::Loop::New(); - SetScopeExitAction([loop] { delete loop; }); - - bool action_run_1 = false; - bool action_run_2 = false; - - auto *seq_action = new FallbackAction(*loop); - SetScopeExitAction([seq_action] { delete seq_action; }); - - seq_action->append(new NondelayAction(*loop, - [&] { - action_run_1 = true; - return false; - } - )); - seq_action->append(new NondelayAction(*loop, - [&] { - EXPECT_TRUE(action_run_1); - action_run_2 = true; - return true; - } - )); - seq_action->setFinishCallback( - [loop](bool is_succ) { - EXPECT_TRUE(is_succ); - loop->exitLoop(); - } - ); - seq_action->start(); - - loop->runLoop(); - EXPECT_TRUE(action_run_2); - EXPECT_EQ(seq_action->index(), 1); -} - -} -} diff --git a/modules/flow/actions/sequence_action.cpp b/modules/flow/actions/sequence_action.cpp index 99aabe4bd08b943a68f8030b49af6ce1a59c90d5..a143ea5c5365657fe76b29f3d8a83708cd40b3fd 100644 --- a/modules/flow/actions/sequence_action.cpp +++ b/modules/flow/actions/sequence_action.cpp @@ -79,11 +79,12 @@ void SequenceAction::startOtheriseFinish() { } void SequenceAction::onChildFinished(bool is_succ) { - if (is_succ) { + if ((finish_condition_ == FinishCondition::kAnySucc && is_succ) || + (finish_condition_ == FinishCondition::kAnyFail && !is_succ)) { + finish(is_succ); + } else { ++index_; startOtheriseFinish(); - } else { - finish(false); } } diff --git a/modules/flow/actions/sequence_action.h b/modules/flow/actions/sequence_action.h index 1774f49ca15dbfd4361f8724680eec01269137ad..10f6d65d9277a720175921bbb92b356cb8751982 100644 --- a/modules/flow/actions/sequence_action.h +++ b/modules/flow/actions/sequence_action.h @@ -7,14 +7,26 @@ namespace tbox { namespace flow { /** - * bool SequenceAction(acton_vec) { - * for (item : action_vec) - * if (!item()) - * return false; + * bool SequenceAction(acton_vec, finish_condition) { + * for (item : action_vec) { + * auto is_succ = item(); + * if (finish_condition == AnySucc && is_succ) + * return is_succ; + * if (finish_condition == AnyFail && !is_succ) + * return is_succ; + * } * return true; * } */ class SequenceAction : public Action { + public: + //! 结束条件 + enum class FinishCondition { + kAllFinish, //!< 全部结束 + kAnyFail, //!< 任一失败 + kAnySucc, //!< 任一成功 + }; + public: using Action::Action; virtual ~SequenceAction(); @@ -25,7 +37,11 @@ class SequenceAction : public Action { int append(Action *action); - int index() const { return index_; } + inline void setFinishCondition(FinishCondition finish_condition) { + finish_condition_ = finish_condition; + } + + inline int index() const { return index_; } protected: virtual bool onStart() override; @@ -39,6 +55,7 @@ class SequenceAction : public Action { void onChildFinished(bool is_succ); private: + FinishCondition finish_condition_ = FinishCondition::kAllFinish; size_t index_ = 0; std::vector children_; }; diff --git a/modules/flow/actions/sequence_action_test.cpp b/modules/flow/actions/sequence_action_test.cpp index 028ed70f5680f16bd8fdb96dcc773ee19f5bd5d6..7649f59614e8cbbdbb6595521963a81211272bc2 100644 --- a/modules/flow/actions/sequence_action_test.cpp +++ b/modules/flow/actions/sequence_action_test.cpp @@ -9,7 +9,7 @@ namespace tbox { namespace flow { -TEST(SequenceAction, AllSucc) { +TEST(SequenceAction, FinishIfAnyFail_AllSucc) { auto loop = event::Loop::New(); SetScopeExitAction([loop] { delete loop; }); @@ -38,6 +38,7 @@ TEST(SequenceAction, AllSucc) { loop->exitLoop(); } ); + seq_action->setFinishCondition(SequenceAction::FinishCondition::kAnyFail); seq_action->start(); loop->runLoop(); @@ -45,7 +46,7 @@ TEST(SequenceAction, AllSucc) { EXPECT_EQ(seq_action->index(), 2); } -TEST(SequenceAction, FailHead) { +TEST(SequenceAction, FinishIfAnyFail_FailHead) { auto loop = event::Loop::New(); SetScopeExitAction([loop] { delete loop; }); @@ -73,6 +74,7 @@ TEST(SequenceAction, FailHead) { loop->exitLoop(); } ); + seq_action->setFinishCondition(SequenceAction::FinishCondition::kAnyFail); seq_action->start(); loop->runLoop(); @@ -82,7 +84,7 @@ TEST(SequenceAction, FailHead) { } -TEST(SequenceAction, FailTail) { +TEST(SequenceAction, FinishIfAnyFail_FailTail) { auto loop = event::Loop::New(); SetScopeExitAction([loop] { delete loop; }); @@ -111,6 +113,7 @@ TEST(SequenceAction, FailTail) { loop->exitLoop(); } ); + seq_action->setFinishCondition(SequenceAction::FinishCondition::kAnyFail); seq_action->start(); loop->runLoop(); @@ -149,5 +152,190 @@ TEST(SequenceAction, TwoSleepAction) { EXPECT_EQ(seq_action->index(), 2); } +TEST(SequenceAction, FinishIfAnySucc_AllFail) { + auto loop = event::Loop::New(); + SetScopeExitAction([loop] { delete loop; }); + + bool action_run_1 = false; + bool action_run_2 = false; + + auto *seq_action = new SequenceAction(*loop); + SetScopeExitAction([seq_action] { delete seq_action; }); + + seq_action->append(new NondelayAction(*loop, + [&] { + action_run_1 = true; + return false; + } + )); + seq_action->append(new NondelayAction(*loop, + [&] { + EXPECT_TRUE(action_run_1); + action_run_2 = true; + return false; + } + )); + seq_action->setFinishCallback( + [loop](bool is_succ) { + EXPECT_TRUE(is_succ); + loop->exitLoop(); + } + ); + seq_action->setFinishCondition(SequenceAction::FinishCondition::kAnySucc); + seq_action->start(); + + loop->runLoop(); + EXPECT_TRUE(action_run_2); + EXPECT_EQ(seq_action->index(), 2); +} + +TEST(SequenceAction, FinishIfAnySucc_SuccHead) { + auto loop = event::Loop::New(); + SetScopeExitAction([loop] { delete loop; }); + + bool action_run_1 = false; + bool action_run_2 = false; + + auto *seq_action = new SequenceAction(*loop); + SetScopeExitAction([seq_action] { delete seq_action; }); + + seq_action->append(new NondelayAction(*loop, + [&] { + action_run_1 = true; + return true; + } + )); + seq_action->append(new NondelayAction(*loop, + [&] { + action_run_2 = true; + return false; + } + )); + seq_action->setFinishCallback( + [loop](bool is_succ) { + EXPECT_TRUE(is_succ); + loop->exitLoop(); + } + ); + seq_action->setFinishCondition(SequenceAction::FinishCondition::kAnySucc); + seq_action->start(); + + loop->runLoop(); + EXPECT_TRUE(action_run_1); + EXPECT_FALSE(action_run_2); + EXPECT_EQ(seq_action->index(), 0); +} + +TEST(SequenceAction, FinishIfAnySucc_SuccTail) { + auto loop = event::Loop::New(); + SetScopeExitAction([loop] { delete loop; }); + + bool action_run_1 = false; + bool action_run_2 = false; + + auto *seq_action = new SequenceAction(*loop); + SetScopeExitAction([seq_action] { delete seq_action; }); + + seq_action->append(new NondelayAction(*loop, + [&] { + action_run_1 = true; + return false; + } + )); + seq_action->append(new NondelayAction(*loop, + [&] { + EXPECT_TRUE(action_run_1); + action_run_2 = true; + return true; + } + )); + seq_action->setFinishCallback( + [loop](bool is_succ) { + EXPECT_TRUE(is_succ); + loop->exitLoop(); + } + ); + seq_action->setFinishCondition(SequenceAction::FinishCondition::kAnySucc); + seq_action->start(); + + loop->runLoop(); + EXPECT_TRUE(action_run_2); + EXPECT_EQ(seq_action->index(), 1); +} + +TEST(SequenceAction, FinishIfAllFinish_AllFail) { + auto loop = event::Loop::New(); + SetScopeExitAction([loop] { delete loop; }); + + bool action_run_1 = false; + bool action_run_2 = false; + + auto *seq_action = new SequenceAction(*loop); + SetScopeExitAction([seq_action] { delete seq_action; }); + + seq_action->append(new NondelayAction(*loop, + [&] { + action_run_1 = true; + return false; + } + )); + seq_action->append(new NondelayAction(*loop, + [&] { + EXPECT_TRUE(action_run_1); + action_run_2 = true; + return false; + } + )); + seq_action->setFinishCallback( + [loop](bool is_succ) { + EXPECT_TRUE(is_succ); + loop->exitLoop(); + } + ); + seq_action->setFinishCondition(SequenceAction::FinishCondition::kAllFinish); + seq_action->start(); + + loop->runLoop(); + EXPECT_TRUE(action_run_2); + EXPECT_EQ(seq_action->index(), 2); +} + +TEST(SequenceAction, FinishIfAllFinish_AllSucc) { + auto loop = event::Loop::New(); + SetScopeExitAction([loop] { delete loop; }); + + bool action_run_1 = false; + bool action_run_2 = false; + + auto *seq_action = new SequenceAction(*loop); + SetScopeExitAction([seq_action] { delete seq_action; }); + + seq_action->append(new NondelayAction(*loop, + [&] { + action_run_1 = true; + return true; + } + )); + seq_action->append(new NondelayAction(*loop, + [&] { + EXPECT_TRUE(action_run_1); + action_run_2 = true; + return true; + } + )); + seq_action->setFinishCallback( + [loop](bool is_succ) { + EXPECT_TRUE(is_succ); + loop->exitLoop(); + } + ); + seq_action->setFinishCondition(SequenceAction::FinishCondition::kAllFinish); + seq_action->start(); + + loop->runLoop(); + EXPECT_TRUE(action_run_2); + EXPECT_EQ(seq_action->index(), 2); +} + } }