diff options
Diffstat (limited to 'sources/shiboken2/libshiboken')
-rw-r--r-- | sources/shiboken2/libshiboken/CMakeLists.txt | 44 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/basewrapper.cpp | 43 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/basewrapper.h | 22 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/bindingmanager.cpp | 9 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkarrayconverter.cpp | 289 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkarrayconverter.h | 171 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkarrayconverter_p.h | 62 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkconverter.cpp | 25 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkconverter.h | 3 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkconverter_p.h | 9 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkenum.cpp | 13 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkenum.h | 2 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkmodule.cpp | 19 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbknumpyarrayconverter.cpp | 308 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/shiboken.h | 1 |
15 files changed, 921 insertions, 99 deletions
diff --git a/sources/shiboken2/libshiboken/CMakeLists.txt b/sources/shiboken2/libshiboken/CMakeLists.txt index 6e725e6af..e87cf07fd 100644 --- a/sources/shiboken2/libshiboken/CMakeLists.txt +++ b/sources/shiboken2/libshiboken/CMakeLists.txt @@ -1,5 +1,22 @@ project(libshiboken) +macro(get_numpy_location) + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "if True: + import sys + import os + numpy = '' + for p in sys.path: + if 'site-' in p: + numpy = os.path.join(p, 'numpy') + if os.path.exists(numpy): + print(os.path.realpath(numpy)) + break" + OUTPUT_VARIABLE PYTHON_NUMPY_LOCATION + OUTPUT_STRIP_TRAILING_WHITESPACE) + message("PYTHON_NUMPY_LOCATION: " ${PYTHON_NUMPY_LOCATION}) +endmacro() + option(ENABLE_VERSION_SUFFIX "Used to use current version in suffix to generated files. This is used to allow multiples versions installed simultaneous." FALSE) if(ENABLE_VERSION_SUFFIX) set(shiboken2_SUFFIX "-${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}") @@ -10,14 +27,6 @@ endif() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sbkversion.h.in" "${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h" @ONLY) -#Find installed sparsehash -find_path(SPARSEHASH_INCLUDE_PATH sparseconfig.h PATH_SUFFIXES "/google/sparsehash") -if(SPARSEHASH_INCLUDE_PATH) - message(STATUS "Using system hash found in: ${SPARSEHASH_INCLUDE_PATH}") -else() - set(SPARSEHASH_INCLUDE_PATH ${CMAKE_SOURCE_DIR}/ext/sparsehash) -endif() - set(libshiboken_MAJOR_VERSION ${shiboken_MAJOR_VERSION}) set(libshiboken_MINOR_VERSION ${shiboken_MINOR_VERSION}) set(libshiboken_MICRO_VERSION ${shiboken_MICRO_VERSION}) @@ -29,6 +38,7 @@ basewrapper.cpp debugfreehook.cpp gilstate.cpp helper.cpp +sbkarrayconverter.cpp sbkconverter.cpp sbkenum.cpp sbkmodule.cpp @@ -41,10 +51,19 @@ qapp_macro.cpp voidptr.cpp ) -include_directories(${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${SBK_PYTHON_INCLUDE_DIR} - ${SPARSEHASH_INCLUDE_PATH}) +get_numpy_location() + +set(libshiboken_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${SBK_PYTHON_INCLUDE_DIR}) + +if (NOT "${PYTHON_NUMPY_LOCATION}" STREQUAL "") + set(libshiboken_INCLUDES ${libshiboken_INCLUDES} ${PYTHON_NUMPY_LOCATION}/core/include) + set(libshiboken_SRC ${libshiboken_SRC} sbknumpyarrayconverter.cpp) + add_definitions(-DHAVE_NUMPY -DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION) +endif() + +set(APIEXTRACTOR_EXTRA_INCLUDES ${APIEXTRACTOR_EXTRA_INCLUDES} ${LIBXSLT_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR}) + +include_directories(${libshiboken_INCLUDES}) add_library(libshiboken SHARED ${libshiboken_SRC}) target_link_libraries(libshiboken ${SBK_PYTHON_LIBRARIES}) set_target_properties(libshiboken PROPERTIES OUTPUT_NAME "shiboken2${shiboken2_SUFFIX}${PYTHON_SHARED_LIBRARY_SUFFIX}" @@ -58,6 +77,7 @@ install(FILES bindingmanager.h gilstate.h helper.h + sbkarrayconverter.h sbkconverter.h sbkenum.h sbkmodule.h diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp index 270a5df94..d7d37971c 100644 --- a/sources/shiboken2/libshiboken/basewrapper.cpp +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -542,7 +542,6 @@ void DeallocVisitor::done() DtorCallerVisitor::done(); } -namespace Module { void init(); } namespace Conversions { void init(); } void init() @@ -551,7 +550,6 @@ void init() if (shibokenAlreadInitialised) return; - Module::init(); Conversions::init(); PyEval_InitThreads(); @@ -681,14 +679,6 @@ bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType) return true; } - -bool hasExternalCppConversions(SbkObjectType*) { return false; } // DEPRECATED. -bool isExternalConvertible(SbkObjectType *, PyObject *) { return false; } // DEPRECATED. -void setExternalCppConversionFunction(SbkObjectType*, ExtendedToCppFunc) {} // DEPRECATED. -void setExternalIsConvertibleFunction(SbkObjectType*, ExtendedIsConvertibleFunc) {} // DEPRECATED. -void* callExternalCppConversion(SbkObjectType*, PyObject*) { return 0; } // DEPRECATED. - - bool hasCast(SbkObjectType* type) { return type->d->mi_specialcast != 0; @@ -721,18 +711,6 @@ void setTypeDiscoveryFunctionV2(SbkObjectType* self, TypeDiscoveryFuncV2 func) self->d->type_discovery = func; } -void setTypeDiscoveryFunction(SbkObjectType* self, TypeDiscoveryFunc func) -{ - self->d->type_discovery = (TypeDiscoveryFuncV2)func; -} - -TypeDiscoveryFunc getTypeDiscoveryFunction(SbkObjectType* self) -{ - // This is an illegal cast because the return value is different, - // but nobody ever used this function, so... =] - return (TypeDiscoveryFunc)self->d->type_discovery; -} - void copyMultimpleheritance(SbkObjectType* self, SbkObjectType* other) { self->d->mi_init = other->d->mi_init; @@ -840,13 +818,15 @@ Py_hash_t hash(PyObject* pyObj) static void setSequenceOwnership(PyObject* pyObj, bool owner) { if (PySequence_Check(pyObj)) { - std::list<SbkObject*> objs = splitPyObject(pyObj); - std::list<SbkObject*>::const_iterator it = objs.begin(); - for(; it != objs.end(); ++it) { - if (owner) - getOwnership(*it); - else - releaseOwnership(*it); + Py_ssize_t size = PySequence_Size(pyObj); + if (size > 0) { + std::list<SbkObject*> objs = splitPyObject(pyObj); + for (auto it = objs.begin(), end = objs.end(); it != end; ++it) { + if (owner) + getOwnership(*it); + else + releaseOwnership(*it); + } } } else if (Object::checkType(pyObj)) { if (owner) @@ -1053,11 +1033,6 @@ void makeValid(SbkObject* self) } } -bool hasParentInfo(SbkObject* pyObj) -{ - return pyObj->d->parentInfo != 0; -} - void* cppPointer(SbkObject* pyObj, PyTypeObject* desiredType) { PyTypeObject* type = Py_TYPE(pyObj); diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h index bd2d6820f..f6a7352f7 100644 --- a/sources/shiboken2/libshiboken/basewrapper.h +++ b/sources/shiboken2/libshiboken/basewrapper.h @@ -151,14 +151,6 @@ LIBSHIBOKEN_API bool isUserType(PyTypeObject* pyObj); */ LIBSHIBOKEN_API bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType); - -LIBSHIBOKEN_API bool hasExternalCppConversions(SbkObjectType*); // DEPRECATED. -LIBSHIBOKEN_API bool isExternalConvertible(SbkObjectType*, PyObject*); // DEPRECATED. -LIBSHIBOKEN_API void setExternalCppConversionFunction(SbkObjectType*, ExtendedToCppFunc); // DEPRECATED. -LIBSHIBOKEN_API void setExternalIsConvertibleFunction(SbkObjectType*, ExtendedIsConvertibleFunc); // DEPRECATED. -LIBSHIBOKEN_API void* callExternalCppConversion(SbkObjectType*, PyObject*); // DEPRECATED. - - /** * Tells if the \p type represents an object of a class with multiple inheritance in C++. * When this occurs, the C++ pointer held by the Python wrapper will need to be cast when @@ -180,9 +172,6 @@ LIBSHIBOKEN_API void setOriginalName(SbkObjectType* self, const char* nam LIBSHIBOKEN_API const char* getOriginalName(SbkObjectType* self); LIBSHIBOKEN_API void setTypeDiscoveryFunctionV2(SbkObjectType* self, TypeDiscoveryFuncV2 func); -LIBSHIBOKEN_API SBK_DEPRECATED(void setTypeDiscoveryFunction(SbkObjectType* self, TypeDiscoveryFunc func)); -LIBSHIBOKEN_API SBK_DEPRECATED(TypeDiscoveryFunc getTypeDiscoveryFunction(SbkObjectType* self)); - LIBSHIBOKEN_API void copyMultimpleheritance(SbkObjectType* self, SbkObjectType* other); LIBSHIBOKEN_API void setMultipleIheritanceFunction(SbkObjectType* self, MultipleInheritanceInitFunction func); LIBSHIBOKEN_API MultipleInheritanceInitFunction getMultipleIheritanceFunction(SbkObjectType* self); @@ -333,11 +322,6 @@ LIBSHIBOKEN_API void releaseOwnership(PyObject* pyObj); LIBSHIBOKEN_API void releaseOwnership(SbkObject* pyObj); /** - * Returns true if the pyObj holds information about their parents. - */ -LIBSHIBOKEN_API bool hasParentInfo(SbkObject* pyObj); - -/** * Get the C++ pointer of type \p desiredType from a Python object. */ LIBSHIBOKEN_API void* cppPointer(SbkObject* pyObj, PyTypeObject* desiredType); @@ -387,12 +371,6 @@ LIBSHIBOKEN_API void setParent(PyObject* parent, PyObject* child); LIBSHIBOKEN_API void removeParent(SbkObject* child, bool giveOwnershipBack = true, bool keepReferenc = false); /** -* \internal This is an internal function called by tp_dealloc, it's exported just for technical reasons. -* \note Do not call this function inside your bindings. -*/ -LIBSHIBOKEN_API void destroyParentInfo(SbkObject* obj, bool removeFromParent = true); - -/** * Mark the object as invalid */ LIBSHIBOKEN_API void invalidate(SbkObject* self); diff --git a/sources/shiboken2/libshiboken/bindingmanager.cpp b/sources/shiboken2/libshiboken/bindingmanager.cpp index d7e122cd7..3308ef972 100644 --- a/sources/shiboken2/libshiboken/bindingmanager.cpp +++ b/sources/shiboken2/libshiboken/bindingmanager.cpp @@ -40,7 +40,6 @@ #include "basewrapper.h" #include "basewrapper_p.h" #include "bindingmanager.h" -#include "google/dense_hash_map" #include "sbkdbg.h" #include "gilstate.h" #include "sbkstring.h" @@ -48,23 +47,23 @@ #include <cstddef> #include <fstream> +#include <unordered_map> namespace Shiboken { -typedef google::dense_hash_map<const void*, SbkObject*> WrapperMap; +typedef std::unordered_map<const void *, SbkObject *> WrapperMap; class Graph { public: typedef std::list<SbkObjectType*> NodeList; - typedef google::dense_hash_map<SbkObjectType*, NodeList> Edges; + typedef std::unordered_map<SbkObjectType *, NodeList> Edges; Edges m_edges; Graph() { - m_edges.set_empty_key(0); } void addEdge(SbkObjectType* from, SbkObjectType* to) @@ -172,8 +171,6 @@ void BindingManager::BindingManagerPrivate::assignWrapper(SbkObject* wrapper, co BindingManager::BindingManager() { m_d = new BindingManager::BindingManagerPrivate; - m_d->wrapperMapper.set_empty_key((WrapperMap::key_type)0); - m_d->wrapperMapper.set_deleted_key((WrapperMap::key_type)1); #ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK debugInstallFreeHook(); diff --git a/sources/shiboken2/libshiboken/sbkarrayconverter.cpp b/sources/shiboken2/libshiboken/sbkarrayconverter.cpp new file mode 100644 index 000000000..c22015709 --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkarrayconverter.cpp @@ -0,0 +1,289 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "sbkarrayconverter.h" +#include "sbkarrayconverter_p.h" +#include "helper.h" +#include "sbkconverter.h" +#include "sbkconverter_p.h" + +#include <longobject.h> +#include <floatobject.h> + +#include <algorithm> + +static SbkArrayConverter *ArrayTypeConverters[Shiboken::Conversions::SBK_ARRAY_IDX_SIZE] [2] = {}; + +namespace Shiboken { +namespace Conversions { + +// Check whether Predicate is true for all elements of a sequence +template <class Predicate> +static bool sequenceAllOf(PyObject *pyIn, Predicate p) +{ + const Py_ssize_t size = PySequence_Size(pyIn); + for (Py_ssize_t i = 0; i < size; ++i) { + PyObject *item = PySequence_GetItem(pyIn, i); + const bool ok = p(item); + Py_XDECREF(item); + if (!ok) + return false; + } + return true; +} + +// Convert a sequence to output iterator +template <class T, class Converter> +inline void convertPySequence(PyObject *pyIn, Converter c, T *out) +{ + const Py_ssize_t size = PySequence_Size(pyIn); + for (Py_ssize_t i = 0; i < size; ++i) { + PyObject *item = PySequence_GetItem(pyIn, i); + *out++ = c(item); + Py_XDECREF(item); + } +} + +// Internal, for usage by numpy +SbkArrayConverter *createArrayConverter(IsArrayConvertibleToCppFunc toCppCheckFunc) +{ + SbkArrayConverter *result = new SbkArrayConverter; + result->toCppConversions.push_back(toCppCheckFunc); + return result; +} + +static PythonToCppFunc unimplementedArrayCheck(PyObject *, int, int) +{ + warning(PyExc_RuntimeWarning, 0, "SbkConverter: Unimplemented C++ array type."); + return nullptr; +} + +SbkArrayConverter *unimplementedArrayConverter() +{ + static SbkArrayConverter *result = createArrayConverter(unimplementedArrayCheck); + return result; +} + +// Integers + +static inline bool intCheck(PyObject *pyIn) +{ +#ifdef IS_PY3K + return PyLong_Check(pyIn); +#else + return PyInt_Check(pyIn); +#endif +} + +static short toShort(PyObject *pyIn) { return short(PyLong_AsLong(pyIn)); } + +static void sequenceToCppShortArray(PyObject *pyIn, void *cppOut) +{ + ArrayHandle<short> *handle = reinterpret_cast<ArrayHandle<short> *>(cppOut); + handle->allocate(PySequence_Size(pyIn)); + convertPySequence(pyIn, toShort, handle->data()); +} + +static inline bool sequenceSizeCheck(PyObject *pyIn, int expectedSize = -1) +{ + if (expectedSize >= 0) { + const int size = int(PySequence_Size(pyIn)); + if (size < expectedSize) { + warning(PyExc_RuntimeWarning, 0, "A sequence of size %d was passed to a function that expects %d.", + size, expectedSize); + return false; + } + } + return true; +} + +static inline bool intArrayCheck(PyObject *pyIn, int expectedSize = -1) +{ + return PySequence_Check(pyIn) && sequenceAllOf(pyIn, intCheck) + && sequenceSizeCheck(pyIn, expectedSize); +} + +static PythonToCppFunc sequenceToCppShortArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */) +{ + return intArrayCheck(pyIn, dim1) ? sequenceToCppShortArray : nullptr; +} + +static short toUnsignedShort(PyObject *pyIn) { return static_cast<unsigned short>(PyLong_AsUnsignedLong(pyIn)); } + +static void sequenceToCppUnsignedShortArray(PyObject *pyIn, void *cppOut) +{ + ArrayHandle<unsigned short> *handle = reinterpret_cast<ArrayHandle<unsigned short> *>(cppOut); + handle->allocate(PySequence_Size(pyIn)); + convertPySequence(pyIn, toUnsignedShort, handle->data()); +} + +static PythonToCppFunc sequenceToCppUnsignedShortArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */) +{ + return intArrayCheck(pyIn, dim1) ? sequenceToCppUnsignedShortArray : nullptr; +} + +static void sequenceToCppIntArray(PyObject *pyIn, void *cppOut) +{ + ArrayHandle<int> *handle = reinterpret_cast<ArrayHandle<int> *>(cppOut); + handle->allocate(PySequence_Size(pyIn)); + convertPySequence(pyIn, _PyLong_AsInt, handle->data()); +} + +static PythonToCppFunc sequenceToCppIntArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */) +{ + return intArrayCheck(pyIn, dim1) ? sequenceToCppIntArray : nullptr; +} + +static void sequenceToCppUnsignedArray(PyObject *pyIn, void *cppOut) +{ + ArrayHandle<unsigned> *handle = reinterpret_cast<ArrayHandle<unsigned> *>(cppOut); + handle->allocate(PySequence_Size(pyIn)); + convertPySequence(pyIn, PyLong_AsUnsignedLong, handle->data()); +} + +static PythonToCppFunc sequenceToCppUnsignedArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */) +{ + return intArrayCheck(pyIn, dim1) ? sequenceToCppUnsignedArray : nullptr; +} + +static void sequenceToCppLongLongArray(PyObject *pyIn, void *cppOut) +{ + ArrayHandle<long long> *handle = reinterpret_cast<ArrayHandle<long long> *>(cppOut); + handle->allocate(PySequence_Size(pyIn)); + convertPySequence(pyIn, PyLong_AsLongLong, handle->data()); +} + +static PythonToCppFunc sequenceToCppLongLongArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */) +{ + return intArrayCheck(pyIn, dim1) ? sequenceToCppLongLongArray : nullptr; +} + +static void sequenceToCppUnsignedLongLongArray(PyObject *pyIn, void *cppOut) +{ + ArrayHandle<unsigned long long> *handle = reinterpret_cast<ArrayHandle<unsigned long long> *>(cppOut); + handle->allocate(PySequence_Size(pyIn)); + convertPySequence(pyIn, PyLong_AsUnsignedLongLong, handle->data()); +} + +static PythonToCppFunc sequenceToCppUnsignedLongLongArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */) +{ + return intArrayCheck(pyIn, dim1) ? sequenceToCppUnsignedLongLongArray : nullptr; +} + +// Float + +static inline bool floatCheck(PyObject *pyIn) { return PyFloat_Check(pyIn); } + +static inline bool floatArrayCheck(PyObject *pyIn, int expectedSize = -1) +{ + return PySequence_Check(pyIn) && sequenceAllOf(pyIn, floatCheck) + && sequenceSizeCheck(pyIn, expectedSize); +} + +static void sequenceToCppDoubleArray(PyObject *pyIn, void *cppOut) +{ + ArrayHandle<double> *handle = reinterpret_cast<ArrayHandle<double> *>(cppOut); + handle->allocate(PySequence_Size(pyIn)); + convertPySequence(pyIn, PyFloat_AsDouble, handle->data()); +} + +static inline float pyToFloat(PyObject *pyIn) { return float(PyFloat_AsDouble(pyIn)); } + +static void sequenceToCppFloatArray(PyObject *pyIn, void *cppOut) +{ + ArrayHandle<float> *handle = reinterpret_cast<ArrayHandle<float> *>(cppOut); + handle->allocate(PySequence_Size(pyIn)); + convertPySequence(pyIn, pyToFloat, handle->data()); +} + +static PythonToCppFunc sequenceToCppFloatArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */) +{ + return floatArrayCheck(pyIn, dim1) ? sequenceToCppFloatArray : nullptr; +} + +static PythonToCppFunc sequenceToCppDoubleArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */) +{ + return floatArrayCheck(pyIn, dim1) ? sequenceToCppDoubleArray : nullptr; +} + +#ifdef HAVE_NUMPY +void initNumPyArrayConverters(); +#endif + +void initArrayConverters() +{ + SbkArrayConverter **start = &ArrayTypeConverters[0][0]; + std::fill(start, start + sizeof(ArrayTypeConverters) / sizeof(ArrayTypeConverters[0][0]), nullptr); + // Populate 1-dimensional sequence converters + ArrayTypeConverters[SBK_DOUBLE_ARRAY_IDX][0] = + createArrayConverter(sequenceToCppDoubleArrayCheck); + ArrayTypeConverters[SBK_FLOAT_ARRAY_IDX][0] = + createArrayConverter(sequenceToCppFloatArrayCheck); + ArrayTypeConverters[SBK_SHORT_ARRAY_IDX][0] = + createArrayConverter(sequenceToCppShortArrayCheck); + ArrayTypeConverters[SBK_UNSIGNEDSHORT_ARRAY_IDX][0] = + createArrayConverter(sequenceToCppUnsignedShortArrayCheck); + ArrayTypeConverters[SBK_INT_ARRAY_IDX][0] = + createArrayConverter(sequenceToCppIntArrayCheck); + ArrayTypeConverters[SBK_UNSIGNEDINT_ARRAY_IDX][0] = + createArrayConverter(sequenceToCppUnsignedArrayCheck); + ArrayTypeConverters[SBK_LONGLONG_ARRAY_IDX][0] = + createArrayConverter(sequenceToCppLongLongArrayCheck); + ArrayTypeConverters[SBK_UNSIGNEDLONGLONG_ARRAY_IDX][0] = + createArrayConverter(sequenceToCppUnsignedLongLongArrayCheck); + +#ifdef HAVE_NUMPY + initNumPyArrayConverters(); +#endif +} + +SbkArrayConverter *arrayTypeConverter(int index, int dimension) +{ + SbkArrayConverter *c = ArrayTypeConverters[index][dimension - 1]; + return c ? c : unimplementedArrayConverter(); +} + +// Internal, for usage by numpy +void setArrayTypeConverter(int index, int dimension, SbkArrayConverter *c) +{ + ArrayTypeConverters[index][dimension - 1] = c; +} + +} // namespace Conversions +} // namespace Shiboken diff --git a/sources/shiboken2/libshiboken/sbkarrayconverter.h b/sources/shiboken2/libshiboken/sbkarrayconverter.h new file mode 100644 index 000000000..f3d3e5f98 --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkarrayconverter.h @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SBKARRAYCONVERTERS_H +#define SBKARRAYCONVERTERS_H + +#include "sbkpython.h" +#include "shibokenmacros.h" + +extern "C" { +struct SbkArrayConverter; +} + +namespace Shiboken { +namespace Conversions { + +enum : int { + SBK_UNIMPLEMENTED_ARRAY_IDX, + SBK_DOUBLE_ARRAY_IDX, + SBK_FLOAT_ARRAY_IDX, + SBK_SHORT_ARRAY_IDX, + SBK_UNSIGNEDSHORT_ARRAY_IDX, + SBK_INT_ARRAY_IDX, + SBK_UNSIGNEDINT_ARRAY_IDX, + SBK_LONGLONG_ARRAY_IDX, + SBK_UNSIGNEDLONGLONG_ARRAY_IDX, + SBK_ARRAY_IDX_SIZE +}; + +/** + * ArrayHandle is the type expected by shiboken2's array converter + * functions. It provides access to array data which it may own + * (in the case of conversions from PySequence) or a flat pointer + * to internal data (in the case of array modules like numpy). + */ + +template <class T> +class ArrayHandle +{ + ArrayHandle(const ArrayHandle &) = delete; + ArrayHandle& operator=(const ArrayHandle &) = delete; +public: + ArrayHandle() {} + ~ArrayHandle() { destroy(); } + + void allocate(Py_ssize_t size); + void setData(T *d, size_t size); + + size_t size() const { return m_size; } + T *data() const { return m_data; } + operator T*() const { return m_data; } + +private: + void destroy(); + + T *m_data = nullptr; + Py_ssize_t m_size = 0; + bool m_owned = false; +}; + +/** + * Similar to ArrayHandle for fixed size 2 dimensional arrays. + * columns is the size of the last dimension + * It only has a setData() methods since it will be used for numpy only. + */ + +template <class T, int columns> +class Array2Handle +{ +public: + typedef T RowType[columns]; + + Array2Handle() {} + + operator RowType*() const { return m_rows; } + + void setData(RowType *d) { m_rows = d; } + +private: + RowType *m_rows = nullptr; +}; + +/// Returns the converter for an array type. +LIBSHIBOKEN_API SbkArrayConverter *arrayTypeConverter(int index, int dimension = 1); + +template <class T> +struct ArrayTypeIndex{ + enum : int { index = SBK_UNIMPLEMENTED_ARRAY_IDX }; +}; + +template <> struct ArrayTypeIndex<double> { enum : int { index = SBK_DOUBLE_ARRAY_IDX }; }; +template <> struct ArrayTypeIndex<float> { enum : int { index = SBK_FLOAT_ARRAY_IDX };}; +template <> struct ArrayTypeIndex<short> { enum : int { index = SBK_SHORT_ARRAY_IDX };}; +template <> struct ArrayTypeIndex<unsigned short> { enum : int { index = SBK_UNSIGNEDSHORT_ARRAY_IDX };}; +template <> struct ArrayTypeIndex<int> { enum : int { index = SBK_INT_ARRAY_IDX };}; +template <> struct ArrayTypeIndex<unsigned> { enum : int { index = SBK_UNSIGNEDINT_ARRAY_IDX };}; +template <> struct ArrayTypeIndex<long long> { enum : int { index = SBK_LONGLONG_ARRAY_IDX };}; +template <> struct ArrayTypeIndex<unsigned long long> { enum : int { index = SBK_UNSIGNEDLONGLONG_ARRAY_IDX };}; + +template<typename T> SbkArrayConverter *ArrayTypeConverter(int dimension) +{ return arrayTypeConverter(ArrayTypeIndex<T>::index, dimension); } + +// ArrayHandle methods +template<class T> +void ArrayHandle<T>::allocate(Py_ssize_t size) +{ + destroy(); + m_data = new T[size]; + m_size = size; + m_owned = true; +} + +template<class T> +void ArrayHandle<T>::setData(T *d, size_t size) +{ + destroy(); + m_data = d; + m_size = size; + m_owned = false; +} + +template<class T> +void ArrayHandle<T>::destroy() +{ + if (m_owned) + delete [] m_data; + m_data = nullptr; + m_size = 0; + m_owned = false; +} + +} // namespace Conversions +} // namespace Shiboken + +#endif // SBKARRAYCONVERTERS_H diff --git a/sources/shiboken2/libshiboken/sbkarrayconverter_p.h b/sources/shiboken2/libshiboken/sbkarrayconverter_p.h new file mode 100644 index 000000000..9384fbcf5 --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkarrayconverter_p.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SBKARRAYCONVERTER_P_H +#define SBKARRAYCONVERTER_P_H + +#include "sbkconverter_p.h" +#include <vector> + +extern "C" +{ + +typedef PythonToCppFunc (*IsArrayConvertibleToCppFunc)(PyObject*, int dim1, int dim2); +/** + * \internal + * Private structure of SbkArrayConverter. + */ + +struct SbkArrayConverter +{ + std::vector<IsArrayConvertibleToCppFunc> toCppConversions; +}; + +} // extern "C" + +#endif // SBKARRAYCONVERTER_P_H diff --git a/sources/shiboken2/libshiboken/sbkconverter.cpp b/sources/shiboken2/libshiboken/sbkconverter.cpp index 0949d803d..0e154da39 100644 --- a/sources/shiboken2/libshiboken/sbkconverter.cpp +++ b/sources/shiboken2/libshiboken/sbkconverter.cpp @@ -39,22 +39,26 @@ #include "sbkconverter.h" #include "sbkconverter_p.h" +#include "sbkarrayconverter_p.h" #include "basewrapper_p.h" #include "bindingmanager.h" -#include "google/dense_hash_map" #include "autodecref.h" #include "sbkdbg.h" #include "helper.h" #include "voidptr.h" +#include <unordered_map> + static SbkConverter** PrimitiveTypeConverters; -typedef google::dense_hash_map<std::string, SbkConverter*> ConvertersMap; +typedef std::unordered_map<std::string, SbkConverter *> ConvertersMap; static ConvertersMap converters; namespace Shiboken { namespace Conversions { +void initArrayConverters(); + void init() { static SbkConverter* primitiveTypeConverters[] = { @@ -79,8 +83,6 @@ void init() PrimitiveTypeConverters = primitiveTypeConverters; assert(converters.empty()); - converters.set_empty_key(""); - converters.set_deleted_key("?"); converters["PY_LONG_LONG"] = primitiveTypeConverters[SBK_PY_LONG_LONG_IDX]; converters["bool"] = primitiveTypeConverters[SBK_BOOL_IDX_1]; converters["char"] = primitiveTypeConverters[SBK_CHAR_IDX]; @@ -98,9 +100,11 @@ void init() converters["unsigned long"] = primitiveTypeConverters[SBK_UNSIGNEDLONG_IDX]; converters["unsigned short"] = primitiveTypeConverters[SBK_UNSIGNEDSHORT_IDX]; converters["void*"] = primitiveTypeConverters[SBK_VOIDPTR_IDX]; + + initArrayConverters(); } -static SbkConverter* createConverterObject(PyTypeObject* type, +SbkConverter *createConverterObject(PyTypeObject *type, PythonToCppFunc toCppPointerConvFunc, IsConvertibleToCppFunc toCppPointerCheckFunc, CppToPythonFunc pointerToPythonFunc, @@ -257,6 +261,17 @@ PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject return IsPythonToCppConvertible(converter, pyIn); } +PythonToCppFunc isPythonToCppConvertible(const SbkArrayConverter *converter, + int dim1, int dim2, PyObject *pyIn) +{ + assert(pyIn); + for (IsArrayConvertibleToCppFunc f : converter->toCppConversions) { + if (PythonToCppFunc c = f(pyIn, dim1, dim2)) + return c; + } + return nullptr; +} + PythonToCppFunc isPythonToCppReferenceConvertible(const SbkObjectType *type, PyObject *pyIn) { if (pyIn != Py_None) { diff --git a/sources/shiboken2/libshiboken/sbkconverter.h b/sources/shiboken2/libshiboken/sbkconverter.h index 7eb666b25..6d40f85cc 100644 --- a/sources/shiboken2/libshiboken/sbkconverter.h +++ b/sources/shiboken2/libshiboken/sbkconverter.h @@ -67,6 +67,7 @@ extern "C" * using the functions provided by the converter API. */ struct SbkConverter; +struct SbkArrayConverter; /** * Given a void pointer to a C++ object, this function must return @@ -241,6 +242,8 @@ LIBSHIBOKEN_API PythonToCppFunc isPythonToCppReferenceConvertible(const SbkObjec /// This is the same as isPythonToCppValueConvertible function. LIBSHIBOKEN_API PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn); +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppConvertible(const SbkArrayConverter *converter, + int dim1, int dim2, PyObject *pyIn); /** * Returns the C++ pointer for the \p pyIn object cast to the type passed via \p desiredType. diff --git a/sources/shiboken2/libshiboken/sbkconverter_p.h b/sources/shiboken2/libshiboken/sbkconverter_p.h index 110358273..cfe3d7e98 100644 --- a/sources/shiboken2/libshiboken/sbkconverter_p.h +++ b/sources/shiboken2/libshiboken/sbkconverter_p.h @@ -533,4 +533,13 @@ struct Primitive<std::string> : TwoPrimitive<std::string> } }; +namespace Shiboken { +namespace Conversions { +SbkConverter *createConverterObject(PyTypeObject *type, + PythonToCppFunc toCppPointerConvFunc, + IsConvertibleToCppFunc toCppPointerCheckFunc, + CppToPythonFunc pointerToPythonFunc, + CppToPythonFunc copyToPythonFunc); +} // namespace Conversions +} // namespace Shiboken #endif // SBK_CONVERTER_P_H diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp index a62448aa6..c817a21de 100644 --- a/sources/shiboken2/libshiboken/sbkenum.cpp +++ b/sources/shiboken2/libshiboken/sbkenum.cpp @@ -492,11 +492,11 @@ bool createGlobalEnumItem(PyTypeObject* enumType, PyObject* module, const char* return false; } -bool createScopedEnumItem(PyTypeObject* enumType, SbkObjectType* scope, const char* itemName, long itemValue) +bool createScopedEnumItem(PyTypeObject *enumType, PyTypeObject *scope, + const char *itemName, long itemValue) { - PyObject* enumItem = createEnumItem(enumType, itemName, itemValue); - if (enumItem) { - if (PyDict_SetItemString(scope->super.ht_type.tp_dict, itemName, enumItem) < 0) + if (PyObject *enumItem = createEnumItem(enumType, itemName, itemValue)) { + if (PyDict_SetItemString(scope->tp_dict, itemName, enumItem) < 0) return false; Py_DECREF(enumItem); return true; @@ -504,6 +504,11 @@ bool createScopedEnumItem(PyTypeObject* enumType, SbkObjectType* scope, const ch return false; } +bool createScopedEnumItem(PyTypeObject* enumType, SbkObjectType* scope, const char* itemName, long itemValue) +{ + return createScopedEnumItem(enumType, &scope->super.ht_type, itemName, itemValue); +} + PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName) { bool newValue = true; diff --git a/sources/shiboken2/libshiboken/sbkenum.h b/sources/shiboken2/libshiboken/sbkenum.h index 4b572dbcc..b01114ba6 100644 --- a/sources/shiboken2/libshiboken/sbkenum.h +++ b/sources/shiboken2/libshiboken/sbkenum.h @@ -95,6 +95,8 @@ namespace Enum */ LIBSHIBOKEN_API bool createGlobalEnumItem(PyTypeObject* enumType, PyObject* module, const char* itemName, long itemValue); /// This function does the same as createGlobalEnumItem, but adds the enum to a Shiboken type or namespace. + LIBSHIBOKEN_API bool createScopedEnumItem(PyTypeObject *enumType, PyTypeObject *scope, + const char *itemName, long itemValue); LIBSHIBOKEN_API bool createScopedEnumItem(PyTypeObject* enumType, SbkObjectType* scope, const char* itemName, long itemValue); LIBSHIBOKEN_API PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName = 0); diff --git a/sources/shiboken2/libshiboken/sbkmodule.cpp b/sources/shiboken2/libshiboken/sbkmodule.cpp index 084e23efa..2ea9d56ac 100644 --- a/sources/shiboken2/libshiboken/sbkmodule.cpp +++ b/sources/shiboken2/libshiboken/sbkmodule.cpp @@ -40,17 +40,13 @@ #include "sbkmodule.h" #include "basewrapper.h" #include "bindingmanager.h" - -// TODO: for performance reasons this should be a sparse_hash_map, -// because there'll be very few modules as keys. The sparse_hash_map -// is missing from the code added in ../ext/sparsehash/google directory. -#include "google/dense_hash_map" +#include <unordered_map> /// This hash maps module objects to arrays of Python types. -typedef google::dense_hash_map<PyObject*, PyTypeObject**> ModuleTypesMap; +typedef std::unordered_map<PyObject *, PyTypeObject **> ModuleTypesMap; /// This hash maps module objects to arrays of converters. -typedef google::dense_hash_map<PyObject*, SbkConverter**> ModuleConvertersMap; +typedef std::unordered_map<PyObject *, SbkConverter **> ModuleConvertersMap; /// All types produced in imported modules are mapped here. static ModuleTypesMap moduleTypes; @@ -61,15 +57,6 @@ namespace Shiboken namespace Module { -void init() -{ - // Initializes type registry for modules. - moduleTypes.set_empty_key((ModuleTypesMap::key_type)0); - moduleTypes.set_deleted_key((ModuleTypesMap::key_type)1); - moduleConverters.set_empty_key((ModuleConvertersMap::key_type)0); - moduleConverters.set_deleted_key((ModuleConvertersMap::key_type)1); -} - PyObject* import(const char* moduleName) { PyObject* sysModules = PyImport_GetModuleDict(); diff --git a/sources/shiboken2/libshiboken/sbknumpyarrayconverter.cpp b/sources/shiboken2/libshiboken/sbknumpyarrayconverter.cpp new file mode 100644 index 000000000..97eab2205 --- /dev/null +++ b/sources/shiboken2/libshiboken/sbknumpyarrayconverter.cpp @@ -0,0 +1,308 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "sbkarrayconverter.h" +#include "helper.h" +#include "sbkconverter.h" +#include "sbkconverter_p.h" +#include "sbkarrayconverter_p.h" + +#include <numpy/arrayobject.h> + +#include <algorithm> +#include <iostream> +#include <cstdint> + +enum { debugNumPy = 0 }; + +struct TypeCharMapping +{ + NPY_TYPES type; + const char *name; +}; + +static const TypeCharMapping typeCharMappings[] = { +{NPY_BYTE, "NPY_BYTE"}, +{NPY_UBYTE, "NPY_UBYTE"}, +{NPY_SHORT, "NPY_SHORT"}, +{NPY_USHORT, "NPY_USHORT"}, +{NPY_INT, "NPY_INT"}, +{NPY_UINT, "NPY_UINT"}, +{NPY_LONG, "NPY_LONG"}, +{NPY_ULONG, "NPY_ULONG"}, +{NPY_LONGLONG, "NPY_LONGLONG"}, +{NPY_ULONGLONG, "NPY_ULONGLONG"}, +{NPY_FLOAT, "NPY_FLOAT"}, +{NPY_DOUBLE, "NPY_DOUBLE"} +}; + +const char *npTypeName(npy_intp t) +{ + const TypeCharMapping *end = typeCharMappings + sizeof(typeCharMappings) / sizeof(typeCharMappings[0]); + const TypeCharMapping *result = + std::find_if(typeCharMappings, end, + [t] (const TypeCharMapping &m) { return m.type == t; }); + return result != end ? result->name : nullptr; +} + +std::ostream &operator<<(std::ostream &str, PyArrayObject *o) +{ + str << "PyArrayObject("; + if (o) { + const npy_intp npType = PyArray_TYPE(o); + if (const char *name = npTypeName(npType)) + str << name; + else + str << "type=" << npType; + const int nDim = PyArray_NDIM(o); + const npy_intp *dims = PyArray_DIMS(o); + for (int d = 0; d < nDim; ++d) + str << '[' << dims[d] << ']'; + str << ", "; + const int flags = PyArray_FLAGS(o); + if ((flags & NPY_ARRAY_C_CONTIGUOUS) != 0) + str << " NPY_ARRAY_C_CONTIGUOUS"; + if ((flags & NPY_ARRAY_F_CONTIGUOUS) != 0) + str << " NPY_ARRAY_F_CONTIGUOUS"; + if ((flags & NPY_ARRAY_OWNDATA) != 0) + str << " NPY_ARRAY_OWNDATA"; + if ((flags & NPY_ARRAY_FORCECAST) != 0) + str << " NPY_ARRAY_FORCECAST"; + if ((flags & NPY_ARRAY_ENSURECOPY) != 0) + str << " NPY_ARRAY_ENSURECOPY"; + if ((flags & NPY_ARRAY_ENSUREARRAY) != 0) + str << " NPY_ARRAY_ENSUREARRAY"; + if ((flags & NPY_ARRAY_ELEMENTSTRIDES) != 0) + str << " NPY_ARRAY_ELEMENTSTRIDES"; + if ((flags & NPY_ARRAY_ALIGNED) != 0) + str << " NPY_ARRAY_ALIGNED"; + if ((flags & NPY_ARRAY_NOTSWAPPED) != 0) + str << " NPY_ARRAY_NOTSWAPPED"; + if ((flags & NPY_ARRAY_WRITEABLE) != 0) + str << " NPY_ARRAY_WRITEABLE"; + if ((flags & NPY_ARRAY_UPDATEIFCOPY) != 0) + str << " NPY_ARRAY_UPDATEIFCOPY"; + } else { + str << '0'; + } + str << ')'; + return str; +} + +namespace Shiboken { +namespace Conversions { + +// Internals from sbkarrayconverter.cpp +SbkArrayConverter *createArrayConverter(IsArrayConvertibleToCppFunc toCppCheckFunc); +void setArrayTypeConverter(int index, int dimension, SbkArrayConverter *c); +SbkArrayConverter *unimplementedArrayConverter(); + +template <int dimension> +static bool isPrimitiveArray(PyObject *pyIn, int expectedNpType) +{ + if (!PyArray_Check(pyIn)) + return false; + PyArrayObject *pya = reinterpret_cast<PyArrayObject *>(pyIn); + if (debugNumPy) { + std::cerr << __FUNCTION__ << "(expectedNpType=" << expectedNpType; + if (const char *name = npTypeName(expectedNpType)) + std::cerr << " (" << name << ')'; + std::cerr << ' ' << pya << '\n'; + } + + const int dim = PyArray_NDIM(pya); + if (dim != dimension) { + warning(PyExc_RuntimeWarning, 0, + "%d dimensional numpy array passed to a function expecting a %d dimensional array.", + dim, dimension); + return false; + } + if ((PyArray_FLAGS(pya) & NPY_ARRAY_C_CONTIGUOUS) == 0) { + warning(PyExc_RuntimeWarning, 0, + "Cannot handle numpy arrays that do not have NPY_ARRAY_C_CONTIGUOUS set."); + return false; + } + const int actualNpType = PyArray_TYPE(pya); + if (actualNpType != expectedNpType) { + const char *actualName = npTypeName(actualNpType); + const char *expectedName = npTypeName(expectedNpType); + warning(PyExc_RuntimeWarning, 0, + "A numpy array of type %d (%s) was passed to a function expecting type %d (%s).", + actualNpType, actualName ? actualName : "", + expectedNpType, expectedName ? expectedName : ""); + return false; + } + return true; +} + +static inline bool primitiveArrayCheck1(PyObject *pyIn, int expectedNpType, int expectedSize) +{ + if (!isPrimitiveArray<1>(pyIn, expectedNpType)) + return false; + if (expectedSize >= 0) { + PyArrayObject *pya = reinterpret_cast<PyArrayObject *>(pyIn); + const int size = int(PyArray_DIMS(pya)[0]); + if (size < expectedSize) { + warning(PyExc_RuntimeWarning, 0, "A numpy array of size %d was passed to a function expects %d.", + size, expectedSize); + return false; + } + } + return true; +} + +// Convert one-dimensional array +template <class T> +static void convertArray1(PyObject *pyIn, void *cppOut) +{ + ArrayHandle<T> *handle = reinterpret_cast<ArrayHandle<T> *>(cppOut); + PyArrayObject *pya = reinterpret_cast<PyArrayObject *>(pyIn); + const npy_intp size = PyArray_DIMS(pya)[0]; + if (debugNumPy) + std::cerr << __FUNCTION__ << ' ' << size << '\n'; + handle->setData(reinterpret_cast<T *>(PyArray_DATA(pya)), size_t(size)); +} + +// Convert 2 dimensional array +template <class T> +static void convertArray2(PyObject *pyIn, void *cppOut) +{ + typedef typename Array2Handle<T, 1>::RowType RowType; + Array2Handle<T, 1> *handle = reinterpret_cast<Array2Handle<T, 1> *>(cppOut); + PyArrayObject *pya = reinterpret_cast<PyArrayObject *>(pyIn); + handle->setData(reinterpret_cast<RowType *>(PyArray_DATA(pya))); +} + +template <class T, int NumPyType> +static PythonToCppFunc checkArray1(PyObject *pyIn, int dim1, int /* dim2 */) +{ + return primitiveArrayCheck1(pyIn, NumPyType, dim1) ? convertArray1<T> : nullptr; +} + +static inline bool primitiveArrayCheck2(PyObject *pyIn, int expectedNpType, int expectedDim1, int expectedDim2) +{ + if (!isPrimitiveArray<2>(pyIn, expectedNpType)) + return false; + if (expectedDim2 >= 0) { + PyArrayObject *pya = reinterpret_cast<PyArrayObject *>(pyIn); + const int dim1 = int(PyArray_DIMS(pya)[0]); + const int dim2 = int(PyArray_DIMS(pya)[1]); + if (dim1 != expectedDim1 || dim2 != expectedDim2) { + warning(PyExc_RuntimeWarning, 0, "A numpy array of size %dx%d was passed to a function that expects %dx%d.", + dim1, dim2, expectedDim1, expectedDim2); + return false; + } + } + return true; +} + +template <class T, int NumPyType> +static PythonToCppFunc checkArray2(PyObject *pyIn, int dim1, int dim2) +{ + return primitiveArrayCheck2(pyIn, NumPyType, dim1, dim2) ? convertArray2<T> : nullptr; +} + +template <class T> +static void setOrExtendArrayConverter(int dimension, IsArrayConvertibleToCppFunc toCppCheckFunc) +{ + SbkArrayConverter *arrayConverter = ArrayTypeConverter<T>(dimension); + if (arrayConverter == unimplementedArrayConverter()) { + arrayConverter = createArrayConverter(toCppCheckFunc); + setArrayTypeConverter(ArrayTypeIndex<T>::index, dimension, arrayConverter); + } else { + arrayConverter->toCppConversions.push_back(toCppCheckFunc); + } +} + +// Extend the converters for primitive type one-dimensional arrays by NumPy ones. +template <class T, int NumPyType> +static inline void extendArrayConverter1() +{ + setOrExtendArrayConverter<T>(1, checkArray1<T, NumPyType>); +} + +// Extend the converters for primitive type one-dimensional arrays by NumPy ones. +template <class T, int NumPyType> +static inline void extendArrayConverter2() +{ + setOrExtendArrayConverter<T>(2, checkArray2<T, NumPyType>); +} + +void initNumPyArrayConverters() +{ + // Expanded from macro "import_array" in __multiarray_api.h + // Make sure to read about the magic defines PY_ARRAY_UNIQUE_SYMBOL etc., + // when changing this or spreading the code over several source files. + if (_import_array() < 0) { + if (debugNumPy) + PyErr_Print(); + PyErr_Clear(); + return; + } + // Extend the converters for primitive types by NumPy ones. + extendArrayConverter1<short, NPY_SHORT>(); + extendArrayConverter2<short, NPY_SHORT>(); + extendArrayConverter1<unsigned short, NPY_SHORT>(); + extendArrayConverter2<unsigned short, NPY_SHORT>(); + extendArrayConverter1<int, NPY_INT>(); + extendArrayConverter2<int, NPY_INT>(); + extendArrayConverter1<unsigned int, NPY_UINT>(); + extendArrayConverter2<unsigned int, NPY_UINT>(); + extendArrayConverter1<long long, NPY_LONGLONG>(); + extendArrayConverter2<long long, NPY_LONGLONG>(); + extendArrayConverter1<unsigned long long, NPY_ULONGLONG>(); + if (sizeof(long) == 8) { // UNIX/LP64: ints typically come as long + extendArrayConverter1<long long, NPY_LONG>(); + extendArrayConverter2<long long, NPY_LONG>(); + extendArrayConverter1<unsigned long long, NPY_ULONG>(); + extendArrayConverter2<unsigned long long, NPY_ULONG>(); + } else if (sizeof(long) == sizeof(int)) { + extendArrayConverter1<int, NPY_LONG>(); + extendArrayConverter1<unsigned, NPY_ULONG>(); + extendArrayConverter2<int, NPY_LONG>(); + extendArrayConverter2<unsigned, NPY_ULONG>(); + } + extendArrayConverter1<float, NPY_FLOAT>(); + extendArrayConverter2<float, NPY_FLOAT>(); + extendArrayConverter1<double, NPY_DOUBLE>(); + extendArrayConverter2<double, NPY_DOUBLE>(); +} + +} // namespace Conversions +} // namespace Shiboken diff --git a/sources/shiboken2/libshiboken/shiboken.h b/sources/shiboken2/libshiboken/shiboken.h index 9f4b8a560..6cdfe65bd 100644 --- a/sources/shiboken2/libshiboken/shiboken.h +++ b/sources/shiboken2/libshiboken/shiboken.h @@ -47,6 +47,7 @@ #include "gilstate.h" #include "threadstatesaver.h" #include "helper.h" +#include "sbkarrayconverter.h" #include "sbkconverter.h" #include "sbkenum.h" #include "sbkmodule.h" |