Rev 4731: messy but working. in http://bazaar.launchpad.net/~jameinel/bzr/2.1-static-tuple

John Arbash Meinel john at arbash-meinel.com
Thu Oct 1 21:58:02 BST 2009


At http://bazaar.launchpad.net/~jameinel/bzr/2.1-static-tuple

------------------------------------------------------------
revno: 4731
revision-id: john at arbash-meinel.com-20091001205755-6gvs1f6njipjbxo6
parent: john at arbash-meinel.com-20091001190635-m0531rj2mebmhjq0
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 2.1-static-tuple
timestamp: Thu 2009-10-01 15:57:55 -0500
message:
  messy but working.
  
  Start exposing the C API using a nice python dict, rather than offsets into an array.
  This is much more convenient and allows a small amount of api skew without
  serious problems. It also allows some safety checks to be performed during
  import.
  
  
  Mostly we just need to clean up the code a bit.
-------------- next part --------------
=== modified file 'bzrlib/_btree_serializer_pyx.pyx'
--- a/bzrlib/_btree_serializer_pyx.pyx	2009-10-01 19:06:35 +0000
+++ b/bzrlib/_btree_serializer_pyx.pyx	2009-10-01 20:57:55 +0000
@@ -59,8 +59,8 @@
 
 # It seems we need to import the definitions so that the pyrex compiler has
 # local names to access them.
-from _static_tuple_c cimport StaticTuple, StaticTuple_API,\
-    import_static_tuple, STATIC_TUPLE_ALL_STRING, StaticTuple_New, \
+from _static_tuple_c cimport StaticTuple, \
+    import_static_tuple_c, STATIC_TUPLE_ALL_STRING, StaticTuple_New, \
     StaticTuple_intern, StaticTuple_SET_ITEM, StaticTuple_CheckExact
 
 
@@ -106,10 +106,7 @@
 cdef object _ST
 _ST = _static_tuple_c.StaticTuple
 # This sets up the StaticTuple C_API functionality
-if import_static_tuple() == -1:
-    raise ImportError('failed to import_static_tuple()')
-if StaticTuple_API == NULL:
-    raise ImportError('StaticTuple_API failed to be initialized.')
+import_static_tuple_c()
 
 
 cdef class BTreeLeafParser:
@@ -151,8 +148,6 @@
         self._end_str = NULL
         self._header_found = 0
         # keys are tuples
