Skip to content

Instantly share code, notes, and snippets.

@amintos
Created September 14, 2012 11:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amintos/3721336 to your computer and use it in GitHub Desktop.
Save amintos/3721336 to your computer and use it in GitHub Desktop.
Example interfacing plain arrays via NumPy
#include "Python.h"
#include "numpy/arrayobject.h"
// ----------------------------------------------------------------------------
// BASIC API
typedef struct {
int data[1024];
} internalColumn;
void setEntry(internalColumn *col, int index, int value)
{
//printf("%i, %i\n", index, value);
(col->data)[index] = value;
}
int getEntry(internalColumn *col, int index)
{
//printf("%i\n", index);
return (col->data)[index];
}
// ----------------------------------------------------------------------------
// WRAPPER TYPE
typedef struct {
PyObject_HEAD
internalColumn data;
} foo_ColumnObject;
// ----------------------------------------------------------------------------
// MAPPING INTERFACE
PyObject * PyColumn_GetItem(foo_ColumnObject *self, PyObject *key);
int PyColumn_SetItem(foo_ColumnObject *self, PyObject *key, PyObject *value);
Py_ssize_t PyColumn_Length(foo_ColumnObject* self);
// ----------------------------------------------------------------------------
// ITERATOR INTERFACE
PyObject * PyColumn_iter(PyObject *self, PyObject *args);
PyObject * ColumnIterator_iter(PyObject *self);
PyObject * ColumnIterator_next(PyObject *self);
// ----------------------------------------------------------------------------
// ITERATOR TYPE
typedef struct {
PyObject_HEAD
foo_ColumnObject *column;
Py_ssize_t iter_count;
Py_ssize_t iter_index;
} foo_ColumnIterator;
// ----------------------------------------------------------------------------
// ITERATOR IMPLEMENTATION
// __iter__ of an iterator should return a new reference on self
PyObject* ColumnIterator_iter(PyObject *self)
{
Py_INCREF(self);
return self;
}
PyObject* ColumnIterator_next(PyObject *self)
{
foo_ColumnIterator *t_self = (foo_ColumnIterator *)self;
if (t_self->iter_index < t_self->iter_count)
{
return PyInt_FromSsize_t(t_self->column->data.data[t_self->iter_index++]);
}
else
{
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
}
static PyTypeObject foo_ColumnIteratorType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"foo.ColumnIterator", /*tp_name*/
sizeof(foo_ColumnIterator), /*tp_basicsize*/
0, /*tp_itemsize*/
0, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER,
/* tp_flags: Py_TPFLAGS_HAVE_ITER tells python to
use tp_iter and tp_iternext fields. */
"Column Iterator", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
ColumnIterator_iter, /* tp_iter: __iter__() method */
ColumnIterator_next /* tp_iternext: next() method */
};
PyObject * PyColumn_iter(PyObject *self, PyObject *args)
{
foo_ColumnIterator* iter = PyObject_New(
foo_ColumnIterator,
&foo_ColumnIteratorType);
iter->iter_count = 1024;
iter->iter_index = 0;
iter->column = (foo_ColumnObject*)(self);
return iter;
}
// ----------------------------------------------------------------------------
// ADAPTER TYPE
// --- Mapping Interface --- //
static PyMappingMethods foo_ColumnType_mapping = {
(lenfunc)PyColumn_Length, // lenfunc PyMappingMethods.mp_length
(binaryfunc)PyColumn_GetItem, // binaryfunc PyMappingMethods.mp_subscript
(objobjargproc)PyColumn_SetItem, // objobjargproc PyMappingMethods.mp_ass_subscript
};
// -!- Mapping Interface -!- //
// --- Array Interface --- //
PyObject * PyColumn_Array(foo_ColumnObject *self, PyObject *args);
// -!- Array Interface -!- //
// --- VMT --- //
static struct PyMethodDef foo_ColumnType_methods[] = {
{"array", &PyColumn_Array, METH_VARARGS, "As Numpy-Array"},
{NULL, NULL, NULL, NULL}
};
// -!- VMT -!- //
static PyTypeObject foo_ColumnType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"foomodule.Column", /*tp_name*/
sizeof(foo_ColumnObject), /*tp_basicsize*/
0, /*tp_itemsize*/
0, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
&foo_ColumnType_mapping, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"Sample Columns", /* tp_doc */
0, //traversrceproc tp_traverse;
/* delete references to contained objects */
0, //inquiry tp_clear;
/* Assigned meaning in release 2.1 */
/* rich comparisons */
0, //richcmpfunc tp_richcompare;
/* weak reference enabler */
0, //long tp_weaklistoffset;
/* Added in release 2.2 */
/* Iterators */
&PyColumn_iter, //getiterfunc tp_iter;
0, //iternextfunc tp_iternext;
/* Attribute descriptor and subclassing stuff */
foo_ColumnType_methods, //struct PyMethodDef *tp_methods;
0, //struct PyMemberDef *tp_members;
0, //struct PyGetSetDef *tp_getset;
0, //struct _typeobject *tp_base;
0, //PyObject *tp_dict;
0, //descrgetfunc tp_descr_get;
0, //descrsetfunc tp_descr_set;
0, //long tp_dictoffset;
0, //initproc tp_init;
0, //allocfunc tp_alloc;
0, //newfunc tp_new;
0, //freefunc tp_free; /* Low-level free-memory routine */
0, //inquiry tp_is_gc; /* For PyObject_IS_GC */
0, //PyObject *tp_bases;
0, //PyObject *tp_mro; /* method resolution order */
0, //PyObject *tp_cache;
0, //PyObject *tp_subclasses;
0, //PyObject *tp_weaklist;
};
// ----------------------------------------------------------------------------
// IMPLEMENTATION
PyObject * PyColumn_GetItem(foo_ColumnObject *self, PyObject *key)
{
int intkey = (int)(((PyIntObject*)key)->ob_ival);
PyObject *result = PyInt_FromLong((long)getEntry(&(self->data), intkey));
Py_INCREF(result);
return result;
}
int PyColumn_SetItem(foo_ColumnObject *self, PyObject *key, PyObject *value)
{
int intkey = (int)(((PyIntObject*)key)->ob_ival);
int intvalue = (int)(((PyIntObject*)value)->ob_ival);
setEntry(&(self->data), intkey, intvalue);
return 0;
}
Py_ssize_t PyColumn_Length(foo_ColumnObject* self) {
return 1024;
}
PyObject * PyColumn_Array(foo_ColumnObject *self, PyObject *args) {
npy_intp dims = {1024};
Py_INCREF(self);
PyObject* array = PyArray_SimpleNewFromData(1, &dims, NPY_INT32, self->data.data);
//PyObject *array = Py_None;
Py_INCREF(array);
return array;
}
// ----------------------------------------------------------------------------
// MOODULE IINITIALIZATION
static PyObject *
ex_foo(PyObject *self, PyObject *args)
{
printf("Hello, world\n");
Py_INCREF(Py_None);
return Py_None;
}
static PyMethodDef example_methods[] = {
{"foo", ex_foo, METH_VARARGS, "foo() doc string"},
{NULL, NULL}
};
PyMODINIT_FUNC
initfoomodule(void)
{
PyObject* this_module;
foo_ColumnType.tp_new = PyType_GenericNew;
if (PyType_Ready(&foo_ColumnType) < 0)
return;
if (PyType_Ready(&foo_ColumnIteratorType) < 0)
return;
this_module = Py_InitModule("foomodule", example_methods);
PyModule_AddObject(this_module, "Column", (PyObject *)&foo_ColumnType);
Py_INCREF(&foo_ColumnType);
Py_INCREF(&foo_ColumnIteratorType);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment