Skip to content

Commit

Permalink
Vendor numpy 2.0 compat header
Browse files Browse the repository at this point in the history
  • Loading branch information
langmm committed Jun 18, 2024
1 parent 93331fe commit ffdd71c
Show file tree
Hide file tree
Showing 2 changed files with 250 additions and 9 deletions.
249 changes: 249 additions & 0 deletions include/rapidjson/npy_2_compat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
/*
* 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 gaurantees 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()
{
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 ? -1 : 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_ */
10 changes: 1 addition & 9 deletions include/rapidjson/pyrj_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,7 @@ extern "C" {
#include <numpy/npy_common.h>
#endif

#if NPY_ABI_VERSION < 0x02000000
#define PyDataType_FIELDS(descr) ((descr)->fields)
#define PyDataType_NAMES(descr) ((descr)->names)
/* #define PyDataType_SUBARRAY(descr) */
#define PyDataType_ELSIZE(descr) ((descr)->elsize)
#define PyDataType_SET_ELSIZE(descr, size) ((descr)->elsize = size)
#define PyArray_DescrProto PyArray_Descr
#define _PyArray_LegacyDescr PyArray_Descr
#endif
#include "npy_2_compat.h"

#endif // YGGDRASIL_DISABLE_PYTHON_C_API

Expand Down

0 comments on commit ffdd71c

Please sign in to comment.