Yaffs site version 1.1
[yaffs-website] / vendor / sebastian / diff / src / Differ.php
index 4960111ed7a791f62a70a71a2e2db5ec427fef75..116c99c4be97301819caca4eae33542811172c08 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
- * This file is part of the Diff package.
+ * This file is part of sebastian/diff.
  *
  * (c) Sebastian Bergmann <sebastian@phpunit.de>
  *
@@ -31,6 +31,7 @@ class Differ
 
     /**
      * @param string $header
+     * @param bool   $showNonDiffLines
      */
     public function __construct($header = "--- Original\n+++ New\n", $showNonDiffLines = true)
     {
@@ -49,23 +50,52 @@ class Differ
      */
     public function diff($from, $to, LongestCommonSubsequence $lcs = null)
     {
-        if (!is_array($from) && !is_string($from)) {
-            $from = (string) $from;
+        $from  = $this->validateDiffInput($from);
+        $to    = $this->validateDiffInput($to);
+        $diff  = $this->diffToArray($from, $to, $lcs);
+        $old   = $this->checkIfDiffInOld($diff);
+        $start = isset($old[0]) ? $old[0] : 0;
+        $end   = \count($diff);
+
+        if ($tmp = \array_search($end, $old)) {
+            $end = $tmp;
         }
 
-        if (!is_array($to) && !is_string($to)) {
-            $to = (string) $to;
+        return $this->getBuffer($diff, $old, $start, $end);
+    }
+
+    /**
+     * Casts variable to string if it is not a string or array.
+     *
+     * @param mixed $input
+     *
+     * @return string
+     */
+    private function validateDiffInput($input)
+    {
+        if (!\is_array($input) && !\is_string($input)) {
+            return (string) $input;
         }
 
-        $buffer = $this->header;
-        $diff   = $this->diffToArray($from, $to, $lcs);
+        return $input;
+    }
 
+    /**
+     * Takes input of the diff array and returns the old array.
+     * Iterates through diff line by line,
+     *
+     * @param array $diff
+     *
+     * @return array
+     */
+    private function checkIfDiffInOld(array $diff)
+    {
         $inOld = false;
         $i     = 0;
         $old   = array();
 
         foreach ($diff as $line) {
-            if ($line[1] ===  0 /* OLD */) {
+            if ($line[1] === 0 /* OLD */) {
                 if ($inOld === false) {
                     $inOld = $i;
                 }
@@ -80,46 +110,85 @@ class Differ
             ++$i;
         }
 
-        $start = isset($old[0]) ? $old[0] : 0;
-        $end   = count($diff);
+        return $old;
+    }
 
-        if ($tmp = array_search($end, $old)) {
-            $end = $tmp;
-        }
+    /**
+     * Generates buffer in string format, returning the patch.
+     *
+     * @param array $diff
+     * @param array $old
+     * @param int   $start
+     * @param int   $end
+     *
+     * @return string
+     */
+    private function getBuffer(array $diff, array $old, $start, $end)
+    {
+        $buffer = $this->header;
 
-        $newChunk = true;
+        if (!isset($old[$start])) {
+            $buffer = $this->getDiffBufferElementNew($diff, $buffer, $start);
+            ++$start;
+        }
 
         for ($i = $start; $i < $end; $i++) {
             if (isset($old[$i])) {
-                $buffer  .= "\n";
-                $newChunk = true;
-                $i        = $old[$i];
+                $i      = $old[$i];
+                $buffer = $this->getDiffBufferElementNew($diff, $buffer, $i);
+            } else {
+                $buffer = $this->getDiffBufferElement($diff, $buffer, $i);
             }
+        }
 
-            if ($newChunk) {
-                if ($this->showNonDiffLines === true) {
-                    $buffer .= "@@ @@\n";
-                }
-                $newChunk = false;
-            }
+        return $buffer;
+    }
 
-            if ($diff[$i][1] === 1 /* ADDED */) {
-                $buffer .= '+' . $diff[$i][0] . "\n";
-            } elseif ($diff[$i][1] === 2 /* REMOVED */) {
-                $buffer .= '-' . $diff[$i][0] . "\n";
-            } elseif ($this->showNonDiffLines === true) {
-                $buffer .= ' ' . $diff[$i][0] . "\n";
-            }
+    /**
+     * Gets individual buffer element.
+     *
+     * @param array  $diff
+     * @param string $buffer
+     * @param int    $diffIndex
+     *
+     * @return string
+     */
+    private function getDiffBufferElement(array $diff, $buffer, $diffIndex)
+    {
+        if ($diff[$diffIndex][1] === 1 /* ADDED */) {
+            $buffer .= '+' . $diff[$diffIndex][0] . "\n";
+        } elseif ($diff[$diffIndex][1] === 2 /* REMOVED */) {
+            $buffer .= '-' . $diff[$diffIndex][0] . "\n";
+        } elseif ($this->showNonDiffLines === true) {
+            $buffer .= ' ' . $diff[$diffIndex][0] . "\n";
         }
 
         return $buffer;
     }
 
+    /**
+     * Gets individual buffer element with opening.
+     *
+     * @param array  $diff
+     * @param string $buffer
+     * @param int    $diffIndex
+     *
+     * @return string
+     */
+    private function getDiffBufferElementNew(array $diff, $buffer, $diffIndex)
+    {
+        if ($this->showNonDiffLines === true) {
+            $buffer .= "@@ @@\n";
+        }
+
+        return $this->getDiffBufferElement($diff, $buffer, $diffIndex);
+    }
+
     /**
      * Returns the diff between two arrays or strings as array.
      *
      * Each array element contains two elements:
-     *   - [0] => string $token
+     *   - [0] => mixed $token
      *   - [1] => 2|1|0
      *
      * - 2: REMOVED: $token was removed from $from
@@ -134,55 +203,37 @@ class Differ
      */
     public function diffToArray($from, $to, LongestCommonSubsequence $lcs = null)
     {
-        preg_match_all('(\r\n|\r|\n)', $from, $fromMatches);
-        preg_match_all('(\r\n|\r|\n)', $to, $toMatches);
-
-        if (is_string($from)) {
-            $from = preg_split('(\r\n|\r|\n)', $from);
+        if (\is_string($from)) {
+            $fromMatches = $this->getNewLineMatches($from);
+            $from        = $this->splitStringByLines($from);
+        } elseif (\is_array($from)) {
+            $fromMatches = array();
+        } else {
+            throw new \InvalidArgumentException('"from" must be an array or string.');
         }
 
-        if (is_string($to)) {
-            $to = preg_split('(\r\n|\r|\n)', $to);
+        if (\is_string($to)) {
+            $toMatches = $this->getNewLineMatches($to);
+            $to        = $this->splitStringByLines($to);
+        } elseif (\is_array($to)) {
+            $toMatches = array();
+        } else {
+            throw new \InvalidArgumentException('"to" must be an array or string.');
         }
 
-        $start      = array();
-        $end        = array();
-        $fromLength = count($from);
-        $toLength   = count($to);
-        $length     = min($fromLength, $toLength);
-
-        for ($i = 0; $i < $length; ++$i) {
-            if ($from[$i] === $to[$i]) {
-                $start[] = $from[$i];
-                unset($from[$i], $to[$i]);
-            } else {
-                break;
-            }
-        }
-
-        $length -= $i;
-
-        for ($i = 1; $i < $length; ++$i) {
-            if ($from[$fromLength - $i] === $to[$toLength - $i]) {
-                array_unshift($end, $from[$fromLength - $i]);
-                unset($from[$fromLength - $i], $to[$toLength - $i]);
-            } else {
-                break;
-            }
-        }
+        list($from, $to, $start, $end) = self::getArrayDiffParted($from, $to);
 
         if ($lcs === null) {
             $lcs = $this->selectLcsImplementation($from, $to);
         }
 
-        $common = $lcs->calculate(array_values($from), array_values($to));
+        $common = $lcs->calculate(\array_values($from), \array_values($to));
         $diff   = array();
 
-        if (isset($fromMatches[0]) && $toMatches[0] &&
-            count($fromMatches[0]) === count($toMatches[0]) &&
-            $fromMatches[0] !== $toMatches[0]) {
+        if ($this->detectUnmatchedLineEndings($fromMatches, $toMatches)) {
             $diff[] = array(
-              '#Warning: Strings contain different line endings!', 0
+                '#Warning: Strings contain different line endings!',
+                0
             );
         }
 
@@ -190,29 +241,29 @@ class Differ
             $diff[] = array($token, 0 /* OLD */);
         }
 
-        reset($from);
-        reset($to);
+        \reset($from);
+        \reset($to);
 
         foreach ($common as $token) {
-            while ((($fromToken = reset($from)) !== $token)) {
-                $diff[] = array(array_shift($from), 2 /* REMOVED */);
+            while (($fromToken = \reset($from)) !== $token) {
+                $diff[] = array(\array_shift($from), 2 /* REMOVED */);
             }
 
-            while ((($toToken = reset($to)) !== $token)) {
-                $diff[] = array(array_shift($to), 1 /* ADDED */);
+            while (($toToken = \reset($to)) !== $token) {
+                $diff[] = array(\array_shift($to), 1 /* ADDED */);
             }
 
             $diff[] = array($token, 0 /* OLD */);
 
-            array_shift($from);
-            array_shift($to);
+            \array_shift($from);
+            \array_shift($to);
         }
 
-        while (($token = array_shift($from)) !== null) {
+        while (($token = \array_shift($from)) !== null) {
             $diff[] = array($token, 2 /* REMOVED */);
         }
 
-        while (($token = array_shift($to)) !== null) {
+        while (($token = \array_shift($to)) !== null) {
             $diff[] = array($token, 1 /* ADDED */);
         }
 
@@ -223,6 +274,32 @@ class Differ
         return $diff;
     }
 
+    /**
+     * Get new strings denoting new lines from a given string.
+     *
+     * @param string $string
+     *
+     * @return array
+     */
+    private function getNewLineMatches($string)
+    {
+        \preg_match_all('(\r\n|\r|\n)', $string, $stringMatches);
+
+        return $stringMatches;
+    }
+
+    /**
+     * Checks if input is string, if so it will split it line-by-line.
+     *
+     * @param string $input
+     *
+     * @return array
+     */
+    private function splitStringByLines($input)
+    {
+        return \preg_split('(\r\n|\r|\n)', $input);
+    }
+
     /**
      * @param array $from
      * @param array $to
@@ -250,12 +327,73 @@ class Differ
      * @param array $from
      * @param array $to
      *
-     * @return int
+     * @return int|float
      */
     private function calculateEstimatedFootprint(array $from, array $to)
     {
-        $itemSize = PHP_INT_SIZE == 4 ? 76 : 144;
+        $itemSize = PHP_INT_SIZE === 4 ? 76 : 144;
+
+        return $itemSize * \pow(\min(\count($from), \count($to)), 2);
+    }
+
+    /**
+     * Returns true if line ends don't match on fromMatches and toMatches.
+     *
+     * @param array $fromMatches
+     * @param array $toMatches
+     *
+     * @return bool
+     */
+    private function detectUnmatchedLineEndings(array $fromMatches, array $toMatches)
+    {
+        return isset($fromMatches[0], $toMatches[0]) &&
+               \count($fromMatches[0]) === \count($toMatches[0]) &&
+               $fromMatches[0] !== $toMatches[0];
+    }
+
+    /**
+     * @param array $from
+     * @param array $to
+     *
+     * @return array
+     */
+    private static function getArrayDiffParted(array &$from, array &$to)
+    {
+        $start = array();
+        $end   = array();
+
+        \reset($to);
+
+        foreach ($from as $k => $v) {
+            $toK = \key($to);
+
+            if ($toK === $k && $v === $to[$k]) {
+                $start[$k] = $v;
+
+                unset($from[$k], $to[$k]);
+            } else {
+                break;
+            }
+        }
+
+        \end($from);
+        \end($to);
+
+        do {
+            $fromK = \key($from);
+            $toK   = \key($to);
+
+            if (null === $fromK || null === $toK || \current($from) !== \current($to)) {
+                break;
+            }
+
+            \prev($from);
+            \prev($to);
+
+            $end = array($fromK => $from[$fromK]) + $end;
+            unset($from[$fromK], $to[$toK]);
+        } while (true);
 
-        return $itemSize * pow(min(count($from), count($to)), 2);
+        return array($from, $to, $start, $end);
     }
 }