323 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			323 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
								 | 
							
								// Copyright (C) 2004 The Trustees of Indiana University.
							 | 
						||
| 
								 | 
							
								// Copyright (C) 2005-2006 Douglas Gregor <doug.gregor -at- gmail.com>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 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
							 | 
						||
| 
								 | 
							
								//           Andrew Lumsdaine
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** @file operations.hpp
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *  This header provides a mapping from function objects to @c MPI_Op
							 | 
						||
| 
								 | 
							
								 *  constants used in MPI collective operations. It also provides
							 | 
						||
| 
								 | 
							
								 *  several new function object types not present in the standard @c
							 | 
						||
| 
								 | 
							
								 *  <functional> header that have direct mappings to @c MPI_Op.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								#ifndef BOOST_MPI_IS_MPI_OP_HPP
							 | 
						||
| 
								 | 
							
								#define BOOST_MPI_IS_MPI_OP_HPP
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <boost/mpi/config.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/mpl/bool.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/mpl/if.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/mpl/and.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/mpi/datatype.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/utility/enable_if.hpp>
							 | 
						||
| 
								 | 
							
								#include <functional>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace boost { namespace mpi {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								template<typename Op, typename T> struct is_mpi_op;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * @brief Determine if a function object type is commutative.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This trait determines if an operation @c Op is commutative when
							 | 
						||
| 
								 | 
							
								 * applied to values of type @c T. Parallel operations such as @c
							 | 
						||
| 
								 | 
							
								 * reduce and @c prefix_sum can be implemented more efficiently with
							 | 
						||
| 
								 | 
							
								 * commutative operations. To mark an operation as commutative, users
							 | 
						||
| 
								 | 
							
								 * should specialize @c is_commutative and derive from the class @c
							 | 
						||
| 
								 | 
							
								 * mpl::true_.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								template<typename Op, typename T>
							 | 
						||
| 
								 | 
							
								struct is_commutative : public mpl::false_ { };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**************************************************************************
							 | 
						||
| 
								 | 
							
								 * Function objects for MPI operations not in <functional> header         *
							 | 
						||
| 
								 | 
							
								 **************************************************************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 *  @brief Compute the maximum of two values.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *  This binary function object computes the maximum of the two values
							 | 
						||
| 
								 | 
							
								 *  it is given. When used with MPI and a type @c T that has an
							 | 
						||
| 
								 | 
							
								 *  associated, built-in MPI data type, translates to @c MPI_MAX.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								struct maximum : public std::binary_function<T, T, T>
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  /** @returns the maximum of x and y. */
							 | 
						||
| 
								 | 
							
								  const T& operator()(const T& x, const T& y) const
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    return x < y? y : x;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 *  @brief Compute the minimum of two values.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *  This binary function object computes the minimum of the two values
							 | 
						||
| 
								 | 
							
								 *  it is given. When used with MPI and a type @c T that has an
							 | 
						||
| 
								 | 
							
								 *  associated, built-in MPI data type, translates to @c MPI_MIN.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								struct minimum : public std::binary_function<T, T, T>
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  /** @returns the minimum of x and y. */
							 | 
						||
| 
								 | 
							
								  const T& operator()(const T& x, const T& y) const
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    return x < y? x : y;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 *  @brief Compute the bitwise AND of two integral values.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *  This binary function object computes the bitwise AND of the two
							 | 
						||
| 
								 | 
							
								 *  values it is given. When used with MPI and a type @c T that has an
							 | 
						||
| 
								 | 
							
								 *  associated, built-in MPI data type, translates to @c MPI_BAND.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								struct bitwise_and : public std::binary_function<T, T, T>
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  /** @returns @c x & y. */
							 | 
						||
| 
								 | 
							
								  T operator()(const T& x, const T& y) const
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    return x & y;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 *  @brief Compute the bitwise OR of two integral values.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *  This binary function object computes the bitwise OR of the two
							 | 
						||
| 
								 | 
							
								 *  values it is given. When used with MPI and a type @c T that has an
							 | 
						||
| 
								 | 
							
								 *  associated, built-in MPI data type, translates to @c MPI_BOR.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								struct bitwise_or : public std::binary_function<T, T, T>
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  /** @returns the @c x | y. */
							 | 
						||
| 
								 | 
							
								  T operator()(const T& x, const T& y) const
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    return x | y;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 *  @brief Compute the logical exclusive OR of two integral values.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *  This binary function object computes the logical exclusive of the
							 | 
						||
