19 #ifndef TIMPI_OP_FUNCTION_H    20 #define TIMPI_OP_FUNCTION_H    22 #include "timpi/timpi_config.h"    32 #endif // TIMPI_HAVE_MPI    35 #ifdef TIMPI_DEFAULT_QUADRUPLE_PRECISION    36 # include <boost/multiprecision/float128.hpp>    41 #include <type_traits>    47 #ifdef TIMPI_DEFAULT_QUADRUPLE_PRECISION    48 # ifdef TIMPI_HAVE_MPI    49 # define TIMPI_MPI_QUAD_BINARY(funcname) \    51 timpi_mpi_quad_##funcname(void * a, void * b, int * len, MPI_Datatype *) \    53   const int size = *len; \    55   TIMPI_DEFAULT_SCALAR_TYPE *in = static_cast<TIMPI_DEFAULT_SCALAR_TYPE*>(a); \    56   TIMPI_DEFAULT_SCALAR_TYPE *inout = static_cast<TIMPI_DEFAULT_SCALAR_TYPE*>(b); \    57   for (int i=0; i != size; ++i) \    58     inout[i] = std::funcname(in[i],inout[i]); \    61 # define TIMPI_MPI_QUAD_LOCATOR(funcname) \    63 timpi_mpi_quad_##funcname##_location(void * a, void * b, int * len, MPI_Datatype *) \    65   const int size = *len; \    67   typedef std::pair<TIMPI_DEFAULT_SCALAR_TYPE, int> dtype; \    69   dtype *in = static_cast<dtype*>(a); \    70   dtype *inout = static_cast<dtype*>(b); \    71   for (int i=0; i != size; ++i) \    73       TIMPI_DEFAULT_SCALAR_TYPE old_inout = inout[i].first; \    74       inout[i].first = std::funcname(in[i].first,inout[i].first); \    75       if (old_inout != inout[i].first) \    76         inout[i].second = in[i].second; \    81 # define TIMPI_MPI_QUAD_BINARY_FUNCTOR(funcname) \    83 timpi_mpi_quad_##funcname(void * a, void * b, int * len, MPI_Datatype *) \    85   const int size = *len; \    87   TIMPI_DEFAULT_SCALAR_TYPE *in = static_cast<TIMPI_DEFAULT_SCALAR_TYPE*>(a); \    88   TIMPI_DEFAULT_SCALAR_TYPE *inout = static_cast<TIMPI_DEFAULT_SCALAR_TYPE*>(b); \    89   for (int i=0; i != size; ++i) \    90     inout[i] = std::funcname<TIMPI_DEFAULT_SCALAR_TYPE>()(in[i],inout[i]); \    94 TIMPI_MPI_QUAD_BINARY(max)
    95 TIMPI_MPI_QUAD_BINARY(min)
    96 TIMPI_MPI_QUAD_LOCATOR(max)
    97 TIMPI_MPI_QUAD_LOCATOR(min)
    98 TIMPI_MPI_QUAD_BINARY_FUNCTOR(plus)
    99 TIMPI_MPI_QUAD_BINARY_FUNCTOR(multiplies)
   101 # endif // TIMPI_HAVE_MPI   102 #endif // TIMPI_DEFAULT_QUADRUPLE_PRECISION   109 struct opfunction_dependent_false : std::false_type
   119 template <
typename T>
   123   static_assert(opfunction_dependent_false<T>::value,
   124                 "Only specializations of OpFunction may be used, did you forget to include a header file (e.g. parallel_algebra.h)?");
   155 #ifdef TIMPI_HAVE_MPI   157 #define TIMPI_PARALLEL_INTEGER_OPS(cxxtype)          \   159   class OpFunction<cxxtype>                             \   162     static MPI_Op max()          { return MPI_MAX; }    \   163     static MPI_Op min()          { return MPI_MIN; }    \   164     static MPI_Op sum()          { return MPI_SUM; }    \   165     static MPI_Op product()      { return MPI_PROD; }   \   166     static MPI_Op logical_and()  { return MPI_LAND; }   \   167     static MPI_Op bitwise_and()  { return MPI_BAND; }   \   168     static MPI_Op logical_or()   { return MPI_LOR; }    \   169     static MPI_Op bitwise_or()   { return MPI_BOR; }    \   170     static MPI_Op logical_xor()  { return MPI_LXOR; }   \   171     static MPI_Op bitwise_xor()  { return MPI_BXOR; }   \   172     static MPI_Op max_location() { return MPI_MAXLOC; } \   173     static MPI_Op min_location() { return MPI_MINLOC; } \   176 #define TIMPI_PARALLEL_FLOAT_OPS(cxxtype)            \   178   class OpFunction<cxxtype>                             \   181     static MPI_Op max()          { return MPI_MAX; }    \   182     static MPI_Op min()          { return MPI_MIN; }    \   183     static MPI_Op sum()          { return MPI_SUM; }    \   184     static MPI_Op product()      { return MPI_PROD; }   \   185     static MPI_Op max_location() { return MPI_MAXLOC; } \   186     static MPI_Op min_location() { return MPI_MINLOC; } \   191 #define TIMPI_PARALLEL_INTEGER_OPS(cxxtype)  \   193   class OpFunction<cxxtype>                     \   197 #define TIMPI_PARALLEL_FLOAT_OPS(cxxtype)    \   199   class OpFunction<cxxtype>                     \   221 #ifdef TIMPI_HAVE_MPI   226   ManageOp(MPI_User_function * func, 
