diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/CallContext.h b/bindings/pyroot/cppyy/CPyCppyy/src/CallContext.h index fc6a43b159b87..c9a19d823c105 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/CallContext.h +++ b/bindings/pyroot/cppyy/CPyCppyy/src/CallContext.h @@ -22,7 +22,11 @@ struct Parameter { union Value { bool fBool; int8_t fInt8; + int16_t fInt16; + int32_t fInt32; uint8_t fUInt8; + uint16_t fUInt16; + uint32_t fUInt32; short fShort; unsigned short fUShort; int fInt; diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/Converters.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/Converters.cxx index 4cef37e74ec90..84a3d8b8e6872 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/Converters.cxx +++ b/bindings/pyroot/cppyy/CPyCppyy/src/Converters.cxx @@ -123,7 +123,9 @@ struct CPyCppyy_tagPyCArgObject { // not public (but stable; note that olde #define ct_c_fcomplex 21 #define ct_c_complex 22 #define ct_c_pointer 23 -#define NTYPES 24 +#define ct_c_int16 24 +#define ct_c_int32 25 +#define NTYPES 26 static std::array gCTypesNames = { "c_bool", "c_char", "c_wchar", "c_byte", "c_ubyte", "c_short", "c_ushort", "c_uint16", @@ -387,6 +389,10 @@ static inline type CPyCppyy_PyLong_As##name(PyObject* pyobject) \ CPPYY_PYLONG_AS_TYPE(UInt8, uint8_t, 0, UCHAR_MAX) CPPYY_PYLONG_AS_TYPE(Int8, int8_t, SCHAR_MIN, SCHAR_MAX) +CPPYY_PYLONG_AS_TYPE(UInt16, uint16_t, 0, UINT16_MAX) +CPPYY_PYLONG_AS_TYPE(Int16, int16_t, INT16_MIN, INT16_MAX) +CPPYY_PYLONG_AS_TYPE(UInt32, uint32_t, 0, UINT32_MAX) +CPPYY_PYLONG_AS_TYPE(Int32, int32_t, INT32_MIN, INT32_MAX) CPPYY_PYLONG_AS_TYPE(UShort, unsigned short, 0, USHRT_MAX) CPPYY_PYLONG_AS_TYPE(Short, short, SHRT_MIN, SHRT_MAX) CPPYY_PYLONG_AS_TYPE(StrictInt, int, INT_MIN, INT_MAX) @@ -782,6 +788,10 @@ CPPYY_IMPL_BASIC_CONST_CHAR_REFCONVERTER(UChar, unsigned char, c_uchar, 0 CPPYY_IMPL_BASIC_CONST_REFCONVERTER(Bool, bool, c_bool, CPyCppyy_PyLong_AsBool) CPPYY_IMPL_BASIC_CONST_REFCONVERTER(Int8, int8_t, c_int8, CPyCppyy_PyLong_AsInt8) CPPYY_IMPL_BASIC_CONST_REFCONVERTER(UInt8, uint8_t, c_uint8, CPyCppyy_PyLong_AsUInt8) +CPPYY_IMPL_BASIC_CONST_REFCONVERTER(Int16, int16_t, c_int16, CPyCppyy_PyLong_AsInt16) +CPPYY_IMPL_BASIC_CONST_REFCONVERTER(UInt16, uint16_t, c_uint16, CPyCppyy_PyLong_AsUInt16) +CPPYY_IMPL_BASIC_CONST_REFCONVERTER(Int32, int32_t, c_int32, CPyCppyy_PyLong_AsInt32) +CPPYY_IMPL_BASIC_CONST_REFCONVERTER(UInt32, uint32_t, c_uint32, CPyCppyy_PyLong_AsUInt32) CPPYY_IMPL_BASIC_CONST_REFCONVERTER(Short, short, c_short, CPyCppyy_PyLong_AsShort) CPPYY_IMPL_BASIC_CONST_REFCONVERTER(UShort, unsigned short, c_ushort, CPyCppyy_PyLong_AsUShort) CPPYY_IMPL_BASIC_CONST_REFCONVERTER(Int, int, c_int, CPyCppyy_PyLong_AsStrictInt) @@ -857,6 +867,10 @@ CPPYY_IMPL_REFCONVERTER(SChar, c_byte, signed char, 'b'); CPPYY_IMPL_REFCONVERTER(UChar, c_ubyte, unsigned char, 'B'); CPPYY_IMPL_REFCONVERTER(Int8, c_int8, int8_t, 'b'); CPPYY_IMPL_REFCONVERTER(UInt8, c_uint8, uint8_t, 'B'); +CPPYY_IMPL_REFCONVERTER(Int16, c_int16, int16_t, 'h'); +CPPYY_IMPL_REFCONVERTER(UInt16, c_uint16, uint16_t, 'H'); +CPPYY_IMPL_REFCONVERTER(Int32, c_int32, int32_t, 'i'); +CPPYY_IMPL_REFCONVERTER(UInt32, c_uint32, uint32_t, 'I'); CPPYY_IMPL_REFCONVERTER(Short, c_short, short, 'h'); CPPYY_IMPL_REFCONVERTER(UShort, c_ushort, unsigned short, 'H'); CPPYY_IMPL_REFCONVERTER_FROM_MEMORY(Int, c_int); @@ -1015,6 +1029,14 @@ CPPYY_IMPL_BASIC_CONVERTER_IB( Int8, int8_t, long, c_int8, PyInt_FromLong, CPyCppyy_PyLong_AsInt8, 'l') CPPYY_IMPL_BASIC_CONVERTER_IB( UInt8, uint8_t, long, c_uint8, PyInt_FromLong, CPyCppyy_PyLong_AsUInt8, 'l') +CPPYY_IMPL_BASIC_CONVERTER_IB( + Int16, int16_t, long, c_int16, PyInt_FromLong, CPyCppyy_PyLong_AsInt16, 'l') +CPPYY_IMPL_BASIC_CONVERTER_IB( + UInt16, uint16_t, long, c_uint16, PyInt_FromLong, CPyCppyy_PyLong_AsUInt16, 'l') +CPPYY_IMPL_BASIC_CONVERTER_IB( + Int32, int32_t, long, c_int32, PyInt_FromLong, CPyCppyy_PyLong_AsInt32, 'l') +CPPYY_IMPL_BASIC_CONVERTER_IB( + UInt32, uint32_t, long, c_uint32, PyInt_FromLong, CPyCppyy_PyLong_AsUInt32, 'l') CPPYY_IMPL_BASIC_CONVERTER_IB( Short, short, long, c_short, PyInt_FromLong, CPyCppyy_PyLong_AsShort, 'l') CPPYY_IMPL_BASIC_CONVERTER_IB( @@ -1750,7 +1772,11 @@ CPPYY_IMPL_ARRAY_CONVERTER(UChar, c_ubyte, unsigned char, 'B', ) CPPYY_IMPL_ARRAY_CONVERTER(Byte, c_ubyte, std::byte, 'B', ) #endif CPPYY_IMPL_ARRAY_CONVERTER(Int8, c_byte, int8_t, 'b', _i8) +CPPYY_IMPL_ARRAY_CONVERTER(Int16, c_int16, int16_t, 'h', _i16) +CPPYY_IMPL_ARRAY_CONVERTER(Int32, c_int32, int32_t, 'i', _i32) CPPYY_IMPL_ARRAY_CONVERTER(UInt8, c_ubyte, uint8_t, 'B', _i8) +CPPYY_IMPL_ARRAY_CONVERTER(UInt16, c_uint16, uint16_t, 'H', _i16) +CPPYY_IMPL_ARRAY_CONVERTER(UInt32, c_uint32, uint32_t, 'I', _i32) CPPYY_IMPL_ARRAY_CONVERTER(Short, c_short, short, 'h', ) CPPYY_IMPL_ARRAY_CONVERTER(UShort, c_ushort, unsigned short, 'H', ) CPPYY_IMPL_ARRAY_CONVERTER(Int, c_int, int, 'i', ) @@ -3466,9 +3492,21 @@ static struct InitConvFactories_t { gf["int8_t"] = (cf_t)+[](cdims_t) { static Int8Converter c{}; return &c; }; gf["const int8_t&"] = (cf_t)+[](cdims_t) { static ConstInt8RefConverter c{}; return &c; }; gf["int8_t&"] = (cf_t)+[](cdims_t) { static Int8RefConverter c{}; return &c; }; + gf["int16_t"] = (cf_t)+[](cdims_t) { static Int16Converter c{}; return &c; }; + gf["const int16_t&"] = (cf_t)+[](cdims_t) { static ConstInt16RefConverter c{}; return &c; }; + gf["int16_t&"] = (cf_t)+[](cdims_t) { static Int16RefConverter c{}; return &c; }; + gf["int32_t"] = (cf_t)+[](cdims_t) { static Int32Converter c{}; return &c; }; + gf["const int32_t&"] = (cf_t)+[](cdims_t) { static ConstInt32RefConverter c{}; return &c; }; + gf["int32_t&"] = (cf_t)+[](cdims_t) { static Int32RefConverter c{}; return &c; }; gf["uint8_t"] = (cf_t)+[](cdims_t) { static UInt8Converter c{}; return &c; }; gf["const uint8_t&"] = (cf_t)+[](cdims_t) { static ConstUInt8RefConverter c{}; return &c; }; gf["uint8_t&"] = (cf_t)+[](cdims_t) { static UInt8RefConverter c{}; return &c; }; + gf["uint16_t"] = (cf_t)+[](cdims_t) { static UInt16Converter c{}; return &c; }; + gf["const uint16_t&"] = (cf_t)+[](cdims_t) { static ConstUInt16RefConverter c{}; return &c; }; + gf["uint16_t&"] = (cf_t)+[](cdims_t) { static UInt16RefConverter c{}; return &c; }; + gf["uint32_t"] = (cf_t)+[](cdims_t) { static UInt32Converter c{}; return &c; }; + gf["const uint32_t&"] = (cf_t)+[](cdims_t) { static ConstUInt32RefConverter c{}; return &c; }; + gf["uint32_t&"] = (cf_t)+[](cdims_t) { static UInt32RefConverter c{}; return &c; }; gf["short"] = (cf_t)+[](cdims_t) { static ShortConverter c{}; return &c; }; gf["const short&"] = (cf_t)+[](cdims_t) { static ConstShortRefConverter c{}; return &c; }; gf["short&"] = (cf_t)+[](cdims_t) { static ShortRefConverter c{}; return &c; }; @@ -3521,7 +3559,11 @@ static struct InitConvFactories_t { gf["std::byte ptr"] = (cf_t)+[](cdims_t d) { return new ByteArrayConverter{d}; }; #endif gf["int8_t ptr"] = (cf_t)+[](cdims_t d) { return new Int8ArrayConverter{d}; }; + gf["int16_t ptr"] = (cf_t)+[](cdims_t d) { return new Int16ArrayConverter{d}; }; + gf["int32_t ptr"] = (cf_t)+[](cdims_t d) { return new Int32ArrayConverter{d}; }; gf["uint8_t ptr"] = (cf_t)+[](cdims_t d) { return new UInt8ArrayConverter{d}; }; + gf["uint16_t ptr"] = (cf_t)+[](cdims_t d) { return new UInt16ArrayConverter{d}; }; + gf["uint32_t ptr"] = (cf_t)+[](cdims_t d) { return new UInt32ArrayConverter{d}; }; gf["short ptr"] = (cf_t)+[](cdims_t d) { return new ShortArrayConverter{d}; }; gf["unsigned short ptr"] = (cf_t)+[](cdims_t d) { return new UShortArrayConverter{d}; }; gf["int ptr"] = (cf_t)+[](cdims_t d) { return new IntArrayConverter{d}; }; diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/DeclareConverters.h b/bindings/pyroot/cppyy/CPyCppyy/src/DeclareConverters.h index b3a4246045ab4..71011ce6b5fc9 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/DeclareConverters.h +++ b/bindings/pyroot/cppyy/CPyCppyy/src/DeclareConverters.h @@ -87,7 +87,11 @@ CPPYY_DECLARE_BASIC_CONVERTER(WChar); CPPYY_DECLARE_BASIC_CONVERTER(Char16); CPPYY_DECLARE_BASIC_CONVERTER(Char32); CPPYY_DECLARE_BASIC_CONVERTER(Int8); +CPPYY_DECLARE_BASIC_CONVERTER(Int16); +CPPYY_DECLARE_BASIC_CONVERTER(Int32); CPPYY_DECLARE_BASIC_CONVERTER(UInt8); +CPPYY_DECLARE_BASIC_CONVERTER(UInt16); +CPPYY_DECLARE_BASIC_CONVERTER(UInt32); CPPYY_DECLARE_BASIC_CONVERTER(Short); CPPYY_DECLARE_BASIC_CONVERTER(UShort); CPPYY_DECLARE_BASIC_CONVERTER(Int); @@ -107,7 +111,11 @@ CPPYY_DECLARE_REFCONVERTER(Char32); CPPYY_DECLARE_REFCONVERTER(SChar); CPPYY_DECLARE_REFCONVERTER(UChar); CPPYY_DECLARE_REFCONVERTER(Int8); +CPPYY_DECLARE_REFCONVERTER(Int16); +CPPYY_DECLARE_REFCONVERTER(Int32); CPPYY_DECLARE_REFCONVERTER(UInt8); +CPPYY_DECLARE_REFCONVERTER(UInt16); +CPPYY_DECLARE_REFCONVERTER(UInt32); CPPYY_DECLARE_REFCONVERTER(Short); CPPYY_DECLARE_REFCONVERTER(UShort); CPPYY_DECLARE_REFCONVERTER(UInt); @@ -214,7 +222,11 @@ CPPYY_DECLARE_ARRAY_CONVERTER(UChar); CPPYY_DECLARE_ARRAY_CONVERTER(Byte); #endif CPPYY_DECLARE_ARRAY_CONVERTER(Int8); +CPPYY_DECLARE_ARRAY_CONVERTER(Int16); +CPPYY_DECLARE_ARRAY_CONVERTER(Int32); CPPYY_DECLARE_ARRAY_CONVERTER(UInt8); +CPPYY_DECLARE_ARRAY_CONVERTER(UInt16); +CPPYY_DECLARE_ARRAY_CONVERTER(UInt32); CPPYY_DECLARE_ARRAY_CONVERTER(Short); CPPYY_DECLARE_ARRAY_CONVERTER(UShort); CPPYY_DECLARE_ARRAY_CONVERTER(Int); diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.cxx index c3f8aaf51f81f..3b0d48e9f1c7c 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.cxx +++ b/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.cxx @@ -1200,3 +1200,43 @@ PyObject* CPyCppyy::CreateLowLevelView_i8(uint8_t** address, cdims_t shape) { LowLevelView* ll = CreateLowLevelViewT(address, shape, "B", "uint8_t"); CPPYY_RET_W_CREATOR(uint8_t**, CreateLowLevelView_i8); } + +PyObject* CPyCppyy::CreateLowLevelView_i16(int16_t* address, cdims_t shape) { + LowLevelView* ll = CreateLowLevelViewT(address, shape, "h", "int16_t"); + CPPYY_RET_W_CREATOR(int16_t*, CreateLowLevelView_i16); +} + +PyObject* CPyCppyy::CreateLowLevelView_i16(int16_t** address, cdims_t shape) { + LowLevelView* ll = CreateLowLevelViewT(address, shape, "h", "int16_t"); + CPPYY_RET_W_CREATOR(int16_t**, CreateLowLevelView_i16); +} + +PyObject* CPyCppyy::CreateLowLevelView_i16(uint16_t* address, cdims_t shape) { + LowLevelView* ll = CreateLowLevelViewT(address, shape, "H", "uint16_t"); + CPPYY_RET_W_CREATOR(uint16_t*, CreateLowLevelView_i16); +} + +PyObject* CPyCppyy::CreateLowLevelView_i16(uint16_t** address, cdims_t shape) { + LowLevelView* ll = CreateLowLevelViewT(address, shape, "H", "uint16_t"); + CPPYY_RET_W_CREATOR(uint16_t**, CreateLowLevelView_i16); +} + +PyObject* CPyCppyy::CreateLowLevelView_i32(int32_t* address, cdims_t shape) { + LowLevelView* ll = CreateLowLevelViewT(address, shape, "i", "int32_t"); + CPPYY_RET_W_CREATOR(int32_t*, CreateLowLevelView_i32); +} + +PyObject* CPyCppyy::CreateLowLevelView_i32(int32_t** address, cdims_t shape) { + LowLevelView* ll = CreateLowLevelViewT(address, shape, "i", "int32_t"); + CPPYY_RET_W_CREATOR(int32_t**, CreateLowLevelView_i32); +} + +PyObject* CPyCppyy::CreateLowLevelView_i32(uint32_t* address, cdims_t shape) { + LowLevelView* ll = CreateLowLevelViewT(address, shape, "I", "uint32_t"); + CPPYY_RET_W_CREATOR(uint32_t*, CreateLowLevelView_i32); +} + +PyObject* CPyCppyy::CreateLowLevelView_i32(uint32_t** address, cdims_t shape) { + LowLevelView* ll = CreateLowLevelViewT(address, shape, "I", "uint32_t"); + CPPYY_RET_W_CREATOR(uint32_t**, CreateLowLevelView_i32); +} diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.h b/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.h index 4186ea09317fc..811af69e2787f 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.h +++ b/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.h @@ -56,6 +56,15 @@ PyObject* CreateLowLevelView_i8(int8_t*, cdims_t shape); PyObject* CreateLowLevelView_i8(int8_t**, cdims_t shape); PyObject* CreateLowLevelView_i8(uint8_t*, cdims_t shape); PyObject* CreateLowLevelView_i8(uint8_t**, cdims_t shape); +PyObject* CreateLowLevelView_i16(int16_t*, cdims_t shape); +PyObject* CreateLowLevelView_i16(int16_t**, cdims_t shape); +PyObject* CreateLowLevelView_i16(uint16_t*, cdims_t shape); +PyObject* CreateLowLevelView_i16(uint16_t**, cdims_t shape); +PyObject* CreateLowLevelView_i32(int32_t*, cdims_t shape); +PyObject* CreateLowLevelView_i32(int32_t**, cdims_t shape); +PyObject* CreateLowLevelView_i32(uint32_t*, cdims_t shape); +PyObject* CreateLowLevelView_i32(uint32_t**, cdims_t shape); + CPPYY_DECL_VIEW_CREATOR(short); CPPYY_DECL_VIEW_CREATOR(unsigned short); CPPYY_DECL_VIEW_CREATOR(int); diff --git a/bindings/pyroot/cppyy/patches/CPyCppyy-Add-converters-and-low-level-views-for-fixed-width-integers.patch b/bindings/pyroot/cppyy/patches/CPyCppyy-Add-converters-and-low-level-views-for-fixed-width-integers.patch new file mode 100644 index 0000000000000..77834c5c3e4b0 --- /dev/null +++ b/bindings/pyroot/cppyy/patches/CPyCppyy-Add-converters-and-low-level-views-for-fixed-width-integers.patch @@ -0,0 +1,250 @@ +From 5ad12352dd0f73a082dc0c6eafbb9537c4ecf3e2 Mon Sep 17 00:00:00 2001 +From: Aaron Jomy +Date: Thu, 24 Apr 2025 13:53:03 +0200 +Subject: [PATCH 1/1] Add converters and low-level views for fixed width + integers + +--- + .../pyroot/cppyy/CPyCppyy/src/CallContext.h | 4 ++ + .../pyroot/cppyy/CPyCppyy/src/Converters.cxx | 44 ++++++++++++++++++- + .../cppyy/CPyCppyy/src/DeclareConverters.h | 12 +++++ + .../cppyy/CPyCppyy/src/LowLevelViews.cxx | 40 +++++++++++++++++ + .../pyroot/cppyy/CPyCppyy/src/LowLevelViews.h | 9 ++++ + 5 files changed, 108 insertions(+), 1 deletion(-) + +diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/CallContext.h b/bindings/pyroot/cppyy/CPyCppyy/src/CallContext.h +index fc6a43b159..c9a19d823c 100644 +--- a/bindings/pyroot/cppyy/CPyCppyy/src/CallContext.h ++++ b/bindings/pyroot/cppyy/CPyCppyy/src/CallContext.h +@@ -22,7 +22,11 @@ struct Parameter { + union Value { + bool fBool; + int8_t fInt8; ++ int16_t fInt16; ++ int32_t fInt32; + uint8_t fUInt8; ++ uint16_t fUInt16; ++ uint32_t fUInt32; + short fShort; + unsigned short fUShort; + int fInt; +diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/Converters.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/Converters.cxx +index 4cef37e74e..84a3d8b8e6 100644 +--- a/bindings/pyroot/cppyy/CPyCppyy/src/Converters.cxx ++++ b/bindings/pyroot/cppyy/CPyCppyy/src/Converters.cxx +@@ -123,7 +123,9 @@ struct CPyCppyy_tagPyCArgObject { // not public (but stable; note that olde + #define ct_c_fcomplex 21 + #define ct_c_complex 22 + #define ct_c_pointer 23 +-#define NTYPES 24 ++#define ct_c_int16 24 ++#define ct_c_int32 25 ++#define NTYPES 26 + + static std::array gCTypesNames = { + "c_bool", "c_char", "c_wchar", "c_byte", "c_ubyte", "c_short", "c_ushort", "c_uint16", +@@ -387,6 +389,10 @@ static inline type CPyCppyy_PyLong_As##name(PyObject* pyobject) \ + + CPPYY_PYLONG_AS_TYPE(UInt8, uint8_t, 0, UCHAR_MAX) + CPPYY_PYLONG_AS_TYPE(Int8, int8_t, SCHAR_MIN, SCHAR_MAX) ++CPPYY_PYLONG_AS_TYPE(UInt16, uint16_t, 0, UINT16_MAX) ++CPPYY_PYLONG_AS_TYPE(Int16, int16_t, INT16_MIN, INT16_MAX) ++CPPYY_PYLONG_AS_TYPE(UInt32, uint32_t, 0, UINT32_MAX) ++CPPYY_PYLONG_AS_TYPE(Int32, int32_t, INT32_MIN, INT32_MAX) + CPPYY_PYLONG_AS_TYPE(UShort, unsigned short, 0, USHRT_MAX) + CPPYY_PYLONG_AS_TYPE(Short, short, SHRT_MIN, SHRT_MAX) + CPPYY_PYLONG_AS_TYPE(StrictInt, int, INT_MIN, INT_MAX) +@@ -782,6 +788,10 @@ CPPYY_IMPL_BASIC_CONST_CHAR_REFCONVERTER(UChar, unsigned char, c_uchar, 0 + CPPYY_IMPL_BASIC_CONST_REFCONVERTER(Bool, bool, c_bool, CPyCppyy_PyLong_AsBool) + CPPYY_IMPL_BASIC_CONST_REFCONVERTER(Int8, int8_t, c_int8, CPyCppyy_PyLong_AsInt8) + CPPYY_IMPL_BASIC_CONST_REFCONVERTER(UInt8, uint8_t, c_uint8, CPyCppyy_PyLong_AsUInt8) ++CPPYY_IMPL_BASIC_CONST_REFCONVERTER(Int16, int16_t, c_int16, CPyCppyy_PyLong_AsInt16) ++CPPYY_IMPL_BASIC_CONST_REFCONVERTER(UInt16, uint16_t, c_uint16, CPyCppyy_PyLong_AsUInt16) ++CPPYY_IMPL_BASIC_CONST_REFCONVERTER(Int32, int32_t, c_int32, CPyCppyy_PyLong_AsInt32) ++CPPYY_IMPL_BASIC_CONST_REFCONVERTER(UInt32, uint32_t, c_uint32, CPyCppyy_PyLong_AsUInt32) + CPPYY_IMPL_BASIC_CONST_REFCONVERTER(Short, short, c_short, CPyCppyy_PyLong_AsShort) + CPPYY_IMPL_BASIC_CONST_REFCONVERTER(UShort, unsigned short, c_ushort, CPyCppyy_PyLong_AsUShort) + CPPYY_IMPL_BASIC_CONST_REFCONVERTER(Int, int, c_int, CPyCppyy_PyLong_AsStrictInt) +@@ -857,6 +867,10 @@ CPPYY_IMPL_REFCONVERTER(SChar, c_byte, signed char, 'b'); + CPPYY_IMPL_REFCONVERTER(UChar, c_ubyte, unsigned char, 'B'); + CPPYY_IMPL_REFCONVERTER(Int8, c_int8, int8_t, 'b'); + CPPYY_IMPL_REFCONVERTER(UInt8, c_uint8, uint8_t, 'B'); ++CPPYY_IMPL_REFCONVERTER(Int16, c_int16, int16_t, 'h'); ++CPPYY_IMPL_REFCONVERTER(UInt16, c_uint16, uint16_t, 'H'); ++CPPYY_IMPL_REFCONVERTER(Int32, c_int32, int32_t, 'i'); ++CPPYY_IMPL_REFCONVERTER(UInt32, c_uint32, uint32_t, 'I'); + CPPYY_IMPL_REFCONVERTER(Short, c_short, short, 'h'); + CPPYY_IMPL_REFCONVERTER(UShort, c_ushort, unsigned short, 'H'); + CPPYY_IMPL_REFCONVERTER_FROM_MEMORY(Int, c_int); +@@ -1015,6 +1029,14 @@ CPPYY_IMPL_BASIC_CONVERTER_IB( + Int8, int8_t, long, c_int8, PyInt_FromLong, CPyCppyy_PyLong_AsInt8, 'l') + CPPYY_IMPL_BASIC_CONVERTER_IB( + UInt8, uint8_t, long, c_uint8, PyInt_FromLong, CPyCppyy_PyLong_AsUInt8, 'l') ++CPPYY_IMPL_BASIC_CONVERTER_IB( ++ Int16, int16_t, long, c_int16, PyInt_FromLong, CPyCppyy_PyLong_AsInt16, 'l') ++CPPYY_IMPL_BASIC_CONVERTER_IB( ++ UInt16, uint16_t, long, c_uint16, PyInt_FromLong, CPyCppyy_PyLong_AsUInt16, 'l') ++CPPYY_IMPL_BASIC_CONVERTER_IB( ++ Int32, int32_t, long, c_int32, PyInt_FromLong, CPyCppyy_PyLong_AsInt32, 'l') ++CPPYY_IMPL_BASIC_CONVERTER_IB( ++ UInt32, uint32_t, long, c_uint32, PyInt_FromLong, CPyCppyy_PyLong_AsUInt32, 'l') + CPPYY_IMPL_BASIC_CONVERTER_IB( + Short, short, long, c_short, PyInt_FromLong, CPyCppyy_PyLong_AsShort, 'l') + CPPYY_IMPL_BASIC_CONVERTER_IB( +@@ -1750,7 +1772,11 @@ CPPYY_IMPL_ARRAY_CONVERTER(UChar, c_ubyte, unsigned char, 'B', ) + CPPYY_IMPL_ARRAY_CONVERTER(Byte, c_ubyte, std::byte, 'B', ) + #endif + CPPYY_IMPL_ARRAY_CONVERTER(Int8, c_byte, int8_t, 'b', _i8) ++CPPYY_IMPL_ARRAY_CONVERTER(Int16, c_int16, int16_t, 'h', _i16) ++CPPYY_IMPL_ARRAY_CONVERTER(Int32, c_int32, int32_t, 'i', _i32) + CPPYY_IMPL_ARRAY_CONVERTER(UInt8, c_ubyte, uint8_t, 'B', _i8) ++CPPYY_IMPL_ARRAY_CONVERTER(UInt16, c_uint16, uint16_t, 'H', _i16) ++CPPYY_IMPL_ARRAY_CONVERTER(UInt32, c_uint32, uint32_t, 'I', _i32) + CPPYY_IMPL_ARRAY_CONVERTER(Short, c_short, short, 'h', ) + CPPYY_IMPL_ARRAY_CONVERTER(UShort, c_ushort, unsigned short, 'H', ) + CPPYY_IMPL_ARRAY_CONVERTER(Int, c_int, int, 'i', ) +@@ -3466,9 +3492,21 @@ public: + gf["int8_t"] = (cf_t)+[](cdims_t) { static Int8Converter c{}; return &c; }; + gf["const int8_t&"] = (cf_t)+[](cdims_t) { static ConstInt8RefConverter c{}; return &c; }; + gf["int8_t&"] = (cf_t)+[](cdims_t) { static Int8RefConverter c{}; return &c; }; ++ gf["int16_t"] = (cf_t)+[](cdims_t) { static Int16Converter c{}; return &c; }; ++ gf["const int16_t&"] = (cf_t)+[](cdims_t) { static ConstInt16RefConverter c{}; return &c; }; ++ gf["int16_t&"] = (cf_t)+[](cdims_t) { static Int16RefConverter c{}; return &c; }; ++ gf["int32_t"] = (cf_t)+[](cdims_t) { static Int32Converter c{}; return &c; }; ++ gf["const int32_t&"] = (cf_t)+[](cdims_t) { static ConstInt32RefConverter c{}; return &c; }; ++ gf["int32_t&"] = (cf_t)+[](cdims_t) { static Int32RefConverter c{}; return &c; }; + gf["uint8_t"] = (cf_t)+[](cdims_t) { static UInt8Converter c{}; return &c; }; + gf["const uint8_t&"] = (cf_t)+[](cdims_t) { static ConstUInt8RefConverter c{}; return &c; }; + gf["uint8_t&"] = (cf_t)+[](cdims_t) { static UInt8RefConverter c{}; return &c; }; ++ gf["uint16_t"] = (cf_t)+[](cdims_t) { static UInt16Converter c{}; return &c; }; ++ gf["const uint16_t&"] = (cf_t)+[](cdims_t) { static ConstUInt16RefConverter c{}; return &c; }; ++ gf["uint16_t&"] = (cf_t)+[](cdims_t) { static UInt16RefConverter c{}; return &c; }; ++ gf["uint32_t"] = (cf_t)+[](cdims_t) { static UInt32Converter c{}; return &c; }; ++ gf["const uint32_t&"] = (cf_t)+[](cdims_t) { static ConstUInt32RefConverter c{}; return &c; }; ++ gf["uint32_t&"] = (cf_t)+[](cdims_t) { static UInt32RefConverter c{}; return &c; }; + gf["short"] = (cf_t)+[](cdims_t) { static ShortConverter c{}; return &c; }; + gf["const short&"] = (cf_t)+[](cdims_t) { static ConstShortRefConverter c{}; return &c; }; + gf["short&"] = (cf_t)+[](cdims_t) { static ShortRefConverter c{}; return &c; }; +@@ -3521,7 +3559,11 @@ public: + gf["std::byte ptr"] = (cf_t)+[](cdims_t d) { return new ByteArrayConverter{d}; }; + #endif + gf["int8_t ptr"] = (cf_t)+[](cdims_t d) { return new Int8ArrayConverter{d}; }; ++ gf["int16_t ptr"] = (cf_t)+[](cdims_t d) { return new Int16ArrayConverter{d}; }; ++ gf["int32_t ptr"] = (cf_t)+[](cdims_t d) { return new Int32ArrayConverter{d}; }; + gf["uint8_t ptr"] = (cf_t)+[](cdims_t d) { return new UInt8ArrayConverter{d}; }; ++ gf["uint16_t ptr"] = (cf_t)+[](cdims_t d) { return new UInt16ArrayConverter{d}; }; ++ gf["uint32_t ptr"] = (cf_t)+[](cdims_t d) { return new UInt32ArrayConverter{d}; }; + gf["short ptr"] = (cf_t)+[](cdims_t d) { return new ShortArrayConverter{d}; }; + gf["unsigned short ptr"] = (cf_t)+[](cdims_t d) { return new UShortArrayConverter{d}; }; + gf["int ptr"] = (cf_t)+[](cdims_t d) { return new IntArrayConverter{d}; }; +diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/DeclareConverters.h b/bindings/pyroot/cppyy/CPyCppyy/src/DeclareConverters.h +index b3a4246045..71011ce6b5 100644 +--- a/bindings/pyroot/cppyy/CPyCppyy/src/DeclareConverters.h ++++ b/bindings/pyroot/cppyy/CPyCppyy/src/DeclareConverters.h +@@ -87,7 +87,11 @@ CPPYY_DECLARE_BASIC_CONVERTER(WChar); + CPPYY_DECLARE_BASIC_CONVERTER(Char16); + CPPYY_DECLARE_BASIC_CONVERTER(Char32); + CPPYY_DECLARE_BASIC_CONVERTER(Int8); ++CPPYY_DECLARE_BASIC_CONVERTER(Int16); ++CPPYY_DECLARE_BASIC_CONVERTER(Int32); + CPPYY_DECLARE_BASIC_CONVERTER(UInt8); ++CPPYY_DECLARE_BASIC_CONVERTER(UInt16); ++CPPYY_DECLARE_BASIC_CONVERTER(UInt32); + CPPYY_DECLARE_BASIC_CONVERTER(Short); + CPPYY_DECLARE_BASIC_CONVERTER(UShort); + CPPYY_DECLARE_BASIC_CONVERTER(Int); +@@ -107,7 +111,11 @@ CPPYY_DECLARE_REFCONVERTER(Char32); + CPPYY_DECLARE_REFCONVERTER(SChar); + CPPYY_DECLARE_REFCONVERTER(UChar); + CPPYY_DECLARE_REFCONVERTER(Int8); ++CPPYY_DECLARE_REFCONVERTER(Int16); ++CPPYY_DECLARE_REFCONVERTER(Int32); + CPPYY_DECLARE_REFCONVERTER(UInt8); ++CPPYY_DECLARE_REFCONVERTER(UInt16); ++CPPYY_DECLARE_REFCONVERTER(UInt32); + CPPYY_DECLARE_REFCONVERTER(Short); + CPPYY_DECLARE_REFCONVERTER(UShort); + CPPYY_DECLARE_REFCONVERTER(UInt); +@@ -214,7 +222,11 @@ CPPYY_DECLARE_ARRAY_CONVERTER(UChar); + CPPYY_DECLARE_ARRAY_CONVERTER(Byte); + #endif + CPPYY_DECLARE_ARRAY_CONVERTER(Int8); ++CPPYY_DECLARE_ARRAY_CONVERTER(Int16); ++CPPYY_DECLARE_ARRAY_CONVERTER(Int32); + CPPYY_DECLARE_ARRAY_CONVERTER(UInt8); ++CPPYY_DECLARE_ARRAY_CONVERTER(UInt16); ++CPPYY_DECLARE_ARRAY_CONVERTER(UInt32); + CPPYY_DECLARE_ARRAY_CONVERTER(Short); + CPPYY_DECLARE_ARRAY_CONVERTER(UShort); + CPPYY_DECLARE_ARRAY_CONVERTER(Int); +diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.cxx +index c3f8aaf51f..3b0d48e9f1 100644 +--- a/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.cxx ++++ b/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.cxx +@@ -1200,3 +1200,43 @@ PyObject* CPyCppyy::CreateLowLevelView_i8(uint8_t** address, cdims_t shape) { + LowLevelView* ll = CreateLowLevelViewT(address, shape, "B", "uint8_t"); + CPPYY_RET_W_CREATOR(uint8_t**, CreateLowLevelView_i8); + } ++ ++PyObject* CPyCppyy::CreateLowLevelView_i16(int16_t* address, cdims_t shape) { ++ LowLevelView* ll = CreateLowLevelViewT(address, shape, "h", "int16_t"); ++ CPPYY_RET_W_CREATOR(int16_t*, CreateLowLevelView_i16); ++} ++ ++PyObject* CPyCppyy::CreateLowLevelView_i16(int16_t** address, cdims_t shape) { ++ LowLevelView* ll = CreateLowLevelViewT(address, shape, "h", "int16_t"); ++ CPPYY_RET_W_CREATOR(int16_t**, CreateLowLevelView_i16); ++} ++ ++PyObject* CPyCppyy::CreateLowLevelView_i16(uint16_t* address, cdims_t shape) { ++ LowLevelView* ll = CreateLowLevelViewT(address, shape, "H", "uint16_t"); ++ CPPYY_RET_W_CREATOR(uint16_t*, CreateLowLevelView_i16); ++} ++ ++PyObject* CPyCppyy::CreateLowLevelView_i16(uint16_t** address, cdims_t shape) { ++ LowLevelView* ll = CreateLowLevelViewT(address, shape, "H", "uint16_t"); ++ CPPYY_RET_W_CREATOR(uint16_t**, CreateLowLevelView_i16); ++} ++ ++PyObject* CPyCppyy::CreateLowLevelView_i32(int32_t* address, cdims_t shape) { ++ LowLevelView* ll = CreateLowLevelViewT(address, shape, "i", "int32_t"); ++ CPPYY_RET_W_CREATOR(int32_t*, CreateLowLevelView_i32); ++} ++ ++PyObject* CPyCppyy::CreateLowLevelView_i32(int32_t** address, cdims_t shape) { ++ LowLevelView* ll = CreateLowLevelViewT(address, shape, "i", "int32_t"); ++ CPPYY_RET_W_CREATOR(int32_t**, CreateLowLevelView_i32); ++} ++ ++PyObject* CPyCppyy::CreateLowLevelView_i32(uint32_t* address, cdims_t shape) { ++ LowLevelView* ll = CreateLowLevelViewT(address, shape, "I", "uint32_t"); ++ CPPYY_RET_W_CREATOR(uint32_t*, CreateLowLevelView_i32); ++} ++ ++PyObject* CPyCppyy::CreateLowLevelView_i32(uint32_t** address, cdims_t shape) { ++ LowLevelView* ll = CreateLowLevelViewT(address, shape, "I", "uint32_t"); ++ CPPYY_RET_W_CREATOR(uint32_t**, CreateLowLevelView_i32); ++} +diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.h b/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.h +index 4186ea0931..811af69e27 100644 +--- a/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.h ++++ b/bindings/pyroot/cppyy/CPyCppyy/src/LowLevelViews.h +@@ -56,6 +56,15 @@ PyObject* CreateLowLevelView_i8(int8_t*, cdims_t shape); + PyObject* CreateLowLevelView_i8(int8_t**, cdims_t shape); + PyObject* CreateLowLevelView_i8(uint8_t*, cdims_t shape); + PyObject* CreateLowLevelView_i8(uint8_t**, cdims_t shape); ++PyObject* CreateLowLevelView_i16(int16_t*, cdims_t shape); ++PyObject* CreateLowLevelView_i16(int16_t**, cdims_t shape); ++PyObject* CreateLowLevelView_i16(uint16_t*, cdims_t shape); ++PyObject* CreateLowLevelView_i16(uint16_t**, cdims_t shape); ++PyObject* CreateLowLevelView_i32(int32_t*, cdims_t shape); ++PyObject* CreateLowLevelView_i32(int32_t**, cdims_t shape); ++PyObject* CreateLowLevelView_i32(uint32_t*, cdims_t shape); ++PyObject* CreateLowLevelView_i32(uint32_t**, cdims_t shape); ++ + CPPYY_DECL_VIEW_CREATOR(short); + CPPYY_DECL_VIEW_CREATOR(unsigned short); + CPPYY_DECL_VIEW_CREATOR(int); +-- +2.43.0 + diff --git a/bindings/pyroot/pythonizations/test/CMakeLists.txt b/bindings/pyroot/pythonizations/test/CMakeLists.txt index 919c39de29290..91d664168d411 100644 --- a/bindings/pyroot/pythonizations/test/CMakeLists.txt +++ b/bindings/pyroot/pythonizations/test/CMakeLists.txt @@ -20,6 +20,7 @@ ROOT_ADD_PYUNITTEST(pyroot_pyz_decorator pythonization_decorator.py) # General pythonizations ROOT_ADD_PYUNITTEST(pyroot_pyz_pretty_printing pretty_printing.py) ROOT_ADD_PYUNITTEST(pyroot_pyz_array_interface array_interface.py PYTHON_DEPS numpy) +ROOT_ADD_PYUNITTEST(pyroot_numpy_views array_conversions.py PYTHON_DEPS numpy) ROOT_ADD_PYUNITTEST(uhi_plotting uhi_plotting.py GENERIC PYTHON_DEPS uhi numpy) ROOT_ADD_PYUNITTEST(uhi_indexing uhi_indexing.py GENERIC PYTHON_DEPS uhi numpy) diff --git a/bindings/pyroot/pythonizations/test/array_conversions.py b/bindings/pyroot/pythonizations/test/array_conversions.py new file mode 100644 index 0000000000000..947a30f751b30 --- /dev/null +++ b/bindings/pyroot/pythonizations/test/array_conversions.py @@ -0,0 +1,137 @@ +import unittest + +import numpy as np +import ROOT + + +class NumpyArrayView(unittest.TestCase): + """ + Test the conversion of interpreter-defined C++ arrays into numpy views + """ + + # typemaps based on https://numpy.org/doc/stable/reference/arrays.scalars.html + cpp_dtypes = [ + "char", + "unsigned char", + "int", + "unsigned int", + "short", + "unsigned short", + "float", + "int8_t", + "uint8_t", + "int16_t", + "uint16_t", + "int32_t", + "uint32_t", + ] + + np_dtypes = [ + np.byte, + np.ubyte, + np.intc, + np.uintc, + np.short, + np.ushort, + np.float32, + np.int8, + np.uint8, + np.int16, + np.uint16, + np.int32, + np.uint32, + ] + + typemap = zip(np_dtypes, cpp_dtypes) + + bounds = { + "char": (-128, 127), + "unsigned char": (0, 255), + "int": (-(2**31), 2**31 - 1), + "unsigned int": (0, 2**32 - 1), + "short": (-(2**15), 2**15 - 1), + "unsigned short": (0, 2**16 - 1), + # FIXME : low level views for 64 bit types (long and double) do not work, upstream interprets the converter with dims = 0, + # which somehow makes this work, however this needs to be investigated further. + "long": (-(2**31), 2**31 - 1), + "long long": (-(2**62), 2**62 - 1), + "unsigned long": (0, 2**32 - 1), + "unsigned long long": (0, 2**64 - 1), + "float": (-3.4e38, 3.4e38), + "double": (-1.7e308, 1.7e308), + "int8_t": (-128, 127), + "uint8_t": (0, 255), + "int16_t": (-(2**15), 2**15 - 1), + "uint16_t": (0, 2**16 - 1), + "int32_t": (-(2**31), 2**31 - 1), + "uint32_t": (0, 2**32 - 1), + } + + def generate_cpp_arrays(self, dtype_cpp): + mn, mx = self.bounds[dtype_cpp] + # sanitize a name for the struct so there's no spaces + tag = dtype_cpp.replace(" ", "_").replace("unsigned_", "u") + + cpp = f""" + struct Foo_{tag} {{ + {dtype_cpp} bar[11][2] = {{}}; + }}; + Foo_{tag} foo_{tag}; + foo_{tag}.bar[0][0] = {mn}; + foo_{tag}.bar[1][1] = {mx}; + foo_{tag}.bar[2][0] = {mn}; + foo_{tag}.bar[3][1] = {mx}; + foo_{tag}.bar[4][0] = {mn}; + foo_{tag}.bar[5][1] = {mx}; + foo_{tag}.bar[6][0] = {mn}; + foo_{tag}.bar[7][1] = {mx}; + foo_{tag}.bar[8][0] = {mn}; + foo_{tag}.bar[9][1] = {mx}; + foo_{tag}.bar[10][0] = {mn}; + """ + ROOT.gInterpreter.ProcessLine(cpp) + return getattr(ROOT, f"foo_{tag}").bar + + def check_shape(self, cpp_arr, np_obj): + self.assertEqual(cpp_arr.shape, np_obj.shape) + + def validate_numpy_view(self, np_obj, dtype): + # obtain bounds for C++ builtins + mn, mx = self.bounds[dtype[1]] + kind = dtype[0] + + if issubclass(kind, np.integer): + cast = int + elif issubclass(kind, np.floating): + + def cast(v): + return float(f"{v:.2e}") + + for i, row in enumerate(np_obj[:11]): + # we check col 0 for even i, 1 for odd i, as the array was filled that way + col = i & 1 + val = cast(row[col]) + + # the expected bound is min for col 0 and max for col 1 + expected = mn if col == 0 else mx + self.assertEqual(val, expected) + + def test_2DArray_NumpyView(self): + """ + Test correct numpy view for different C++ builtin-type 2D arrays + """ + for dtype in self.typemap: + cpp_arr = self.generate_cpp_arrays(dtype[1]) + try: + np_obj = np.frombuffer(cpp_arr, dtype[0], count=11 * 2).reshape(11, 2) + except ValueError: + print(f"numpy frombuffer failed with types {dtype}") + a = np.dtype(dtype[0]).itemsize + ROOT.gInterpreter.Declare(f"size_t sz = sizeof({dtype[1]});") + print(f"Numpy size: {a}, C++ size: {ROOT.sz}") + self.check_shape(cpp_arr, np_obj) + self.validate_numpy_view(np_obj, dtype) + + +if __name__ == "__main__": + unittest.main()