diff --git a/cpp/csp/python/CMakeLists.txt b/cpp/csp/python/CMakeLists.txt index 45f265534..13f934f12 100644 --- a/cpp/csp/python/CMakeLists.txt +++ b/cpp/csp/python/CMakeLists.txt @@ -3,7 +3,8 @@ set(CSPTYPESIMPL_PUBLIC_HEADERS CspTypeFactory.h PyCspEnum.h PyCspType.h - PyStruct.h) + PyStruct.h + PyStructList.h) add_library(csptypesimpl csptypesimpl.cpp @@ -11,7 +12,8 @@ add_library(csptypesimpl PyCspEnum.cpp PyCspType.cpp PyStruct.cpp - PyStructToJson.cpp) + PyStructToJson.cpp + PyStructList.hi) set_target_properties(csptypesimpl PROPERTIES PUBLIC_HEADER "${CSPTYPESIMPL_PUBLIC_HEADERS}") target_compile_definitions(csptypesimpl PUBLIC RAPIDJSON_HAS_STDSTRING=1) target_link_libraries(csptypesimpl csp_core csp_types) @@ -39,7 +41,8 @@ set(CSPIMPL_PUBLIC_HEADERS PyOutputAdapterWrapper.h PyOutputProxy.h PyConstants.h - PyStructToJson.h) + PyStructToJson.h + PyStructList.h) add_library(cspimpl SHARED cspimpl.cpp @@ -70,6 +73,7 @@ add_library(cspimpl SHARED PyManagedSimInputAdapter.cpp PyTimerAdapter.cpp PyConstants.cpp + PyStructList.hi ${CSPIMPL_PUBLIC_HEADERS}) set_target_properties(cspimpl PROPERTIES PUBLIC_HEADER "${CSPIMPL_PUBLIC_HEADERS}") diff --git a/cpp/csp/python/Conversions.h b/cpp/csp/python/Conversions.h index 891bfe3f6..31d473be9 100644 --- a/cpp/csp/python/Conversions.h +++ b/cpp/csp/python/Conversions.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -762,6 +763,29 @@ inline PyObject * toPython( const std::vector & v, const CspType & typ return list.release(); } +template +inline PyObject * toPython( const std::vector & v, const CspType & type, const PyStruct * pystruct ) +{ + assert( type.type() == CspType::Type::ARRAY ); + + const CspTypePtr elemType = static_cast( type ).elemType(); + using ElemT = typename CspType::Type::toCArrayElemType::type; + size_t sz = v.size(); + + // TODO: Implement more efficient list allocation by pre-allocating the space and filling it using PyList_SET_ITEM. + // As of now, the problem is that Python is not allowing to resize the list via API, and it cannot allocate the list at the base of PyStructList, it can only allocate it somewhere in memory not under control. + PyObject * psl = PyStructList::PyType.tp_alloc( &PyStructList::PyType, 0 ); + new ( psl ) PyStructList( const_cast( pystruct ), const_cast &>( v ), *elemType ); + + for( size_t index = 0; index < sz; ++index ) + { + PyObjectPtr element = PyObjectPtr::own( toPython( v[ index ], *elemType ) ); + PyList_Append( ( PyObject * ) psl, element.get() ); + } + + return psl; +} + template struct FromPython> { diff --git a/cpp/csp/python/InitHelper.h b/cpp/csp/python/InitHelper.h index 3023919ec..5df1ed956 100644 --- a/cpp/csp/python/InitHelper.h +++ b/cpp/csp/python/InitHelper.h @@ -20,7 +20,7 @@ class __attribute__ ((visibility ("hidden"))) InitHelper bool registerCallback( InitCallback cb ); - static InitCallback typeInitCallback( PyTypeObject * pyType, std::string name ); + static InitCallback typeInitCallback( PyTypeObject * pyType, std::string name, PyTypeObject * baseType = nullptr ); static InitCallback moduleMethodsCallback( PyMethodDef * methods ); static InitCallback moduleMethod( const char * name, PyCFunction func, int flags, const char * doc ); @@ -50,9 +50,11 @@ inline InitHelper & InitHelper::instance() return s_instance; } -inline InitHelper::InitCallback InitHelper::typeInitCallback( PyTypeObject * pyType, std::string name ) +inline InitHelper::InitCallback InitHelper::typeInitCallback( PyTypeObject * pyType, std::string name, PyTypeObject * baseType ) { - InitCallback cb = [pyType,name]( PyObject * module ) { + InitCallback cb = [pyType,name,baseType]( PyObject * module ) { + if( baseType ) + pyType -> tp_base = baseType; if( PyType_Ready( pyType ) < 0 ) return false; diff --git a/cpp/csp/python/PyStruct.cpp b/cpp/csp/python/PyStruct.cpp index 4e5f031de..ccb821311 100644 --- a/cpp/csp/python/PyStruct.cpp +++ b/cpp/csp/python/PyStruct.cpp @@ -3,8 +3,8 @@ #include #include #include +#include #include - #include #include @@ -395,8 +395,10 @@ PyTypeObject PyStructMeta::PyType = { //PyStruct -PyObject * getattr_( const StructField* field, const Struct * struct_ ) +PyObject * getattr_( const StructField * field, const Struct * struct_ ) { + assert( field -> type() -> type() != CspType::Type::ARRAY ); + PyObject *v = switchCspType( field -> type(), [ field, struct_ ]( auto tag ) { using CType = typename decltype(tag)::type; @@ -407,6 +409,21 @@ PyObject * getattr_( const StructField* field, const Struct * struct_ ) return v; } +PyObject * getarrayattr_( const StructField * field, const PyStruct * pystruct ) +{ + assert( field -> type() -> type() == CspType::Type::ARRAY ); + + const CspArrayType * arrayType = static_cast( field -> type().get() ); + PyObject *v = ArraySubTypeSwitch::invoke( arrayType -> elemType(), [ field, pystruct ]( auto tag ) + { + using StorageT = typename CspType::Type::toCArrayStorageType::type; + using ArrayT = typename StructField::upcast>::type; + auto * typedField = static_cast( field ); + return toPython( typedField -> value( pystruct -> struct_.get() ), *field -> type(), pystruct ); + } ); + return v; +} + PyObject * PyStruct::getattr( PyObject * attr ) { auto * field = structMeta() -> field( attr ); @@ -424,7 +441,9 @@ PyObject * PyStruct::getattr( PyObject * attr ) return nullptr; } - return getattr_( field, ( const Struct *)struct_.get() ); + if( field -> type() -> type() == CspType::Type::ARRAY ) + return getarrayattr_( field, this ); + return getattr_( field, ( const Struct * ) struct_.get() ); } void PyStruct::setattr( Struct * s, PyObject * attr, PyObject * value ) @@ -997,4 +1016,24 @@ PyTypeObject PyStruct::PyType = { REGISTER_TYPE_INIT( &PyStructMeta::PyType, "PyStructMeta" ) REGISTER_TYPE_INIT( &PyStruct::PyType, "PyStruct" ) +// Instantiate all templates for PyStructList class +template struct PyStructList; +template struct PyStructList; +template struct PyStructList; +template struct PyStructList; +template struct PyStructList; +template struct PyStructList; +template struct PyStructList; +template struct PyStructList; +template struct PyStructList; +template struct PyStructList; +template struct PyStructList; +template struct PyStructList; +template struct PyStructList; +template struct PyStructList