1 // Copyright (c) 2017 Commissariat à l'énergie atomique et aux énergies alternatives (CEA)
2 // Copyright (c) 2017 Centre national de la recherche scientifique (CNRS)
3 // Copyright (c) 2020 Simons Foundation
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0.txt
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 // Authors: Olivier Parcollet, Nils Wentzell
18 
19 #pragma once
20 #include "../pyref.hpp"
21 #include "./complex.hpp"
22 
23 #include <numpy/arrayobject.h>
24 
25 namespace cpp2py {
26 
27   // PyObject *
28   template <> struct py_converter<PyObject *> {
c2pycpp2py::py_converter29     static PyObject *c2py(PyObject *ob) { return ob; }
py2ccpp2py::py_converter30     static PyObject *py2c(PyObject *ob) { return ob; }
is_convertiblecpp2py::py_converter31     static bool is_convertible(PyObject *ob, bool raise_exception) { return true; }
32   };
33 
34   // --- bool
35   template <> struct py_converter<bool> {
c2pycpp2py::py_converter36     static PyObject *c2py(bool b) {
37       if (b)
38         Py_RETURN_TRUE;
39       else
40         Py_RETURN_FALSE;
41     }
py2ccpp2py::py_converter42     static bool py2c(PyObject *ob) { return ob == Py_True; }
is_convertiblecpp2py::py_converter43     static bool is_convertible(PyObject *ob, bool raise_exception) {
44       if (PyBool_Check(ob)) return true;
45       if (raise_exception) { PyErr_SetString(PyExc_TypeError, ("Cannot convert "s + to_string(ob) + " to bool"s).c_str()); }
46       return false;
47     }
48   };
49 
50   // --- long
51 
52   namespace details {
53     template <typename I> struct py_converter_impl {
c2pycpp2py::details::py_converter_impl54       static PyObject *c2py(I i) { return PyLong_FromLong(long(i)); }
py2ccpp2py::details::py_converter_impl55       static I py2c(PyObject *ob) {
56         if (PyLong_Check(ob)) { return I(PyLong_AsLong(ob)); }
57         // Convert NPY Scalar Type to Builtin Type
58         pyref py_builtin = PyObject_CallMethod(ob, "item", NULL);
59         return I(PyLong_AsLong(py_builtin));
60       }
is_convertiblecpp2py::details::py_converter_impl61       static bool is_convertible(PyObject *ob, bool raise_exception) {
62         if (PyLong_Check(ob)) return true;
63         if (PyArray_CheckScalar(ob)) {
64           pyref py_arr = PyArray_FromScalar(ob, NULL);
65           if (PyArray_ISINTEGER((PyObject *)py_arr)) return true;
66         }
67         if (raise_exception) { PyErr_SetString(PyExc_TypeError, ("Cannot convert "s + to_string(ob) + " to integer type"s).c_str()); }
68         return false;
69       }
70     };
71   } // namespace details
72 
73   template <> struct py_converter<long> : details::py_converter_impl<long> {};
74   template <> struct py_converter<int> : details::py_converter_impl<int> {};
75   template <> struct py_converter<unsigned int> : details::py_converter_impl<unsigned int> {};
76   template <> struct py_converter<unsigned long> : details::py_converter_impl<unsigned long> {};
77   template <> struct py_converter<unsigned long long> : details::py_converter_impl<unsigned long long> {};
78 
79   // --- double
80 
81   template <> struct py_converter<double> {
c2pycpp2py::py_converter82     static PyObject *c2py(double x) { return PyFloat_FromDouble(x); }
py2ccpp2py::py_converter83     static double py2c(PyObject *ob) {
84       if (PyFloat_Check(ob) || PyLong_Check(ob)) { return PyFloat_AsDouble(ob); }
85       // Convert NPY Scalar Type to Builtin Type
86       pyref py_builtin = PyObject_CallMethod(ob, "item", NULL);
87       return PyFloat_AsDouble(py_builtin);
88     }
is_convertiblecpp2py::py_converter89     static bool is_convertible(PyObject *ob, bool raise_exception) {
90       if (PyFloat_Check(ob) || PyLong_Check(ob)) return true;
91       if (PyArray_CheckScalar(ob)) {
92         pyref py_arr = PyArray_FromScalar(ob, NULL);
93         if (PyArray_ISINTEGER((PyObject*)py_arr) or PyArray_ISFLOAT((PyObject*)py_arr)) return true;
94       }
95       if (raise_exception) { PyErr_SetString(PyExc_TypeError, ("Cannot convert "s + to_string(ob) + " to double"s).c_str()); }
96       return false;
97     }
98   };
99 
100 } // namespace cpp2py
101