| // (C) Copyright 2007 |
| // Douglas Gregor <doug.gregor -at- gmail.com> |
| // Andreas Kloeckner <inform -at- tiker.net> |
| |
| // Use, modification and distribution is subject to the Boost Software |
| // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| |
| // Authors: Douglas Gregor, Andreas Kloeckner |
| |
| /** @file py_nonblocking.cpp |
| * |
| * This file reflects the Boost.MPI nonblocking operations into Python |
| * functions. |
| */ |
| |
| #include <vector> |
| #include <iterator> |
| #include <algorithm> |
| #include <boost/operators.hpp> |
| #include <boost/python.hpp> |
| #include <boost/python/stl_iterator.hpp> |
| #include <boost/python/suite/indexing/vector_indexing_suite.hpp> |
| #include <boost/mpi.hpp> |
| #include "request_with_value.hpp" |
| |
| using namespace std; |
| using namespace boost::python; |
| using namespace boost::mpi; |
| |
| |
| |
| |
| namespace |
| { |
| template <class ValueType, class RequestIterator> |
| class py_call_output_iterator : |
| public boost::output_iterator_helper< |
| py_call_output_iterator<ValueType, RequestIterator> > |
| { |
| private: |
| object m_callable; |
| RequestIterator m_request_iterator; |
| |
| public: |
| explicit py_call_output_iterator(object callable, |
| const RequestIterator &req_it) |
| : m_callable(callable), m_request_iterator(req_it) |
| { } |
| |
| py_call_output_iterator &operator=(ValueType const &v) |
| { |
| m_callable((m_request_iterator++)->get_value_or_none(), v); |
| return *this; |
| } |
| }; |
| |
| |
| |
| |
| typedef std::vector<python::request_with_value> request_list; |
| typedef py_call_output_iterator<status, request_list::iterator> |
| status_value_iterator; |
| |
| |
| |
| |
| std::auto_ptr<request_list> make_request_list_from_py_list(object iterable) |
| { |
| std::auto_ptr<request_list> result(new request_list); |
| std::copy( |
| stl_input_iterator<python::request_with_value>(iterable), |
| stl_input_iterator<python::request_with_value>(), |
| back_inserter(*result)); |
| return result; |
| } |
| |
| |
| |
| |
| class request_list_indexing_suite : |
| public vector_indexing_suite<request_list, false, request_list_indexing_suite> |
| { |
| public: |
| // FIXME: requests are not comparable, thus __contains__ makes no sense. |
| // Unfortunately, indexing_suites insist on having __contains__ available. |
| // Just make it error out for now. |
| |
| static bool |
| contains(request_list& container, request const& key) |
| { |
| PyErr_SetString(PyExc_NotImplementedError, "mpi requests are not comparable"); |
| throw error_already_set(); |
| } |
| }; |
| |
| |
| |
| |
| void check_request_list_not_empty(const request_list &requests) |
| { |
| if (requests.size() == 0) |
| { |
| PyErr_SetString(PyExc_ValueError, "cannot wait on an empty request vector"); |
| throw error_already_set(); |
| } |
| |
| } |
| |
| |
| |
| |
| |
| object wrap_wait_any(request_list &requests) |
| { |
| check_request_list_not_empty(requests); |
| |
| pair<status, request_list::iterator> result = |
| wait_any(requests.begin(), requests.end()); |
| |
| return make_tuple( |
| result.second->get_value_or_none(), |
| result.first, |
| distance(requests.begin(), result.second)); |
| } |
| |
| |
| |
| |
| object wrap_test_any(request_list &requests) |
| { |
| check_request_list_not_empty(requests); |
| ::boost::optional<pair<status, request_list::iterator> > result = |
| test_any(requests.begin(), requests.end()); |
| |
| if (result) |
| return make_tuple( |
| result->second->get_value_or_none(), |
| result->first, |
| distance(requests.begin(), result->second)); |
| else |
| return object(); |
| } |
| |
| |
| |
| |
| |
| void wrap_wait_all(request_list &requests, object py_callable) |
| { |
| check_request_list_not_empty(requests); |
| if (py_callable != object()) |
| wait_all(requests.begin(), requests.end(), |
| status_value_iterator(py_callable, requests.begin())); |
| else |
| wait_all(requests.begin(), requests.end()); |
| } |
| |
| |
| |
| |
| bool wrap_test_all(request_list &requests, object py_callable) |
| { |
| check_request_list_not_empty(requests); |
| if (py_callable != object()) |
| return test_all(requests.begin(), requests.end(), |
| status_value_iterator(py_callable, requests.begin())); |
| else |
| return test_all(requests.begin(), requests.end()); |
| } |
| |
| |
| |
| |
| int wrap_wait_some(request_list &requests, object py_callable) |
| { |
| check_request_list_not_empty(requests); |
| request_list::iterator first_completed; |
| if (py_callable != object()) |
| first_completed = wait_some(requests.begin(), requests.end(), |
| status_value_iterator(py_callable, requests.begin())).second; |
| else |
| first_completed = wait_some(requests.begin(), requests.end()); |
| |
| return distance(requests.begin(), first_completed); |
| } |
| |
| |
| |
| |
| int wrap_test_some(request_list &requests, object py_callable) |
| { |
| check_request_list_not_empty(requests); |
| request_list::iterator first_completed; |
| if (py_callable != object()) |
| first_completed = test_some(requests.begin(), requests.end(), |
| status_value_iterator(py_callable, requests.begin())).second; |
| else |
| first_completed = test_some(requests.begin(), requests.end()); |
| |
| return distance(requests.begin(), first_completed); |
| } |
| } |
| |
| |
| |
| |
| namespace boost { namespace mpi { namespace python { |
| |
| extern const char* request_list_init_docstring; |
| extern const char* request_list_append_docstring; |
| |
| extern const char* nonblocking_wait_any_docstring; |
| extern const char* nonblocking_test_any_docstring; |
| extern const char* nonblocking_wait_all_docstring; |
| extern const char* nonblocking_test_all_docstring; |
| extern const char* nonblocking_wait_some_docstring; |
| extern const char* nonblocking_test_some_docstring; |
| |
| void export_nonblocking() |
| { |
| using boost::python::arg; |
| |
| { |
| typedef request_list cl; |
| class_<cl>("RequestList", "A list of Request objects.") |
| .def("__init__", make_constructor(make_request_list_from_py_list), |
| /*arg("iterable"),*/ request_list_init_docstring) |
| .def(request_list_indexing_suite()) |
| ; |
| } |
| |
| def("wait_any", wrap_wait_any, |
| (arg("requests")), |
| nonblocking_wait_any_docstring); |
| def("test_any", wrap_test_any, |
| (arg("requests")), |
| nonblocking_test_any_docstring); |
| |
| def("wait_all", wrap_wait_all, |
| (arg("requests"), arg("callable") = object()), |
| nonblocking_wait_all_docstring); |
| def("test_all", wrap_test_all, |
| (arg("requests"), arg("callable") = object()), |
| nonblocking_test_all_docstring); |
| |
| def("wait_some", wrap_wait_some, |
| (arg("requests"), arg("callable") = object()), |
| nonblocking_wait_some_docstring); |
| def("test_some", wrap_test_some, |
| (arg("requests"), arg("callable") = object()), |
| nonblocking_test_some_docstring); |
| } |
| |
| } } } |