66#ifndef __eigenpy_utils_map_hpp__
77#define __eigenpy_utils_map_hpp__
88
9+ #include " eigenpy/pickle-vector.hpp"
10+
11+ #include < boost/python/suite/indexing/map_indexing_suite.hpp>
12+ #include < boost/python/stl_iterator.hpp>
913#include < boost/python/suite/indexing/map_indexing_suite.hpp>
14+ #include < boost/python/to_python_converter.hpp>
15+ #include < map>
1016
1117namespace eigenpy {
1218namespace details {
@@ -31,31 +37,165 @@ struct overload_base_get_item_for_std_map
3137 typename Container::iterator i = container.get ().find (idx);
3238 if (i == container.get ().end ()) {
3339 PyErr_SetString (PyExc_KeyError, " Invalid key" );
34- bp ::throw_error_already_set ();
40+ boost::python ::throw_error_already_set ();
3541 }
3642
37- typename bp:: to_python_indirect<data_type&,
38- bp ::detail::make_reference_holder>
43+ typename boost::python:: to_python_indirect<
44+ data_type&, boost::python ::detail::make_reference_holder>
3945 convert;
40- return bp:: object (bp ::handle<>(convert (i->second )));
46+ return boost::python:: object (boost::python ::handle<>(convert (i->second )));
4147 }
4248
4349 static index_type convert_index (Container& /* container*/ , PyObject* i_) {
44- bp ::extract<key_type const &> i (i_);
50+ boost::python ::extract<key_type const &> i (i_);
4551 if (i.check ()) {
4652 return i ();
4753 } else {
48- bp ::extract<key_type> i (i_);
54+ boost::python ::extract<key_type> i (i_);
4955 if (i.check ()) return i ();
5056 }
5157
5258 PyErr_SetString (PyExc_TypeError, " Invalid index type" );
53- bp ::throw_error_already_set ();
59+ boost::python ::throw_error_already_set ();
5460 return index_type ();
5561 }
5662};
5763
5864} // namespace details
65+
66+ // /////////////////////////////////////////////////////////////////////////////
67+ // The following snippet of code has been taken from the header
68+ // https://github.com/loco-3d/crocoddyl/blob/v2.1.0/bindings/python/crocoddyl/utils/map-converter.hpp
69+ // The Crocoddyl library is written by Carlos Mastalli, Nicolas Mansard and
70+ // Rohan Budhiraja.
71+ // /////////////////////////////////////////////////////////////////////////////
72+
73+ namespace python {
74+
75+ namespace bp = boost::python;
76+
77+ /* *
78+ * @brief Create a pickle interface for the std::map
79+ *
80+ * @param[in] Container Map type to be pickled
81+ * \sa Pickle
82+ */
83+ template <typename Container>
84+ struct PickleMap : public PickleVector <Container> {
85+ static void setstate (bp::object op, bp::tuple tup) {
86+ Container& o = bp::extract<Container&>(op)();
87+ bp::stl_input_iterator<typename Container::value_type> begin (tup[0 ]), end;
88+ o.insert (begin, end);
89+ }
90+ };
91+
92+ // / Conversion from dict to map solution proposed in
93+ // / https://stackoverflow.com/questions/6116345/boostpython-possible-to-automatically-convert-from-dict-stdmap
94+ // / This template encapsulates the conversion machinery.
95+ template <typename Container>
96+ struct dict_to_map {
97+ static void register_converter () {
98+ bp::converter::registry::push_back (&dict_to_map::convertible,
99+ &dict_to_map::construct,
100+ bp::type_id<Container>());
101+ }
102+
103+ // / Check if conversion is possible
104+ static void * convertible (PyObject* object) {
105+ // Check if it is a list
106+ if (!PyObject_GetIter (object)) return 0 ;
107+ return object;
108+ }
109+
110+ // / Perform the conversion
111+ static void construct (PyObject* object,
112+ bp::converter::rvalue_from_python_stage1_data* data) {
113+ // convert the PyObject pointed to by `object` to a bp::dict
114+ bp::handle<> handle (bp::borrowed (object)); // "smart ptr"
115+ bp::dict dict (handle);
116+
117+ // get a pointer to memory into which we construct the map
118+ // this is provided by the Python runtime
119+ typedef bp::converter::rvalue_from_python_storage<Container> storage_type;
120+ void * storage = reinterpret_cast <storage_type*>(data)->storage .bytes ;
121+
122+ // placement-new allocate the result
123+ new (storage) Container ();
124+
125+ // iterate over the dictionary `dict`, fill up the map `map`
126+ Container& map (*(static_cast <Container*>(storage)));
127+ bp::list keys (dict.keys ());
128+ int keycount (static_cast <int >(bp::len (keys)));
129+ for (int i = 0 ; i < keycount; ++i) {
130+ // get the key
131+ bp::object keyobj (keys[i]);
132+ bp::extract<typename Container::key_type> keyproxy (keyobj);
133+ if (!keyproxy.check ()) {
134+ PyErr_SetString (PyExc_KeyError, " Bad key type" );
135+ bp::throw_error_already_set ();
136+ }
137+ typename Container::key_type key = keyproxy ();
138+
139+ // get the corresponding value
140+ bp::object valobj (dict[keyobj]);
141+ bp::extract<typename Container::mapped_type> valproxy (valobj);
142+ if (!valproxy.check ()) {
143+ PyErr_SetString (PyExc_ValueError, " Bad value type" );
144+ bp::throw_error_already_set ();
145+ }
146+ typename Container::mapped_type val = valproxy ();
147+ map[key] = val;
148+ }
149+
150+ // remember the location for later
151+ data->convertible = storage;
152+ }
153+
154+ static bp::dict todict (Container& self) {
155+ bp::dict dict;
156+ typename Container::const_iterator it;
157+ for (it = self.begin (); it != self.end (); ++it) {
158+ dict.setdefault (it->first , it->second );
159+ }
160+ return dict;
161+ }
162+ };
163+
164+ /* *
165+ * @brief Expose an std::map from a type given as template argument.
166+ *
167+ * @param[in] T Type to expose as std::map<T>.
168+ * @param[in] Compare Type for the Compare in std::map<T,Compare,Allocator>.
169+ * @param[in] Allocator Type for the Allocator in
170+ * std::map<T,Compare,Allocator>.
171+ * @param[in] NoProxy When set to false, the elements will be copied when
172+ * returned to Python.
173+ */
174+ template <class Key , class T , class Compare = std::less<Key>,
175+ class Allocator = std::allocator<std::pair<const Key, T> >,
176+ bool NoProxy = false >
177+ struct StdMapPythonVisitor
178+ : public bp::map_indexing_suite<
179+ typename std::map<Key, T, Compare, Allocator>, NoProxy>,
180+ public dict_to_map<std::map<Key, T, Compare, Allocator> > {
181+ typedef std::map<Key, T, Compare, Allocator> Container;
182+ typedef dict_to_map<Container> FromPythonDictConverter;
183+
184+ static void expose (const std::string& class_name,
185+ const std::string& doc_string = " " ) {
186+ namespace bp = bp;
187+
188+ bp::class_<Container>(class_name.c_str (), doc_string.c_str ())
189+ .def (StdMapPythonVisitor ())
190+ .def (" todict" , &FromPythonDictConverter::todict, bp::arg (" self" ),
191+ " Returns the std::map as a Python dictionary." )
192+ .def_pickle (PickleMap<Container>());
193+ // Register conversion
194+ FromPythonDictConverter::register_converter ();
195+ }
196+ };
197+
198+ } // namespace python
59199} // namespace eigenpy
60200
61201#endif // ifndef __eigenpy_utils_map_hpp__
0 commit comments