Skip to content

Remove complexity #42

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions lib/jblond/Diff/Renderer/SequenceMatcherHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace jblond\Diff\Renderer;

/**
* Sequence matcher helper functions for Diff
*
* PHP version 7.2 or greater
*
* @package jblond\Diff
* @author Mario Brandt <[email protected]>
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
* @version 2.0.0
* @link https://github.com/JBlond/php-diff
*/
class SequenceMatcherHelper
{
/**
* Helper function that provides the ability to return the value for a key
* in an array of it exists, or if it doesn't then return a default value.
* Essentially cleaner than doing a series of if (isset()) {} else {} calls.
*
* @param array $array The array to search.
* @param string|int $key The key to check that exists.
* @param mixed $default The value to return as the default value if the key doesn't exist.
* @return mixed The value from the array if the key exists or otherwise the default.
*/
protected function arrayGetDefault(array $array, $key, $default)
{
if (isset($array[$key])) {
return $array[$key];
}
return $default;
}

/**
* Sort an array by the nested arrays it contains. Helper function for getMatchingBlocks
*
* @param array $aArray First array to compare.
* @param array $bArray Second array to compare.
* @return int -1, 0 or 1, as expected by the usort function.
*/
protected function tupleSort(array $aArray, array $bArray): int
{
$max = max(count($aArray), count($bArray));
for ($counter = 0; $counter < $max; ++$counter) {
if ($aArray[$counter] < $bArray[$counter]) {
return -1;
} elseif ($aArray[$counter] > $bArray[$counter]) {
return 1;
}
}

if (count($aArray) == count($bArray)) {
return 0;
}
if (count($aArray) < count($bArray)) {
return -1;
}
return 1;
}
}
100 changes: 28 additions & 72 deletions lib/jblond/Diff/SequenceMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace jblond\Diff;

use InvalidArgumentException;
use jblond\Diff\Renderer\SequenceMatcherHelper;

