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