Completed
Push — master ( 96cbf3...9bcdfc )
by Steve
03:03 queued 01:23
created

TextLineLCS::setLcs()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * (c) Steve Nebes <[email protected]>
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace SN\RangeDifferencer\Core;
13
14
class TextLineLCS extends AbstractLCS
15
{
16
    /** @var TextLine[] */
17
    private $lines1 = [];
18
19
    /** @var TextLine[] */
20
    private $lines2 = [];
21
22
    /** @var array[TextLine[]] */
0 ignored issues
show
Documentation Bug introduced by
The doc comment array[TextLine[]] at position 1 could not be parsed: Expected ']' at position 1, but found '['.
Loading history...
23
    private $lcs = [];
24
25
    /**
26
     * Default values.
27
     *
28
     * @param TextLine[] $lines1
29
     * @param TextLine[] $lines2
30
     */
31
    public function __construct(array $lines1, array $lines2)
32
    {
33
        $this->lines1 = $lines1;
34
        $this->lines2 = $lines2;
35
    }
36
37
    /**
38
     * @return array[TextLine[]]
0 ignored issues
show
Documentation Bug introduced by
The doc comment array[TextLine[]] at position 1 could not be parsed: Expected ']' at position 1, but found '['.
Loading history...
39
     */
40
    public function getResult(): array
41
    {
42
        $length = $this->getLength();
43
        $result = array_fill(0, 2, null);
44
45
        if (0 === $length) {
46
            return $result;
47
        }
48
49
        $result[0] = $this->compactAndShiftLCS($this->lcs[0], $length, $this->lines1);
50
        $result[1] = $this->compactAndShiftLCS($this->lcs[1], $length, $this->lines2);
51
52
        return $result;
53
    }
54
55
    /**
56
     * @return int
57
     */
58
    protected function getLength1(): int
59
    {
60
        return \count($this->lines1);
61
    }
62
63
    /**
64
     * @return int
65
     */
66
    protected function getLength2(): int
67
    {
68
        return \count($this->lines2);
69
    }
70
71
    /**
72
     * @param int $i1
73
     * @param int $i2
74
     * @return bool
75
     */
76
    protected function isRangeEqual(int $i1, int $i2): bool
77
    {
78
        return $this->lines1[$i1]->isSameText($this->lines2[$i2]);
79
    }
80
81
    /**
82
     * @param int $sl1
83
     * @param int $sl2
84
     */
85
    protected function setLcs(int $sl1, int $sl2): void
86
    {
87
        $this->lcs[0][$sl1] = $this->lines1[$sl1];
88
        $this->lcs[1][$sl1] = $this->lines2[$sl2];
89
    }
90
91
    /**
92
     * @param int $lcsLength
93
     */
94
    protected function initializeLcs(int $lcsLength): void
95
    {
96
        $this->lcs = array_fill(0, 2, array_fill(0, $lcsLength, null));
97
    }
98
99
    /**
100
     * @param TextLine[] $lcsSide
101
     * @param int        $len
102
     * @param TextLine[] $original
103
     * @return array
104
     */
105
    private function compactAndShiftLCS(array &$lcsSide, int $len, array &$original): array
106
    {
107
        /** @var TextLine[] $result */
108
        $result = array_fill(0, $len, null);
109
110
        if (0 === $len) {
111
            return $result;
112
        }
113
114
        $j = 0;
115
116
        while (null === $lcsSide[$j]) {
117
            $j++;
118
        }
119
120
        $result[0] = $lcsSide[$j];
121
        $j++;
122
123
        for ($i = 1; $i < $len; $i++) {
124
            while (null === $lcsSide[$j]) {
125
                $j++;
126
            }
127
128
            if ($original[$result[$i - 1]->getLineNumber() + 1]->isSameText($lcsSide[$j])) {
129
                $result[$i] = $original[$result[$i - 1]->getLineNumber() + 1];
130
            } else {
131
                $result[$i] = $lcsSide[$j];
132
            }
133
134
            $j++;
135
        }
136
137
        return $result;
138
    }
139
140
    /**
141
     * @param string $text
142
     * @return TextLine[]
143
     */
144
    public static function getTextLines(string $text): array
145
    {
146
        $lines = [];
147
        $begin = 0;
148
        $end = static::getEOL($text, 0);
149
        $lineNum = 0;
150
151
        while (-1 !== $end) {
152
            $lines[] = new TextLine($lineNum++, \mb_substr($text, $begin, $end - $begin));
153
            $begin = $end + 1;
154
            $end = static::getEOL($text, $begin);
155
156
            if ($end === $begin && "\r" === \mb_substr($text, $begin - 1, 1)  && "\n" === \mb_substr($text, $begin, 1)) {
157
                // We have \r followed by \n, skip it.
158
                $begin = $end + 1;
159
                $end = static::getEOL($text, $begin);
160
            }
161
        }
162
163
        $lines[] = new TextLine($lineNum, \mb_substr($text, $begin));
164
165
        return $lines;
166
    }
167
168
    /**
169
     * @param string $text
170
     * @param int    $start
171
     * @return int
172
     */
173
    private static function getEOL(string $text, int $start): int
174
    {
175
        $max = \mb_strlen($text);
176
177
        for ($i = $start; $i < $max; $i++) {
178
            $c = \mb_substr($text, $i, 1);
179
180
            if ("\n" === $c || "\r" === $c) {
181
                return $i;
182
            }
183
        }
184
185
        return -1;
186
    }
187
}
188