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 <map> 21 #include "../traits.hpp" 22 #include "../pyref.hpp" 23 24 namespace cpp2py { 25 26 template <typename K, typename V> struct py_converter<std::map<K, V>> { 27 c2pycpp2py::py_converter28 template <typename M> static PyObject *c2py(M &&m) { 29 static_assert(is_instantiation_of_v<std::map, std::decay_t<M>>, "Logic Error"); 30 31 PyObject *d = PyDict_New(); 32 for (auto &[key, val] : m) { 33 pyref k, v; 34 if constexpr (std::is_reference_v<M>) { 35 k = convert_to_python(key); 36 v = convert_to_python(val); 37 } else { // Map passed as rvalue 38 k = convert_to_python(std::move(key)); 39 v = convert_to_python(std::move(val)); 40 } 41 42 // if the K is a list, we transform into a tuple 43 if (PyList_Check(k)) k = PyList_AsTuple(k); 44 45 if (k.is_null() or v.is_null() or (PyDict_SetItem(d, k, v) == -1)) { 46 Py_DECREF(d); 47 return NULL; 48 } // error 49 } 50 return d; 51 } 52 53 // ---------------------------------------------- 54 is_convertiblecpp2py::py_converter55 static bool is_convertible(PyObject *ob, bool raise_exception) { 56 if (!PyDict_Check(ob)) goto _false; 57 { 58 pyref keys = PyDict_Keys(ob); 59 pyref values = PyDict_Values(ob); 60 int len = PyDict_Size(ob); 61 for (int i = 0; i < len; i++) { 62 if (!py_converter<K>::is_convertible(PyList_GET_ITEM((PyObject *)keys, i), raise_exception)) goto _false; //borrowed ref 63 if (!py_converter<V>::is_convertible(PyList_GET_ITEM((PyObject *)values, i), raise_exception)) goto _false; //borrowed ref 64 } 65 return true; 66 } 67 _false: 68 if (raise_exception) { PyErr_SetString(PyExc_TypeError, ("Cannot convert "s + to_string(ob) + " to std::map"s).c_str()); } 69 return false; 70 } 71 72 // ---------------------------------------------- 73 py2ccpp2py::py_converter74 static std::map<K, V> py2c(PyObject *ob) { 75 pyref keys = PyDict_Keys(ob); 76 pyref values = PyDict_Values(ob); 77 std::map<K, V> res; 78 int len = PyDict_Size(ob); 79 for (int i = 0; i < len; i++) 80 res.emplace(py_converter<K>::py2c(PyList_GET_ITEM((PyObject *)keys, i)), //borrowed ref 81 py_converter<V>::py2c(PyList_GET_ITEM((PyObject *)values, i))); //borrowed ref 82 return res; 83 } 84 }; 85 } // namespace cpp2py 86