public function diff(Delta $other) { $delta = new self(); if ($this->getOperations() === $other->getOperations()) { return $delta; } $strings = array_map(function (OperationCollection $operations) use($other) { return implode(array_map(function (OperationInterface $operation) use($operations, $other) { if ($operation->getType() === OperationInterface::TYPE_INSERT) { return is_string($operation->getValue()) ? $operation->getValue() : chr(0); } throw new \RuntimeException(sprintf('diff() called %s non-document', $operations === $other->getOperations() ? 'on' : 'with')); }, $operations->toArray())); }, [$this->getOperations(), $other->getOperations()]); $diffResults = FastDiff::diff($strings[0], $strings[1]); $thisIterator = $this->getOperations()->getIterator(); $otherIterator = $other->getOperations()->getIterator(); foreach ($diffResults as $diffResult) { $length = mb_strlen($diffResult[1]); while ($length > 0) { $operationLength = 0; switch ($diffResult[0]) { case FastDiff::DIFF_INSERT: $operationLength = min($otherIterator->getPeekLength(), $length); $delta->push($otherIterator->next($operationLength)); break; case FastDiff::DIFF_DELETE: $operationLength = min($length, $thisIterator->getPeekLength()); $thisIterator->next($operationLength); $delta->delete($operationLength); break; case FastDiff::DIFF_EQUAL: $operationLength = min($thisIterator->getPeekLength(), $otherIterator->getPeekLength(), $length); $thisOperation = $thisIterator->next($operationLength); $otherOperation = $otherIterator->next($operationLength); if ($thisOperation->getValue() === $otherOperation->getValue()) { $delta->retain($operationLength, $this->diffAttributes($thisOperation->getAttributes(), $otherOperation->getAttributes())); } else { $delta->push($otherOperation)->delete($operationLength); } break; } $length -= $operationLength; } } return $delta->chop(); }