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