123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- // 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/core/enable_if.hpp>
- #include <boost/core/uncaught_exceptions.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
- {
- typedef T first_argument_type;
- typedef T second_argument_type;
- typedef T result_type;
- /** @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
- {
- typedef T first_argument_type;
- typedef T second_argument_type;
- typedef T result_type;
- /** @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
- {
- typedef T first_argument_type;
- typedef T second_argument_type;
- typedef T result_type;
- /** @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
- {
- typedef T first_argument_type;
- typedef T second_argument_type;
- typedef T result_type;
- /** @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
- {
- typedef T first_argument_type;
- typedef T second_argument_type;
- typedef T result_type;
- /** @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
- {
- typedef T first_argument_type;
- typedef T second_argument_type;
- typedef T result_type;
- /** @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:
- user_op()
- {
- BOOST_MPI_CHECK_RESULT(MPI_Op_create,
- (&user_op<Op, T>::perform,
- is_commutative<Op, T>::value,
- &mpi_op));
- }
- ~user_op()
- {
- if (boost::core::uncaught_exceptions() > 0) {
- // 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 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);
- Op op;
- std::transform(invec, invec + *plen, outvec, outvec, op);
- }
- };
- } // end namespace detail
- } } // end namespace boost::mpi
- #endif // BOOST_MPI_GET_MPI_OP_HPP
|