Rev 4733: Factor out some of the C API code into some helper headers. in http://bazaar.launchpad.net/~jameinel/bzr/2.1-static-tuple
John Arbash Meinel
john at arbash-meinel.com
Thu Oct 1 22:34:43 BST 2009
At http://bazaar.launchpad.net/~jameinel/bzr/2.1-static-tuple
------------------------------------------------------------
revno: 4733
revision-id: john at arbash-meinel.com-20091001213436-d7vbe0xr17eave03
parent: john at arbash-meinel.com-20091001210016-qpui2k190ngeslyh
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 2.1-static-tuple
timestamp: Thu 2009-10-01 16:34:36 -0500
message:
Factor out some of the C API code into some helper headers.
This should make the process a bit easier, if we ever decide to do
something similar again.
-------------- next part --------------
=== added file 'bzrlib/_export_c_api.h'
--- a/bzrlib/_export_c_api.h 1970-01-01 00:00:00 +0000
+++ b/bzrlib/_export_c_api.h 2009-10-01 21:34:36 +0000
@@ -0,0 +1,71 @@
+/* Copyright (C) 2009 Canonical Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+/* This file contains helper functions for exporting a C API for a CPython
+ * extension module.
+ */
+
+#ifndef _EXPORT_C_API_H_
+#define _EXPORT_C_API_H_
+
+static const char *_C_API_NAME = "_C_API";
+
+/**
+ * Add a C function to the modules _C_API
+ * This wraps the function in a PyCObject, and inserts that into a dict.
+ * The key of the dict is the function name, and the description is the
+ * signature of the function.
+ * This is generally called during a modules init_MODULE function.
+ *
+ * @param module A Python module (the one being initialized)
+ * @param funcname The name of the function being exported
+ * @param func A pointer to the function
+ * @param signature The C signature of the function
+ * @return 0 if everything is successful, -1 if there is a problem. An
+ * exception should also be set
+ */
+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;
+ Py_DECREF(d);
+ return 0;
+bad:
+ Py_XDECREF(c_obj);
+ Py_XDECREF(d);
+ return -1;
+}
+
+#endif // _EXPORT_C_API_H_
=== added file 'bzrlib/_import_c_api.h'
--- a/bzrlib/_import_c_api.h 1970-01-01 00:00:00 +0000
+++ b/bzrlib/_import_c_api.h 2009-10-01 21:34:36 +0000
@@ -0,0 +1,186 @@
+/* Copyright (C) 2009 Canonical Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _IMPORT_C_API_H_
+#define _IMPORT_C_API_H_
+
+/**
+ * Helper functions to eliminate some of the boilerplate when importing a C API
+ * from a CPython extension module.
+ *
+ * For more information see _export_c_api.h
+ */
+
+static const char *_C_API_NAME = "_C_API";
+
+/**
+ * Import a function from the _C_API_NAME dict that is part of module.
+ *
+ * @param module The Python module we are importing from
+ * the attribute _C_API_NAME will be used as a dictionary
+ * containing the function pointer we are looking for.
+ * @param funcname Name of the function we want to import
+ * @param func A pointer to the function handle where we will store the
+ * function.
+ * @param signature The C signature of the function. This is validated
+ * against the signature stored in the C api, to make sure
+ * there is no versioning skew.
+ */
+static int _import_function(PyObject *module, const char *funcname,
+ void **func, const char *signature)
+{
+ PyObject *d = NULL;
+ PyObject *c_obj = NULL;
+ const 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;
+ }
+ *func = PyCObject_AsVoidPtr(c_obj);
+ Py_DECREF(d);
+ return 0;
+bad:
+ Py_XDECREF(d);
+ return -1;
+}
+
+
+/**
+ * Get a pointer to an exported PyTypeObject.
+ *
+ * @param module The Python module we are importing from
+ * @param class_name Attribute of the module that should reference the
+ * Type object. Note that a PyTypeObject is the python
+ * description of the type, not the raw C structure.
+ * @return A Pointer to the requested type object. On error NULL will be
+ * returned and an exception will be set.
+ */
+static PyTypeObject *
+_import_type(PyObject *module, const 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;
+}
+
+
+struct function_description
+{
+ const char *name;
+ void **pointer;
+ const char *signature;
+};
+
+struct type_description
+{
+ const char *name;
+ PyTypeObject **pointer;
+};
+
+/**
+ * Helper for importing several functions and types in a data-driven manner.
+ *
+ * @param module The name of the module we will be importing
+ * @param functions A list of function_description objects, describing the
+ * functions being imported.
+ * The list should be terminated with {NULL} to indicate
+ * there are no more functions to import.
+ * @param types A list of type_description objects describing type
+ * objects that we want to import. The list should be
+ * terminated with {NULL} to indicate there are no more
+ * types to import.
+ * @return 0 on success, -1 on error and an exception should be set.
+ */
+
+static int
+_import_extension_module(const char *module_name,
+ struct function_description *functions,
+ struct type_description *types)
+{
+ PyObject *module = NULL;
+ struct function_description *cur_func;
+ struct type_description *cur_type;
+ int ret_code;
+
+ module = PyImport_ImportModule(module_name);
+ if (!module)
+ goto bad;
+ if (functions != NULL) {
+ cur_func = functions;
+ while (cur_func->name != NULL) {
+ ret_code = _import_function(module, cur_func->name,
+ cur_func->pointer,
+ cur_func->signature);
+ if (ret_code < 0)
+ goto bad;
+ cur_func++;
+ }
+ }
+ if (types != NULL) {
+ PyTypeObject *type_p = NULL;
+ cur_type = types;
+ while (cur_type->name != NULL) {
+ type_p = _import_type(module, cur_type->name);
+ if (type_p == NULL)
+ goto bad;
+ *(cur_type->pointer) = type_p;
+ cur_type++;
+ }
+ }
+
+ Py_XDECREF(module);
+ return 0;
+bad:
+ Py_XDECREF(module);
+ return -1;
+}
+
+
+#endif // _IMPORT_C_API_H_
=== modified file 'bzrlib/_static_tuple_c.c'
--- a/bzrlib/_static_tuple_c.c 2009-10-01 21:00:16 +0000
+++ b/bzrlib/_static_tuple_c.c 2009-10-01 21:34:36 +0000
@@ -21,6 +21,7 @@
#define STATIC_TUPLE_MODULE
#include "_static_tuple_c.h"
+#include "_export_c_api.h"
#include "python-compat.h"
@@ -716,35 +717,6 @@
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;
- Py_DECREF(d);
- return 0;
-bad:
- Py_XDECREF(c_obj);
- Py_XDECREF(d);
- return -1;
-}
-
static void
setup_c_api(PyObject *m)
{
=== modified file 'bzrlib/_static_tuple_c.h'
--- a/bzrlib/_static_tuple_c.h 2009-10-01 21:00:16 +0000
+++ b/bzrlib/_static_tuple_c.h 2009-10-01 21:34:36 +0000
@@ -66,23 +66,23 @@
PyObject *table[0];
} KeyIntern;
-#define StaticTuple_CheckExact(op) (Py_TYPE(op) == &StaticTuple_Type)
#define StaticTuple_SET_ITEM(key, offset, val) \
((((StaticTuple*)(key))->items[(offset)]) = ((PyObject *)(val)))
#define StaticTuple_GET_ITEM(key, offset) (((StaticTuple*)key)->items[offset])
-static const char *_C_API_NAME = "_C_API";
-
#ifdef STATIC_TUPLE_MODULE
/* Used when compiling _static_tuple_c.c */
static StaticTuple * StaticTuple_New(Py_ssize_t);
static StaticTuple * StaticTuple_intern(StaticTuple *self);
+#define StaticTuple_CheckExact(op) (Py_TYPE(op) == &StaticTuple_Type)
#else
/* Used as the foreign api */
+#include "_import_c_api.h"
+
static StaticTuple *(*StaticTuple_New)(Py_ssize_t);
static StaticTuple *(*StaticTuple_intern)(StaticTuple *);
static PyTypeObject *_p_StaticTuple_Type;
@@ -91,99 +91,23 @@
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);
- Py_DECREF(d);
- return 0;
-bad:
- 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_c(void)
{
- /* 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;
+ struct function_description functions[] = {
+ {"StaticTuple_New", (void **)&StaticTuple_New,
+ "StaticTuple *(Py_ssize_t)"},
+ {"StaticTuple_intern", (void **)&StaticTuple_intern,
+ "StaticTuple *(StaticTuple *)"},
+ {"_StaticTuple_CheckExact", (void **)&_StaticTuple_CheckExact,
+ "int(PyObject *)"},
+ {NULL}};
+ struct type_description types[] = {
+ {"StaticTuple", &_p_StaticTuple_Type},
+ {NULL}};
+ return _import_extension_module("bzrlib._static_tuple_c",
+ functions, types);
}
#endif // !STATIC_TUPLE_MODULE
More information about the bazaar-commits
mailing list