| 
								 | 
							
								 *  two values it is given. When used with MPI and a type @c T that has
							 | 
						||
| 
								 | 
							
								 *  an associated, built-in MPI data type, translates to @c MPI_LXOR.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								struct logical_xor : public std::binary_function<T, T, T>
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  /** @returns the logical exclusive OR of x and y. */
							 | 
						||
| 
								 | 
							
								  T operator()(const T& x, const T& y) const
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    return (x || y) && !(x && y);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 *  @brief Compute the bitwise exclusive OR of two integral values.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *  This binary function object computes the bitwise exclusive OR of
							 | 
						||
| 
								 | 
							
								 *  the two values it is given. When used with MPI and a type @c T that
							 | 
						||
| 
								 | 
							
								 *  has an associated, built-in MPI data type, translates to @c
							 | 
						||
| 
								 | 
							
								 *  MPI_BXOR.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								struct bitwise_xor : public std::binary_function<T, T, T>
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  /** @returns @c x ^ y. */
							 | 
						||
| 
								 | 
							
								  T operator()(const T& x, const T& y) const
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    return x ^ y;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**************************************************************************
							 | 
						||
| 
								 | 
							
								 * MPI_Op queries                                                         *
							 | 
						||
| 
								 | 
							
								 **************************************************************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 *  @brief Determine if a function object has an associated @c MPI_Op.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *  This trait determines if a function object type @c Op, when used
							 | 
						||
| 
								 | 
							
								 *  with argument type @c T, has an associated @c MPI_Op. If so, @c
							 | 
						||
| 
								 | 
							
								 *  is_mpi_op<Op,T> will derive from @c mpl::false_ and will
							 | 
						||
| 
								 | 
							
								 *  contain a static member function @c op that takes no arguments but
							 | 
						||
| 
								 | 
							
								 *  returns the associated @c MPI_Op value. For instance, @c
							 | 
						||
| 
								 | 
							
								 *  is_mpi_op<std::plus<int>,int>::op() returns @c MPI_SUM.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *  Users may specialize @c is_mpi_op for any other class templates
							 | 
						||
| 
								 | 
							
								 *  that map onto operations that have @c MPI_Op equivalences, such as
							 | 
						||
| 
								 | 
							
								 *  bitwise OR, logical and, or maximum. However, users are encouraged
							 | 
						||
| 
								 | 
							
								 *  to use the standard function objects in the @c functional and @c
							 | 
						||
| 
								 | 
							
								 *  boost/mpi/operations.hpp headers whenever possible. For
							 | 
						||
| 
								 | 
							
								 *  function objects that are class templates with a single template
							 | 
						||
| 
								 | 
							
								 *  parameter, it may be easier to specialize @c is_builtin_mpi_op.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								template<typename Op, typename T>
							 | 
						||
| 
								 | 
							
								struct is_mpi_op : public mpl::false_ { };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// INTERNAL ONLY
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								struct is_mpi_op<maximum<T>, T>
							 | 
						||
| 
								 | 
							
								  : public boost::mpl::or_<is_mpi_integer_datatype<T>,
							 | 
						||
| 
								 | 
							
								                           is_mpi_floating_point_datatype<T> >
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  static MPI_Op op() { return MPI_MAX; }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// INTERNAL ONLY
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								struct is_mpi_op<minimum<T>, T>
							 | 
						||
| 
								 | 
							
								  : public boost::mpl::or_<is_mpi_integer_datatype<T>,
							 | 
						||
| 
								 | 
							
								                           is_mpi_floating_point_datatype<T> >
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  static MPI_Op op() { return MPI_MIN; }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// INTERNAL ONLY
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								 struct is_mpi_op<std::plus<T>, T>
							 | 
						||
| 
								 | 
							
								  : public boost::mpl::or_<is_mpi_integer_datatype<T>,
							 | 
						||
| 
								 | 
							
								                           is_mpi_floating_point_datatype<T>,
							 | 
						||
| 
								 | 
							
								                           is_mpi_complex_datatype<T> >
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  static MPI_Op op() { return MPI_SUM; }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// INTERNAL ONLY
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								 struct is_mpi_op<std::multiplies<T>, T>
							 | 
						||
| 
								 | 
							
								  : public boost::mpl::or_<is_mpi_integer_datatype<T>,
							 | 
						||
| 
								 | 
							
								                           is_mpi_floating_point_datatype<T>,
							 | 
						||
