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::auto_ptr<request_list> make_request_list_from_py_list(object iterable)
70 std::auto_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 test_all(requests.begin(), requests.end(),
167 status_value_iterator(py_callable, requests.begin()));
169 return 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);