15
15
# along with this program; if not, write to the Free Software
 
16
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
 
18
from __future__ import absolute_import
 
19
20
from bisect import bisect
 
22
 
from bzrlib.trace import mutter
 
25
 
__all__ = ['PatienceSequenceMatcher', 'unified_diff', 'unified_diff_files']
 
 
23
from .trace import mutter
 
28
26
def unique_lcs_py(a, b):
 
 
42
40
    # set index[line in a] = position of line in a unless
 
43
41
    # a is a duplicate, in which case it's set to None
 
45
 
    for i in xrange(len(a)):
 
 
43
    for i, line in enumerate(a):
 
51
48
    # make btoa[i] = position of line i in a, unless
 
52
49
    # that line doesn't occur exactly once in both,
 
53
50
    # in which case it's set to None
 
 
80
77
        # as an optimization, check if the next line comes right after
 
81
78
        # the previous line, because usually it does
 
82
79
        elif stacks and stacks[k] < apos and (k == len(stacks) - 1 or
 
 
80
                                              stacks[k + 1] > apos):
 
86
83
            k = bisect(stacks, apos)
 
88
 
            backpointers[bpos] = lasts[k-1]
 
 
85
            backpointers[bpos] = lasts[k - 1]
 
89
86
        if k < len(stacks):
 
 
127
124
    oldlength = len(answer)
 
128
125
    if alo == ahi or blo == bhi:
 
132
129
    for apos, bpos in unique_lcs_py(a[alo:ahi], b[blo:bhi]):
 
133
130
        # recurse between lines which are unique in each file and match
 
136
133
        # Most of the time, you will have a sequence of similar entries
 
137
 
        if last_a_pos+1 != apos or last_b_pos+1 != bpos:
 
138
 
            recurse_matches_py(a, b, last_a_pos+1, last_b_pos+1,
 
139
 
                apos, bpos, answer, maxrecursion - 1)
 
 
134
        if last_a_pos + 1 != apos or last_b_pos + 1 != bpos:
 
 
136
                a, b, last_a_pos + 1, last_b_pos + 1, apos, bpos, answer,
 
140
138
        last_a_pos = apos
 
141
139
        last_b_pos = bpos
 
142
140
        answer.append((apos, bpos))
 
143
141
    if len(answer) > oldlength:
 
144
142
        # find matches between the last match and the end
 
145
 
        recurse_matches_py(a, b, last_a_pos+1, last_b_pos+1,
 
 
143
        recurse_matches_py(a, b, last_a_pos + 1, last_b_pos + 1,
 
146
144
                           ahi, bhi, answer, maxrecursion - 1)
 
147
145
    elif a[alo] == b[blo]:
 
148
146
        # find matching lines at the very beginning
 
 
159
157
        while nahi > alo and nbhi > blo and a[nahi - 1] == b[nbhi - 1]:
 
162
 
        recurse_matches_py(a, b, last_a_pos+1, last_b_pos+1,
 
 
160
        recurse_matches_py(a, b, last_a_pos + 1, last_b_pos + 1,
 
163
161
                           nahi, nbhi, answer, maxrecursion - 1)
 
164
 
        for i in xrange(ahi - nahi):
 
 
162
        for i in range(ahi - nahi):
 
165
163
            answer.append((nahi + i, nbhi + i))
 
 
244
242
        # Matches now has individual line pairs of
 
245
243
        # line A matches line B, at the given offsets
 
246
244
        self.matching_blocks = _collapse_sequences(matches)
 
247
 
        self.matching_blocks.append( (len(self.a), len(self.b), 0) )
 
 
245
        self.matching_blocks.append((len(self.a), len(self.b), 0))
 
248
246
        if PatienceSequenceMatcher_py._do_check_consistency:
 
250
248
                _check_consistency(self.matching_blocks)