Imported Upstream version 1.57.0
[platform/upstream/boost.git] / libs / mpi / src / python / py_nonblocking.cpp
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 test_all(requests.begin(), requests.end(), 
167           status_value_iterator(py_callable, requests.begin()));
168     else
169       return 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 } } }