117 if (count($this->granularity) === 0) {
123 $this->from_offset = 0;
124 $this->last_edit = null;
125 $this->stackpointer = 0;
126 $this->edits = array();
132 $this->opcodes->setOpcodes($this->edits);
146 $delimiters = $this->granularity[$this->stackpointer++];
147 $has_next_stage = $this->stackpointer < count($this->granularity);
151 $diff = (is_array($diff)) ? $diff : array();
153 foreach ($diff as $fragment) {
156 if ($fragment instanceof
Replace && $has_next_stage) {
158 substr($this->from_text, $this->from_offset, $fragment->getFromLen()),
163 elseif ($fragment instanceof
Copy && $this->last_edit instanceof
Copy) {
164 $this->edits[count($this->edits)-1]->increase($fragment->getFromLen());
165 $this->from_offset += $fragment->getFromLen();
171 $this->edits[] = $this->last_edit = $fragment;
172 $this->from_offset += $fragment->getFromLen();
176 $this->stackpointer--;
191 if (empty($delimiters)) {
199 $to_text_len = strlen($to_text);
203 $jobs = array(array(0, $from_text_len, 0, $to_text_len));
204 $cached_array_keys = array();
207 while ($job = array_pop($jobs)) {
210 list($from_segment_start, $from_segment_end, $to_segment_start, $to_segment_end) = $job;
213 $from_segment_length = $from_segment_end - $from_segment_start;
214 $to_segment_length = $to_segment_end - $to_segment_start;
216 if (!$from_segment_length || !$to_segment_length ) {
218 if ( $from_segment_length ) {
219 $result[$from_segment_start * 4] =
new Delete($from_segment_length);
220 }
else if ( $to_segment_length ) {
221 $result[$from_segment_start * 4 + 1] =
new Insert(substr($to_text, $to_segment_start, $to_segment_length));
228 $best_copy_length = 0;
230 $from_base_fragment_index = $from_segment_start;
231 $cached_array_keys_for_current_segment = array();
233 while ( $from_base_fragment_index < $from_segment_end ) {
235 $from_base_fragment = $from_fragments[$from_base_fragment_index];
236 $from_base_fragment_length = strlen($from_base_fragment);
239 if (!isset($cached_array_keys_for_current_segment[$from_base_fragment])) {
241 if ( !isset($cached_array_keys[$from_base_fragment]) ) {
242 $to_all_fragment_indices = $cached_array_keys[$from_base_fragment] = array_keys($to_fragments, $from_base_fragment,
true);
245 $to_all_fragment_indices = $cached_array_keys[$from_base_fragment];
249 if ($to_segment_start > 0 || $to_segment_end < $to_text_len) {
251 $to_fragment_indices = array();
253 foreach ($to_all_fragment_indices as $to_fragment_index) {
255 if ($to_fragment_index < $to_segment_start) {
259 if ($to_fragment_index >= $to_segment_end) {
263 $to_fragment_indices[] = $to_fragment_index;
266 $cached_array_keys_for_current_segment[$from_base_fragment] = $to_fragment_indices;
269 $to_fragment_indices = $to_all_fragment_indices;
273 $to_fragment_indices = $cached_array_keys_for_current_segment[$from_base_fragment];
277 foreach ($to_fragment_indices as $to_base_fragment_index) {
279 $fragment_index_offset = $from_base_fragment_length;
284 $fragment_from_index = $from_base_fragment_index + $fragment_index_offset;
286 if ($fragment_from_index >= $from_segment_end) {
290 $fragment_to_index = $to_base_fragment_index + $fragment_index_offset;
292 if ($fragment_to_index >= $to_segment_end) {
296 if ($from_fragments[$fragment_from_index] !== $to_fragments[$fragment_to_index]) {
300 $fragment_length = strlen($from_fragments[$fragment_from_index]);
301 $fragment_index_offset += $fragment_length;
304 if ($fragment_index_offset > $best_copy_length) {
305 $best_copy_length = $fragment_index_offset;
306 $best_from_start = $from_base_fragment_index;
307 $best_to_start = $to_base_fragment_index;
311 $from_base_fragment_index += strlen($from_base_fragment);
315 if ($best_copy_length >= $from_segment_length / 2) {
321 if ( $from_base_fragment_index + $best_copy_length >= $from_segment_end ) {
326 if ($best_copy_length) {
327 $jobs[] = array($from_segment_start, $best_from_start, $to_segment_start, $best_to_start);
328 $result[$best_from_start * 4 + 2] =
new Copy($best_copy_length);
329 $jobs[] = array($best_from_start + $best_copy_length, $from_segment_end, $best_to_start + $best_copy_length, $to_segment_end);
331 $result[$from_segment_start * 4 ] =
new Replace($from_segment_length, substr($to_text, $to_segment_start, $to_segment_length));
335 ksort($result, SORT_NUMERIC);
336 return array_values($result);
349 $jobs = array(array(0, strlen(
$from_text), 0, strlen($to_text)));
351 while ($job = array_pop($jobs)) {
354 list($from_segment_start, $from_segment_end, $to_segment_start, $to_segment_end) = $job;
356 $from_segment_len = $from_segment_end - $from_segment_start;
357 $to_segment_len = $to_segment_end - $to_segment_start;
360 if (!$from_segment_len || !$to_segment_len) {
362 if ($from_segment_len) {
363 $result[$from_segment_start * 4 + 0] =
new Delete($from_segment_len);
364 }
else if ( $to_segment_len ) {
365 $result[$from_segment_start * 4 + 1] =
new Insert(substr($to_text, $to_segment_start, $to_segment_len));
371 if ($from_segment_len >= $to_segment_len) {
373 $copy_len = $to_segment_len;
377 $to_copy_start = $to_segment_start;
378 $to_copy_start_max = $to_segment_end - $copy_len;
380 while ($to_copy_start <= $to_copy_start_max) {
382 $from_copy_start = strpos(substr(
$from_text, $from_segment_start, $from_segment_len), substr($to_text, $to_copy_start, $copy_len));
384 if ($from_copy_start !==
false) {
385 $from_copy_start += $from_segment_start;
396 $copy_len = $from_segment_len;
400 $from_copy_start = $from_segment_start;
401 $from_copy_start_max = $from_segment_end - $copy_len;
403 while ($from_copy_start <= $from_copy_start_max) {
405 $to_copy_start = strpos(substr($to_text, $to_segment_start, $to_segment_len), substr(
$from_text, $from_copy_start, $copy_len));
407 if ($to_copy_start !==
false) {
408 $to_copy_start += $to_segment_start;
421 $jobs[] = array($from_segment_start, $from_copy_start, $to_segment_start, $to_copy_start);
422 $result[$from_copy_start * 4 + 2] =
new Copy($copy_len);
423 $jobs[] = array($from_copy_start + $copy_len, $from_segment_end, $to_copy_start + $copy_len, $to_segment_end);
427 $result[$from_segment_start * 4] =
new Replace($from_segment_len, substr($to_text, $to_segment_start, $to_segment_len));
431 ksort($result, SORT_NUMERIC);
432 return array_values($result);
449 if (empty($delimiters)) {
450 $chars = str_split($text, 1);
451 $chars[strlen($text)] =
'';
456 $fragments = array();
462 $end += strcspn($text, $delimiters, $end);
463 $end += strspn($text, $delimiters, $end);
465 if ($end === $start) {
469 $fragments[$start] = substr($text, $start, $end - $start);
473 $fragments[$start] =
'';