Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:40:59

0001 // Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
0002 
0003 // Use, modification and distribution is subject to the Boost Software
0004 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 /** @file nonblocking.hpp
0008  *
0009  *  This header defines operations for completing non-blocking
0010  *  communication requests.
0011  */
0012 #ifndef BOOST_MPI_NONBLOCKING_HPP
0013 #define BOOST_MPI_NONBLOCKING_HPP
0014 
0015 #include <boost/mpi/config.hpp>
0016 #include <vector>
0017 #include <iterator> // for std::iterator_traits
0018 #include <boost/optional.hpp>
0019 #include <utility> // for std::pair
0020 #include <algorithm> // for iter_swap, reverse
0021 #include <boost/static_assert.hpp>
0022 #include <boost/mpi/request.hpp>
0023 #include <boost/mpi/status.hpp>
0024 #include <boost/mpi/exception.hpp>
0025 
0026 namespace boost { namespace mpi {
0027 
0028 /** 
0029  *  @brief Wait until any non-blocking request has completed.
0030  *
0031  *  This routine takes in a set of requests stored in the iterator
0032  *  range @c [first,last) and waits until any of these requests has
0033  *  been completed. It provides functionality equivalent to 
0034  *  @c MPI_Waitany.
0035  *
0036  *  @param first The iterator that denotes the beginning of the
0037  *  sequence of request objects.
0038  *
0039  *  @param last The iterator that denotes the end of the sequence of
0040  *  request objects. This may not be equal to @c first.
0041  *
0042  *  @returns A pair containing the status object that corresponds to
0043  *  the completed operation and the iterator referencing the completed
0044  *  request.
0045  */
0046 template<typename ForwardIterator>
0047 std::pair<status, ForwardIterator> 
0048 wait_any(ForwardIterator first, ForwardIterator last)
0049 {
0050   using std::advance;
0051 
0052   BOOST_ASSERT(first != last);
0053   
0054   typedef typename std::iterator_traits<ForwardIterator>::difference_type
0055     difference_type;
0056 
0057   bool all_trivial_requests = true;
0058   difference_type n = 0;
0059   ForwardIterator current = first;
0060   while (true) {
0061     // Check if we have found a completed request. If so, return it.
0062     if (current->active()) {
0063       optional<status> result = current->test();
0064       if (bool(result)) {
0065         return std::make_pair(*result, current);
0066       }
0067     }
0068     
0069     // Check if this request (and all others before it) are "trivial"
0070     // requests, e.g., they can be represented with a single
0071     // MPI_Request.
0072     // We could probably ignore non trivial request that are inactive,
0073     // but we can assume that a mix of trivial and non trivial requests
0074     // is unlikely enough not to care.
0075     all_trivial_requests = all_trivial_requests && current->trivial();
0076 
0077     // Move to the next request.
0078     ++n;
0079     if (++current == last) {
0080       // We have reached the end of the list. If all requests thus far
0081       // have been trivial, we can call MPI_Waitany directly, because
0082       // it may be more efficient than our busy-wait semantics.
0083       if (all_trivial_requests) {
0084         std::vector<MPI_Request> requests;
0085         requests.reserve(n);
0086         for (current = first; current != last; ++current) {
0087           requests.push_back(*current->trivial());
0088         }
0089 
0090         // Let MPI wait until one of these operations completes.
0091         int index;
0092         status stat;
0093         BOOST_MPI_CHECK_RESULT(MPI_Waitany, 
0094                                (n, detail::c_data(requests), &index, &stat.m_status));
0095 
0096         // We don't have a notion of empty requests or status objects,
0097         // so this is an error.
0098         if (index == MPI_UNDEFINED)
0099           boost::throw_exception(exception("MPI_Waitany", MPI_ERR_REQUEST));
0100 
0101         // Find the iterator corresponding to the completed request.
0102         current = first;
0103         advance(current, index);
0104         *current->trivial() = requests[index];
0105         return std::make_pair(stat, current);
0106       }
0107 
0108       // There are some nontrivial requests, so we must continue our
0109       // busy waiting loop.
0110       n = 0;
0111       current = first;
0112       all_trivial_requests = true;
0113     }
0114   }
0115 
0116   // We cannot ever get here
0117   BOOST_ASSERT(false);
0118 }
0119 
0120 /** 
0121  *  @brief Test whether any non-blocking request has completed.
0122  *
0123  *  This routine takes in a set of requests stored in the iterator
0124  *  range @c [first,last) and tests whether any of these requests has
0125  *  been completed. This routine is similar to @c wait_any, but will
0126  *  not block waiting for requests to completed. It provides
0127  *  functionality equivalent to @c MPI_Testany.
0128  *
0129  *  @param first The iterator that denotes the beginning of the
0130  *  sequence of request objects.
0131  *
0132  *  @param last The iterator that denotes the end of the sequence of
0133  *  request objects. 
0134  *
0135  *  @returns If any outstanding requests have completed, a pair
0136  *  containing the status object that corresponds to the completed
0137  *  operation and the iterator referencing the completed
0138  *  request. Otherwise, an empty @c optional<>.
0139  */
0140 template<typename ForwardIterator>
0141 optional<std::pair<status, ForwardIterator> >
0142 test_any(ForwardIterator first, ForwardIterator last)
0143 {
0144   while (first != last) {
0145     // Check if we have found a completed request. If so, return it.
0146     if (optional<status> result = first->test()) {
0147       return std::make_pair(*result, first);
0148     }
0149     ++first;
0150   }
0151 
0152   // We found nothing
0153   return optional<std::pair<status, ForwardIterator> >();
0154 }
0155 
0156 /** 
0157  *  @brief Wait until all non-blocking requests have completed.
0158  *
0159  *  This routine takes in a set of requests stored in the iterator
0160  *  range @c [first,last) and waits until all of these requests have
0161  *  been completed. It provides functionality equivalent to 
0162  *  @c MPI_Waitall.
0163  *
0164  *  @param first The iterator that denotes the beginning of the
0165  *  sequence of request objects.
0166  *
0167  *  @param last The iterator that denotes the end of the sequence of
0168  *  request objects. 
0169  *
0170  *  @param out If provided, an output iterator through which the
0171  *  status of each request will be emitted. The @c status objects are
0172  *  emitted in the same order as the requests are retrieved from 
0173  *  @c [first,last).
0174  *
0175  *  @returns If an @p out parameter was provided, the value @c out
0176  *  after all of the @c status objects have been emitted.
0177  */
0178 template<typename ForwardIterator, typename OutputIterator>
0179 OutputIterator 
0180 wait_all(ForwardIterator first, ForwardIterator last, OutputIterator out)
0181 {
0182   typedef typename std::iterator_traits<ForwardIterator>::difference_type
0183     difference_type;
0184 
0185   using std::distance;
0186 
0187   difference_type num_outstanding_requests = distance(first, last);
0188 
0189   std::vector<status> results(num_outstanding_requests);
0190   std::vector<bool> completed(num_outstanding_requests);
0191 
0192   while (num_outstanding_requests > 0) {
0193     bool all_trivial_requests = true;
0194     difference_type idx = 0;
0195     for (ForwardIterator current = first; current != last; ++current, ++idx) {
0196       if (!completed[idx]) {
0197         if (!current->active()) {
0198           completed[idx] = true;
0199           --num_outstanding_requests;
0200         } else if (optional<status> stat = current->test()) {
0201           // This outstanding request has been completed. We're done.
0202           results[idx] = *stat;
0203           completed[idx] = true;
0204           --num_outstanding_requests;
0205           all_trivial_requests = false;
0206         } else {
0207           // Check if this request (and all others before it) are "trivial"
0208           // requests, e.g., they can be represented with a single
0209           // MPI_Request.
0210           all_trivial_requests = all_trivial_requests && current->trivial();
0211         }
0212       }
0213     }
0214 
0215     // If we have yet to fulfill any requests and all of the requests
0216     // are trivial (i.e., require only a single MPI_Request to be
0217     // fulfilled), call MPI_Waitall directly.
0218     if (all_trivial_requests 
0219         && num_outstanding_requests == (difference_type)results.size()) {
0220       std::vector<MPI_Request> requests;
0221       requests.reserve(num_outstanding_requests);
0222       for (ForwardIterator current = first; current != last; ++current)
0223         requests.push_back(*current->trivial());
0224 
0225       // Let MPI wait until all of these operations completes.
0226       std::vector<MPI_Status> stats(num_outstanding_requests);
0227       BOOST_MPI_CHECK_RESULT(MPI_Waitall, 
0228                              (num_outstanding_requests, detail::c_data(requests), 
0229                               detail::c_data(stats)));
0230 
0231       for (std::vector<MPI_Status>::iterator i = stats.begin(); 
0232            i != stats.end(); ++i, ++out) {
0233         status stat;
0234         stat.m_status = *i;
0235         *out = stat;
0236       }
0237 
0238       return out;
0239     }
0240 
0241     all_trivial_requests = false;
0242   }
0243 
0244   return std::copy(results.begin(), results.end(), out);
0245 }
0246 
0247 /**
0248  * \overload
0249  */
0250 template<typename ForwardIterator>
0251 void
0252 wait_all(ForwardIterator first, ForwardIterator last)
0253 {
0254   typedef typename std::iterator_traits<ForwardIterator>::difference_type
0255     difference_type;
0256 
0257   using std::distance;
0258 
0259   difference_type num_outstanding_requests = distance(first, last);
0260 
0261   std::vector<bool> completed(num_outstanding_requests, false);
0262 
0263   while (num_outstanding_requests > 0) {
0264     bool all_trivial_requests = true;
0265 
0266     difference_type idx = 0;
0267     for (ForwardIterator current = first; current != last; ++current, ++idx) {
0268       if (!completed[idx]) {
0269         if (!current->active()) {
0270           completed[idx] = true;
0271           --num_outstanding_requests;
0272         } else if (optional<status> stat = current->test()) {
0273           // This outstanding request has been completed.
0274           completed[idx] = true;
0275           --num_outstanding_requests;
0276           all_trivial_requests = false;
0277         } else {
0278           // Check if this request (and all others before it) are "trivial"
0279           // requests, e.g., they can be represented with a single
0280           // MPI_Request.
0281           all_trivial_requests = all_trivial_requests && current->trivial();
0282         }
0283       }
0284     }
0285 
0286     // If we have yet to fulfill any requests and all of the requests
0287     // are trivial (i.e., require only a single MPI_Request to be
0288     // fulfilled), call MPI_Waitall directly.
0289     if (all_trivial_requests 
0290         && num_outstanding_requests == (difference_type)completed.size()) {
0291       std::vector<MPI_Request> requests;
0292       requests.reserve(num_outstanding_requests);
0293       for (ForwardIterator current = first; current != last; ++current)
0294         requests.push_back(*current->trivial());
0295 
0296       // Let MPI wait until all of these operations completes.
0297       BOOST_MPI_CHECK_RESULT(MPI_Waitall, 
0298                              (num_outstanding_requests, detail::c_data(requests), 
0299                               MPI_STATUSES_IGNORE));
0300 
0301       // Signal completion
0302       num_outstanding_requests = 0;
0303     }
0304   }
0305 }
0306 
0307 /** 
0308  *  @brief Tests whether all non-blocking requests have completed.
0309  *
0310  *  This routine takes in a set of requests stored in the iterator
0311  *  range @c [first,last) and determines whether all of these requests
0312  *  have been completed. However, due to limitations of the underlying
0313  *  MPI implementation, if any of the requests refers to a
0314  *  non-blocking send or receive of a serialized data type, @c
0315  *  test_all will always return the equivalent of @c false (i.e., the
0316  *  requests cannot all be finished at this time). This routine
0317  *  performs the same functionality as @c wait_all, except that this
0318  *  routine will not block. This routine provides functionality
0319  *  equivalent to @c MPI_Testall.
0320  *
0321  *  @param first The iterator that denotes the beginning of the
0322  *  sequence of request objects.
0323  *
0324  *  @param last The iterator that denotes the end of the sequence of
0325  *  request objects. 
0326  *
0327  *  @param out If provided and all requests hav been completed, an
0328  *  output iterator through which the status of each request will be
0329  *  emitted. The @c status objects are emitted in the same order as
0330  *  the requests are retrieved from @c [first,last).
0331  *
0332  *  @returns If an @p out parameter was provided, the value @c out
0333  *  after all of the @c status objects have been emitted (if all
0334  *  requests were completed) or an empty @c optional<>. If no @p out
0335  *  parameter was provided, returns @c true if all requests have
0336  *  completed or @c false otherwise.
0337  */
0338 template<typename ForwardIterator, typename OutputIterator>
0339 optional<OutputIterator>
0340 test_all(ForwardIterator first, ForwardIterator last, OutputIterator out)
0341 {
0342   std::vector<MPI_Request> requests;
0343   for (; first != last; ++first) {
0344     // If we have a non-trivial request, then no requests can be
0345     // completed.
0346     if (!first->trivial()) {
0347       return optional<OutputIterator>();
0348     }
0349     requests.push_back(*first->trivial());
0350   }
0351 
0352   int flag = 0;
0353   int n = requests.size();
0354   std::vector<MPI_Status> stats(n);
0355   BOOST_MPI_CHECK_RESULT(MPI_Testall, (n, detail::c_data(requests), &flag, detail::c_data(stats)));
0356   if (flag) {
0357     for (int i = 0; i < n; ++i, ++out) {
0358       status stat;
0359       stat.m_status = stats[i];
0360       *out = stat;
0361     }
0362     return out;
0363   } else {
0364     return optional<OutputIterator>();
0365   }
0366 }
0367 
0368 /**
0369  *  \overload
0370  */
0371 template<typename ForwardIterator>
0372 bool
0373 test_all(ForwardIterator first, ForwardIterator last)
0374 {
0375   std::vector<MPI_Request> requests;
0376   for (; first != last; ++first) {
0377     // If we have a non-trivial request, then no requests can be
0378     // completed.
0379     if (!first->trivial()) {
0380       return false;
0381     }
0382     requests.push_back(*first->trivial());
0383   }
0384 
0385   int flag = 0;
0386   int n = requests.size();
0387   BOOST_MPI_CHECK_RESULT(MPI_Testall, 
0388                          (n, detail::c_data(requests), &flag, MPI_STATUSES_IGNORE));
0389   return flag != 0;
0390 }
0391 
0392 /** 
0393  *  @brief Wait until some non-blocking requests have completed.
0394  *
0395  *  This routine takes in a set of requests stored in the iterator
0396  *  range @c [first,last) and waits until at least one of the requests
0397  *  has completed. It then completes all of the requests it can,
0398  *  partitioning the input sequence into pending requests followed by
0399  *  completed requests. If an output iterator is provided, @c status
0400  *  objects will be emitted for each of the completed requests. This
0401  *  routine provides functionality equivalent to @c MPI_Waitsome.
0402  *
0403  *  @param first The iterator that denotes the beginning of the
0404  *  sequence of request objects.
0405  *
0406  *  @param last The iterator that denotes the end of the sequence of
0407  *  request objects. This may not be equal to @c first.
0408  *
0409  *  @param out If provided, the @c status objects corresponding to
0410  *  completed requests will be emitted through this output iterator.
0411 
0412  *  @returns If the @p out parameter was provided, a pair containing
0413  *  the output iterator @p out after all of the @c status objects have
0414  *  been written through it and an iterator referencing the first
0415  *  completed request. If no @p out parameter was provided, only the
0416  *  iterator referencing the first completed request will be emitted.
0417  */
0418 template<typename BidirectionalIterator, typename OutputIterator>
0419 std::pair<OutputIterator, BidirectionalIterator> 
0420 wait_some(BidirectionalIterator first, BidirectionalIterator last,
0421           OutputIterator out)
0422 {
0423   using std::advance;
0424 
0425   if (first == last)
0426     return std::make_pair(out, first);
0427   
0428   typedef typename std::iterator_traits<BidirectionalIterator>::difference_type
0429     difference_type;
0430 
0431   bool all_trivial_requests = true;
0432   difference_type n = 0;
0433   BidirectionalIterator current = first;
0434   BidirectionalIterator start_of_completed = last;
0435   while (true) {
0436     // Check if we have found a completed request. 
0437     if (optional<status> result = current->test()) {
0438       using std::iter_swap;
0439 
0440       // Emit the resulting status object
0441       *out++ = *result;
0442 
0443       // We're expanding the set of completed requests
0444       --start_of_completed;
0445 
0446       if (current == start_of_completed) {
0447         // If we have hit the end of the list of pending
0448         // requests. Finish up by fixing the order of the completed
0449         // set to match the order in which we emitted status objects,
0450         // then return.
0451         std::reverse(start_of_completed, last);
0452         return std::make_pair(out, start_of_completed);
0453       }
0454 
0455       // Swap the request we just completed with the last request that
0456       // has not yet been tested.
0457       iter_swap(current, start_of_completed);
0458 
0459       continue;
0460     }
0461 
0462     // Check if this request (and all others before it) are "trivial"
0463     // requests, e.g., they can be represented with a single
0464     // MPI_Request.
0465     all_trivial_requests = all_trivial_requests && current->trivial();
0466 
0467     // Move to the next request.
0468     ++n;
0469     if (++current == start_of_completed) {
0470       if (start_of_completed != last) {
0471         // We have satisfied some requests. Make the order of the
0472         // completed requests match that of the status objects we've
0473         // already emitted and we're done.
0474         std::reverse(start_of_completed, last);
0475         return std::make_pair(out, start_of_completed);
0476       }
0477 
0478       // We have reached the end of the list. If all requests thus far
0479       // have been trivial, we can call MPI_Waitsome directly, because
0480       // it may be more efficient than our busy-wait semantics.
0481       if (all_trivial_requests) {
0482         std::vector<MPI_Request> requests;
0483         std::vector<int> indices(n);
0484         std::vector<MPI_Status> stats(n);
0485         requests.reserve(n);
0486         for (current = first; current != last; ++current)
0487           requests.push_back(*current->trivial());
0488 
0489         // Let MPI wait until some of these operations complete.
0490         int num_completed;
0491         BOOST_MPI_CHECK_RESULT(MPI_Waitsome, 
0492                                (n, detail::c_data(requests), &num_completed, detail::c_data(indices),
0493                                 detail::c_data(stats)));
0494 
0495         // Translate the index-based result of MPI_Waitsome into a
0496         // partitioning on the requests.
0497         int current_offset = 0;
0498         current = first;
0499         for (int index = 0; index < num_completed; ++index, ++out) {
0500           using std::iter_swap;
0501 
0502           // Move "current" to the request object at this index
0503           advance(current, indices[index] - current_offset);
0504           current_offset = indices[index];
0505 
0506           // Emit the status object
0507           status stat;
0508           stat.m_status = stats[index];
0509           *out = stat;
0510 
0511           // Finish up the request and swap it into the "completed
0512           // requests" partition.
0513           *current->trivial() = requests[indices[index]];
0514           --start_of_completed;
0515           iter_swap(current, start_of_completed);
0516         }
0517 
0518         // We have satisfied some requests. Make the order of the
0519         // completed requests match that of the status objects we've
0520         // already emitted and we're done.
0521         std::reverse(start_of_completed, last);
0522         return std::make_pair(out, start_of_completed);
0523       }
0524 
0525       // There are some nontrivial requests, so we must continue our
0526       // busy waiting loop.
0527       n = 0;
0528       current = first;
0529     }
0530   }
0531 
0532   // We cannot ever get here
0533   BOOST_ASSERT(false);
0534 }
0535 
0536 /**
0537  *  \overload
0538  */
0539 template<typename BidirectionalIterator>
0540 BidirectionalIterator
0541 wait_some(BidirectionalIterator first, BidirectionalIterator last)
0542 {
0543   using std::advance;
0544 
0545   if (first == last)
0546     return first;
0547   
0548   typedef typename std::iterator_traits<BidirectionalIterator>::difference_type
0549     difference_type;
0550 
0551   bool all_trivial_requests = true;
0552   difference_type n = 0;
0553   BidirectionalIterator current = first;
0554   BidirectionalIterator start_of_completed = last;
0555   while (true) {
0556     // Check if we have found a completed request. 
0557     if (optional<status> result = current->test()) {
0558       using std::iter_swap;
0559 
0560       // We're expanding the set of completed requests
0561       --start_of_completed;
0562 
0563       // If we have hit the end of the list of pending requests, we're
0564       // done.
0565       if (current == start_of_completed)
0566         return start_of_completed;
0567 
0568       // Swap the request we just completed with the last request that
0569       // has not yet been tested.
0570       iter_swap(current, start_of_completed);
0571 
0572       continue;
0573     }
0574 
0575     // Check if this request (and all others before it) are "trivial"
0576     // requests, e.g., they can be represented with a single
0577     // MPI_Request.
0578     all_trivial_requests = all_trivial_requests && current->trivial();
0579 
0580     // Move to the next request.
0581     ++n;
0582     if (++current == start_of_completed) {
0583         // If we have satisfied some requests, we're done.
0584       if (start_of_completed != last)
0585         return start_of_completed;
0586 
0587       // We have reached the end of the list. If all requests thus far
0588       // have been trivial, we can call MPI_Waitsome directly, because
0589       // it may be more efficient than our busy-wait semantics.
0590       if (all_trivial_requests) {
0591         std::vector<MPI_Request> requests;
0592         std::vector<int> indices(n);
0593         requests.reserve(n);
0594         for (current = first; current != last; ++current)
0595           requests.push_back(*current->trivial());
0596 
0597         // Let MPI wait until some of these operations complete.
0598         int num_completed;
0599         BOOST_MPI_CHECK_RESULT(MPI_Waitsome, 
0600                                (n, detail::c_data(requests), &num_completed, detail::c_data(indices),
0601                                 MPI_STATUSES_IGNORE));
0602 
0603         // Translate the index-based result of MPI_Waitsome into a
0604         // partitioning on the requests.
0605         int current_offset = 0;
0606         current = first;
0607         for (int index = 0; index < num_completed; ++index) {
0608           using std::iter_swap;
0609 
0610           // Move "current" to the request object at this index
0611           advance(current, indices[index] - current_offset);
0612           current_offset = indices[index];
0613 
0614           // Finish up the request and swap it into the "completed
0615           // requests" partition.
0616           *current->trivial() = requests[indices[index]];
0617           --start_of_completed;
0618           iter_swap(current, start_of_completed);
0619         }
0620 
0621         // We have satisfied some requests, so we are done.
0622         return start_of_completed;
0623       }
0624 
0625       // There are some nontrivial requests, so we must continue our
0626       // busy waiting loop.
0627       n = 0;
0628       current = first;
0629     }
0630   }
0631 
0632   // We cannot ever get here
0633   BOOST_ASSERT(false);
0634 }
0635 
0636 /** 
0637  *  @brief Test whether some non-blocking requests have completed.
0638  *
0639  *  This routine takes in a set of requests stored in the iterator
0640  *  range @c [first,last) and tests to see if any of the requests has
0641  *  completed. It completes all of the requests it can, partitioning
0642  *  the input sequence into pending requests followed by completed
0643  *  requests. If an output iterator is provided, @c status objects
0644  *  will be emitted for each of the completed requests. This routine
0645  *  is similar to @c wait_some, but does not wait until any requests
0646  *  have completed. This routine provides functionality equivalent to
0647  *  @c MPI_Testsome.
0648  *
0649  *  @param first The iterator that denotes the beginning of the
0650  *  sequence of request objects.
0651  *
0652  *  @param last The iterator that denotes the end of the sequence of
0653  *  request objects. This may not be equal to @c first.
0654  *
0655  *  @param out If provided, the @c status objects corresponding to
0656  *  completed requests will be emitted through this output iterator.
0657 
0658  *  @returns If the @p out parameter was provided, a pair containing
0659  *  the output iterator @p out after all of the @c status objects have
0660  *  been written through it and an iterator referencing the first
0661  *  completed request. If no @p out parameter was provided, only the
0662  *  iterator referencing the first completed request will be emitted.
0663  */
0664 template<typename BidirectionalIterator, typename OutputIterator>
0665 std::pair<OutputIterator, BidirectionalIterator> 
0666 test_some(BidirectionalIterator first, BidirectionalIterator last,
0667           OutputIterator out)
0668 {
0669   BidirectionalIterator current = first;
0670   BidirectionalIterator start_of_completed = last;
0671   while (current != start_of_completed) {
0672     // Check if we have found a completed request. 
0673     if (optional<status> result = current->test()) {
0674       using std::iter_swap;
0675 
0676       // Emit the resulting status object
0677       *out++ = *result;
0678 
0679       // We're expanding the set of completed requests
0680       --start_of_completed;
0681 
0682       // Swap the request we just completed with the last request that
0683       // has not yet been tested.
0684       iter_swap(current, start_of_completed);
0685 
0686       continue;
0687     }
0688 
0689     // Move to the next request.
0690     ++current;
0691   }
0692 
0693   // Finish up by fixing the order of the completed set to match the
0694   // order in which we emitted status objects, then return.
0695   std::reverse(start_of_completed, last);
0696   return std::make_pair(out, start_of_completed);
0697 }
0698 
0699 /**
0700  *  \overload
0701  */
0702 template<typename BidirectionalIterator>
0703 BidirectionalIterator
0704 test_some(BidirectionalIterator first, BidirectionalIterator last)
0705 {
0706   BidirectionalIterator current = first;
0707   BidirectionalIterator start_of_completed = last;
0708   while (current != start_of_completed) {
0709     // Check if we have found a completed request. 
0710     if (optional<status> result = current->test()) {
0711       using std::iter_swap;
0712 
0713       // We're expanding the set of completed requests
0714       --start_of_completed;
0715 
0716       // Swap the request we just completed with the last request that
0717       // has not yet been tested.
0718       iter_swap(current, start_of_completed);
0719 
0720       continue;
0721     }
0722 
0723     // Move to the next request.
0724     ++current;
0725   }
0726 
0727   return start_of_completed;
0728 }
0729 
0730 } } // end namespace boost::mpi
0731 
0732 
0733 #endif // BOOST_MPI_NONBLOCKING_HPP