Utils::stableSort()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 9.568
c 0
b 0
f 0
cc 4
nc 4
nop 2
1
<?php
2
/**
3
 * This file is part of Yacc package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
declare(strict_types=1);
9
10
namespace PhpYacc\Support;
11
12
use PhpYacc\Compress\Compress;
13
use PhpYacc\Grammar\Context;
14
use PhpYacc\Lalr\BitSet;
15
use PhpYacc\Lalr\Lr1;
16
17
/**
18
 * Class Utils.
19
 */
20
final class Utils
21
{
22
    /**
23
     * @param string $char
24
     *
25
     * @return bool
26
     */
27
    public static function isWhite(string $char): bool
28
    {
29
        return $char === ' ' || $char === "\t" || $char === "\r" || $char === "\x0b" || $char === "\x0c";
30
    }
31
32
    /**
33
     * @param string $char
34
     *
35
     * @return bool
36
     */
37
    public static function isSymChar(string $char): bool
38
    {
39
        return ctype_alnum($char) || $char === '_';
40
    }
41
42
    /**
43
     * @param string $char
44
     *
45
     * @return bool
46
     */
47
    public static function isOctal(string $char): bool
48
    {
49
        $n = \ord($char);
50
51
        return $n >= 48 && $n <= 55;
52
    }
53
54
    /**
55
     * @param string $string
56
     *
57
     * @return int
58
     */
59
    public static function characterValue(string $string): int
60
    {
61
        $n = 0;
62
        $length = \mb_strlen($string);
63
64
        if ($length === 0) {
65
            return 0;
66
        }
67
68
        $c = $string[$n++];
69
70
        if ($c !== '\\') {
71
            return \ord($c);
72
        }
73
74
        $c = $string[$n++];
75
        if (self::isOctal($c)) {
76
            $value = (int) $c;
77
            for ($i = 0; $n < $length && self::isOctal($string[$n]) && $i < 3; $i++) {
78
                $value = $value * 8 + $string[$n++];
79
            }
80
81
            return $value;
82
        }
83
84
        switch ($c) {
85
            case 'n':
86
                return \ord("\n");
87
            case 't':
88
                return \ord("\t");
89
            case 'b':
90
                return \ord("\x08");
91
            case 'r':
92
                return \ord("\r");
93
            case 'f':
94
                return \ord("\x0C");
95
            case 'v':
96
                return \ord("\x0B");
97
            case 'a':
98
                return \ord("\x07");
99
            default:
100
                return \ord($c);
101
        }
102
    }
103
104
    /**
105
     * @param array    $array
106
     * @param callable $cmp
107
     */
108
    public static function stableSort(array &$array, callable $cmp)
109
    {
110
        $indexedArray = [];
111
        $i = 0;
112
        foreach ($array as $item) {
113
            $indexedArray[] = [$item, $i++];
114
        }
115
116
        \usort($indexedArray, function (array $a, array $b) use ($cmp) {
117
            $result = $cmp($a[0], $b[0]);
118
            if ($result !== 0) {
119
                return $result;
120
            }
121
122
            return $a[1] - $b[1];
123
        });
124
125
        $array = [];
126
        foreach ($indexedArray as $item) {
127
            $array[] = $item[0];
128
        }
129
    }
130
131
    /**
132
     * @param array $array
133
     * @param int   $length
134
     *
135
     * @return bool
136
     */
137
    public static function vacantRow(array $array, int $length): bool
138
    {
139
        for ($i = 0; $i < $length; $i++) {
140
            if ($array[$i] !== Compress::VACANT) {
141
                return false;
142
            }
143
        }
144
145
        return true;
146
    }
147
148
    /**
149
     * @param array $a
150
     * @param array $b
151
     * @param int   $length
152
     *
153
     * @return bool
154
     */
155
    public static function eqRow(array $a, array $b, int $length): bool
156
    {
157
        for ($i = 0; $i < $length; $i++) {
158
            if ($a[$i] !== $b[$i]) {
159
                return false;
160
            }
161
        }
162
163
        return true;
164
    }
165
166
    /**
167
     * @param int $action
168
     *
169
     * @return string
170
     */
171
    public static function printAction(int $action): string
172
    {
173
        if ($action === Compress::VACANT) {
174
            return '  . ';
175
        }
176
177
        return \sprintf('%4d', $action);
178
    }
179
180
    /**
181
     * @param Lr1|null $left
182
     * @param Lr1|null $right
183
     *
184
     * @return bool
185
     */
186
    public static function isSameSet(Lr1 $left = null, Lr1 $right = null): bool
187
    {
188
        $p = $left;
189
        $t = $right;
190
        while ($t !== null) {
191
            // Not using !== here intentionally
192
            if ($p === null || $p->item != $t->item) {
193
                return false;
194
            }
195
            $p = $p->next;
196
            $t = $t->next;
197
        }
198
199
        return $p === null || $p->isHeadItem();
200
    }
201
202
    /**
203
     * @param Context $ctx
204
     * @param BitSet  $set
205
     *
206
     * @return string
207
     */
208
    public static function dumpSet(Context $ctx, BitSet $set): string
209
    {
210
        $result = '';
211
        foreach ($set as $code) {
212
            $symbol = $ctx->symbols[$code];
213
            $result .= "{$symbol->name} ";
214
        }
215
216
        return $result;
217
    }
218
}
219