Chris@14
|
1 <?php declare(strict_types=1);
|
Chris@14
|
2 /*
|
Chris@14
|
3 * This file is part of sebastian/diff.
|
Chris@14
|
4 *
|
Chris@14
|
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
|
Chris@14
|
6 *
|
Chris@14
|
7 * For the full copyright and license information, please view the LICENSE
|
Chris@14
|
8 * file that was distributed with this source code.
|
Chris@14
|
9 */
|
Chris@14
|
10
|
Chris@14
|
11 namespace SebastianBergmann\Diff;
|
Chris@14
|
12
|
Chris@14
|
13 final class MemoryEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator
|
Chris@14
|
14 {
|
Chris@14
|
15 /**
|
Chris@14
|
16 * {@inheritdoc}
|
Chris@14
|
17 */
|
Chris@14
|
18 public function calculate(array $from, array $to): array
|
Chris@14
|
19 {
|
Chris@14
|
20 $cFrom = \count($from);
|
Chris@14
|
21 $cTo = \count($to);
|
Chris@14
|
22
|
Chris@14
|
23 if ($cFrom === 0) {
|
Chris@14
|
24 return [];
|
Chris@14
|
25 }
|
Chris@14
|
26
|
Chris@14
|
27 if ($cFrom === 1) {
|
Chris@14
|
28 if (\in_array($from[0], $to, true)) {
|
Chris@14
|
29 return [$from[0]];
|
Chris@14
|
30 }
|
Chris@14
|
31
|
Chris@14
|
32 return [];
|
Chris@14
|
33 }
|
Chris@14
|
34
|
Chris@14
|
35 $i = (int) ($cFrom / 2);
|
Chris@14
|
36 $fromStart = \array_slice($from, 0, $i);
|
Chris@14
|
37 $fromEnd = \array_slice($from, $i);
|
Chris@14
|
38 $llB = $this->length($fromStart, $to);
|
Chris@14
|
39 $llE = $this->length(\array_reverse($fromEnd), \array_reverse($to));
|
Chris@14
|
40 $jMax = 0;
|
Chris@14
|
41 $max = 0;
|
Chris@14
|
42
|
Chris@14
|
43 for ($j = 0; $j <= $cTo; $j++) {
|
Chris@14
|
44 $m = $llB[$j] + $llE[$cTo - $j];
|
Chris@14
|
45
|
Chris@14
|
46 if ($m >= $max) {
|
Chris@14
|
47 $max = $m;
|
Chris@14
|
48 $jMax = $j;
|
Chris@14
|
49 }
|
Chris@14
|
50 }
|
Chris@14
|
51
|
Chris@14
|
52 $toStart = \array_slice($to, 0, $jMax);
|
Chris@14
|
53 $toEnd = \array_slice($to, $jMax);
|
Chris@14
|
54
|
Chris@14
|
55 return \array_merge(
|
Chris@14
|
56 $this->calculate($fromStart, $toStart),
|
Chris@14
|
57 $this->calculate($fromEnd, $toEnd)
|
Chris@14
|
58 );
|
Chris@14
|
59 }
|
Chris@14
|
60
|
Chris@14
|
61 private function length(array $from, array $to): array
|
Chris@14
|
62 {
|
Chris@14
|
63 $current = \array_fill(0, \count($to) + 1, 0);
|
Chris@14
|
64 $cFrom = \count($from);
|
Chris@14
|
65 $cTo = \count($to);
|
Chris@14
|
66
|
Chris@14
|
67 for ($i = 0; $i < $cFrom; $i++) {
|
Chris@14
|
68 $prev = $current;
|
Chris@14
|
69
|
Chris@14
|
70 for ($j = 0; $j < $cTo; $j++) {
|
Chris@14
|
71 if ($from[$i] === $to[$j]) {
|
Chris@14
|
72 $current[$j + 1] = $prev[$j] + 1;
|
Chris@14
|
73 } else {
|
Chris@14
|
74 $current[$j + 1] = \max($current[$j], $prev[$j + 1]);
|
Chris@14
|
75 }
|
Chris@14
|
76 }
|
Chris@14
|
77 }
|
Chris@14
|
78
|
Chris@14
|
79 return $current;
|
Chris@14
|
80 }
|
Chris@14
|
81 }
|