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