Mercurial > hg > isophonics-drupal-site
comparison vendor/nikic/php-parser/lib/PhpParser/Internal/Differ.php @ 13:5fb285c0d0e3
Update Drupal core to 8.4.7 via Composer. Security update; I *think* we've
been lucky to get away with this so far, as we don't support self-registration
which seems to be used by the so-called "drupalgeddon 2" attack that 8.4.5
was vulnerable to.
author | Chris Cannam |
---|---|
date | Mon, 23 Apr 2018 09:33:26 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
12:7a779792577d | 13:5fb285c0d0e3 |
---|---|
1 <?php declare(strict_types=1); | |
2 | |
3 namespace PhpParser\Internal; | |
4 | |
5 /** | |
6 * Implements the Myers diff algorithm. | |
7 * | |
8 * Myers, Eugene W. "An O (ND) difference algorithm and its variations." | |
9 * Algorithmica 1.1 (1986): 251-266. | |
10 * | |
11 * @internal | |
12 */ | |
13 class Differ | |
14 { | |
15 private $isEqual; | |
16 | |
17 /** | |
18 * Create differ over the given equality relation. | |
19 * | |
20 * @param callable $isEqual Equality relation with signature function($a, $b) : bool | |
21 */ | |
22 public function __construct(callable $isEqual) { | |
23 $this->isEqual = $isEqual; | |
24 } | |
25 | |
26 /** | |
27 * Calculate diff (edit script) from $old to $new. | |
28 * | |
29 * @param array $old Original array | |
30 * @param array $new New array | |
31 * | |
32 * @return DiffElem[] Diff (edit script) | |
33 */ | |
34 public function diff(array $old, array $new) { | |
35 list($trace, $x, $y) = $this->calculateTrace($old, $new); | |
36 return $this->extractDiff($trace, $x, $y, $old, $new); | |
37 } | |
38 | |
39 /** | |
40 * Calculate diff, including "replace" operations. | |
41 * | |
42 * If a sequence of remove operations is followed by the same number of add operations, these | |
43 * will be coalesced into replace operations. | |
44 * | |
45 * @param array $old Original array | |
46 * @param array $new New array | |
47 * | |
48 * @return DiffElem[] Diff (edit script), including replace operations | |
49 */ | |
50 public function diffWithReplacements(array $old, array $new) { | |
51 return $this->coalesceReplacements($this->diff($old, $new)); | |
52 } | |
53 | |
54 private function calculateTrace(array $a, array $b) { | |
55 $n = \count($a); | |
56 $m = \count($b); | |
57 $max = $n + $m; | |
58 $v = [1 => 0]; | |
59 $trace = []; | |
60 for ($d = 0; $d <= $max; $d++) { | |
61 $trace[] = $v; | |
62 for ($k = -$d; $k <= $d; $k += 2) { | |
63 if ($k === -$d || ($k !== $d && $v[$k-1] < $v[$k+1])) { | |
64 $x = $v[$k+1]; | |
65 } else { | |
66 $x = $v[$k-1] + 1; | |
67 } | |
68 | |
69 $y = $x - $k; | |
70 while ($x < $n && $y < $m && ($this->isEqual)($a[$x], $b[$y])) { | |
71 $x++; | |
72 $y++; | |
73 } | |
74 | |
75 $v[$k] = $x; | |
76 if ($x >= $n && $y >= $m) { | |
77 return [$trace, $x, $y]; | |
78 } | |
79 } | |
80 } | |
81 throw new \Exception('Should not happen'); | |
82 } | |
83 | |
84 private function extractDiff(array $trace, int $x, int $y, array $a, array $b) { | |
85 $result = []; | |
86 for ($d = \count($trace) - 1; $d >= 0; $d--) { | |
87 $v = $trace[$d]; | |
88 $k = $x - $y; | |
89 | |
90 if ($k === -$d || ($k !== $d && $v[$k-1] < $v[$k+1])) { | |
91 $prevK = $k + 1; | |
92 } else { | |
93 $prevK = $k - 1; | |
94 } | |
95 | |
96 $prevX = $v[$prevK]; | |
97 $prevY = $prevX - $prevK; | |
98 | |
99 while ($x > $prevX && $y > $prevY) { | |
100 $result[] = new DiffElem(DiffElem::TYPE_KEEP, $a[$x-1], $b[$y-1]); | |
101 $x--; | |
102 $y--; | |
103 } | |
104 | |
105 if ($d === 0) { | |
106 break; | |
107 } | |
108 | |
109 while ($x > $prevX) { | |
110 $result[] = new DiffElem(DiffElem::TYPE_REMOVE, $a[$x-1], null); | |
111 $x--; | |
112 } | |
113 | |
114 while ($y > $prevY) { | |
115 $result[] = new DiffElem(DiffElem::TYPE_ADD, null, $b[$y-1]); | |
116 $y--; | |
117 } | |
118 } | |
119 return array_reverse($result); | |
120 } | |
121 | |
122 /** | |
123 * Coalesce equal-length sequences of remove+add into a replace operation. | |
124 * | |
125 * @param DiffElem[] $diff | |
126 * @return DiffElem[] | |
127 */ | |
128 private function coalesceReplacements(array $diff) { | |
129 $newDiff = []; | |
130 $c = \count($diff); | |
131 for ($i = 0; $i < $c; $i++) { | |
132 $diffType = $diff[$i]->type; | |
133 if ($diffType !== DiffElem::TYPE_REMOVE) { | |
134 $newDiff[] = $diff[$i]; | |
135 continue; | |
136 } | |
137 | |
138 $j = $i; | |
139 while ($j < $c && $diff[$j]->type === DiffElem::TYPE_REMOVE) { | |
140 $j++; | |
141 } | |
142 | |
143 $k = $j; | |
144 while ($k < $c && $diff[$k]->type === DiffElem::TYPE_ADD) { | |
145 $k++; | |
146 } | |
147 | |
148 if ($j - $i === $k - $j) { | |
149 $len = $j - $i; | |
150 for ($n = 0; $n < $len; $n++) { | |
151 $newDiff[] = new DiffElem( | |
152 DiffElem::TYPE_REPLACE, $diff[$i + $n]->old, $diff[$j + $n]->new | |
153 ); | |
154 } | |
155 } else { | |
156 for (; $i < $k; $i++) { | |
157 $newDiff[] = $diff[$i]; | |
158 } | |
159 } | |
160 $i = $k - 1; | |
161 } | |
162 return $newDiff; | |
163 } | |
164 } |