GetOpCodes returns a list of 5-tuples describing how to turn a into b. Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the tuple preceding it, and likewise for j1 == the previous j2. The tags are characters, with thes
()
| 437 | // |
| 438 | // 'e' (equal): a[i1:i2] == b[j1:j2] |
| 439 | func (m *SequenceMatcher) GetOpCodes() []OpCode { |
| 440 | if m.opCodes != nil { |
| 441 | return m.opCodes |
| 442 | } |
| 443 | i, j := 0, 0 |
| 444 | matching := m.GetMatchingBlocks() |
| 445 | opCodes := make([]OpCode, 0, len(matching)) |
| 446 | for _, m := range matching { |
| 447 | // invariant: we've pumped out correct diffs to change |
| 448 | // a[:i] into b[:j], and the next matching block is |
| 449 | // a[ai:ai+size] == b[bj:bj+size]. So we need to pump |
| 450 | // out a diff to change a[i:ai] into b[j:bj], pump out |
| 451 | // the matching block, and move (i,j) beyond the match |
| 452 | ai, bj, size := m.A, m.B, m.Size |
| 453 | tag := byte(0) |
| 454 | if i < ai && j < bj { |
| 455 | tag = 'r' |
| 456 | } else if i < ai { |
| 457 | tag = 'd' |
| 458 | } else if j < bj { |
| 459 | tag = 'i' |
| 460 | } |
| 461 | if tag > 0 { |
| 462 | opCodes = append(opCodes, OpCode{tag, i, ai, j, bj}) |
| 463 | } |
| 464 | i, j = ai+size, bj+size |
| 465 | // the list of matching blocks is terminated by a |
| 466 | // sentinel with size 0 |
| 467 | if size > 0 { |
| 468 | opCodes = append(opCodes, OpCode{'e', ai, i, bj, j}) |
| 469 | } |
| 470 | } |
| 471 | m.opCodes = opCodes |
| 472 | return m.opCodes |
| 473 | } |
| 474 | |
| 475 | // GetGroupedOpCodes isolates change clusters by eliminating ranges with no changes. |
| 476 | // |