]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // (C) Copyright 2007 |
2 | // Douglas Gregor <doug.gregor -at- gmail.com> | |
3 | // Andreas Kloeckner <inform -at- tiker.net> | |
4 | ||
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) | |
8 | ||
9 | // Authors: Douglas Gregor, Andreas Kloeckner | |
10 | ||
11 | /** @file py_nonblocking.cpp | |
12 | * | |
13 | * This file reflects the Boost.MPI nonblocking operations into Python | |
14 | * functions. | |
15 | */ | |
16 | ||
17 | #include <vector> | |
18 | #include <iterator> | |
19 | #include <algorithm> | |
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> | |
f67539c2 | 25 | #include <boost/shared_ptr.hpp> |
7c673cae FG |
26 | #include "request_with_value.hpp" |
27 | ||
28 | using namespace std; | |
29 | using namespace boost::python; | |
30 | using namespace boost::mpi; | |
31 | ||
7c673cae FG |
32 | namespace |
33 | { | |
34 | template <class ValueType, class RequestIterator> | |
35 | class py_call_output_iterator : | |
36 | public boost::output_iterator_helper< | |
37 | py_call_output_iterator<ValueType, RequestIterator> > | |
38 | { | |
39 | private: | |
40 | object m_callable; | |
41 | RequestIterator m_request_iterator; | |
42 | ||
43 | public: | |
44 | explicit py_call_output_iterator(object callable, | |
45 | const RequestIterator &req_it) | |
46 | : m_callable(callable), m_request_iterator(req_it) | |
47 | { } | |
48 | ||
49 | py_call_output_iterator &operator=(ValueType const &v) | |
50 | { | |
51 | m_callable((m_request_iterator++)->get_value_or_none(), v); | |
52 | return *this; | |
53 | } | |
54 | }; | |
55 | ||
56 | ||
57 | ||
7c673cae FG |
58 | typedef std::vector<python::request_with_value> request_list; |
59 | typedef py_call_output_iterator<status, request_list::iterator> | |
60 | status_value_iterator; | |
61 | ||
62 | ||
f67539c2 | 63 | boost::shared_ptr<request_list> make_request_list_from_py_list(object iterable) |
7c673cae | 64 | { |
f67539c2 | 65 | boost::shared_ptr<request_list> result(new request_list); |
7c673cae FG |
66 | std::copy( |
67 | stl_input_iterator<python::request_with_value>(iterable), | |
68 | stl_input_iterator<python::request_with_value>(), | |
69 | back_inserter(*result)); | |
70 | return result; | |
71 | } | |
72 | ||
73 | ||
74 | ||
75 | ||
76 | class request_list_indexing_suite : | |
77 | public vector_indexing_suite<request_list, false, request_list_indexing_suite> | |
78 | { | |
79 | public: | |
80 | // FIXME: requests are not comparable, thus __contains__ makes no sense. | |
81 | // Unfortunately, indexing_suites insist on having __contains__ available. | |
82 | // Just make it error out for now. | |
83 | ||
84 | static bool | |
85 | contains(request_list& container, request const& key) | |
86 | { | |
87 | PyErr_SetString(PyExc_NotImplementedError, "mpi requests are not comparable"); | |
88 | throw error_already_set(); | |
89 | } | |
90 | }; | |
91 | ||
92 | ||
93 | ||
94 | ||
95 | void check_request_list_not_empty(const request_list &requests) | |
96 | { | |
97 | if (requests.size() == 0) | |
98 | { | |
99 | PyErr_SetString(PyExc_ValueError, "cannot wait on an empty request vector"); | |
100 | throw error_already_set(); | |
101 | } | |
102 | ||
103 | } | |
104 | ||
105 | ||
106 | ||
107 | ||
108 | ||
109 | object wrap_wait_any(request_list &requests) | |
110 | { | |
111 | check_request_list_not_empty(requests); | |
112 | ||
113 | pair<status, request_list::iterator> result = | |
114 | wait_any(requests.begin(), requests.end()); | |
115 | ||
116 | return boost::python::make_tuple( | |
117 | result.second->get_value_or_none(), | |
118 | result.first, | |
119 | distance(requests.begin(), result.second)); | |
120 | } | |
121 | ||
122 | ||
123 | ||
124 | ||
125 | object wrap_test_any(request_list &requests) | |
126 | { | |
127 | check_request_list_not_empty(requests); | |
128 | ::boost::optional<pair<status, request_list::iterator> > result = | |
129 | test_any(requests.begin(), requests.end()); | |
130 | ||
131 | if (result) | |
132 | return boost::python::make_tuple( | |
133 | result->second->get_value_or_none(), | |
134 | result->first, | |
135 | distance(requests.begin(), result->second)); | |
136 | else | |
137 | return object(); | |
138 | } | |
139 | ||
140 | ||
141 | ||
142 | ||
143 | ||
144 | void wrap_wait_all(request_list &requests, object py_callable) | |
145 | { | |
146 | check_request_list_not_empty(requests); | |
147 | if (py_callable != object()) | |
148 | wait_all(requests.begin(), requests.end(), | |
149 | status_value_iterator(py_callable, requests.begin())); | |
150 | else | |
151 | wait_all(requests.begin(), requests.end()); | |
152 | } | |
153 | ||
154 | ||
155 | ||
156 | ||
157 | bool wrap_test_all(request_list &requests, object py_callable) | |
158 | { | |
159 | check_request_list_not_empty(requests); | |
160 | if (py_callable != object()) | |
161 | return bool(test_all(requests.begin(), requests.end(), | |
162 | status_value_iterator(py_callable, requests.begin()))); | |
163 | else | |
164 | return bool(test_all(requests.begin(), requests.end())); | |
165 | } | |
166 | ||
167 | ||
168 | ||
169 | ||
170 | int wrap_wait_some(request_list &requests, object py_callable) | |
171 | { | |
172 | check_request_list_not_empty(requests); | |
173 | request_list::iterator first_completed; | |
174 | if (py_callable != object()) | |
175 | first_completed = wait_some(requests.begin(), requests.end(), | |
176 | status_value_iterator(py_callable, requests.begin())).second; | |
177 | else | |
178 | first_completed = wait_some(requests.begin(), requests.end()); | |
179 | ||
180 | return distance(requests.begin(), first_completed); | |
181 | } | |
182 | ||
183 | ||
184 | ||
185 | ||
186 | int wrap_test_some(request_list &requests, object py_callable) | |
187 | { | |
188 | check_request_list_not_empty(requests); | |
189 | request_list::iterator first_completed; | |
190 | if (py_callable != object()) | |
191 | first_completed = test_some(requests.begin(), requests.end(), | |
192 | status_value_iterator(py_callable, requests.begin())).second; | |
193 | else | |
194 | first_completed = test_some(requests.begin(), requests.end()); | |
195 | ||
196 | return distance(requests.begin(), first_completed); | |
197 | } | |
198 | } | |
199 | ||
200 | ||
201 | ||
202 | ||
203 | namespace boost { namespace mpi { namespace python { | |
204 | ||
205 | extern const char* request_list_init_docstring; | |
206 | extern const char* request_list_append_docstring; | |
207 | ||
208 | extern const char* nonblocking_wait_any_docstring; | |
209 | extern const char* nonblocking_test_any_docstring; | |
210 | extern const char* nonblocking_wait_all_docstring; | |
211 | extern const char* nonblocking_test_all_docstring; | |
212 | extern const char* nonblocking_wait_some_docstring; | |
213 | extern const char* nonblocking_test_some_docstring; | |
214 | ||
215 | void export_nonblocking() | |
216 | { | |
217 | using boost::python::arg; | |
218 | ||
219 | { | |
220 | typedef request_list cl; | |
221 | class_<cl>("RequestList", "A list of Request objects.") | |
222 | .def("__init__", make_constructor(make_request_list_from_py_list), | |
223 | /*arg("iterable"),*/ request_list_init_docstring) | |
224 | .def(request_list_indexing_suite()) | |
225 | ; | |
226 | } | |
227 | ||
228 | def("wait_any", wrap_wait_any, | |
229 | (arg("requests")), | |
230 | nonblocking_wait_any_docstring); | |
231 | def("test_any", wrap_test_any, | |
232 | (arg("requests")), | |
233 | nonblocking_test_any_docstring); | |
234 | ||
235 | def("wait_all", wrap_wait_all, | |
236 | (arg("requests"), arg("callable") = object()), | |
237 | nonblocking_wait_all_docstring); | |
238 | def("test_all", wrap_test_all, | |
239 | (arg("requests"), arg("callable") = object()), | |
240 | nonblocking_test_all_docstring); | |
241 | ||
242 | def("wait_some", wrap_wait_some, | |
243 | (arg("requests"), arg("callable") = object()), | |
244 | nonblocking_wait_some_docstring); | |
245 | def("test_some", wrap_test_some, | |
246 | (arg("requests"), arg("callable") = object()), | |
247 | nonblocking_test_some_docstring); | |
248 | } | |
249 | ||
250 | } } } |