6.4. Extending the Numba backend¶
Todo
write this
Warning
This part of the documentation is obsolete and will be rewritten once the user-facing extension API stabilizes.
6.4.1. Helper Lib¶
numba/_helperlib.c addition of struct and adapter function:
typedef struct {
double lo;
double hi;
} intervalstruct_t;
static
int Numba_adapt_interval(PyObject *obj, intervalstruct_t* ivstruct) {
PyObject* lodata = PyObject_GetAttrString(obj, "lo");
ivstruct->lo = PyFloat_AsDouble(lodata);
PyObject* hidata = PyObject_GetAttrString(obj, "hi");
ivstruct->hi = PyFloat_AsDouble(hidata);
return 0;
}
Building C Helpers dict:
static PyObject *
build_c_helpers_dict(void)
{
PyObject *dct = PyDict_New();
if (dct == NULL)
goto error;
#define declmethod(func) do { \
PyObject *val = PyLong_FromVoidPtr(&Numba_##func); \
if (val == NULL) goto error; \
if (PyDict_SetItemString(dct, #func, val)) { \
Py_DECREF(val); \
goto error; \
} \
Py_DECREF(val); \
} while (0)
declmethod(sdiv);
declmethod(srem);
declmethod(udiv);
declmethod(urem);
declmethod(cpow);
declmethod(complex_adaptor);
declmethod(extract_record_data);
declmethod(release_record_buffer);
declmethod(adapt_ndarray);
declmethod(ndarray_new);
declmethod(extract_np_datetime);
declmethod(create_np_datetime);
declmethod(extract_np_timedelta);
declmethod(create_np_timedelta);
declmethod(recreate_record);
declmethod(round_even);
declmethod(roundf_even);
declmethod(fptoui);
declmethod(fptouif);
declmethod(gil_ensure);
declmethod(gil_release);
declmethod(adapt_interval);
#define MATH_UNARY(F, R, A) declmethod(F);
#define MATH_BINARY(F, R, A, B) declmethod(F);
#include "mathnames.inc"
#undef MATH_UNARY
#undef MATH_BINARY
#undef declmethod
return dct;
error:
Py_XDECREF(dct);
return NULL;
}
6.4.2. Python API¶
In numba.pythonapi. Add to to_native_value:
elif isinstance(typ, types.IntervalType):
return self.to_native_interval(obj)
Add methods:
def to_native_interval(self, interval):
voidptr = Type.pointer(Type.int(8))
nativeivcls = self.context.make_interval()
nativeiv = nativeivcls(self.context, self.builder)
ivptr = nativeiv._getpointer()
ptr = self.builder.bitcast(ivptr, voidptr)
errcode = self.interval_adaptor(interval, ptr)
failed = cgutils.is_not_null(self.builder, errcode)
with cgutils.if_unlikely(self.builder, failed):
# TODO
self.builder.unreachable()
return self.builder.load(ivptr)
def interval_adaptor(self, interval, ptr):
voidptr = Type.pointer(Type.int(8))
fnty = Type.function(Type.int(), [self.pyobj, voidptr])
fn = self._get_function(fnty, name="numba_adapt_interval")
fn.args[0].add_attribute(lc.ATTR_NO_CAPTURE)
fn.args[1].add_attribute(lc.ATTR_NO_CAPTURE)
return self.builder.call(fn, (interval, ptr))
6.4.3. Target Interval Objects¶
numba.targets.intervalobj.py:
from numba import cgutils, types
from numba.targets.imputils import builtin_attr, impl_attribute
def make_interval():
"""
Return the Structure representation of an interval
"""
# This structure should be kept in sync with Numba_adapt_interval()
# in _helperlib.c.
class IntervalTemplate(cgutils.Structure):
_fields = [('lo', types.float64),
('hi', types.float64),
]
return IntervalTemplate
@builtin_attr
@impl_attribute(types.Kind(types.IntervalType), 'lo', types.float64)
def interval_lo(context, builder, typ, value):
ivty = make_interval()
iv = ivty(context, builder, value)
return iv.lo
@builtin_attr
@impl_attribute(types.Kind(types.IntervalType), 'hi', types.float64)
def interval_hi(context, builder, typ, value):
ivty = make_interval()
iv = ivty(context, builder, value)
return iv.hi
6.4.4. Base Target¶
Add get_data_type handling for interval type and make_interval method.