• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <boost/shared_ptr.hpp>
26 #include "request_with_value.hpp"
27 
28 using namespace std;
29 using namespace boost::python;
30 using namespace boost::mpi;
31 
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:
py_call_output_iterator(object callable,const RequestIterator & req_it)44       explicit py_call_output_iterator(object callable,
45           const RequestIterator &req_it)
46         : m_callable(callable), m_request_iterator(req_it)
47       { }
48 
operator =(ValueType const & v)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 
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 
make_request_list_from_py_list(object iterable)63   boost::shared_ptr<request_list> make_request_list_from_py_list(object iterable)
64   {
65     boost::shared_ptr<request_list> result(new request_list);
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
contains(request_list & container,request const & key)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 
check_request_list_not_empty(const request_list & requests)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 
wrap_wait_any(request_list & requests)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 
wrap_test_any(request_list & requests)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 
wrap_wait_all(request_list & requests,object py_callable)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 
wrap_test_all(request_list & requests,object py_callable)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 
wrap_wait_some(request_list & requests,object py_callable)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 
wrap_test_some(request_list & requests,object py_callable)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 
export_nonblocking()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 } } }
251