-        if StaticTuple_API == NULL:
-            raise ImportError('failed to import_static_tuple()')
 
     cdef extract_key(self, char * last):
         """Extract a key.

=== modified file 'bzrlib/_chk_map_pyx.pyx'
--- a/bzrlib/_chk_map_pyx.pyx	2009-10-01 19:06:35 +0000
+++ b/bzrlib/_chk_map_pyx.pyx	2009-10-01 20:57:55 +0000
@@ -61,15 +61,15 @@
 
 # It seems we need to import the definitions so that the pyrex compiler has
 # local names to access them.
-from _static_tuple_c cimport StaticTuple, StaticTuple_API,\
-    import_static_tuple, STATIC_TUPLE_ALL_STRING, StaticTuple_New, \
+from _static_tuple_c cimport StaticTuple,\
+    import_static_tuple_c, STATIC_TUPLE_ALL_STRING, StaticTuple_New, \
     StaticTuple_intern, StaticTuple_SET_ITEM, StaticTuple_CheckExact
 
 
 from bzrlib import _static_tuple_c
 # This sets up the StaticTuple C_API functionality
-if import_static_tuple() == -1 or StaticTuple_API == NULL:
-    raise ImportError('failed to import_static_tuple()')
+if import_static_tuple_c() != 0:
+    raise ImportError('der borken')
 
 cdef object _LeafNode
 _LeafNode = None

=== modified file 'bzrlib/_static_tuple_c.c'
--- a/bzrlib/_static_tuple_c.c	2009-10-01 19:06:35 +0000
+++ b/bzrlib/_static_tuple_c.c	2009-10-01 20:57:55 +0000
@@ -73,6 +73,8 @@
 StaticTuple_intern(StaticTuple *self)
 {
     PyObject *unique_key = NULL;
+    fprintf(stderr, "In StaticTuple_intern @%x @%x\n", StaticTuple_intern,
+    &StaticTuple_intern);
 
     if (_interned_tuples == NULL) {
         Py_INCREF(self);
@@ -138,6 +140,7 @@
 StaticTuple_New(Py_ssize_t size)
 {
     StaticTuple *stuple;
+    fprintf(stderr, "in StaticTuple_New @%x  ", &StaticTuple_New);
     if (size < 0) {
         PyErr_BadInternalCall();
         return NULL;
@@ -147,6 +150,7 @@
         Py_INCREF(_empty_tuple);
         return _empty_tuple;
     }
+    fprintf(stderr, "Creating new StaticTuple with size %d\n", size);
     /* Note that we use PyObject_NewVar because we want to allocate a variable
      * width entry. However we *aren't* truly a PyVarObject because we don't
      * use a long for ob_size. Instead we use a plain 'size' that is an int,
@@ -716,20 +720,47 @@
     return StaticTuple_CheckExact(obj);
 }
 
+static int _export_function(PyObject *module, char *funcname,
+                            void *func, char *signature)
+{
+    PyObject *d = NULL;
+    PyObject *c_obj = NULL;
+
+    d = PyObject_GetAttrString(module, _C_API_NAME);
+    if (!d) {
+        PyErr_Clear();
+        d = PyDict_New();
+        if (!d)
+            goto bad;
+        Py_INCREF(d);
+        if (PyModule_AddObject(module, _C_API_NAME, d) < 0)
+            goto bad;
+    }
+    c_obj = PyCObject_FromVoidPtrAndDesc(func, signature, 0);
+    if (!c_obj)
+        goto bad;
+    if (PyDict_SetItemString(d, funcname, c_obj) < 0)
+        goto bad;
+    fprintf(stderr, "Exported %s@%x\n", funcname, func);
+    Py_DECREF(d);
+    return 0;
+bad:
+    fprintf(stderr, "Failed to export %s@%x\n", funcname, func);
+    Py_XDECREF(c_obj);
+    Py_XDECREF(d);
+    return -1;
+}
+
 static void
 setup_c_api(PyObject *m)
 {
-    static void *StaticTuple_API[StaticTuple_API_pointers];
-    PyObject *c_api_object;
-
-    StaticTuple_API[StaticTuple_New_NUM] = (void *)StaticTuple_New;
-    StaticTuple_API[StaticTuple_intern_NUM] = (void *)StaticTuple_intern;
-    StaticTuple_API[StaticTuple_CheckExact_NUM] = 
-        (void*)_StaticTuple_CheckExact; 
-    c_api_object = PyCObject_FromVoidPtr((void *)StaticTuple_API, NULL);
-    if (c_api_object != NULL) {
-        PyModule_AddObject(m, "_C_API", c_api_object);
-    }
+    fprintf(stderr, "exporting %s\n", _C_API_NAME);
+    _export_function(m, "StaticTuple_New", StaticTuple_New,
+        "StaticTuple *(Py_ssize_t)");
+    _export_function(m, "StaticTuple_intern", StaticTuple_intern,
+        "StaticTuple *(StaticTuple *)");
+    _export_function(m, "_StaticTuple_CheckExact", _StaticTuple_CheckExact,
+        "int(PyObject *)");
 }
 
 

=== modified file 'bzrlib/_static_tuple_c.h'
--- a/bzrlib/_static_tuple_c.h	2009-10-01 19:06:35 +0000
+++ b/bzrlib/_static_tuple_c.h	2009-10-01 20:57:55 +0000
@@ -18,6 +18,7 @@
 #ifndef _STATIC_TUPLE_H_
 #define _STATIC_TUPLE_H_
 #include <Python.h>
+#include <string.h>
 
 #define STATIC_TUPLE_HAS_HASH 0
 /* Caching the hash adds memory, but allows us to save a little time during
@@ -64,7 +65,6 @@
     PyObject_VAR_HEAD
     PyObject *table[0];
 } KeyIntern;
-// extern PyTypeObject StaticTuple_Type;
 
 #define StaticTuple_CheckExact(op) (Py_TYPE(op) == &StaticTuple_Type)
 #define StaticTuple_SET_ITEM(key, offset, val) \
@@ -72,13 +72,7 @@
 #define StaticTuple_GET_ITEM(key, offset) (((StaticTuple*)key)->items[offset])
 
 
-/* C API Functions */
-#define StaticTuple_New_NUM 0
-#define StaticTuple_intern_NUM 1
-#define StaticTuple_CheckExact_NUM 2
-
-/* Total number of C API Pointers */
-#define StaticTuple_API_pointers 3
+static const char *_C_API_NAME = "_C_API";
 
 #ifdef STATIC_TUPLE_MODULE
 /* Used when compiling _static_tuple_c.c */
@@ -87,43 +81,112 @@
 static StaticTuple * StaticTuple_intern(StaticTuple *self);
 
 #else
-/* Used by foriegn callers */
-static void **StaticTuple_API;
+/* Used as the foreign api */
 
 static StaticTuple *(*StaticTuple_New)(Py_ssize_t);
 static StaticTuple *(*StaticTuple_intern)(StaticTuple *);
-#undef StaticTuple_CheckExact
-static int (*StaticTuple_CheckExact)(PyObject *);
+static PyTypeObject *_p_StaticTuple_Type;
+
+#define StaticTuple_CheckExact(op) (Py_TYPE(op) == _p_StaticTuple_Type)
+static int (*_StaticTuple_CheckExact)(PyObject *);
+
+
+static int _import_function(PyObject *module, char *funcname,
+                            void **f, char *signature)
+{
+    PyObject *d = NULL;
+    PyObject *c_obj = NULL;
+    char *desc = NULL;
+
+    d = PyObject_GetAttrString(module, _C_API_NAME);
+    if (!d) {
+        // PyObject_GetAttrString sets an appropriate exception
+        goto bad;
+    }
+    c_obj = PyDict_GetItemString(d, funcname);
+    if (!c_obj) {
+        // PyDict_GetItemString does not set an exception
+        PyErr_Format(PyExc_AttributeError,
+            "Module %s did not export a function named %s\n",
+            PyModule_GetName(module), funcname);
+        goto bad;
+    }
+    desc = (char *)PyCObject_GetDesc(c_obj);
+    if (!desc || strcmp(desc, signature) != 0) {
+        if (desc == NULL) {
+            desc = "<null>";
+        }
+        PyErr_Format(PyExc_TypeError,
+            "C function %s.%s has wrong signature (expected %s, got %s)",
+                PyModule_GetName(module), funcname, signature, desc);
+        goto bad;
+    }
+    *f = PyCObject_AsVoidPtr(c_obj);
+    fprintf(stderr, "Imported function %s @%x\n", funcname, *f);
+    Py_DECREF(d);
+    return 0;
+bad:
+    fprintf(stderr, "Returning -1\n");
+    Py_XDECREF(d);
+    return -1;
+}
+
+
+static PyTypeObject *
+_import_type(PyObject *module, char *class_name)
+{
+    PyObject *type = NULL;
+
+    type = PyObject_GetAttrString(module, class_name);
+    if (!type) {
+        goto bad;
+    }
+    if (!PyType_Check(type)) {
+        PyErr_Format(PyExc_TypeError,
+            "%s.%s is not a type object",
+            PyModule_GetName(module), class_name);
+        goto bad;
+    }
+    return (PyTypeObject *)type;
+bad:
+    Py_XDECREF(type);
+    return NULL;
+}
 
 
 /* Return -1 and set exception on error, 0 on success */
 static int
-import_static_tuple(void)
+import_static_tuple_c(void)
 {
-    PyObject *module = PyImport_ImportModule("bzrlib._static_tuple_c");
-    PyObject *c_api_object;
-
-    if (module == NULL) {
-        fprintf(stderr, "Failed to find module _static_tuple_c.\n");
-        return -1;
-    }
-    c_api_object = PyObject_GetAttrString(module, "_C_API");
-    if (c_api_object == NULL) {
-        fprintf(stderr, "Failed to find _static_tuple_c._C_API.\n");
-        return -1;
-    }
-    if (!PyCObject_Check(c_api_object)) {
-        fprintf(stderr, "_static_tuple_c._C_API not a CObject.\n");
-        Py_DECREF(c_api_object);
-        return -1;
-    }
-    StaticTuple_API = (void **)PyCObject_AsVoidPtr(c_api_object);
-    StaticTuple_New = StaticTuple_API[StaticTuple_New_NUM];
-    StaticTuple_intern = StaticTuple_API[StaticTuple_intern_NUM];
-    StaticTuple_CheckExact = StaticTuple_API[StaticTuple_CheckExact_NUM];
-    Py_DECREF(c_api_object);
+    /* This is modeled after the implementation in Pyrex, which uses a
+     * dictionary and descriptors, rather than using plain offsets into a
+     * void ** array.
+     */
+    PyObject *module = NULL;
+    
+    module = PyImport_ImportModule("bzrlib._static_tuple_c");
+    if (!module) goto bad;
+    if (_import_function(module, "StaticTuple_New", (void **)&StaticTuple_New,
+                         "StaticTuple *(Py_ssize_t)") < 0)
+        goto bad;
+    if (_import_function(module, "StaticTuple_intern",
+                         (void **)&StaticTuple_intern,
+                         "StaticTuple *(StaticTuple *)") < 0)
+        goto bad;
+    if (_import_function(module, "_StaticTuple_CheckExact",
+                         (void **)&_StaticTuple_CheckExact,
+                         "int(PyObject *)") < 0)
+        goto bad;
+    _p_StaticTuple_Type = _import_type(module, "StaticTuple");
+    if (!_p_StaticTuple_Type) {
+        goto bad;
+    }
+    Py_DECREF(module); 
     return 0;
+bad:
+    Py_XDECREF(module);
+    return -1;
 }
 
-#endif
-#endif // _STATIC_TUPLE_H_
+#endif // !STATIC_TUPLE_MODULE
+#endif // !_STATIC_TUPLE_H_

=== modified file 'bzrlib/_static_tuple_c.pxd'
--- a/bzrlib/_static_tuple_c.pxd	2009-10-01 19:06:35 +0000
+++ b/bzrlib/_static_tuple_c.pxd	2009-10-01 20:57:55 +0000
@@ -32,8 +32,7 @@
         # cdef unsigned char _unused1
         cdef PyObject *items[0]
 
-    void **StaticTuple_API
-    int import_static_tuple()
+    int import_static_tuple_c() except -1
     # ctypedef object (*st_new_type)(Py_ssize_t)
     # st_new_type st_new
     int STATIC_TUPLE_ALL_STRING



More information about the bazaar-commits mailing list