/**
* Sequence matcher for Diff
Expand All @@ -20,7 +21,7 @@
* @version 2.0.0
* @link https://github.com/JBlond/php-diff
*/
class SequenceMatcher
class SequenceMatcher extends SequenceMatcherHelper
{
/**
* @var string|array Either a string or an array containing a callback function to determine
Expand Down Expand Up @@ -236,32 +237,32 @@ private function isBJunk(string $bString): bool
* that the junk element appears in the block. Extend it as far as possible
* by matching only junk elements in both $a and $b.
*
* @param int $alo The lower constraint for the first sequence.
* @param int $ahi The upper constraint for the first sequence.
* @param int $blo The lower constraint for the second sequence.
* @param int $bhi The upper constraint for the second sequence.
* @param int $aLower The lower constraint for the first sequence.
* @param int $aUpper The upper constraint for the first sequence.
* @param int $bLower The lower constraint for the second sequence.
* @param int $bUpper The upper constraint for the second sequence.
* @return array Array containing the longest match that includes the starting position in $a,
* start in $b and the length/size.
*/
public function findLongestMatch(int $alo, int $ahi, int $blo, int $bhi): array
public function findLongestMatch(int $aLower, int $aUpper, int $bLower, int $bUpper): array
{
$old = $this->old;
$new = $this->new;

$bestI = $alo;
$bestJ = $blo;
$bestI = $aLower;
$bestJ = $bLower;
$bestSize = 0;

$j2Len = [];
$nothing = [];

for ($i = $alo; $i < $ahi; ++$i) {
for ($i = $aLower; $i < $aUpper; ++$i) {
$newJ2Len = [];
$jDict = $this->arrayGetDefault($this->b2j, $old[$i], $nothing);
foreach ($jDict as $j) {
if ($j < $blo) {
if ($j < $bLower) {
continue;
} elseif ($j >= $bhi) {
} elseif ($j >= $bUpper) {
break;
}

Expand All @@ -278,8 +279,8 @@ public function findLongestMatch(int $alo, int $ahi, int $blo, int $bhi): array
}

while (
$bestI > $alo &&
$bestJ > $blo &&
$bestI > $aLower &&
$bestJ > $bLower &&
!$this->isBJunk($new[$bestJ - 1]) &&
!$this->linesAreDifferent($bestI - 1, $bestJ - 1)
) {
Expand All @@ -289,17 +290,17 @@ public function findLongestMatch(int $alo, int $ahi, int $blo, int $bhi): array
}

while (
$bestI + $bestSize < $ahi &&
($bestJ + $bestSize) < $bhi &&
$bestI + $bestSize < $aUpper &&
($bestJ + $bestSize) < $bUpper &&
!$this->isBJunk($new[$bestJ + $bestSize]) &&
!$this->linesAreDifferent($bestI + $bestSize, $bestJ + $bestSize)
) {
++$bestSize;
}

while (
$bestI > $alo &&
$bestJ > $blo &&
$bestI > $aLower &&
$bestJ > $bLower &&
$this->isBJunk($new[$bestJ - 1]) &&
!$this->linesAreDifferent($bestI - 1, $bestJ - 1)
) {
Expand All @@ -309,8 +310,8 @@ public function findLongestMatch(int $alo, int $ahi, int $blo, int $bhi): array
}

while (
$bestI + $bestSize < $ahi &&
$bestJ + $bestSize < $bhi &&
$bestI + $bestSize < $aUpper &&
$bestJ + $bestSize < $bUpper &&
$this->isBJunk($new[$bestJ + $bestSize]) &&
!$this->linesAreDifferent($bestI + $bestSize, $bestJ + $bestSize)
) {
Expand Down Expand Up @@ -384,26 +385,26 @@ public function getMatchingBlocks(): array

$matchingBlocks = [];
while (!empty($queue)) {
[$alo, $ahi, $blo, $bhi] = array_pop($queue);
$longestMatch = $this->findLongestMatch($alo, $ahi, $blo, $bhi);
[$aLower, $aUpper, $bLower, $bUpper] = array_pop($queue);
$longestMatch = $this->findLongestMatch($aLower, $aUpper, $bLower, $bUpper);
[$list1, $list2, $list3] = $longestMatch;
if ($list3) {
$matchingBlocks[] = $longestMatch;
if ($alo < $list1 && $blo < $list2) {
if ($aLower < $list1 && $bLower < $list2) {
$queue[] = [
$alo,
$aLower,
$list1,
$blo,
$bLower,
$list2
];
}

if ($list1 + $list3 < $ahi && $list2 + $list3 < $bhi) {
if ($list1 + $list3 < $aUpper && $list2 + $list3 < $bUpper) {
$queue[] = [
$list1 + $list3,
$ahi,
$aUpper,
$list2 + $list3,
$bhi
$bUpper
];
}
}
Expand Down Expand Up @@ -614,49 +615,4 @@ public function getGroupedOpCodes(): array

return $groups;
}

/**
* Helper function that provides the ability to return the value for a key
* in an array of it exists, or if it doesn't then return a default value.
* Essentially cleaner than doing a series of if (isset()) {} else {} calls.
*
* @param array $array The array to search.
* @param string|int $key The key to check that exists.
* @param mixed $default The value to return as the default value if the key doesn't exist.
* @return mixed The value from the array if the key exists or otherwise the default.
*/
private function arrayGetDefault(array $array, $key, $default)
{
if (isset($array[$key])) {
return $array[$key];
}
return $default;
}

/**
* Sort an array by the nested arrays it contains. Helper function for getMatchingBlocks
*
* @param array $aArray First array to compare.
* @param array $bArray Second array to compare.
* @return int -1, 0 or 1, as expected by the usort function.
*/
private function tupleSort(array $aArray, array $bArray): int
{
$max = max(count($aArray), count($bArray));
for ($counter = 0; $counter < $max; ++$counter) {
if ($aArray[$counter] < $bArray[$counter]) {
return -1;
} elseif ($aArray[$counter] > $bArray[$counter]) {
return 1;
}
}

if (count($aArray) == count($bArray)) {
return 0;
}
if (count($aArray) < count($bArray)) {
return -1;
}
return 1;
}
}