numbox.utils
numbox.utils.highlevel
Dynamically defining StructRef
Defining numba StructRef requires writing a lot of boilerplate code.
A utility for concise definition of StructRef types that supports caching
is provided in numbox.utils.highlevel.make_structref()
. To use it,
define a separate module such as type_classes.py such as:
from numba.experimental.structref import register
from numba.core.types import StructRef
@register
class DataStructTypeClass(StructRef):
pass
Then in a different module main.py define:
from numba.core.types import float32, unicode_type
from numpy import isclose
from numbox.utils.highlevel import make_structref
from type_classes import DataStructTypeClass
def derive_output(struct_):
if struct_.control == "double":
return struct_.value * 2
else:
return struct_.value
data_struct = make_structref(
"DataStruct",
{"value": float32, "control": unicode_type},
DataStructTypeClass,
struct_methods={
"derive_output": derive_output
}
)
if __name__ == "__main__":
data_1 = data_struct(3.14, "double")
data_2 = data_struct(2.17, "something else")
assert isclose(data_1.derive_output(), 6.28)
assert isclose(data_2.derive_output(), 2.17)
- numbox.utils.highlevel.cres(sig, **kwargs)[source]
Returns Python proxy to FunctionType rather than CPUDispatcher returned by njit
- numbox.utils.highlevel.make_structref(struct_name: str, struct_fields: Iterable[str] | Dict[str, Type], struct_type_class: type | Type, *, struct_methods: Dict[str, Callable] | None = None, jit_options: dict | None = None)[source]
Makes structure type with struct_name and struct_fields from the StructRef type class.
A unique struct_type_class for each structref needs to be provided. If caching of code that will be using the created struct type is desired, these type class(es) need/s to be defined in a python module that is not executed. (Same requirement is also to observed even when the full definition of StructRef is entirely hard-coded rather than created dynamically.)
In particular, that’s why struct_type_class cannot be incorporated into the dynamic compile / exec routine here.
Dictionary of methods to be bound to the created structref can be provided as well. Struct methods will get inlined into the caller if numba deems it to be optimal (even if jit_options says otherwise), therefore changing the methods code without poking the jitted caller can result in a stale cache - when the latter is cached. This is not an exclusive limitation of a dynamic structref creation via this function and is equally true when the structref definition is coded explicitly.
numbox.utils.lowlevel
- numbox.utils.lowlevel.extract_struct_member(context: BaseContext, builder: IRBuilder, struct_fe_ty: StructRef, struct_obj, member_name: str, incref: bool = False)[source]
For the given struct object of the given numba (front-end) type extract member with the given name (must be literal, available at compile time)
- numbox.utils.lowlevel.get_func_p_from_func_struct(builder: IRBuilder, func_struct)[source]
Extract void* function pointer from the low-level FunctionType structure
- numbox.utils.lowlevel.get_str_from_p_as_int(p)[source]
Given pointer to null-terminated array of characters as an integer p, return unicode string object copying the original string’s data
- numbox.utils.lowlevel.get_unicode_data_p(s)[source]
Given Python unicode string, return pointer to its data payload, array of null-terminated characters. See https://github.com/numba/numba/blob/release0.61/numba/cpython/unicode.py#L83
- numbox.utils.lowlevel.populate_structref(context, builder, signature, structref_type_, structref_, args, ordered_args_names, decref_old=False)[source]
Store args with the corresponding ordered names ordered_args_names in structref with type structref_type_ and payload at data_pointer.
Based on numba.experimental.structref::define_attributes::struct_setattr_impl
Do not call decref_old when populating a newly-created structref, as there’s nothing to decref there.