Chris@0: and Chris@0: * licensed under GPL. Chris@0: */ Chris@0: class Diff { Chris@0: Chris@0: /** Chris@0: * The list of differences as an array of diff operations. Chris@0: * Chris@0: * @var \Drupal\Component\Diff\Engine\DiffOp[] Chris@0: */ Chris@0: protected $edits; Chris@0: Chris@0: /** Chris@0: * Constructor. Chris@0: * Computes diff between sequences of strings. Chris@0: * Chris@0: * @param array $from_lines Chris@0: * An array of strings. Chris@0: * (Typically these are lines from a file.) Chris@0: * @param array $to_lines Chris@0: * An array of strings. Chris@0: */ Chris@0: public function __construct($from_lines, $to_lines) { Chris@0: $eng = new DiffEngine(); Chris@0: $this->edits = $eng->diff($from_lines, $to_lines); Chris@0: //$this->_check($from_lines, $to_lines); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Compute reversed Diff. Chris@0: * Chris@0: * SYNOPSIS: Chris@0: * Chris@0: * $diff = new Diff($lines1, $lines2); Chris@0: * $rev = $diff->reverse(); Chris@0: * @return object Chris@0: * A Diff object representing the inverse of the original diff. Chris@0: */ Chris@0: public function reverse() { Chris@0: $rev = $this; Chris@0: $rev->edits = []; Chris@0: foreach ($this->edits as $edit) { Chris@0: $rev->edits[] = $edit->reverse(); Chris@0: } Chris@0: return $rev; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Check for empty diff. Chris@0: * Chris@0: * @return bool True iff two sequences were identical. Chris@0: */ Chris@0: public function isEmpty() { Chris@0: foreach ($this->edits as $edit) { Chris@0: if ($edit->type != 'copy') { Chris@0: return FALSE; Chris@0: } Chris@0: } Chris@0: return TRUE; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Compute the length of the Longest Common Subsequence (LCS). Chris@0: * Chris@0: * This is mostly for diagnostic purposed. Chris@0: * Chris@0: * @return int The length of the LCS. Chris@0: */ Chris@0: public function lcs() { Chris@0: $lcs = 0; Chris@0: foreach ($this->edits as $edit) { Chris@0: if ($edit->type == 'copy') { Chris@0: $lcs += sizeof($edit->orig); Chris@0: } Chris@0: } Chris@0: return $lcs; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the original set of lines. Chris@0: * Chris@0: * This reconstructs the $from_lines parameter passed to the Chris@0: * constructor. Chris@0: * Chris@0: * @return array The original sequence of strings. Chris@0: */ Chris@0: public function orig() { Chris@0: $lines = []; Chris@0: Chris@0: foreach ($this->edits as $edit) { Chris@0: if ($edit->orig) { Chris@0: array_splice($lines, sizeof($lines), 0, $edit->orig); Chris@0: } Chris@0: } Chris@0: return $lines; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the closing set of lines. Chris@0: * Chris@0: * This reconstructs the $to_lines parameter passed to the Chris@0: * constructor. Chris@0: * Chris@0: * @return array The sequence of strings. Chris@0: */ Chris@0: public function closing() { Chris@0: $lines = []; Chris@0: Chris@0: foreach ($this->edits as $edit) { Chris@0: if ($edit->closing) { Chris@0: array_splice($lines, sizeof($lines), 0, $edit->closing); Chris@0: } Chris@0: } Chris@0: return $lines; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Check a Diff for validity. Chris@0: * Chris@0: * This is here only for debugging purposes. Chris@0: */ Chris@0: public function check($from_lines, $to_lines) { Chris@0: if (serialize($from_lines) != serialize($this->orig())) { Chris@0: trigger_error("Reconstructed original doesn't match", E_USER_ERROR); Chris@0: } Chris@0: if (serialize($to_lines) != serialize($this->closing())) { Chris@0: trigger_error("Reconstructed closing doesn't match", E_USER_ERROR); Chris@0: } Chris@0: Chris@0: $rev = $this->reverse(); Chris@0: if (serialize($to_lines) != serialize($rev->orig())) { Chris@0: trigger_error("Reversed original doesn't match", E_USER_ERROR); Chris@0: } Chris@0: if (serialize($from_lines) != serialize($rev->closing())) { Chris@0: trigger_error("Reversed closing doesn't match", E_USER_ERROR); Chris@0: } Chris@0: Chris@0: $prevtype = 'none'; Chris@0: foreach ($this->edits as $edit) { Chris@0: if ( $prevtype == $edit->type ) { Chris@0: trigger_error("Edit sequence is non-optimal", E_USER_ERROR); Chris@0: } Chris@0: $prevtype = $edit->type; Chris@0: } Chris@0: Chris@0: $lcs = $this->lcs(); Chris@0: trigger_error('Diff okay: LCS = ' . $lcs, E_USER_NOTICE); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the list of differences as an array of diff operations. Chris@0: * Chris@0: * @return \Drupal\Component\Diff\Engine\DiffOp[] Chris@0: * The list of differences as an array of diff operations. Chris@0: */ Chris@0: public function getEdits() { Chris@0: return $this->edits; Chris@0: } Chris@0: Chris@0: }