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 "../traits.hpp"
21 #include "../pyref.hpp"
22 
23 namespace cpp2py {
24 
25   template <typename T1, typename T2> struct py_converter<std::pair<T1, T2>> {
26 
c2pycpp2py::py_converter27     template <typename P> static PyObject *c2py(P &&p) {
28       static_assert(is_instantiation_of_v<std::pair, std::decay_t<P>>, "Logic error");
29       pyref x1 = convert_to_python(std::get<0>(std::forward<P>(p)));
30       pyref x2 = convert_to_python(std::get<1>(std::forward<P>(p)));
31 
32       if (x1.is_null() or x2.is_null()) return NULL;
33       return PyTuple_Pack(2, (PyObject *)x1, (PyObject *)x2);
34     }
35 
is_convertiblecpp2py::py_converter36     static bool is_convertible(PyObject *ob, bool raise_exception) {
37       if (!PySequence_Check(ob)) goto _false;
38       {
39         pyref seq = PySequence_Fast(ob, "expected a sequence");
40         if (!py_converter<T1>::is_convertible(PySequence_Fast_GET_ITEM((PyObject *)seq, 0), raise_exception)) goto _false; // borrowed ref
41         if (!py_converter<T2>::is_convertible(PySequence_Fast_GET_ITEM((PyObject *)seq, 1), raise_exception)) goto _false; // borrowed ref
42         return true;
43       }
44     _false:
45       if (raise_exception) { PyErr_SetString(PyExc_TypeError, ("Cannot convert "s + to_string(ob) + " to std::pair"s).c_str()); }
46       return false;
47     }
48 
py2ccpp2py::py_converter49     static std::pair<T1, T2> py2c(PyObject *ob) {
50       pyref seq = PySequence_Fast(ob, "expected a sequence");
51       return std::make_pair(py_converter<T1>::py2c(PySequence_Fast_GET_ITEM((PyObject *)seq, 0)),
52                             py_converter<T2>::py2c(PySequence_Fast_GET_ITEM((PyObject *)seq, 1)));
53     }
54   };
55 } // namespace cpp2py
56