protected function bisect($text1, $text2, $deadline)
{
// Cache the text lengths to prevent multiple calls.
$text1Length = mb_strlen($text1);
$text2Length = mb_strlen($text2);
$maxD = (int) (($text1Length + $text2Length + 1) / 2);
$vOffset = $maxD;
$vLength = 2 * $maxD;
$v1 = array_fill(0, $vLength, -1);
$v1[$vOffset + 1] = 0;
$v2 = $v1;
$delta = $text1Length - $text2Length;
// If the total number of characters is odd, then the front path will collide with the reverse path.
$front = $delta % 2 != 0;
// Offsets for start and end of k loop.
// Prevents mapping of space beyond the grid.
$k1Start = 0;
$k1End = 0;
$k2Start = 0;
$k2End = 0;
for ($d = 0; $d < $maxD; $d++) {
// Bail out if deadline is reached.
if (microtime(1) > $deadline) {
break;
}
// Walk the front path one step.
for ($k1 = -$d + $k1Start; $k1 < $d + 1 - $k1End; $k1 += 2) {
$k1Offset = $vOffset + $k1;
if ($k1 == -$d || $k1 != $d && $v1[$k1Offset - 1] < $v1[$k1Offset + 1]) {
$x1 = $v1[$k1Offset + 1];
} else {
$x1 = $v1[$k1Offset - 1] + 1;
}
$y1 = $x1 - $k1;
while ($x1 < $text1Length && $y1 < $text2Length && mb_substr($text1, $x1, 1) == mb_substr($text2, $y1, 1)) {
$x1++;
$y1++;
}
$v1[$k1Offset] = $x1;
if ($x1 > $text1Length) {
// Ran off the right of the graph.
$k1End += 2;
} elseif ($y1 > $text2Length) {
// Ran off the bottom of the graph.
$k1Start += 2;
} elseif ($front) {
$k2Offset = $vOffset + $delta - $k1;
if ($k2Offset >= 0 && $k2Offset < $vLength && $v2[$k2Offset] != -1) {
// Mirror x2 onto top-left coordinate system.
$x2 = $text1Length - $v2[$k2Offset];
if ($x1 >= $x2) {
// Overlap detected.
return $this->bisectSplit($text1, $text2, $x1, $y1, $deadline);
}
}
}
}
// Walk the reverse path one step.
for ($k2 = -$d + $k2Start; $k2 < $d + 1 - $k2End; $k2 += 2) {
$k2Offset = $vOffset + $k2;
if ($k2 == -$d || $k2 != $d && $v2[$k2Offset - 1] < $v2[$k2Offset + 1]) {
$x2 = $v2[$k2Offset + 1];
} else {
$x2 = $v2[$k2Offset - 1] + 1;
}
$y2 = $x2 - $k2;
while ($x2 < $text1Length && $y2 < $text2Length && mb_substr($text1, -$x2 - 1, 1) == mb_substr($text2, -$y2 - 1, 1)) {
$x2++;
$y2++;
}
$v2[$k2Offset] = $x2;
if ($x2 > $text1Length) {
// Ran off the right of the graph.
$k2End += 2;
} elseif ($y2 > $text2Length) {
// Ran off the bottom of the graph.
$k2Start += 2;
} elseif (!$front) {
$k1Offset = $vOffset + $delta - $k2;
if ($k1Offset >= 0 && $k1Offset < $vLength && $v1[$k1Offset] != -1) {
$x1 = $v1[$k1Offset];
$y1 = $vOffset + $x1 - $k1Offset;
// Mirror x2 onto top-left coordinate system.
$x2 = $text1Length - $x2;
if ($x1 >= $x2) {
// Overlap detected.
return $this->bisectSplit($text1, $text2, $x1, $y1, $deadline);
}
}
}
}
}
// Diff took too long and hit the deadline or
// number of diffs equals number of characters, no commonality at all.
return array(array(self::DELETE, $text1), array(self::INSERT, $text2));
}