Skip to content

Commit 3280a55

Browse files
committed
feat(flow):1.12.28, 添加 RandomSelectAction,实现随机选择子动作的功能
1 parent 01b5177 commit 3280a55

File tree

7 files changed

+266
-1
lines changed

7 files changed

+266
-1
lines changed

modules/flow/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ set(TBOX_FLOW_SOURCES
5151
actions/switch_action.cpp
5252
actions/execute_cmd_action.cpp
5353
actions/execute_in_thread_action.cpp
54+
actions/random_select_action.cpp
5455
to_graphviz.cpp)
5556

5657
set(TBOX_FLOW_TEST_SOURCES
@@ -74,6 +75,7 @@ set(TBOX_FLOW_TEST_SOURCES
7475
actions/switch_action_test.cpp
7576
actions/execute_cmd_action_test.cpp
7677
actions/execute_in_thread_action_test.cpp
78+
actions/random_select_action_test.cpp
7779
to_graphviz_test.cpp)
7880

7981
add_library(${TBOX_LIBRARY_NAME} ${TBOX_BUILD_LIB_TYPE} ${TBOX_FLOW_SOURCES})
@@ -136,6 +138,7 @@ install(
136138
actions/switch_action.h
137139
actions/execute_cmd_action.h
138140
actions/execute_in_thread_action.h
141+
actions/random_select_action.h
139142
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tbox/flow/actions
140143
)
141144

modules/flow/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ HEAD_FILES = \
5151
actions/switch_action.h \
5252
actions/execute_cmd_action.h \
5353
actions/execute_in_thread_action.h \
54+
actions/random_select_action.h \
5455
to_graphviz.h \
5556

5657
CPP_SRC_FILES = \
@@ -75,6 +76,7 @@ CPP_SRC_FILES = \
7576
actions/switch_action.cpp \
7677
actions/execute_cmd_action.cpp \
7778
actions/execute_in_thread_action.cpp \
79+
actions/random_select_action.cpp \
7880
to_graphviz.cpp \
7981

8082
CXXFLAGS := -DMODULE_ID='"tbox.flow"' $(CXXFLAGS)
@@ -101,6 +103,7 @@ TEST_CPP_SRC_FILES = \
101103
actions/switch_action_test.cpp \
102104
actions/execute_cmd_action_test.cpp \
103105
actions/execute_in_thread_action_test.cpp \
106+
actions/random_select_action_test.cpp \
104107
to_graphviz_test.cpp \
105108

106109
TEST_LDFLAGS := $(LDFLAGS) -ltbox_flow -ltbox_eventx -ltbox_event -ltbox_util -ltbox_base -ldl
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* .============.
3+
* // M A K E / \
4+
* // C++ DEV / \
5+
* // E A S Y / \/ \
6+
* ++ ----------. \/\ .
7+
* \\ \ \ /\ /
8+
* \\ \ \ /
9+
* \\ \ \ /
10+
* -============'
11+
*
12+
* Copyright (c) 2018 Hevake and contributors, all rights reserved.
13+
*
14+
* This file is part of cpp-tbox (https://github.com/cpp-main/cpp-tbox)
15+
* Use of this source code is governed by MIT license that can be found
16+
* in the LICENSE file in the root of the source tree. All contributing
17+
* project authors may be found in the CONTRIBUTORS.md file in the root
18+
* of the source tree.
19+
*/
20+
#include "random_select_action.h"
21+
22+
#include <random>
23+
#include <tbox/base/log.h>
24+
#include <tbox/base/json.hpp>
25+
26+
namespace tbox {
27+
namespace flow {
28+
29+
using namespace std::placeholders;
30+
31+
RandomSelectAction::RandomSelectAction(event::Loop &loop)
32+
: SerialAssembleAction(loop, "RandomSelect")
33+
{ }
34+
35+
RandomSelectAction::~RandomSelectAction() {
36+
for (auto action : children_)
37+
delete action;
38+
}
39+
40+
void RandomSelectAction::toJson(Json &js) const {
41+
SerialAssembleAction::toJson(js);
42+
43+
Json &js_children = js["children"];
44+
for (auto action : children_) {
45+
Json js_child;
46+
action->toJson(js_child);
47+
js_children.push_back(std::move(js_child));
48+
}
49+
}
50+
51+
int RandomSelectAction::addChild(Action *child) {
52+
if (child == nullptr) {
53+
LogWarn("%d:%s[%s], add child %d:%s[%s] fail, child == nullptr",
54+
id(), type().c_str(), label().c_str());
55+
return false;
56+
}
57+
58+
if (!child->setParent(this))
59+
return false;
60+
61+
int index = children_.size();
62+
child->setFinishCallback(std::bind(&RandomSelectAction::onLastChildFinished, this, _1, _2, _3));
63+
child->setBlockCallback(std::bind(&RandomSelectAction::block, this, _1, _2));
64+
children_.push_back(child);
65+
66+
return index;
67+
}
68+
69+
bool RandomSelectAction::isReady() const {
70+
if (children_.empty()) {
71+
LogWarn("%d:%s[%s], no child, not ready");
72+
return false;
73+
}
74+
75+
for (auto child : children_) {
76+
if (!child->isReady())
77+
return false;
78+
}
79+
return true;
80+
}
81+
82+
void RandomSelectAction::onStart() {
83+
SerialAssembleAction::onStart();
84+
85+
std::random_device rd;
86+
std::mt19937 gen(rd());
87+
std::uniform_int_distribution<> dis(0, children_.size() - 1);
88+
89+
startThisAction(children_.at(dis(gen)));
90+
}
91+
92+
void RandomSelectAction::onReset() {
93+
for (auto child : children_)
94+
child->reset();
95+
96+
SerialAssembleAction::onReset();
97+
}
98+
99+
}
100+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* .============.
3+
* // M A K E / \
4+
* // C++ DEV / \
5+
* // E A S Y / \/ \
6+
* ++ ----------. \/\ .
7+
* \\ \ \ /\ /
8+
* \\ \ \ /
9+
* \\ \ \ /
10+
* -============'
11+
*
12+
* Copyright (c) 2018 Hevake and contributors, all rights reserved.
13+
*
14+
* This file is part of cpp-tbox (https://github.com/cpp-main/cpp-tbox)
15+
* Use of this source code is governed by MIT license that can be found
16+
* in the LICENSE file in the root of the source tree. All contributing
17+
* project authors may be found in the CONTRIBUTORS.md file in the root
18+
* of the source tree.
19+
*/
20+
#ifndef TBOX_FLOW_RANDOM_SELECT_ACTION_H_20221002
21+
#define TBOX_FLOW_RANDOM_SELECT_ACTION_H_20221002
22+
23+
#include "assemble_action.h"
24+
25+
namespace tbox {
26+
namespace flow {
27+
28+
/**
29+
* 随机选择动作
30+
*
31+
* 模拟实现以下流程
32+
* bool RandomSelectAction(action_vec) {
33+
* int index = rand() % action_vec.size();
34+
* return action_vec[index]();
35+
* }
36+
*/
37+
class RandomSelectAction : public SerialAssembleAction {
38+
public:
39+
explicit RandomSelectAction(event::Loop &loop);
40+
virtual ~RandomSelectAction();
41+
42+
virtual void toJson(Json &js) const override;
43+
virtual int addChild(Action *action) override;
44+
virtual bool isReady() const override;
45+
46+
protected:
47+
virtual void onStart() override;
48+
virtual void onReset() override;
49+
50+
private:
51+
std::vector<Action*> children_;
52+
};
53+
54+
}
55+
}
56+
57+
#endif //TBOX_FLOW_RANDOM_SELECT_ACTION_H_20221002
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* .============.
3+
* // M A K E / \
4+
* // C++ DEV / \
5+
* // E A S Y / \/ \
6+
* ++ ----------. \/\ .
7+
* \\ \ \ /\ /
8+
* \\ \ \ /
9+
* \\ \ \ /
10+
* -============'
11+
*
12+
* Copyright (c) 2018 Hevake and contributors, all rights reserved.
13+
*
14+
* This file is part of cpp-tbox (https://github.com/cpp-main/cpp-tbox)
15+
* Use of this source code is governed by MIT license that can be found
16+
* in the LICENSE file in the root of the source tree. All contributing
17+
* project authors may be found in the CONTRIBUTORS.md file in the root
18+
* of the source tree.
19+
*/
20+
#include <gtest/gtest.h>
21+
#include <tbox/event/loop.h>
22+
#include <tbox/base/scope_exit.hpp>
23+
24+
#include "random_select_action.h"
25+
#include "function_action.h"
26+
#include "succ_fail_action.h"
27+
#include "repeat_action.h"
28+
29+
namespace tbox {
30+
namespace flow {
31+
32+
TEST(RandomSelectAction, IsReady) {
33+
auto loop = event::Loop::New();
34+
SetScopeExitAction([loop] { delete loop; });
35+
36+
RandomSelectAction random_select_action(*loop);
37+
EXPECT_FALSE(random_select_action.isReady());
38+
39+
random_select_action.addChild(new SuccAction(*loop));
40+
EXPECT_TRUE(random_select_action.isReady());
41+
42+
random_select_action.addChild(new FailAction(*loop));
43+
EXPECT_TRUE(random_select_action.isReady());
44+
}
45+
46+
TEST(RandomSelectAction, OneChild) {
47+
auto loop = event::Loop::New();
48+
SetScopeExitAction([loop] { delete loop; });
49+
50+
RandomSelectAction random_select_action(*loop);
51+
random_select_action.addChild(new SuccAction(*loop));
52+
53+
loop->exitLoop(std::chrono::milliseconds(10));
54+
55+
bool is_finished = false;
56+
random_select_action.setFinishCallback(
57+
[&] (bool is_succ, const Action::Reason &, const Action::Trace &) {
58+
is_finished = true;
59+
EXPECT_TRUE(is_succ);
60+
}
61+
);
62+
random_select_action.start();
63+
64+
loop->runLoop();
65+
EXPECT_TRUE(is_finished);
66+
}
67+
68+
//! 在 RandomSelectAction 下添加 10 个 FunctionAction。
69+
//! 用 RepeatAction 反复执行 100 次,观察是否每个 FunctionAction 都被执行过
70+
TEST(RandomSelectAction, TenChildren) {
71+
auto loop = event::Loop::New();
72+
SetScopeExitAction([loop] { delete loop; });
73+
74+
std::set<int> run_mark;
75+
RepeatAction repeat_action(*loop, 100);
76+
77+
auto random_select_action = new RandomSelectAction(*loop);
78+
repeat_action.setChild(random_select_action);
79+
80+
for (int i = 0; i < 10; ++i) {
81+
random_select_action->addChild(
82+
new FunctionAction(*loop, [&, i] { run_mark.insert(i); return true; })
83+
);
84+
}
85+
repeat_action.start();
86+
87+
loop->exitLoop(std::chrono::milliseconds(10));
88+
loop->runLoop();
89+
90+
//! 检查是否每个FunctionAction都被执行到
91+
for (int i = 0; i < 10; ++i) {
92+
EXPECT_EQ(run_mark.count(i), 1);
93+
}
94+
}
95+
96+
}
97+
}

modules/flow/actions/sequence_action.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ int SequenceAction::addChild(Action *child) {
7272
}
7373

7474
bool SequenceAction::isReady() const {
75+
if (children_.empty()) {
76+
LogWarn("%d:%s[%s], no child, not ready");
77+
return false;
78+
}
79+
7580
for (auto child : children_) {
7681
if (!child->isReady())
7782
return false;

version.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@
2121
# TBOX版本号
2222
TBOX_VERSION_MAJOR := 1
2323
TBOX_VERSION_MINOR := 12
24-
TBOX_VERSION_REVISION := 27
24+
TBOX_VERSION_REVISION := 28

0 commit comments

Comments
 (0)