1 #ifndef MAHOTAS_NUMPYPP_NUMPY_HPP_INCLUDE_GUARD_LPC_
2 #define MAHOTAS_NUMPYPP_NUMPY_HPP_INCLUDE_GUARD_LPC_
3 /* Copyright 2010-2014 (C)
4  * Luis Pedro Coelho <luis@luispedro.org>
5  * License: MIT
6  */
7 
8 #include <complex>
9 
10 #include <Python.h>
11 #include <numpy/ndarrayobject.h>
12 
13 namespace numpy {
14 
15 template <typename T>
16 inline
17 npy_intp dtype_code();
18 
19 #define DECLARE_DTYPE_CODE(type, constant) \
20     template <> inline \
21     npy_intp dtype_code<type>() { return constant; } \
22     \
23     template <> inline \
24     npy_intp dtype_code<const type>() { return constant; } \
25     \
26     template <> inline \
27     npy_intp dtype_code<volatile type>() { return constant; } \
28     \
29     template <> inline \
30     npy_intp dtype_code<volatile const type>() { return constant; }
31 
DECLARE_DTYPE_CODE(bool,NPY_BOOL)32 DECLARE_DTYPE_CODE(bool, NPY_BOOL)
33 DECLARE_DTYPE_CODE(float, NPY_FLOAT)
34 DECLARE_DTYPE_CODE(char, NPY_BYTE)
35 DECLARE_DTYPE_CODE(unsigned char, NPY_UBYTE)
36 DECLARE_DTYPE_CODE(short, NPY_SHORT)
37 DECLARE_DTYPE_CODE(unsigned short, NPY_USHORT)
38 DECLARE_DTYPE_CODE(int, NPY_INT)
39 DECLARE_DTYPE_CODE(long, NPY_LONG)
40 DECLARE_DTYPE_CODE(unsigned long, NPY_ULONG)
41 DECLARE_DTYPE_CODE(long long, NPY_LONGLONG)
42 DECLARE_DTYPE_CODE(unsigned long long, NPY_ULONGLONG)
43 DECLARE_DTYPE_CODE(double, NPY_DOUBLE)
44 #if defined(NPY_FLOAT128)
45 DECLARE_DTYPE_CODE(npy_float128, NPY_FLOAT128)
46 #endif /* NPY_FLOAT128 */
47 DECLARE_DTYPE_CODE(std::complex<float>, NPY_CFLOAT)
48 DECLARE_DTYPE_CODE(std::complex<double>, NPY_CDOUBLE)
49 DECLARE_DTYPE_CODE(unsigned int, NPY_UINT)
50 
51 template<typename T>
52 bool check_type(PyArrayObject* a) { return !!PyArray_EquivTypenums(PyArray_TYPE(a), dtype_code<T>()); }
53 
54 template<typename T>
check_type(PyObject * a)55 bool check_type(PyObject* a) { return check_type<T>(reinterpret_cast<PyArrayObject*>(a)); }
56 
57 
58 template<typename T>
59 struct no_ptr { typedef T type; };
60 template<typename T>
61 struct no_ptr<T*> { typedef T type; };
62 template<typename T>
63 struct no_ptr<const T*> { typedef T type; };
64 
65 template<typename T>
ndarray_cast(PyArrayObject * a)66 T ndarray_cast(PyArrayObject* a) {
67     assert(check_type<typename no_ptr<T>::type>(a));
68     assert(PyArray_ISALIGNED(a));
69     // The reason for the intermediate ``as_voidp`` variable is the following:
70     // around version 1.7.0, numpy played with having ``PyArray_DATA`` return
71     // ``char*`` as opposed to ``void*``. ``reinterpret_cast`` from void* was
72     // actually against the standard in C++ pre C++11 (although G++ accepts
73     // it).
74     //
75     // This roundabout way works on all these versions.
76     void* as_voidp = PyArray_DATA(a);
77     return const_cast<T>(static_cast<T>(as_voidp));
78 }
79 template<typename T>
ndarray_cast(PyObject * pa)80 T ndarray_cast(PyObject* pa) {
81     assert(PyArray_Check(pa));
82     return ndarray_cast<T>((PyArrayObject*)pa);
83 }
84 
85 }
86 
87 #endif // MAHOTAS_NUMPYPP_NUMPY_HPP_INCLUDE_GUARD_LPC_
88