public function cleanupEfficiency()
{
$diffs = $this->getChanges();
$changes = false;
// Stack of indices where equalities are found.
$equalities = array();
// Always equal to diffs[equalities[-1]][1]
$lastequality = null;
// Index of current position.
$pointer = 0;
// Is there an insertion operation before the last equality.
$pre_ins = false;
// Is there a deletion operation before the last equality.
$pre_del = false;
// Is there an insertion operation after the last equality.
$post_ins = false;
// Is there a deletion operation after the last equality.
$post_del = false;
while ($pointer < count($diffs)) {
if ($diffs[$pointer][0] == self::EQUAL) {
if (mb_strlen($diffs[$pointer][1]) < $this->getEditCost() && ($post_ins || $post_del)) {
// Candidate found.
$equalities[] = $pointer;
$pre_ins = $post_ins;
$pre_del = $post_del;
$lastequality = $diffs[$pointer][1];
} else {
// Not a candidate, and can never become one.
$equalities = array();
$lastequality = null;
}
$post_ins = false;
$post_del = false;
} else {
if ($diffs[$pointer][0] == self::DELETE) {
$post_del = true;
} else {
$post_ins = true;
}
// Five types to be split:
// <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
// <ins>A</ins>X<ins>C</ins><del>D</del>
// <ins>A</ins><del>B</del>X<ins>C</ins>
// <ins>A</del>X<ins>C</ins><del>D</del>
// <ins>A</ins><del>B</del>X<del>C</del>
// TODO refactor condition
if ($lastequality != '' && ($pre_ins && $pre_del && $post_ins && $post_del || mb_strlen($lastequality) < $this->getEditCost() / 2 && $pre_ins + $pre_del + $post_del + $post_ins == 3)) {
$insertPointer = array_pop($equalities);
// Duplicate record.
array_splice($diffs, $insertPointer, 0, array(array(self::DELETE, $lastequality)));
// Change second copy to insert.
$diffs[$insertPointer + 1][0] = self::INSERT;
// Throw away the previous equality (it needs to be reevaluated).
if (count($equalities)) {
array_pop($equalities);
}
$lastequality = null;
if ($pre_ins && $pre_del) {
// No changes made which could affect previous entry, keep going.
$post_ins = true;
$post_del = true;
$equalities = array();
} else {
if (count($equalities)) {
// Throw away the previous equality.
array_pop($equalities);
}
if (count($equalities)) {
$pointer = end($equalities);
} else {
$pointer = -1;
}
$post_ins = false;
$post_del = false;
}
$changes = true;
}
}
$pointer++;
}
$this->setChanges($diffs);
if ($changes) {
$this->cleanupMerge();
}
return $this;
}