mercurial/cffi/bdiff.py
branchstable
changeset 33572 857876ebaed4
parent 30346 9cc438bf7d9a
parent 32513 25b37900d6e0
child 43076 2372284d9457
--- a/mercurial/cffi/bdiff.py	Wed Jul 05 11:24:22 2017 -0400
+++ b/mercurial/cffi/bdiff.py	Wed Jul 19 07:51:41 2017 -0500
@@ -1,31 +1,76 @@
+# bdiff.py - CFFI implementation of bdiff.c
+#
+# Copyright 2016 Maciej Fijalkowski <fijall@gmail.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
 from __future__ import absolute_import
 
-import cffi
-import os
+import struct
 
-ffi = cffi.FFI()
-ffi.set_source("_bdiff_cffi",
-    open(os.path.join(os.path.join(os.path.dirname(__file__), '..'),
-        'bdiff.c')).read(), include_dirs=['mercurial'])
-ffi.cdef("""
-struct bdiff_line {
-    int hash, n, e;
-    ssize_t len;
-    const char *l;
-};
+from ..pure.bdiff import *
+from . import _bdiff
+
+ffi = _bdiff.ffi
+lib = _bdiff.lib
 
-struct bdiff_hunk;
-struct bdiff_hunk {
-    int a1, a2, b1, b2;
-    struct bdiff_hunk *next;
-};
+def blocks(sa, sb):
+    a = ffi.new("struct bdiff_line**")
+    b = ffi.new("struct bdiff_line**")
+    ac = ffi.new("char[]", str(sa))
+    bc = ffi.new("char[]", str(sb))
+    l = ffi.new("struct bdiff_hunk*")
+    try:
+        an = lib.bdiff_splitlines(ac, len(sa), a)
+        bn = lib.bdiff_splitlines(bc, len(sb), b)
+        if not a[0] or not b[0]:
+            raise MemoryError
+        count = lib.bdiff_diff(a[0], an, b[0], bn, l)
+        if count < 0:
+            raise MemoryError
+        rl = [None] * count
+        h = l.next
+        i = 0
+        while h:
+            rl[i] = (h.a1, h.a2, h.b1, h.b2)
+            h = h.next
+            i += 1
+    finally:
+        lib.free(a[0])
+        lib.free(b[0])
+        lib.bdiff_freehunks(l.next)
+    return rl
 
-int bdiff_splitlines(const char *a, ssize_t len, struct bdiff_line **lr);
-int bdiff_diff(struct bdiff_line *a, int an, struct bdiff_line *b, int bn,
-    struct bdiff_hunk *base);
-void bdiff_freehunks(struct bdiff_hunk *l);
-void free(void*);
-""")
+def bdiff(sa, sb):
+    a = ffi.new("struct bdiff_line**")
+    b = ffi.new("struct bdiff_line**")
+    ac = ffi.new("char[]", str(sa))
+    bc = ffi.new("char[]", str(sb))
+    l = ffi.new("struct bdiff_hunk*")
+    try:
+        an = lib.bdiff_splitlines(ac, len(sa), a)
+        bn = lib.bdiff_splitlines(bc, len(sb), b)
+        if not a[0] or not b[0]:
+            raise MemoryError
+        count = lib.bdiff_diff(a[0], an, b[0], bn, l)
+        if count < 0:
+            raise MemoryError
+        rl = []
+        h = l.next
+        la = lb = 0
+        while h:
+            if h.a1 != la or h.b1 != lb:
+                lgt = (b[0] + h.b1).l - (b[0] + lb).l
+                rl.append(struct.pack(">lll", (a[0] + la).l - a[0].l,
+                                      (a[0] + h.a1).l - a[0].l, lgt))
+                rl.append(str(ffi.buffer((b[0] + lb).l, lgt)))
+            la = h.a2
+            lb = h.b2
+            h = h.next
 
-if __name__ == '__main__':
-    ffi.compile()
+    finally:
+        lib.free(a[0])
+        lib.free(b[0])
+        lib.bdiff_freehunks(l.next)
+    return "".join(rl)