/*
|
* This header file defines relevant features which:
|
* - Require runtime inspection depending on the NumPy version.
|
* - May be needed when compiling with an older version of NumPy to allow
|
* a smooth transition.
|
*
|
* As such, it is shipped with NumPy 2.0, but designed to be vendored in full
|
* or parts by downstream projects.
|
*
|
* It must be included after any other includes. `import_array()` must have
|
* been called in the scope or version dependency will misbehave, even when
|
* only `PyUFunc_` API is used.
|
*
|
* If required complicated defs (with inline functions) should be written as:
|
*
|
* #if NPY_FEATURE_VERSION >= NPY_2_0_API_VERSION
|
* Simple definition when NumPy 2.0 API is guaranteed.
|
* #else
|
* static inline definition of a 1.x compatibility shim
|
* #if NPY_ABI_VERSION < 0x02000000
|
* Make 1.x compatibility shim the public API (1.x only branch)
|
* #else
|
* Runtime dispatched version (1.x or 2.x)
|
* #endif
|
* #endif
|
*
|
* An internal build always passes NPY_FEATURE_VERSION >= NPY_2_0_API_VERSION
|
*/
|
|
#ifndef NUMPY_CORE_INCLUDE_NUMPY_NPY_2_COMPAT_H_
|
#define NUMPY_CORE_INCLUDE_NUMPY_NPY_2_COMPAT_H_
|
|
/*
|
* New macros for accessing real and complex part of a complex number can be
|
* found in "npy_2_complexcompat.h".
|
*/
|
|
|
/*
|
* This header is meant to be included by downstream directly for 1.x compat.
|
* In that case we need to ensure that users first included the full headers
|
* and not just `ndarraytypes.h`.
|
*/
|
|
#ifndef NPY_FEATURE_VERSION
|
#error "The NumPy 2 compat header requires `import_array()` for which " \
|
"the `ndarraytypes.h` header include is not sufficient. Please " \
|
"include it after `numpy/ndarrayobject.h` or similar.\n" \
|
"To simplify inclusion, you may use `PyArray_ImportNumPy()` " \
|
"which is defined in the compat header and is lightweight (can be)."
|
#endif
|
|
#if NPY_ABI_VERSION < 0x02000000
|
/*
|
* Define 2.0 feature version as it is needed below to decide whether we
|
* compile for both 1.x and 2.x (defining it guarantees 1.x only).
|
*/
|
#define NPY_2_0_API_VERSION 0x00000012
|
/*
|
* If we are compiling with NumPy 1.x, PyArray_RUNTIME_VERSION so we
|
* pretend the `PyArray_RUNTIME_VERSION` is `NPY_FEATURE_VERSION`.
|
* This allows downstream to use `PyArray_RUNTIME_VERSION` if they need to.
|
*/
|
#define PyArray_RUNTIME_VERSION NPY_FEATURE_VERSION
|
/* Compiling on NumPy 1.x where these are the same: */
|
#define PyArray_DescrProto PyArray_Descr
|
#endif
|
|
|
/*
|
* Define a better way to call `_import_array()` to simplify backporting as
|
* we now require imports more often (necessary to make ABI flexible).
|
*/
|
#ifdef import_array1
|
|
static inline int
|
PyArray_ImportNumPyAPI(void)
|
{
|
if (NPY_UNLIKELY(PyArray_API == NULL)) {
|
import_array1(-1);
|
}
|
return 0;
|
}
|
|
#endif /* import_array1 */
|
|
|
/*
|
* NPY_DEFAULT_INT
|
*
|
* The default integer has changed, `NPY_DEFAULT_INT` is available at runtime
|
* for use as type number, e.g. `PyArray_DescrFromType(NPY_DEFAULT_INT)`.
|
*
|
* NPY_RAVEL_AXIS
|
*
|
* This was introduced in NumPy 2.0 to allow indicating that an axis should be
|
* raveled in an operation. Before NumPy 2.0, NPY_MAXDIMS was used for this purpose.
|
*
|
* NPY_MAXDIMS
|
*
|
* A constant indicating the maximum number dimensions allowed when creating
|
* an ndarray.
|
*
|
* NPY_NTYPES_LEGACY
|
*
|
* The number of built-in NumPy dtypes.
|
*/
|
#if NPY_FEATURE_VERSION >= NPY_2_0_API_VERSION
|
#define NPY_DEFAULT_INT NPY_INTP
|
#define NPY_RAVEL_AXIS NPY_MIN_INT
|
#define NPY_MAXARGS 64
|
|
#elif NPY_ABI_VERSION < 0x02000000
|
#define NPY_DEFAULT_INT NPY_LONG
|
#define NPY_RAVEL_AXIS 32
|
#define NPY_MAXARGS 32
|
|
/* Aliases of 2.x names to 1.x only equivalent names */
|
#define NPY_NTYPES NPY_NTYPES_LEGACY
|
#define PyArray_DescrProto PyArray_Descr
|
#define _PyArray_LegacyDescr PyArray_Descr
|
/* NumPy 2 definition always works, but add it for 1.x only */
|
#define PyDataType_ISLEGACY(dtype) (1)
|
#else
|
#define NPY_DEFAULT_INT \
|
(PyArray_RUNTIME_VERSION >= NPY_2_0_API_VERSION ? NPY_INTP : NPY_LONG)
|
#define NPY_RAVEL_AXIS \
|
(PyArray_RUNTIME_VERSION >= NPY_2_0_API_VERSION ? NPY_MIN_INT : 32)
|
#define NPY_MAXARGS \
|
(PyArray_RUNTIME_VERSION >= NPY_2_0_API_VERSION ? 64 : 32)
|
#endif
|
|
|
/*
|
* Access inline functions for descriptor fields. Except for the first
|
* few fields, these needed to be moved (elsize, alignment) for
|
* additional space. Or they are descriptor specific and are not generally
|
* available anymore (metadata, c_metadata, subarray, names, fields).
|
*
|
* Most of these are defined via the `DESCR_ACCESSOR` macro helper.
|
*/
|
#if NPY_FEATURE_VERSION >= NPY_2_0_API_VERSION || NPY_ABI_VERSION < 0x02000000
|
/* Compiling for 1.x or 2.x only, direct field access is OK: */
|
|
static inline void
|
PyDataType_SET_ELSIZE(PyArray_Descr *dtype, npy_intp size)
|
{
|
dtype->elsize = size;
|
}
|
|
static inline npy_uint64
|
PyDataType_FLAGS(const PyArray_Descr *dtype)
|
{
|
#if NPY_FEATURE_VERSION >= NPY_2_0_API_VERSION
|
return dtype->flags;
|
#else
|
return (unsigned char)dtype->flags; /* Need unsigned cast on 1.x */
|
#endif
|
}
|
|
#define DESCR_ACCESSOR(FIELD, field, type, legacy_only) \
|
static inline type \
|
PyDataType_##FIELD(const PyArray_Descr *dtype) { \
|
if (legacy_only && !PyDataType_ISLEGACY(dtype)) { \
|
return (type)0; \
|
} \
|
return ((_PyArray_LegacyDescr *)dtype)->field; \
|
}
|
#else /* compiling for both 1.x and 2.x */
|
|
static inline void
|
PyDataType_SET_ELSIZE(PyArray_Descr *dtype, npy_intp size)
|
{
|
if (PyArray_RUNTIME_VERSION >= NPY_2_0_API_VERSION) {
|
((_PyArray_DescrNumPy2 *)dtype)->elsize = size;
|
}
|
else {
|
((PyArray_DescrProto *)dtype)->elsize = (int)size;
|
}
|
}
|
|
static inline npy_uint64
|
PyDataType_FLAGS(const PyArray_Descr *dtype)
|
{
|
if (PyArray_RUNTIME_VERSION >= NPY_2_0_API_VERSION) {
|
return ((_PyArray_DescrNumPy2 *)dtype)->flags;
|
}
|
else {
|
return (unsigned char)((PyArray_DescrProto *)dtype)->flags;
|
}
|
}
|
|
/* Cast to LegacyDescr always fine but needed when `legacy_only` */
|
#define DESCR_ACCESSOR(FIELD, field, type, legacy_only) \
|
static inline type \
|
PyDataType_##FIELD(const PyArray_Descr *dtype) { \
|
if (legacy_only && !PyDataType_ISLEGACY(dtype)) { \
|
return (type)0; \
|
} \
|
if (PyArray_RUNTIME_VERSION >= NPY_2_0_API_VERSION) { \
|
return ((_PyArray_LegacyDescr *)dtype)->field; \
|
} \
|
else { \
|
return ((PyArray_DescrProto *)dtype)->field; \
|
} \
|
}
|
#endif
|
|
DESCR_ACCESSOR(ELSIZE, elsize, npy_intp, 0)
|
DESCR_ACCESSOR(ALIGNMENT, alignment, npy_intp, 0)
|
DESCR_ACCESSOR(METADATA, metadata, PyObject *, 1)
|
DESCR_ACCESSOR(SUBARRAY, subarray, PyArray_ArrayDescr *, 1)
|
DESCR_ACCESSOR(NAMES, names, PyObject *, 1)
|
DESCR_ACCESSOR(FIELDS, fields, PyObject *, 1)
|
DESCR_ACCESSOR(C_METADATA, c_metadata, NpyAuxData *, 1)
|
|
#undef DESCR_ACCESSOR
|
|
|
#if !(defined(NPY_INTERNAL_BUILD) && NPY_INTERNAL_BUILD)
|
#if NPY_FEATURE_VERSION >= NPY_2_0_API_VERSION
|
static inline PyArray_ArrFuncs *
|
PyDataType_GetArrFuncs(const PyArray_Descr *descr)
|
{
|
return _PyDataType_GetArrFuncs(descr);
|
}
|
#elif NPY_ABI_VERSION < 0x02000000
|
static inline PyArray_ArrFuncs *
|
PyDataType_GetArrFuncs(const PyArray_Descr *descr)
|
{
|
return descr->f;
|
}
|
#else
|
static inline PyArray_ArrFuncs *
|
PyDataType_GetArrFuncs(const PyArray_Descr *descr)
|
{
|
if (PyArray_RUNTIME_VERSION >= NPY_2_0_API_VERSION) {
|
return _PyDataType_GetArrFuncs(descr);
|
}
|
else {
|
return ((PyArray_DescrProto *)descr)->f;
|
}
|
}
|
#endif
|
|
|
#endif /* not internal build */
|
|
#endif /* NUMPY_CORE_INCLUDE_NUMPY_NPY_2_COMPAT_H_ */
|