int commute, MPI_Op * op)
   229     timpi_call_mpi(MPI_Op_create(func, commute, 
_op));
   240 #define TIMPI_MPI_OPFUNCTION(mpiname, funcname) \   241   static MPI_Op mpiname() { \   242     static MPI_Op TIMPI_MPI_##mpiname = MPI_OP_NULL; \   243     if (TIMPI_MPI_##mpiname == MPI_OP_NULL) \   245         (std::make_unique<ManageOp>(timpi_mpi_##funcname, true, &TIMPI_MPI_##mpiname)); \   246     return TIMPI_MPI_##mpiname;  \   249 #ifdef TIMPI_DEFAULT_QUADRUPLE_PRECISION   250 # ifdef TIMPI_HAVE_MPI   255     TIMPI_MPI_OPFUNCTION(max, quad_max)
   256     TIMPI_MPI_OPFUNCTION(min, quad_min)
   257     TIMPI_MPI_OPFUNCTION(sum, quad_plus)
   258     TIMPI_MPI_OPFUNCTION(product, quad_multiplies)
   260     TIMPI_MPI_OPFUNCTION(max_location, quad_max_location)
   261     TIMPI_MPI_OPFUNCTION(min_location, quad_min_location)
   267 #endif // TIMPI_DEFAULT_QUADRUPLE_PRECISION   269 #ifdef TIMPI_HAVE_MPI   271 # define TIMPI_MPI_PAIR_BINARY(funcname) \   273 timpi_mpi_pair_##funcname(void * a, void * b, int * len, MPI_Datatype *) \   275   const int size = *len; \   277   const std::pair<T,U> * in = static_cast<std::pair<T,U> *>(a); \   278   std::pair<T,U> * inout = static_cast<std::pair<T,U> *>(b); \   279   for (int i=0; i != size; ++i) \   281       inout[i].first = std::funcname(in[i].first,inout[i].first); \   282       inout[i].second = std::funcname(in[i].second,inout[i].second); \   286 # define TIMPI_MPI_PAIR_LOCATOR(funcname) \   288 timpi_mpi_pair_##funcname##_location(void * a, void * b, int * len, MPI_Datatype *) \   290   const int size = *len; \   292   typedef std::pair<std::pair<T,U>, int> dtype; \   294   dtype *in = static_cast<dtype*>(a); \   295   dtype *inout = static_cast<dtype*>(b); \   296   for (int i=0; i != size; ++i) \   298       std::pair<T,U> old_inout = inout[i].first; \   299       inout[i].first.first  = std::funcname(in[i].first.first, inout[i].first.first); \   300       inout[i].first.second = std::funcname(in[i].first.second,inout[i].first.second); \   301       if (old_inout != inout[i].first) \   302         inout[i].second = in[i].second; \   307 # define TIMPI_MPI_PAIR_BINARY_FUNCTOR(funcname) \   309 timpi_mpi_pair_##funcname(void * a, void * b, int * len, MPI_Datatype *) \   311   const int size = *len; \   313   const std::pair<T,U> * in = static_cast<std::pair<T,U> *>(a); \   314   std::pair<T,U> * inout = static_cast<std::pair<T,U> *>(b); \   315   for (int i=0; i != size; ++i) \   317       inout[i].first  = std::funcname<T>()(in[i].first, inout[i].first); \   318       inout[i].second = std::funcname<T>()(in[i].second,inout[i].second); \   323   template<
typename T, 
typename U>
   326     TIMPI_MPI_PAIR_BINARY(max)
   327     TIMPI_MPI_PAIR_BINARY(min)
   328     TIMPI_MPI_PAIR_LOCATOR(max)
   329     TIMPI_MPI_PAIR_LOCATOR(min)
   330     TIMPI_MPI_PAIR_BINARY_FUNCTOR(plus)
   331     TIMPI_MPI_PAIR_BINARY_FUNCTOR(multiplies)
   334     TIMPI_MPI_OPFUNCTION(max, pair_max)
   335     TIMPI_MPI_OPFUNCTION(min, pair_min)
   336     TIMPI_MPI_OPFUNCTION(sum, pair_plus)
   337     TIMPI_MPI_OPFUNCTION(product, pair_multiplies)
   339     TIMPI_MPI_OPFUNCTION(max_location, pair_max_location)
   340     TIMPI_MPI_OPFUNCTION(min_location, pair_min_location)
   342 # else // TIMPI_HAVE_MPI   343   template<
typename T, 
typename U>
   349 #endif // TIMPI_OP_FUNCTION_H 
ManageOp(MPI_User_function *func, int commute, MPI_Op *op)
virtual ~ManageOp() override
TIMPI_PARALLEL_FLOAT_OPS(float)
The SemiPermanent "class" is basically just a place for a destructor vtable. 
TIMPI_PARALLEL_INTEGER_OPS(char)
Templated class to provide the appropriate MPI reduction operations for use with built-in C types or ...