StateMap   A
last analyzed

Complexity

Total Complexity 26

Size/Duplication

Total Lines 183
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 46
dl 0
loc 183
rs 10
c 1
b 0
f 0
wmc 26

16 Methods

Rating   Name   Duplication   Size   Complexity  
A getStartState() 0 7 2
A replaceStartStateList() 0 4 1
A stateExists() 0 3 1
A getValidState() 0 7 2
A importState() 0 9 3
A createState() 0 9 2
A isFinishState() 0 5 1
A stateValueExists() 0 3 1
A getValueState() 0 8 2
A addStartState() 0 8 3
A getStateValue() 0 3 1
A getStartStateList() 0 3 1
A isStartState() 0 5 1
A getStateList() 0 3 1
A addFinishState() 0 8 3
A getFinishStateList() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Remorhaz\UniLex\RegExp\FSM;
6
7
use Remorhaz\UniLex\Exception;
8
9
use function array_key_first;
10
use function array_keys;
11
use function count;
12
13
class StateMap implements StateMapInterface
14
{
15
    private $lastStateId = 0;
16
17
    private $stateList = [];
18
19
    private $startStateList = [];
20
21
    private $finishStateList = [];
22
23
    /**
24
     * @param bool $value
25
     * @return int
26
     * @throws Exception
27
     */
28
    public function createState($value = true): int
29
    {
30
        if (is_null($value)) {
0 ignored issues
show
introduced by
The condition is_null($value) is always false.
Loading history...
31
            throw new Exception("Null state value is not allowed");
32
        }
33
        $stateId = ++$this->lastStateId;
34
        $this->stateList[$stateId] = $value;
35
36
        return $stateId;
37
    }
38
39
    /**
40
     * @return int[]
41
     */
42
    public function getStateList(): array
43
    {
44
        return array_keys($this->stateList);
45
    }
46
47
    /**
48
     * @param int $stateId
49
     * @return mixed
50
     * @throws Exception
51
     */
52
    public function getStateValue(int $stateId)
53
    {
54
        return $this->stateList[$this->getValidState($stateId)];
55
    }
56
57
    /**
58
     * @param     $value
59
     * @param int ...$stateList
60
     * @throws Exception
61
     */
62
    public function importState($value, int ...$stateList): void
63
    {
64
        foreach ($stateList as $stateId) {
65
            if (isset($this->stateList[$stateId])) {
66
                throw new Exception("State {$stateId} already exists");
67
            }
68
            $this->stateList[$stateId] = $value;
69
        }
70
        $this->lastStateId = max(array_keys($this->stateList));
71
    }
72
73
    /**
74
     * @param int ...$stateList
75
     * @throws Exception
76
     */
77
    public function addStartState(int ...$stateList): void
78
    {
79
        foreach ($stateList as $stateId) {
80
            $validStateId = $this->getValidState($stateId);
81
            if (isset($this->startStateList[$validStateId])) {
82
                throw new Exception("Start state {$validStateId} is already set");
83
            }
84
            $this->startStateList[$validStateId] = $this->stateList[$validStateId];
85
        }
86
    }
87
88
    /**
89
     * @return int
90
     * @throws Exception
91
     */
92
    public function getStartState(): int
93
    {
94
        if (count($this->startStateList) == 1) {
95
            return array_key_first($this->startStateList);
0 ignored issues
show
Bug Best Practice introduced by
The expression return array_key_first($this->startStateList) could return the type null|string which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
96
        }
97
98
        throw new Exception("Start state is undefined");
99
    }
100
101
    public function getStartStateList(): array
102
    {
103
        return array_keys($this->startStateList);
104
    }
105
106
    public function replaceStartStateList(int ...$stateIdList): void
107
    {
108
        $this->startStateList = [];
109
        $this->addStartState(...$stateIdList);
110
    }
111
112
    /**
113
     * @param int[] $stateList
114
     * @throws Exception
115
     */
116
    public function addFinishState(int ...$stateList): void
117
    {
118
        foreach ($stateList as $stateId) {
119
            $validStateId = $this->getValidState($stateId);
120
            if (isset($this->finishStateList[$validStateId])) {
121
                throw new Exception("Finish state {$validStateId} is already set");
122
            }
123
            $this->finishStateList[$validStateId] = $this->stateList[$validStateId];
124
        }
125
    }
126
127
    /**
128
     * @param int $stateId
129
     * @return bool
130
     * @throws Exception
131
     */
132
    public function isFinishState(int $stateId): bool
133
    {
134
        $validStateId = $this->getValidState($stateId);
135
136
        return isset($this->finishStateList[$validStateId]);
137
    }
138
139
    /**
140
     * @param int $stateId
141
     * @return bool
142
     * @throws Exception
143
     */
144
    public function isStartState(int $stateId): bool
145
    {
146
        $validStateId = $this->getValidState($stateId);
147
148
        return isset($this->startStateList[$validStateId]);
149
    }
150
151
    /**
152
     * @return int[]
153
     */
154
    public function getFinishStateList(): array
155
    {
156
        return array_keys($this->finishStateList);
157
    }
158
159
    public function stateExists(int $stateId): bool
160
    {
161
        return isset($this->stateList[$stateId]);
162
    }
163
164
    public function stateValueExists($value): bool
165
    {
166
        return false !== array_search($value, $this->stateList);
167
    }
168
169
    /**
170
     * @param $value
171
     * @return false|int|string
172
     * @throws Exception
173
     */
174
    public function getValueState($value)
175
    {
176
        $stateId = array_search($value, $this->stateList);
177
        if (false === $stateId) {
178
            throw new Exception("Value not found in state map");
179
        }
180
181
        return $stateId;
182
    }
183
184
    /**
185
     * @param int $stateId
186
     * @return int
187
     * @throws Exception
188
     */
189
    private function getValidState(int $stateId): int
190
    {
191
        if (!$this->stateExists($stateId)) {
192
            throw new Exception("State {$stateId} is undefined");
193
        }
194
195
        return $stateId;
196
    }
197
}
198