[meld] Cache merged diffs by disallowing arbitrary text sequences



commit f04a838c547c43b16e074c9c2f36736c6d14e1c2
Author: Kai Willadsen <kai willadsen gmail com>
Date:   Sun Jun 7 16:16:55 2009 +1000

    Cache merged diffs by disallowing arbitrary text sequences
    
    In theory, the Differ interface allowed changes to be requested based on
    arbitrary text sequences. However, in practice, Differ's change accessors
    were only ever called using raw buffer text. Caching the merged diffs
    allows us to do significantly less work.

 diffutil.py |   25 +++++++++++++++----------
 filediff.py |   18 +++++++++---------
 2 files changed, 24 insertions(+), 19 deletions(-)
---
diff --git a/diffutil.py b/diffutil.py
index a941927..019b778 100644
--- a/diffutil.py
+++ b/diffutil.py
@@ -74,6 +74,10 @@ class Differ(object):
         self.num_sequences = 0
         self.seqlength = [0, 0, 0]
         self.diffs = [[], []]
+        self._merge_cache = []
+
+    def _update_merge_cache(self, texts):
+        self._merge_cache = [c for c in self._merge_diffs(self.diffs[0], self.diffs[1], texts)]
 
     def change_sequence(self, sequence, startidx, sizechange, texts):
         assert sequence in (0, 1, 2)
@@ -82,6 +86,7 @@ class Differ(object):
         if sequence == 2 or (sequence == 1 and self.num_sequences == 3):
             self._change_sequence(1, sequence, startidx, sizechange, texts)
         self.seqlength[sequence] += sizechange
+        self._update_merge_cache(texts)
 
     def _locate_chunk(self, whichdiffs, sequence, line):
         """Find the index of the chunk which contains line."""
@@ -128,34 +133,33 @@ class Differ(object):
                                                 for c in self.diffs[which][hiidx:] ]
         self.diffs[which][loidx:hiidx] = newdiffs
 
-    def all_changes(self, texts):
-        for c in self._merge_diffs(self.diffs[0], self.diffs[1], texts):
-            yield c
+    def all_changes(self):
+        return iter(self._merge_cache)
 
-    def pair_changes(self, fromindex, toindex, texts):
+    def pair_changes(self, fromindex, toindex):
         """Give all changes between file1 and either file0 or file2.
         """
         if fromindex == 1:
             seq = toindex/2
-            for c in self.all_changes( texts ):
+            for c in self._merge_cache:
                 if c[seq]:
                     yield c[seq]
         else:
             seq = fromindex/2
-            for c in self.all_changes( texts ):
+            for c in self._merge_cache:
                 if c[seq]:
                     yield reverse_chunk(c[seq])
 
-    def single_changes(self, textindex, texts):
+    def single_changes(self, textindex):
         """Give changes for single file only. do not return 'equal' hunks.
         """
         if textindex in (0,2):
             seq = textindex/2
-            for cs in self.all_changes( texts ):
+            for cs in self._merge_cache:
                 if cs[seq]:
                     yield reverse_chunk(cs[seq]) + (1,)
         else:
-            for cs in self.all_changes( texts ):
+            for cs in self._merge_cache:
                 if cs[0]:
                     yield cs[0] + (0,)
                 elif cs[1]:
@@ -241,7 +245,7 @@ class Differ(object):
                 for c in self._auto_merge(using, texts):
                     yield c
 
-    def set_sequences_iter(self, *sequences):
+    def set_sequences_iter(self, sequences, texts):
         assert 0 <= len(sequences) <= 3
         self.diffs = [[], []]
         self.num_sequences = len(sequences)
@@ -253,5 +257,6 @@ class Differ(object):
             while work.next() == None:
                 yield None
             self.diffs[i] = matcher.get_difference_opcodes()
+        self._update_merge_cache(texts)
         yield 1
 
diff --git a/filediff.py b/filediff.py
index f825525..5e9441b 100644
--- a/filediff.py
+++ b/filediff.py
@@ -591,7 +591,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
         yield _("[%s] Computing differences") % self.label_text
         panetext = [self._filter_text(p) for p in panetext]
         lines = map(lambda x: x.split("\n"), panetext)
-        step = self.linediffer.set_sequences_iter(*lines)
+        step = self.linediffer.set_sequences_iter(lines, self._get_texts())
         while step.next() == None:
             yield 1
 
@@ -628,7 +628,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
             for tagname in taglist:
                 tag = table.lookup(tagname)
                 b.remove_tag(tag, b.get_start_iter(), b.get_end_iter() )
-        for chunk in self.linediffer.all_changes(self._get_texts()):
+        for chunk in self.linediffer.all_changes():
             for i,c in enumerate(chunk):
                 if c and c[0] == "replace":
                     bufs = self.textbuffer[1], self.textbuffer[i*2]
@@ -696,7 +696,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
                 context.rectangle(0, ypos0, width, ypos1 - ypos0)
                 context.fill()
 
-        for change in self.linediffer.single_changes(pane, self._get_texts()):
+        for change in self.linediffer.single_changes(pane):
             change, skip = self._consume_blank_lines(change, pane, change[5])
             if skip:
                 continue
@@ -938,7 +938,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
             for (i,adj) in others:
                 mbegin,mend, obegin,oend = 0, self._get_line_count(master), 0, self._get_line_count(i)
                 # look for the chunk containing 'line'
-                for c in self.linediffer.pair_changes(master, i, self._get_texts()):
+                for c in self.linediffer.pair_changes(master, i):
                     c = c[1:]
                     if c[0] >= line:
                         mend = c[0]
@@ -1000,7 +1000,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
                 "insert":solid_green,
                 "replace":solid_blue,
                 "delete":solid_green}
-        for c in self.linediffer.single_changes(textindex, self._get_texts()):
+        for c in self.linediffer.single_changes(textindex):
             assert c[0] != "equal"
             c, skip = self._consume_blank_lines(c, textindex, c[5])
             if skip:
@@ -1066,7 +1066,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
             curline = -1
         c = None
         if direction == gdk.SCROLL_DOWN:
-            for c in self.linediffer.single_changes(1, self._get_texts()):
+            for c in self.linediffer.single_changes(1):
                 assert c[0] != "equal"
                 c, skip = self._consume_blank_lines(c, 1, c[5])
                 if skip:
@@ -1074,7 +1074,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
                 if c[1] > curline:
                     break
         else: #direction == gdk.SCROLL_UP
-            for chunk in self.linediffer.single_changes(1, self._get_texts()):
+            for chunk in self.linediffer.single_changes(1):
                 chunk, skip = self._consume_blank_lines(chunk, 1, chunk[5])
                 if skip:
                     continue
@@ -1161,7 +1161,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
             context.paint()
             context.identity_matrix()
 
-        for c in self.linediffer.pair_changes(which, which+1, self._get_texts()):
+        for c in self.linediffer.pair_changes(which, which + 1):
             c, skip = self._consume_blank_lines(c, which, which + 1)
             if skip:
                 continue
@@ -1243,7 +1243,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
             dst = which + 1 - side
             adj = self.scrolledwindow[src].get_vadjustment()
 
-            for c in self.linediffer.pair_changes(src, dst, self._get_texts()):
+            for c in self.linediffer.pair_changes(src, dst):
                 c, skip = self._consume_blank_lines(c, src, dst)
                 if skip:
                     continue



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]