GCC Code Coverage Report


Directory: ./
File: bindings/python/crocoddyl/utils/map-converter.hpp
Date: 2025-06-03 08:14:12
Exec Total Coverage
Lines: 0 49 0.0%
Functions: 0 96 0.0%
Branches: 0 78 0.0%

Line Branch Exec Source
1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (C) 2019-2022, LAAS-CNRS, University of Edinburgh, INRIA
5 // Copyright note valid unless otherwise stated in individual files.
6 // All rights reserved.
7 ///////////////////////////////////////////////////////////////////////////////
8
9 #ifndef BINDINGS_PYTHON_CROCODDYL_UTILS_MAP_CONVERTER_HPP_
10 #define BINDINGS_PYTHON_CROCODDYL_UTILS_MAP_CONVERTER_HPP_
11
12 #include <boost/python/stl_iterator.hpp>
13 #include <boost/python/suite/indexing/map_indexing_suite.hpp>
14 #include <boost/python/to_python_converter.hpp>
15
16 #include "python/crocoddyl/utils/vector-converter.hpp"
17
18 namespace crocoddyl {
19 namespace python {
20
21 namespace bp = boost::python;
22
23 /**
24 * @brief Create a pickle interface for the std::map
25 *
26 * @param[in] Container Map type to be pickled
27 * \sa Pickle
28 */
29 template <typename Container>
30 struct PickleMap : public eigenpy::PickleVector<Container> {
31 static void setstate(bp::object op, bp::tuple tup) {
32 Container& o = bp::extract<Container&>(op)();
33 bp::stl_input_iterator<typename Container::value_type> begin(tup[0]), end;
34 o.insert(begin, end);
35 }
36 };
37
38 /// Conversion from dict to map solution proposed in
39 /// https://stackoverflow.com/questions/6116345/boostpython-possible-to-automatically-convert-from-dict-stdmap
40 /// This template encapsulates the conversion machinery.
41 template <typename Container>
42 struct dict_to_map {
43 static void register_converter() {
44 bp::converter::registry::push_back(&dict_to_map::convertible,
45 &dict_to_map::construct,
46 bp::type_id<Container>());
47 }
48
49 /// Check if conversion is possible
50 static void* convertible(PyObject* object) {
51 // Check if it is a list
52 if (!PyObject_GetIter(object)) return 0;
53 return object;
54 }
55
56 /// Perform the conversion
57 static void construct(PyObject* object,
58 bp::converter::rvalue_from_python_stage1_data* data) {
59 // convert the PyObject pointed to by `object` to a bp::dict
60 bp::handle<> handle(bp::borrowed(object)); // "smart ptr"
61 bp::dict dict(handle);
62
63 // get a pointer to memory into which we construct the map
64 // this is provided by the Python runtime
65 typedef bp::converter::rvalue_from_python_storage<Container> storage_type;
66 void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;
67
68 // placement-new allocate the result
69 new (storage) Container();
70
71 // iterate over the dictionary `dict`, fill up the map `map`
72 Container& map(*(static_cast<Container*>(storage)));
73 bp::list keys(dict.keys());
74 int keycount(static_cast<int>(bp::len(keys)));
75 for (int i = 0; i < keycount; ++i) {
76 // get the key
77 bp::object keyobj(keys[i]);
78 bp::extract<typename Container::key_type> keyproxy(keyobj);
79 if (!keyproxy.check()) {
80 PyErr_SetString(PyExc_KeyError, "Bad key type");
81 bp::throw_error_already_set();
82 }
83 typename Container::key_type key = keyproxy();
84
85 // get the corresponding value
86 bp::object valobj(dict[keyobj]);
87 bp::extract<typename Container::mapped_type> valproxy(valobj);
88 if (!valproxy.check()) {
89 PyErr_SetString(PyExc_ValueError, "Bad value type");
90 bp::throw_error_already_set();
91 }
92 typename Container::mapped_type val = valproxy();
93 map[key] = val;
94 }
95
96 // remember the location for later
97 data->convertible = storage;
98 }
99
100 static bp::dict todict(Container& self) {
101 bp::dict dict;
102 typename Container::const_iterator it;
103 for (it = self.begin(); it != self.end(); ++it) {
104 dict.setdefault(it->first, it->second);
105 }
106 return dict;
107 }
108 };
109
110 /**
111 * @brief Expose an std::map from a type given as template argument.
112 *
113 * @param[in] T Type to expose as std::map<T>.
114 * @param[in] Compare Type for the Compare in std::map<T,Compare,Allocator>.
115 * @param[in] Allocator Type for the Allocator in
116 * std::map<T,Compare,Allocator>.
117 * @param[in] NoProxy When set to false, the elements will be copied when
118 * returned to Python.
119 */
120 template <class Key, class T, class Compare = std::less<Key>,
121 class Allocator = std::allocator<std::pair<const Key, T> >,
122 bool NoProxy = false>
123 struct StdMapPythonVisitor
124 : public bp::map_indexing_suite<
125 typename std::map<Key, T, Compare, Allocator>, NoProxy>,
126 public dict_to_map<std::map<Key, T, Compare, Allocator> > {
127 typedef std::map<Key, T, Compare, Allocator> Container;
128 typedef dict_to_map<Container> FromPythonDictConverter;
129
130 static void expose(const std::string& class_name,
131 const std::string& doc_string = "") {
132 namespace bp = bp;
133
134 bp::class_<Container>(class_name.c_str(), doc_string.c_str())
135 .def(StdMapPythonVisitor())
136 .def("todict", &FromPythonDictConverter::todict, bp::arg("self"),
137 "Returns the std::map as a Python dictionary.")
138 .def_pickle(PickleMap<Container>());
139 // Register conversion
140 FromPythonDictConverter::register_converter();
141 }
142 };
143
144 } // namespace python
145 } // namespace crocoddyl
146
147 #endif // BINDINGS_PYTHON_CROCODDYL_UTILS_MAP_CONVERTER_HPP_
148