mercurial/cffi/bdiff.py
author spectral <spectral@google.com>
Mon, 06 Aug 2018 12:52:33 -0700
changeset 38993 081cc9a95b65
parent 33572 857876ebaed4
child 43076 2372284d9457
permissions -rw-r--r--
match: add visitchildrenset complement to visitdir `visitdir(d)` lets a caller query whether the directory is part of the matcher. It can receive a response of 'all' (yes, and all children, you can stop calling visitdir now), False (no, and no children either), or True (yes, either something in this directory or a child is part of the matcher). `visitchildrenset(d)` augments that by instead of returning True, it returns a list of items to actually investigate. With this, code can be modified from: for f in self.all_items: if match.visitdir(self.dir + '/' + f): <do stuff> to be: for f in self.all_items.intersect(match.visitchildrenset(self.dir)): <do stuff> use of this function can provide significant performance improvements, especially when using narrow (so that the matcher is much smaller than the stuff we see on disk) and/or treemanifests (so that we can avoid loading manifests for trees that aren't part of the matcher). Differential Revision: https://phab.mercurial-scm.org/D4130

# 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 struct

from ..pure.bdiff import *
from . import _bdiff

ffi = _bdiff.ffi
lib = _bdiff.lib

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

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

    finally:
        lib.free(a[0])
        lib.free(b[0])
        lib.bdiff_freehunks(l.next)
    return "".join(rl)