// Copyright Jim Bosch 2010-2012. // Copyright Stefan Seefeld 2016. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifdef _MSC_VER #include #endif #define BOOST_PYTHON_NUMPY_INTERNAL #include #define DTYPE_FROM_CODE(code) \ dtype(python::detail::new_reference(reinterpret_cast(PyArray_DescrFromType(code)))) #define BUILTIN_INT_DTYPE(bits) \ template <> struct builtin_int_dtype \ { \ static dtype get() { return DTYPE_FROM_CODE(NPY_INT ## bits);} \ }; \ template <> struct builtin_int_dtype \ { \ static dtype get() { return DTYPE_FROM_CODE(NPY_UINT ## bits);} \ }; \ template BOOST_NUMPY_DECL dtype get_int_dtype(); \ template BOOST_NUMPY_DECL dtype get_int_dtype() #define BUILTIN_FLOAT_DTYPE(bits) \ template <> struct builtin_float_dtype \ { \ static dtype get() { return DTYPE_FROM_CODE(NPY_FLOAT ## bits);} \ }; \ template BOOST_NUMPY_DECL dtype get_float_dtype() #define BUILTIN_COMPLEX_DTYPE(bits) \ template <> struct builtin_complex_dtype \ { \ static dtype get() { return DTYPE_FROM_CODE(NPY_COMPLEX ## bits);} \ }; \ template BOOST_NUMPY_DECL dtype get_complex_dtype() namespace boost { namespace python { namespace converter { NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArrayDescr_Type, numpy::dtype) } // namespace boost::python::converter namespace numpy { namespace detail { dtype builtin_dtype::get() { return DTYPE_FROM_CODE(NPY_BOOL); } template struct builtin_int_dtype; template struct builtin_float_dtype; template struct builtin_complex_dtype; template dtype get_int_dtype() { return builtin_int_dtype::get(); } template dtype get_float_dtype() { return builtin_float_dtype::get(); } template dtype get_complex_dtype() { return builtin_complex_dtype::get(); } BUILTIN_INT_DTYPE(8); BUILTIN_INT_DTYPE(16); BUILTIN_INT_DTYPE(32); BUILTIN_INT_DTYPE(64); #ifdef NPY_FLOAT16 BUILTIN_FLOAT_DTYPE(16); #endif BUILTIN_FLOAT_DTYPE(32); BUILTIN_FLOAT_DTYPE(64); BUILTIN_COMPLEX_DTYPE(64); BUILTIN_COMPLEX_DTYPE(128); #if NPY_BITSOF_LONGDOUBLE > NPY_BITSOF_DOUBLE template <> struct builtin_float_dtype< NPY_BITSOF_LONGDOUBLE > { static dtype get() { return DTYPE_FROM_CODE(NPY_LONGDOUBLE); } }; template dtype get_float_dtype< NPY_BITSOF_LONGDOUBLE >(); template <> struct builtin_complex_dtype< 2 * NPY_BITSOF_LONGDOUBLE > { static dtype get() { return DTYPE_FROM_CODE(NPY_CLONGDOUBLE); } }; template dtype get_complex_dtype< 2 * NPY_BITSOF_LONGDOUBLE >(); #endif } // namespace detail python::detail::new_reference dtype::convert(object const & arg, bool align) { PyArray_Descr* obj=NULL; if (align) { if (PyArray_DescrAlignConverter(arg.ptr(), &obj) < 0) throw_error_already_set(); } else { if (PyArray_DescrConverter(arg.ptr(), &obj) < 0) throw_error_already_set(); } return python::detail::new_reference(reinterpret_cast(obj)); } int dtype::get_itemsize() const { #if NPY_ABI_VERSION < 0x02000000 return reinterpret_cast(ptr())->elsize; #else return PyDataType_ELSIZE(reinterpret_cast(ptr())); #endif } bool equivalent(dtype const & a, dtype const & b) { return a == b; } namespace { namespace pyconv = boost::python::converter; template class array_scalar_converter { public: static PyTypeObject const * get_pytype() { // This implementation depends on the fact that get_builtin returns pointers to objects // NumPy has declared statically, and that the typeobj member also refers to a static // object. That means we don't need to do any reference counting. // In fact, I'm somewhat concerned that increasing the reference count of any of these // might cause leaks, because I don't think Boost.Python ever decrements it, but it's // probably a moot point if everything is actually static. return reinterpret_cast(dtype::get_builtin().ptr())->typeobj; } static void * convertible(PyObject * obj) { if (obj->ob_type == get_pytype()) { return obj; } else { dtype dt(python::detail::borrowed_reference(obj->ob_type)); if (equivalent(dt, dtype::get_builtin())) { return obj; } } return 0; } static void convert(PyObject * obj, pyconv::rvalue_from_python_stage1_data* data) { void * storage = reinterpret_cast*>(data)->storage.bytes; // We assume std::complex is a "standard layout" here and elsewhere; not guaranteed by // C++03 standard, but true in every known implementation (and guaranteed by C++11). PyArray_ScalarAsCtype(obj, reinterpret_cast(storage)); data->convertible = storage; } static void declare() { pyconv::registry::push_back(&convertible, &convert, python::type_id() #ifndef BOOST_PYTHON_NO_PY_SIGNATURES , &get_pytype #endif ); } }; } // anonymous void dtype::register_scalar_converters() { array_scalar_converter::declare(); array_scalar_converter::declare(); array_scalar_converter::declare(); array_scalar_converter::declare(); array_scalar_converter::declare(); array_scalar_converter::declare(); array_scalar_converter::declare(); #ifdef _MSC_VER // Since the npy_(u)int32 types are defined as long types and treated // as being different from the int32 types, these converters must be declared // explicitely. array_scalar_converter::declare(); array_scalar_converter::declare(); #endif array_scalar_converter::declare(); array_scalar_converter::declare(); array_scalar_converter::declare(); array_scalar_converter::declare(); array_scalar_converter< std::complex >::declare(); array_scalar_converter< std::complex >::declare(); #if NPY_BITSOF_LONGDOUBLE > NPY_BITSOF_DOUBLE array_scalar_converter::declare(); array_scalar_converter< std::complex >::declare(); #endif } }}} // namespace boost::python::numpy