Bläddra i källkod

Add C version of bisect_find_sha.

Jelmer Vernooij 16 år sedan
förälder
incheckning
6bad333ad2
2 ändrade filer med 78 tillägg och 12 borttagningar
  1. 57 0
      dulwich/_pack.c
  2. 21 12
      dulwich/pack.py

+ 57 - 0
dulwich/_pack.c

@@ -20,6 +20,17 @@
 #include <Python.h>
 #include <stdint.h>
 
+static int py_is_sha(PyObject *sha)
+{
+    if (!PyString_Check(sha))
+        return 0;
+
+    if (PyString_Size(sha) != 20)
+        return 0;
+
+    return 1;
+}
+
 
 static size_t get_delta_header_size(uint8_t *delta, int *index, int length)
 {
@@ -116,8 +127,54 @@ static PyObject *py_apply_delta(PyObject *self, PyObject *args)
     return ret;
 }
 
+static PyObject *py_bisect_find_sha(PyObject *self, PyObject *args)
+{
+    PyObject *unpack_name;
+    char *sha;
+    int sha_len;
+	int start, end;
+    int idx;
+    if (!PyArg_ParseTuple(args, "iis#O", &start, &end, 
+						  &sha, &sha_len, &unpack_name))
+        return NULL;
+
+    if (sha_len != 20) {
+        PyErr_SetString(PyExc_ValueError, "Sha is not 20 bytes long");
+        return NULL;
+    }
+    if (start > end) {
+        PyErr_SetString(PyExc_AssertionError, "start > end");
+        return NULL;
+    }
+
+    while (start <= end) {
+        PyObject *file_sha;
+        int i = (start + end)/2;
+        int cmp;
+        file_sha = PyObject_CallFunction(unpack_name, "i", i);
+        if (file_sha == NULL) {
+            return NULL;
+        }
+        if (!py_is_sha(file_sha)) {
+            PyErr_SetString(PyExc_TypeError, "unpack_name returned non-sha object");
+            return NULL;
+        }
+        cmp = memcmp(PyString_AsString(file_sha), sha, 20);
+        if (cmp < 0)
+            start = i + 1;
+        else if (cmp > 0)
+            end = i - 1;
+        else {
+			return PyInt_FromLong(i);
+        }
+    }
+    Py_RETURN_NONE;
+}
+
+
 static PyMethodDef py_pack_methods[] = {
 	{ "apply_delta", (PyCFunction)py_apply_delta, METH_VARARGS, NULL },
+    { "bisect_find_sha", (PyCFunction)py_bisect_find_sha, METH_VARARGS, NULL },
 };
 
 void init_pack(void)

+ 21 - 12
dulwich/pack.py

@@ -128,6 +128,21 @@ def load_pack_index(filename):
         return PackIndex1(filename, file=f)
 
 
+def bisect_find_sha(start, end, sha, unpack_name):
+    assert start <= end
+    while start <= end:
+        i = (start + end)/2
+        file_sha = unpack_name(i)
+        x = cmp(file_sha, sha)
+        if x < 0:
+            start = i + 1
+        elif x > 0:
+            end = i - 1
+        else:
+            return i
+    return None
+
+
 class PackIndex(object):
     """An index in to a packfile.
   
@@ -263,17 +278,11 @@ class PackIndex(object):
         else:
             start = self._fan_out_table[idx-1]
         end = self._fan_out_table[idx]
-        assert start <= end
-        while start <= end:
-            i = (start + end)/2
-            file_sha = self._unpack_name(i)
-            if file_sha < sha:
-                start = i + 1
-            elif file_sha > sha:
-                end = i - 1
-            else:
-                return self._unpack_offset(i)
-        return None
+        i = bisect_find_sha(start, end, sha, self._unpack_name)
+        if i is None:
+            return None
+        return self._unpack_offset(i)
+            
 
 
 class PackIndex1(PackIndex):
@@ -963,6 +972,6 @@ def load_packs(path):
 
 
 try:
-    from dulwich._pack import apply_delta
+    from dulwich._pack import apply_delta, bisect_find_sha
 except ImportError:
     pass