| 
								 | 
							
								                           is_mpi_complex_datatype<T> >
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  static MPI_Op op() { return MPI_PROD; }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// INTERNAL ONLY
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								 struct is_mpi_op<std::logical_and<T>, T>
							 | 
						||
| 
								 | 
							
								  : public boost::mpl::or_<is_mpi_integer_datatype<T>,
							 | 
						||
| 
								 | 
							
								                           is_mpi_logical_datatype<T> >
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  static MPI_Op op() { return MPI_LAND; }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// INTERNAL ONLY
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								 struct is_mpi_op<std::logical_or<T>, T>
							 | 
						||
| 
								 | 
							
								  : public boost::mpl::or_<is_mpi_integer_datatype<T>,
							 | 
						||
| 
								 | 
							
								                           is_mpi_logical_datatype<T> >
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  static MPI_Op op() { return MPI_LOR; }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// INTERNAL ONLY
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								 struct is_mpi_op<logical_xor<T>, T>
							 | 
						||
| 
								 | 
							
								  : public boost::mpl::or_<is_mpi_integer_datatype<T>,
							 | 
						||
| 
								 | 
							
								                           is_mpi_logical_datatype<T> >
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  static MPI_Op op() { return MPI_LXOR; }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// INTERNAL ONLY
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								 struct is_mpi_op<bitwise_and<T>, T>
							 | 
						||
| 
								 | 
							
								  : public boost::mpl::or_<is_mpi_integer_datatype<T>,
							 | 
						||
| 
								 | 
							
								                           is_mpi_byte_datatype<T> >
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  static MPI_Op op() { return MPI_BAND; }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// INTERNAL ONLY
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								 struct is_mpi_op<bitwise_or<T>, T>
							 | 
						||
| 
								 | 
							
								  : public boost::mpl::or_<is_mpi_integer_datatype<T>,
							 | 
						||
| 
								 | 
							
								                           is_mpi_byte_datatype<T> >
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  static MPI_Op op() { return MPI_BOR; }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// INTERNAL ONLY
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								 struct is_mpi_op<bitwise_xor<T>, T>
							 | 
						||
| 
								 | 
							
								  : public boost::mpl::or_<is_mpi_integer_datatype<T>,
							 | 
						||
| 
								 | 
							
								                           is_mpi_byte_datatype<T> >
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  static MPI_Op op() { return MPI_BXOR; }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace detail {
							 | 
						||
| 
								 | 
							
								  // A helper class used to create user-defined MPI_Ops
							 | 
						||
| 
								 | 
							
								  template<typename Op, typename T>
							 | 
						||
| 
								 | 
							
								  class user_op
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								  public:
							 | 
						||
| 
								 | 
							
								    explicit user_op(Op& op)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      BOOST_MPI_CHECK_RESULT(MPI_Op_create,
							 | 
						||
| 
								 | 
							
								                             (&user_op<Op, T>::perform,
							 | 
						||
| 
								 | 
							
								                              is_commutative<Op, T>::value,
							 | 
						||
| 
								 | 
							
								                              &mpi_op));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      op_ptr = &op;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ~user_op()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      if (std::uncaught_exception()) {
							 | 
						||
| 
								 | 
							
								        // Ignore failure cases: there are obviously other problems
							 | 
						||
| 
								 | 
							
								        // already, and we don't want to cause program termination if
							 | 
						||
| 
								 | 
							
								        // MPI_Op_free fails.
							 | 
						||
| 
								 | 
							
								        MPI_Op_free(&mpi_op);
							 | 
						||
| 
								 | 
							
								      } else {
							 | 
						||
| 
								 | 
							
								        BOOST_MPI_CHECK_RESULT(MPI_Op_free, (&mpi_op));
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    MPI_Op& get_mpi_op()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      return mpi_op;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  private:
							 | 
						||
| 
								 | 
							
								    MPI_Op mpi_op;
							 | 
						||
| 
								 | 
							
								    static Op* op_ptr;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    static void BOOST_MPI_CALLING_CONVENTION perform(void* vinvec, void* voutvec, int* plen, MPI_Datatype*)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      T* invec = static_cast<T*>(vinvec);
							 | 
						||
| 
								 | 
							
								      T* outvec = static_cast<T*>(voutvec);
							 | 
						||
| 
								 | 
							
								      std::transform(invec, invec + *plen, outvec, outvec, *op_ptr);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  template<typename Op, typename T> Op* user_op<Op, T>::op_ptr = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								} // end namespace detail
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								} } // end namespace boost::mpi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif // BOOST_MPI_GET_MPI_OP_HPP
							 |