2 // Douglas Gregor <doug.gregor -at- gmail.com>
3 // Andreas Kloeckner <inform -at- tiker.net>
5 // Use, modification and distribution is subject to the Boost Software
6 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
9 // Authors: Douglas Gregor, Andreas Kloeckner
11 /** @file py_nonblocking.cpp
13 * This file reflects the Boost.MPI nonblocking operations into Python
20 #include <boost/operators.hpp>
21 #include <boost/python.hpp>
22 #include <boost/python/stl_iterator.hpp>
23 #include <boost/python/suite/indexing/vector_indexing_suite.hpp>
24 #include <boost/mpi.hpp>
25 #include "request_with_value.hpp"
28 using namespace boost::python
;
29 using namespace boost::mpi
;
36 template <class ValueType
, class RequestIterator
>
37 class py_call_output_iterator
:
38 public boost::output_iterator_helper
<
39 py_call_output_iterator
<ValueType
, RequestIterator
> >
43 RequestIterator m_request_iterator
;
46 explicit py_call_output_iterator(object callable
,
47 const RequestIterator
&req_it
)
48 : m_callable(callable
), m_request_iterator(req_it
)
51 py_call_output_iterator
&operator=(ValueType
const &v
)
53 m_callable((m_request_iterator
++)->get_value_or_none(), v
);
61 typedef std::vector
<python::request_with_value
> request_list
;
62 typedef py_call_output_iterator
<status
, request_list::iterator
>
63 status_value_iterator
;
68 std::shared_ptr
<request_list
> make_request_list_from_py_list(object iterable
)
70 std::shared_ptr
<request_list
> result(new request_list
);
72 stl_input_iterator
<python::request_with_value
>(iterable
),
73 stl_input_iterator
<python::request_with_value
>(),
74 back_inserter(*result
));
81 class request_list_indexing_suite
:
82 public vector_indexing_suite
<request_list
, false, request_list_indexing_suite
>
85 // FIXME: requests are not comparable, thus __contains__ makes no sense.
86 // Unfortunately, indexing_suites insist on having __contains__ available.
87 // Just make it error out for now.
90 contains(request_list
& container
, request
const& key
)
92 PyErr_SetString(PyExc_NotImplementedError
, "mpi requests are not comparable");
93 throw error_already_set();
100 void check_request_list_not_empty(const request_list
&requests
)
102 if (requests
.size() == 0)
104 PyErr_SetString(PyExc_ValueError
, "cannot wait on an empty request vector");
105 throw error_already_set();
114 object
wrap_wait_any(request_list
&requests
)
116 check_request_list_not_empty(requests
);
118 pair
<status
, request_list::iterator
> result
=
119 wait_any(requests
.begin(), requests
.end());
121 return boost::python::make_tuple(
122 result
.second
->get_value_or_none(),
124 distance(requests
.begin(), result
.second
));
130 object
wrap_test_any(request_list
&requests
)
132 check_request_list_not_empty(requests
);
133 ::boost::optional
<pair
<status
, request_list::iterator
> > result
=
134 test_any(requests
.begin(), requests
.end());
137 return boost::python::make_tuple(
138 result
->second
->get_value_or_none(),
140 distance(requests
.begin(), result
->second
));
149 void wrap_wait_all(request_list
&requests
, object py_callable
)
151 check_request_list_not_empty(requests
);
152 if (py_callable
!= object())
153 wait_all(requests
.begin(), requests
.end(),
154 status_value_iterator(py_callable
, requests
.begin()));
156 wait_all(requests
.begin(), requests
.end());
162 bool wrap_test_all(request_list
&requests
, object py_callable
)
164 check_request_list_not_empty(requests
);
165 if (py_callable
!= object())
166 return bool(test_all(requests
.begin(), requests
.end(),
167 status_value_iterator(py_callable
, requests
.begin())));
169 return bool(test_all(requests
.begin(), requests
.end()));
175 int wrap_wait_some(request_list
&requests
, object py_callable
)
177 check_request_list_not_empty(requests
);
178 request_list::iterator first_completed
;
179 if (py_callable
!= object())
180 first_completed
= wait_some(requests
.begin(), requests
.end(),
181 status_value_iterator(py_callable
, requests
.begin())).second
;
183 first_completed
= wait_some(requests
.begin(), requests
.end());
185 return distance(requests
.begin(), first_completed
);
191 int wrap_test_some(request_list
&requests
, object py_callable
)
193 check_request_list_not_empty(requests
);
194 request_list::iterator first_completed
;
195 if (py_callable
!= object())
196 first_completed
= test_some(requests
.begin(), requests
.end(),
197 status_value_iterator(py_callable
, requests
.begin())).second
;
199 first_completed
= test_some(requests
.begin(), requests
.end());
201 return distance(requests
.begin(), first_completed
);
208 namespace boost
{ namespace mpi
{ namespace python
{
210 extern const char* request_list_init_docstring
;
211 extern const char* request_list_append_docstring
;
213 extern const char* nonblocking_wait_any_docstring
;
214 extern const char* nonblocking_test_any_docstring
;
215 extern const char* nonblocking_wait_all_docstring
;
216 extern const char* nonblocking_test_all_docstring
;
217 extern const char* nonblocking_wait_some_docstring
;
218 extern const char* nonblocking_test_some_docstring
;
220 void export_nonblocking()
222 using boost::python::arg
;
225 typedef request_list cl
;
226 class_
<cl
>("RequestList", "A list of Request objects.")
227 .def("__init__", make_constructor(make_request_list_from_py_list
),
228 /*arg("iterable"),*/ request_list_init_docstring
)
229 .def(request_list_indexing_suite())
233 def("wait_any", wrap_wait_any
,
235 nonblocking_wait_any_docstring
);
236 def("test_any", wrap_test_any
,
238 nonblocking_test_any_docstring
);
240 def("wait_all", wrap_wait_all
,
241 (arg("requests"), arg("callable") = object()),
242 nonblocking_wait_all_docstring
);
243 def("test_all", wrap_test_all
,
244 (arg("requests"), arg("callable") = object()),
245 nonblocking_test_all_docstring
);
247 def("wait_some", wrap_wait_some
,
248 (arg("requests"), arg("callable") = object()),
249 nonblocking_wait_some_docstring
);
250 def("test_some", wrap_test_some
,
251 (arg("requests"), arg("callable") = object()),
252 nonblocking_test_some_docstring
);