]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/python/src/numpy/dtype.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / python / src / numpy / dtype.cpp
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)
6
7 #ifdef _MSC_VER
8 #include <boost/cstdint.hpp>
9 #endif
10 #define BOOST_PYTHON_NUMPY_INTERNAL
11 #include <boost/python/numpy/internal.hpp>
12
13 #define DTYPE_FROM_CODE(code) \
14 dtype(python::detail::new_reference(reinterpret_cast<PyObject*>(PyArray_DescrFromType(code))))
15
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); } \
19 }; \
20 template <> struct builtin_int_dtype< bits, true > { \
21 static dtype get() { return DTYPE_FROM_CODE(NPY_UINT ## bits); } \
22 }; \
23 template dtype get_int_dtype< bits, false >(); \
24 template dtype get_int_dtype< bits, true >()
25
26 #define BUILTIN_FLOAT_DTYPE(bits) \
27 template <> struct builtin_float_dtype< bits > { \
28 static dtype get() { return DTYPE_FROM_CODE(NPY_FLOAT ## bits); } \
29 }; \
30 template dtype get_float_dtype< bits >()
31
32 #define BUILTIN_COMPLEX_DTYPE(bits) \
33 template <> struct builtin_complex_dtype< bits > { \
34 static dtype get() { return DTYPE_FROM_CODE(NPY_COMPLEX ## bits); } \
35 }; \
36 template dtype get_complex_dtype< bits >()
37
38 namespace boost { namespace python { namespace converter {
39 NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArrayDescr_Type, numpy::dtype)
40 } // namespace boost::python::converter
41
42 namespace numpy {
43 namespace detail {
44
45 dtype builtin_dtype<bool,true>::get() { return DTYPE_FROM_CODE(NPY_BOOL); }
46
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;
50
51 template <int bits, bool isUnsigned> dtype get_int_dtype() {
52 return builtin_int_dtype<bits,isUnsigned>::get();
53 }
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(); }
56
57 BUILTIN_INT_DTYPE(8);
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); }
69 };
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); }
73 };
74 template dtype get_complex_dtype< 2 * NPY_BITSOF_LONGDOUBLE >();
75 #endif
76
77 } // namespace detail
78
79 python::detail::new_reference dtype::convert(object const & arg, bool align)
80 {
81 PyArray_Descr* obj=NULL;
82 if (align)
83 {
84 if (PyArray_DescrAlignConverter(arg.ptr(), &obj) < 0)
85 throw_error_already_set();
86 }
87 else
88 {
89 if (PyArray_DescrConverter(arg.ptr(), &obj) < 0)
90 throw_error_already_set();
91 }
92 return python::detail::new_reference(reinterpret_cast<PyObject*>(obj));
93 }
94
95 int dtype::get_itemsize() const { return reinterpret_cast<PyArray_Descr*>(ptr())->elsize;}
96
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:
104 #ifdef _MSC_VER
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>()))) {
111 return true;
112 } else {
113 return PyArray_EquivTypes(
114 reinterpret_cast<PyArray_Descr*>(a.ptr()),
115 reinterpret_cast<PyArray_Descr*>(b.ptr())
116 );
117 }
118 #else
119 return PyArray_EquivTypes(
120 reinterpret_cast<PyArray_Descr*>(a.ptr()),
121 reinterpret_cast<PyArray_Descr*>(b.ptr())
122 );
123 #endif
124 }
125
126 namespace
127 {
128
129 namespace pyconv = boost::python::converter;
130
131 template <typename T>
132 class array_scalar_converter
133 {
134 public:
135
136 static PyTypeObject const * get_pytype()
137 {
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;
145 }
146
147 static void * convertible(PyObject * obj)
148 {
149 if (obj->ob_type == get_pytype())
150 {
151 return obj;
152 }
153 else
154 {
155 dtype dt(python::detail::borrowed_reference(obj->ob_type));
156 if (equivalent(dt, dtype::get_builtin<T>()))
157 {
158 return obj;
159 }
160 }
161 return 0;
162 }
163
164 static void convert(PyObject * obj, pyconv::rvalue_from_python_stage1_data* data)
165 {
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;
171 }
172
173 static void declare()
174 {
175 pyconv::registry::push_back(&convertible, &convert, python::type_id<T>()
176 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
177 , &get_pytype
178 #endif
179 );
180 }
181
182 };
183
184 } // anonymous
185
186 void dtype::register_scalar_converters()
187 {
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();
195 #ifdef _MSC_VER
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
198 // explicitely.
199 array_scalar_converter<boost::uint32_t>::declare();
200 array_scalar_converter<boost::int32_t>::declare();
201 #endif
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();
211 #endif
212 }
213
214 }}} // namespace boost::python::numpy