source: branches/asap-3.x/src/pyconversions.h@ 2756

Last change on this file since 2756 was 575, checked in by mar637, 20 years ago

STL <-> python sequence conversions

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.8 KB
Line 
1/* -*- mode:c++ -*- */
2
3/** @file
4
5Boost.Python conversion functions from STL containers to Python
6sequences and vice versa.
7
8$Id: pyconversions.h 575 2005-04-07 02:11:59Z mar637 $
9
10*/
11
12#ifndef PY_CONVERSIONS_H
13#define PY_CONVERSIONS_H
14
15#include <vector>
16
17#include <boost/python.hpp>
18
19using namespace boost::python;
20
21/** A wrapper of a conversion function to convert a STL vector to a
22 Python tuple. This class satisfies the requirements of the
23 boost::python::to_python_converter conversion template argument.
24
25 Copied from
26 scitbx/include/scitbx/boost_python/container_conversions.h that is
27 described in the <a
28 href="http://www.boost.org/libs/python/doc/v2/faq.html">
29 Boost.Python FAQ. </a>
30
31 @author Ralf W. Grosse-Kunstleve <rwgk@yahoo.com> of
32 <a href="http://www.lbl.gov/">Lawrence Berkeley National Laboratory</a>
33*/
34 template < typename ContainerType >
35 struct to_tuple
36 {
37 /** Creates and returns a Python @c tuple from the elements copied
38 from a STL container. The @c ContainerType must be a vector,
39 but may contain any type of object supported by the
40 boost::python::object constructor. */
41 static PyObject* convert (ContainerType const& c)
42 {
43 using boost::python::incref; // works around gcc 2.96 bug
44 using boost::python::list; // dito
45 list result;
46 typename ContainerType::const_iterator i = c.begin();
47 for( ; i != c.end(); ++i)
48 {
49 result.append(*i);
50 }
51 return incref(tuple(result).ptr());
52 }
53 };
54
55/** Converts an STL vector of T objects to Python tuple.
56
57 Copied from
58 scitbx/include/scitbx/boost_python/container_conversions.h that is
59 described in the <a
60 href="http://www.boost.org/libs/python/doc/v2/faq.html">
61 Boost.Python FAQ. </a>
62
63 @author Ralf W. Grosse-Kunstleve <rwgk@yahoo.com> of
64 <a href="http://www.lbl.gov/">Lawrence Berkeley National Laboratory</a>
65*/
66 template < typename T >
67 struct std_vector_to_tuple
68 {
69 std_vector_to_tuple ()
70 {
71 to_python_converter < std::vector < T >,
72 to_tuple < std::vector < T > > > ();
73 }
74 };
75
76// /** Interface to AxesType enumeration. */
77// struct AxesOwner
78// {
79// public:
80// AxesOwner(){};
81// typedef AxesType enum_type;
82// };
83
84// /** Conversion of AxesType enumeration. */
85// struct EnumTypeConverters
86// : python::enum_as_int_converters <AxesOwner::enum_type>
87// {
88// };
89
90/** Default operations on all containers for conversion from Python
91 container to C++ one.
92
93 Copied from
94 scitbx/include/scitbx/boost_python/container_conversions.h that is
95 described in the <a
96 href="http://www.boost.org/libs/python/doc/v2/faq.html">
97 Boost.Python FAQ. </a>
98
99 @author Ralf W. Grosse-Kunstleve <rwgk@yahoo.com> of
100 <a href="http://www.lbl.gov/">Lawrence Berkeley National Laboratory</a>
101*/
102 struct default_policy
103 {
104 static bool check_convertibility_per_element() { return false; }
105
106 template <typename ContainerType>
107 static bool check_size(boost::type<ContainerType>, std::size_t sz)
108 {
109 return true;
110 }
111
112 template <typename ContainerType>
113 static void assert_size(boost::type<ContainerType>, std::size_t sz) {}
114
115 template <typename ContainerType>
116 static void reserve(ContainerType& a, std::size_t sz) {}
117 };
118
119/** Operations on containers that have variable capacity for
120 conversion from Python container to C++ one.
121
122 Copied from
123 scitbx/include/scitbx/boost_python/container_conversions.h that is
124 described in the <a
125 href="http://www.boost.org/libs/python/doc/v2/faq.html">
126 Boost.Python FAQ. </a>
127
128 @author Ralf W. Grosse-Kunstleve <rwgk@yahoo.com> of
129 <a href="http://www.lbl.gov/">Lawrence Berkeley National Laboratory</a>
130*/
131 struct variable_capacity_policy : default_policy
132 {
133 template <typename ContainerType>
134 static void reserve(ContainerType& a, std::size_t sz)
135 {
136 a.reserve(sz);
137 }
138
139 template <typename ContainerType, typename ValueType>
140 static void set_value(ContainerType& a, std::size_t i, ValueType const& v)
141 {
142 assert(a.size() == i);
143 a.push_back(v);
144 }
145 };
146
147/** Conversion of Python sequence to C++ container.
148
149 Copied from
150 scitbx/include/scitbx/boost_python/container_conversions.h that is
151 described in the <a
152 href="http://www.boost.org/libs/python/doc/v2/faq.html">
153 Boost.Python FAQ. </a>
154
155 @author Ralf W. Grosse-Kunstleve <rwgk@yahoo.com> of
156 <a href="http://www.lbl.gov/">Lawrence Berkeley National Laboratory</a>
157*/
158 template <typename ContainerType, typename ConversionPolicy>
159 struct from_python_sequence
160 {
161 typedef typename ContainerType::value_type container_element_type;
162
163 from_python_sequence()
164 {
165 boost::python::converter::registry::push_back(
166 &convertible,
167 &construct,
168 boost::python::type_id<ContainerType>());
169 }
170
171 /** Appears to return @a obj_ptr if it is type of Python sequence
172 that can be convertible to C++ container. */
173 static void* convertible(PyObject* obj_ptr)
174 {
175 using namespace boost::python;
176 using boost::python::allow_null; // works around gcc 2.96 bug
177 {
178 // Restriction to list, tuple, iter, xrange until
179 // Boost.Python overload resolution is enhanced.
180 //
181 // add PySequence_Check() for numarray.
182 //
183 if (!( PyList_Check(obj_ptr)
184 || PyTuple_Check(obj_ptr)
185 || PyIter_Check(obj_ptr)
186 || PyRange_Check(obj_ptr)
187 || PySequence_Check(obj_ptr) )) return 0;
188 }
189 handle<> obj_iter(allow_null(PyObject_GetIter(obj_ptr)));
190 if (!obj_iter.get()) { // must be convertible to an iterator
191 PyErr_Clear();
192 return 0;
193 }
194 if (ConversionPolicy::check_convertibility_per_element()) {
195 int obj_size = PyObject_Length(obj_ptr);
196 if (obj_size < 0) { // must be a measurable sequence
197 PyErr_Clear();
198 return 0;
199 }
200 if (!ConversionPolicy::check_size(
201 boost::type<ContainerType>(), obj_size)) return 0;
202 bool is_range = PyRange_Check(obj_ptr);
203 //std::size_t i=0;
204 int i = 0;
205#ifndef _MSC_VER // because it causes c1001: internal compiler error
206 for(;;i++) {
207 handle<> py_elem_hdl(allow_null(PyIter_Next(obj_iter.get())));
208 if (PyErr_Occurred()) {
209 PyErr_Clear();
210 return 0;
211 }
212 if (!py_elem_hdl.get()) break; // end of iteration
213 object py_elem_obj(py_elem_hdl);
214 extract<container_element_type> elem_proxy(py_elem_obj);
215 if (!elem_proxy.check()) return 0;
216 if (is_range) break; // in a range all elements are of the same type
217 }
218 if (!is_range) assert(i == obj_size );
219#endif
220 }
221 return obj_ptr;
222 }
223
224 /** Constructs a C++ container from a Python sequence. */
225 static void construct(
226 PyObject* obj_ptr,
227 boost::python::converter::rvalue_from_python_stage1_data* data)
228 {
229 using namespace boost::python;
230 using boost::python::allow_null; // works around gcc 2.96 bug
231 using boost::python::converter::rvalue_from_python_storage; // dito
232 using boost::python::throw_error_already_set; // dito
233 handle<> obj_iter(PyObject_GetIter(obj_ptr));
234 void* storage = (
235 (rvalue_from_python_storage<ContainerType>*)
236 data)->storage.bytes;
237 new (storage) ContainerType();
238 data->convertible = storage;
239 ContainerType& result = *((ContainerType*)storage);
240 std::size_t i=0;
241 for(;;i++) {
242 handle<> py_elem_hdl(allow_null(PyIter_Next(obj_iter.get())));
243 if (PyErr_Occurred()) throw_error_already_set();
244 if (!py_elem_hdl.get()) break; // end of iteration
245 object py_elem_obj(py_elem_hdl);
246 extract<container_element_type> elem_proxy(py_elem_obj);
247 ConversionPolicy::set_value(result, i, elem_proxy());
248 }
249 ConversionPolicy::assert_size(boost::type<ContainerType>(), i);
250 }
251
252 };
253
254#endif // PY_CONVERSIONS_H
Note: See TracBrowser for help on using the repository browser.