1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "state_machine.h"
17
18 namespace utility {
InitState(const std::string & name)19 void StateMachine::InitState(const std::string &name)
20 {
21 auto it = states_.find(name);
22 if (it != states_.end()) {
23 current_ = it->second.get();
24 Transition(it->first);
25 }
26 }
27
Move(std::unique_ptr<State> & state)28 void StateMachine::Move(std::unique_ptr<State> &state)
29 {
30 if (state != nullptr) {
31 auto it = states_.find(state->Name());
32 if (it == states_.end()) {
33 states_[state->Name()] = std::move(state);
34 }
35 }
36 }
37
ProcessMessage(const Message & msg) const38 bool StateMachine::ProcessMessage(const Message &msg) const
39 {
40 State *current = current_;
41 if (current == nullptr) {
42 return false;
43 } else {
44 while (!current->Dispatch(msg)) {
45 current = current->parent_;
46 if (current == nullptr) {
47 return false;
48 }
49 }
50 }
51
52 return true;
53 }
54
GetState() const55 const StateMachine::State *StateMachine::GetState() const
56 {
57 return current_;
58 }
59
Transition(const std::string & name)60 void StateMachine::Transition(const std::string &name)
61 {
62 auto it = states_.find(name);
63 if (it != states_.end()) {
64 std::array<State *, STACK_DEPTH> dstStack { nullptr, nullptr, nullptr, nullptr, nullptr };
65
66 int dstDepth = GetStateDepth(*it->second);
67 State *tmp = it->second.get();
68 for (int i = 0; i < dstDepth; i++) {
69 dstStack[dstDepth - i - 1] = tmp;
70 tmp = tmp->parent_;
71 }
72
73 int sameDepth;
74 for (sameDepth = 0; sameDepth < STACK_DEPTH; sameDepth++) {
75 if (dstStack[sameDepth] != stack_[sameDepth]) {
76 break;
77 }
78 }
79
80 for (int i = top_; i > sameDepth; i--) {
81 stack_[i - 1]->Exit();
82 }
83 current_ = it->second.get();
84
85 stack_ = dstStack;
86 for (int i = sameDepth; i < dstDepth; i++) {
87 stack_[i]->Entry();
88 }
89 top_ = dstDepth;
90 }
91 }
92
GetStateDepth(State & state)93 inline int StateMachine::GetStateDepth(State &state)
94 {
95 int depth = 0;
96 State *tmp = &state;
97 while (tmp != nullptr) {
98 depth++;
99 tmp = tmp->parent_;
100 }
101
102 return depth;
103 }
104 } // namespace utility