Hello again list,

This is the implementation of a class for references
in pytables.

Unfortunately, it does not work yet since there is
a but in numpy, that I already reported but isn't fixed.
And it seems impossible to fix from within pytables.

So, here, the implementation of a class reference:

---------------- reference.pyx ---------------------------
""" Pyrex special numpy class for HDF5 references

Defines one class: reference
"""

from definitions cimport H5Rcreate, H5R_OBJECT, hobj_ref_t
from hdf5Extension cimport File

from numpy import typeDict

cdef extern from "Python.h":
    ctypedef struct PyObject:
        pass
    ctypedef struct PyTypeObject:
        object (*tp_new)(PyTypeObject *, PyObject *, PyObject *)
        object (*tp_alloc)(PyTypeObject *, Py_ssize_t)
        void (*tp_free)(void *)
    cdef object PyObject_Init(PyObject *, PyTypeObject *)
    cdef PyObject *Py_None
    cdef void Py_INCREF(PyObject *)

cdef extern from "numpy/ndarrayobject.h":
    ctypedef int npy_intp
    ctypedef object (PyArray_GetItemFunc) (void *, void *)
    ctypedef int (PyArray_SetItemFunc) (object, void *, void *)
    ctypedef void (PyArray_CopySwapFunc) (void *, void *, int, void *)
    ctypedef struct PyArray_ArrFuncs:
        PyArray_GetItemFunc *getitem
        PyArray_SetItemFunc *setitem
        PyArray_CopySwapFunc *copyswap
    ctypedef class numpy.dtype [object PyArray_Descr]: # type PyArrayDescr_Type
        cdef PyTypeObject *typeobj
        cdef char kind
        cdef char type
        cdef char byteorder
        cdef char hasobject
        cdef int elsize
        cdef int alignment
        cdef PyArray_ArrFuncs *f
    ctypedef class numpy.ndarray [object PyArrayObject]:
        cdef dtype descr
    ctypedef class numpy.generic [object PyObject]:
        pass
    cdef PyTypeObject PyArrayDescr_Type
    cdef PyTypeObject PyGenericArrType_Type
    ctypedef struct PyArray_Descr:
        pass
    cdef void import_array()
    cdef int PyArray_RegisterDataType(dtype d)

import_array()

cdef class reference(generic):
    # members defined in .pxd
    """ This class represents a reference in a HDF5 table.

    It is designed to be a numpy user type. It does not know
    the file the reference is in. """
    def __init__(self, dest):
        """ Create a reference to node dest """
        cdef File file
        if dest is None:
            return
        file = dest._v_file
        H5Rcreate(&self.ref, file.file_id, dest._v_pathname, H5R_OBJECT, -1)

    def __str__(self):
        return "R%x" % self.ref

    def deref(self, file):
        """ Find and return the referenced node in file.

        Attention! This is a slow function, so don't call it
        more often than necessary. """
        cdef hobj_ref_t tmp
        # The following loop sounds ridiculous, unfortunately, that's
        # the only way to retrieve the name of a referenced object.
        # Starting HDF5 1.8.0, one could use H5Rget_name, but it
        # also performs a tree traversal. It would be faster, though,
        # since both Python and H5Rcreate have some overhead.
        cdef File f
        f = file
        for node in file:
            H5Rcreate(&tmp, f.file_id, node._v_pathname, H5R_OBJECT, -1)
            if tmp == self.ref:
                return node
        raise HDF5Error("could not find referenced object")

# numpy uses a strange, own way of allocating memory, not supported
# directly by pyrex, thus the following two functions:
# (In a bright future, this might be unnecessary)
cdef object tp_new(PyTypeObject *t, PyObject *a, PyObject *b):
    return t.tp_alloc(t, 0)
(<PyTypeObject *> reference).tp_new = tp_new
(<PyTypeObject *> reference).tp_free = PyGenericArrType_Type.tp_free

# Besides defining a class for the datatype, numpy needs
# one dtype objects which describes the class and will be registered
# with numpy.

cdef PyArray_Descr stype
cdef dtype type
type = PyObject_Init(<PyObject *> &stype, &PyArrayDescr_Type)

type.typeobj = <PyTypeObject *> reference
type.kind = c'r'
type.type = c'r'
type.byteorder = c'='
type.hasobject = 0
type.elsize = 8
type.alignment = 8 # TODO: is that true? always?

# The following functions define how to cope with a reference
cdef PyArray_ArrFuncs arrfuncs
cdef object getitem(hobj_ref_t *ip, ndarray ap):
    cdef reference ret
    ret = reference(None)
    ret.ref = ip[0]
    return ret
arrfuncs.getitem = <PyArray_GetItemFunc *> getitem

cdef int setitem(reference op, hobj_ref_t *ov, ndarray ap):
    ov[0] = op.ref
    return 0
arrfuncs.setitem = <PyArray_SetItemFunc *> setitem

cdef void copyswap(hobj_ref_t *dst, hobj_ref_t *src, int swap, void *arr):
    dst[0] = src[0]
arrfuncs.copyswap = <PyArray_CopySwapFunc *> copyswap
type.f = &arrfuncs

# now we can register the new datatype!
PyArray_RegisterDataType(type)
typeDict["r"] = reference
typeDict["r8"] = reference
typeDict["reference"] = reference
--------------- end of reference.pyx ----------------------

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Pytables-users mailing list
Pytables-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/pytables-users

Reply via email to