TransitionMap::getTransitionList()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Remorhaz\UniLex\RegExp\FSM;
6
7
use Remorhaz\UniLex\Exception;
8
9
class TransitionMap
10
{
11
    private $stateMap;
12
13
    private $transitionMap = [];
14
15
    public function __construct(StateMapInterface $stateMap)
16
    {
17
        $this->stateMap = $stateMap;
18
    }
19
20
    /**
21
     * @param int $fromStateId
22
     * @param int $toStateId
23
     * @param $data
24
     * @throws Exception
25
     */
26
    public function addTransition(int $fromStateId, int $toStateId, $data): void
27
    {
28
        if ($this->transitionExists($fromStateId, $toStateId)) {
29
            throw new Exception("Transition {$fromStateId}->{$toStateId} is already added");
30
        }
31
        $this->replaceTransition($fromStateId, $toStateId, $data);
32
    }
33
34
    /**
35
     * @param int $fromStateId
36
     * @param int $toStateId
37
     * @param $data
38
     * @throws Exception
39
     */
40
    public function replaceTransition(int $fromStateId, int $toStateId, $data): void
41
    {
42
        [$validFromStateId, $validToStateId] = $this->getValidTransitionStates($fromStateId, $toStateId);
43
        $this->transitionMap[$validFromStateId][$validToStateId] = $data;
44
    }
45
46
    /**
47
     * @param int $fromStateId
48
     * @param int $toStateId
49
     * @return bool
50
     * @throws Exception
51
     */
52
    public function transitionExists(int $fromStateId, int $toStateId): bool
53
    {
54
        [$validFromStateId, $validToStateId] = $this->getValidTransitionStates($fromStateId, $toStateId);
55
        return isset($this->transitionMap[$validFromStateId][$validToStateId]);
56
    }
57
58
    /**
59
     * @param int $fromStateId
60
     * @param int $toStateId
61
     * @return mixed
62
     * @throws Exception
63
     */
64
    public function getTransition(int $fromStateId, int $toStateId)
65
    {
66
        if (!$this->transitionExists($fromStateId, $toStateId)) {
67
            throw new Exception("Transition {$fromStateId}->{$toStateId} is not defined");
68
        }
69
        [$validFromStateId, $validToStateId] = $this->getValidTransitionStates($fromStateId, $toStateId);
70
        return $this->transitionMap[$validFromStateId][$validToStateId];
71
    }
72
73
    public function getTransitionList(): array
74
    {
75
        return $this->transitionMap;
76
    }
77
78
    public function getExitList(int $stateIn): array
79
    {
80
        return $this->transitionMap[$stateIn] ?? [];
81
    }
82
83
    public function getEnterList(int $stateOut): array
84
    {
85
        $result = [];
86
        foreach ($this->transitionMap as $stateIn => $stateOutMap) {
87
            if (isset($stateOutMap[$stateOut])) {
88
                $result[$stateIn] = $stateOutMap[$stateOut];
89
            }
90
        }
91
        return $result;
92
    }
93
94
    public function onEachTransition(callable $callback): void
95
    {
96
        foreach ($this->transitionMap as $stateIn => $stateOutMap) {
97
            foreach ($stateOutMap as $stateOut => $data) {
98
                call_user_func($callback, $data, $stateIn, $stateOut);
99
            }
100
        }
101
    }
102
103
    public function replaceEachTransition(callable $callback): void
104
    {
105
        $replaceCallback = function ($data, int $stateIn, int $stateOut) use ($callback) {
106
            $newData = call_user_func($callback, $data, $stateIn, $stateOut);
107
            $this->replaceTransition($stateIn, $stateOut, $newData);
108
        };
109
        $this->onEachTransition($replaceCallback);
110
    }
111
112
    /**
113
     * @param int $fromStateId
114
     * @param int $toStateId
115
     * @return array
116
     * @throws Exception
117
     */
118
    private function getValidTransitionStates(int $fromStateId, int $toStateId): array
119
    {
120
        if (!$this->stateMap->stateExists($fromStateId)) {
121
            throw new Exception("Invalid transition start state: {$fromStateId}");
122
        }
123
        if (!$this->stateMap->stateExists($toStateId)) {
124
            throw new Exception("Invalid transition finish state: {$toStateId}");
125
        }
126
        return [$fromStateId, $toStateId];
127
    }
128
}
129