]>
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> | |
25 | #include "request_with_value.hpp" | |
26 | ||
27 | using namespace std; | |
28 | using namespace boost::python; | |
29 | using namespace boost::mpi; | |
30 | ||
31 | ||
32 | ||
33 | ||
34 | namespace | |
35 | { | |
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> > | |
40 | { | |
41 | private: | |
42 | object m_callable; | |
43 | RequestIterator m_request_iterator; | |
44 | ||
45 | public: | |
46 | explicit py_call_output_iterator(object callable, | |
47 | const RequestIterator &req_it) | |
48 | : m_callable(callable), m_request_iterator(req_it) | |
49 | { } | |
50 | ||
51 | py_call_output_iterator &operator=(ValueType const &v) | |
52 | { | |
53 | m_callable((m_request_iterator++)->get_value_or_none(), v); | |
54 | return *this; | |
55 | } | |
56 | }; | |
57 | ||
58 | ||
59 | ||
60 | ||
61 | typedef std::vector<python::request_with_value> request_list; | |
62 | typedef py_call_output_iterator<status, request_list::iterator> | |
63 | status_value_iterator; | |
64 | ||
65 | ||
66 | ||
67 | ||
68 | std::auto_ptr<request_list> make_request_list_from_py_list(object iterable) | |
69 | { | |
70 | std::auto_ptr<request_list> result(new request_list); | |
71 | std::copy( | |
72 | stl_input_iterator<python::request_with_value>(iterable), | |
73 | stl_input_iterator<python::request_with_value>(), | |
74 | back_inserter(*result)); | |
75 | return result; | |
76 | } | |
77 | ||
78 | ||
79 | ||
80 | ||
81 | class request_list_indexing_suite : | |
82 | public vector_indexing_suite<request_list, false, request_list_indexing_suite> | |
83 | { | |
84 | public: | |
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. | |
88 | ||
89 | static bool | |
90 | contains(request_list& container, request const& key) | |
91 | { | |
92 | PyErr_SetString(PyExc_NotImplementedError, "mpi requests are not comparable"); | |
93 | throw error_already_set(); | |
94 | } | |
95 | }; | |
96 | ||
97 | ||
98 | ||
99 | ||
100 | void check_request_list_not_empty(const request_list &requests) | |
101 | { | |
102 | if (requests.size() == 0) | |
103 | { | |
104 | PyErr_SetString(PyExc_ValueError, "cannot wait on an empty request vector"); | |
105 | throw error_already_set(); | |
106 | } | |
107 | ||
108 | } | |
109 | ||
110 | ||
111 | ||
112 | ||
113 | ||
114 | object wrap_wait_any(request_list &requests) | |
115 | { | |
116 | check_request_list_not_empty(requests); | |
117 | ||
118 | pair<status, request_list::iterator> result = | |
119 | wait_any(requests.begin(), requests.end()); | |
120 | ||
121 | return boost::python::make_tuple( | |
122 | result.second->get_value_or_none(), | |
123 | result.first, | |
124 | distance(requests.begin(), result.second)); | |
125 | } | |
126 | ||
127 | ||
128 | ||
129 | ||
130 | object wrap_test_any(request_list &requests) | |
131 | { | |
132 | check_request_list_not_empty(requests); | |
133 | ::boost::optional<pair<status, request_list::iterator> > result = | |
134 | test_any(requests.begin(), requests.end()); | |
135 | ||
136 | if (result) | |
137 | return boost::python::make_tuple( | |
138 | result->second->get_value_or_none(), | |
139 | result->first, | |
140 | distance(requests.begin(), result->second)); | |
141 | else | |
142 | return object(); | |
143 | } | |
144 | ||
145 | ||
146 | ||
147 | ||
148 | ||
149 | void wrap_wait_all(request_list &requests, object py_callable) | |
150 | { | |
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())); | |
155 | else | |
156 | wait_all(requests.begin(), requests.end()); | |
157 | } | |
158 | ||
159 | ||
160 | ||
161 | ||
162 | bool wrap_test_all(request_list &requests, object py_callable) | |
163 | { | |
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()))); | |
168 | else | |
169 | return bool(test_all(requests.begin(), requests.end())); | |
170 | } | |
171 | ||
172 | ||
173 | ||
174 | ||
175 | int wrap_wait_some(request_list &requests, object py_callable) | |
176 | { | |
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; | |
182 | else | |
183 | first_completed = wait_some(requests.begin(), requests.end()); | |
184 | ||
185 | return distance(requests.begin(), first_completed); | |
186 | } | |
187 | ||
188 | ||
189 | ||
190 | ||
191 | int wrap_test_some(request_list &requests, object py_callable) | |
192 | { | |
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; | |
198 | else | |
199 | first_completed = test_some(requests.begin(), requests.end()); | |
200 | ||
201 | return distance(requests.begin(), first_completed); | |
202 | } | |
203 | } | |
204 | ||
205 | ||
206 | ||
207 | ||
208 | namespace boost { namespace mpi { namespace python { | |
209 | ||
210 | extern const char* request_list_init_docstring; | |
211 | extern const char* request_list_append_docstring; | |
212 | ||
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; | |
219 | ||
220 | void export_nonblocking() | |
221 | { | |
222 | using boost::python::arg; | |
223 | ||
224 | { | |
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()) | |
230 | ; | |
231 | } | |
232 | ||
233 | def("wait_any", wrap_wait_any, | |
234 | (arg("requests")), | |
235 | nonblocking_wait_any_docstring); | |
236 | def("test_any", wrap_test_any, | |
237 | (arg("requests")), | |
238 | nonblocking_test_any_docstring); | |
239 | ||
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); | |
246 | ||
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); | |
253 | } | |
254 | ||
255 | } } } |