Completed
Push — master ( 42324d...1863b6 )
by Steve
03:59 queued 02:04
created

TextLineLCS::compactAndShiftLCS()   A

Complexity

Conditions 6
Paths 11

Size

Total Lines 33
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

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