| // 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 |