1 // Copyright Jim Bosch 2010-2012.
2 // Copyright Stefan Seefeld 2016.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
8 #include <boost/cstdint.hpp>
10 #define BOOST_PYTHON_NUMPY_INTERNAL
11 #include <boost/python/numpy/internal.hpp>
13 #define DTYPE_FROM_CODE(code) \
14 dtype(python::detail::new_reference(reinterpret_cast<PyObject*>(PyArray_DescrFromType(code))))
16 #define BUILTIN_INT_DTYPE(bits) \
17 template <> struct builtin_int_dtype< bits, false > { \
18 static dtype get() { return DTYPE_FROM_CODE(NPY_INT ## bits); } \
20 template <> struct builtin_int_dtype< bits, true > { \
21 static dtype get() { return DTYPE_FROM_CODE(NPY_UINT ## bits); } \
23 template dtype get_int_dtype< bits, false >(); \
24 template dtype get_int_dtype< bits, true >()
26 #define BUILTIN_FLOAT_DTYPE(bits) \
27 template <> struct builtin_float_dtype< bits > { \
28 static dtype get() { return DTYPE_FROM_CODE(NPY_FLOAT ## bits); } \
30 template dtype get_float_dtype< bits >()
32 #define BUILTIN_COMPLEX_DTYPE(bits) \
33 template <> struct builtin_complex_dtype< bits > { \
34 static dtype get() { return DTYPE_FROM_CODE(NPY_COMPLEX ## bits); } \
36 template dtype get_complex_dtype< bits >()
38 namespace boost
{ namespace python
{ namespace converter
{
39 NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArrayDescr_Type
, numpy::dtype
)
40 } // namespace boost::python::converter
45 dtype builtin_dtype
<bool,true>::get() { return DTYPE_FROM_CODE(NPY_BOOL
); }
47 template <int bits
, bool isUnsigned
> struct builtin_int_dtype
;
48 template <int bits
> struct builtin_float_dtype
;
49 template <int bits
> struct builtin_complex_dtype
;
51 template <int bits
, bool isUnsigned
> dtype
get_int_dtype() {
52 return builtin_int_dtype
<bits
,isUnsigned
>::get();
54 template <int bits
> dtype
get_float_dtype() { return builtin_float_dtype
<bits
>::get(); }
55 template <int bits
> dtype
get_complex_dtype() { return builtin_complex_dtype
<bits
>::get(); }
58 BUILTIN_INT_DTYPE(16);
59 BUILTIN_INT_DTYPE(32);
60 BUILTIN_INT_DTYPE(64);
61 BUILTIN_FLOAT_DTYPE(16);
62 BUILTIN_FLOAT_DTYPE(32);
63 BUILTIN_FLOAT_DTYPE(64);
64 BUILTIN_COMPLEX_DTYPE(64);
65 BUILTIN_COMPLEX_DTYPE(128);
66 #if NPY_BITSOF_LONGDOUBLE > NPY_BITSOF_DOUBLE
67 template <> struct builtin_float_dtype
< NPY_BITSOF_LONGDOUBLE
> {
68 static dtype
get() { return DTYPE_FROM_CODE(NPY_LONGDOUBLE
); }
70 template dtype get_float_dtype
< NPY_BITSOF_LONGDOUBLE
>();
71 template <> struct builtin_complex_dtype
< 2 * NPY_BITSOF_LONGDOUBLE
> {
72 static dtype
get() { return DTYPE_FROM_CODE(NPY_CLONGDOUBLE
); }
74 template dtype get_complex_dtype
< 2 * NPY_BITSOF_LONGDOUBLE
>();
79 python::detail::new_reference
dtype::convert(object
const & arg
, bool align
)
81 PyArray_Descr
* obj
=NULL
;
84 if (PyArray_DescrAlignConverter(arg
.ptr(), &obj
) < 0)
85 throw_error_already_set();
89 if (PyArray_DescrConverter(arg
.ptr(), &obj
) < 0)
90 throw_error_already_set();
92 return python::detail::new_reference(reinterpret_cast<PyObject
*>(obj
));
95 int dtype::get_itemsize() const { return reinterpret_cast<PyArray_Descr
*>(ptr())->elsize
;}
97 bool equivalent(dtype
const & a
, dtype
const & b
) {
98 // On Windows x64, the behaviour described on
99 // http://docs.scipy.org/doc/numpy/reference/c-api.array.html for
100 // PyArray_EquivTypes unfortunately does not extend as expected:
101 // "For example, on 32-bit platforms, NPY_LONG and NPY_INT are equivalent".
102 // This should also hold for 64-bit platforms (and does on Linux), but not
103 // on Windows. Implement an alternative:
105 if (sizeof(long) == sizeof(int) &&
106 // Manually take care of the type equivalence.
107 ((a
== dtype::get_builtin
<long>() || a
== dtype::get_builtin
<int>()) &&
108 (b
== dtype::get_builtin
<long>() || b
== dtype::get_builtin
<int>()) ||
109 (a
== dtype::get_builtin
<unsigned int>() || a
== dtype::get_builtin
<unsigned long>()) &&
110 (b
== dtype::get_builtin
<unsigned int>() || b
== dtype::get_builtin
<unsigned long>()))) {
113 return PyArray_EquivTypes(
114 reinterpret_cast<PyArray_Descr
*>(a
.ptr()),
115 reinterpret_cast<PyArray_Descr
*>(b
.ptr())
119 return PyArray_EquivTypes(
120 reinterpret_cast<PyArray_Descr
*>(a
.ptr()),
121 reinterpret_cast<PyArray_Descr
*>(b
.ptr())
129 namespace pyconv
= boost::python::converter
;
131 template <typename T
>
132 class array_scalar_converter
136 static PyTypeObject
const * get_pytype()
138 // This implementation depends on the fact that get_builtin returns pointers to objects
139 // NumPy has declared statically, and that the typeobj member also refers to a static
140 // object. That means we don't need to do any reference counting.
141 // In fact, I'm somewhat concerned that increasing the reference count of any of these
142 // might cause leaks, because I don't think Boost.Python ever decrements it, but it's
143 // probably a moot point if everything is actually static.
144 return reinterpret_cast<PyArray_Descr
*>(dtype::get_builtin
<T
>().ptr())->typeobj
;
147 static void * convertible(PyObject
* obj
)
149 if (obj
->ob_type
== get_pytype())
155 dtype
dt(python::detail::borrowed_reference(obj
->ob_type
));
156 if (equivalent(dt
, dtype::get_builtin
<T
>()))
164 static void convert(PyObject
* obj
, pyconv::rvalue_from_python_stage1_data
* data
)
166 void * storage
= reinterpret_cast<pyconv::rvalue_from_python_storage
<T
>*>(data
)->storage
.bytes
;
167 // We assume std::complex is a "standard layout" here and elsewhere; not guaranteed by
168 // C++03 standard, but true in every known implementation (and guaranteed by C++11).
169 PyArray_ScalarAsCtype(obj
, reinterpret_cast<T
*>(storage
));
170 data
->convertible
= storage
;
173 static void declare()
175 pyconv::registry::push_back(&convertible
, &convert
, python::type_id
<T
>()
176 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
186 void dtype::register_scalar_converters()
188 array_scalar_converter
<bool>::declare();
189 array_scalar_converter
<npy_uint8
>::declare();
190 array_scalar_converter
<npy_int8
>::declare();
191 array_scalar_converter
<npy_uint16
>::declare();
192 array_scalar_converter
<npy_int16
>::declare();
193 array_scalar_converter
<npy_uint32
>::declare();
194 array_scalar_converter
<npy_int32
>::declare();
196 // Since the npy_(u)int32 types are defined as long types and treated
197 // as being different from the int32 types, these converters must be declared
199 array_scalar_converter
<boost::uint32_t>::declare();
200 array_scalar_converter
<boost::int32_t>::declare();
202 array_scalar_converter
<npy_uint64
>::declare();
203 array_scalar_converter
<npy_int64
>::declare();
204 array_scalar_converter
<float>::declare();
205 array_scalar_converter
<double>::declare();
206 array_scalar_converter
< std::complex<float> >::declare();
207 array_scalar_converter
< std::complex<double> >::declare();
208 #if NPY_BITSOF_LONGDOUBLE > NPY_BITSOF_DOUBLE
209 array_scalar_converter
<long double>::declare();
210 array_scalar_converter
< std::complex<long double> >::declare();
214 }}} // namespace boost::python::numpy