Skip to content

Commit

Permalink
Merge pull request #13473 from bangerth/is_mpi_type
Browse files Browse the repository at this point in the history
  • Loading branch information
masterleinad committed Mar 4, 2022
2 parents 600b14a + 6a3643a commit 0fe3491
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 2 deletions.
5 changes: 5 additions & 0 deletions doc/news/changes/minor/20220301Bangerth
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
New: There is now a template variable Utilities::MPI::is_mpi_type that
can be used to query whether a data type is a natively supported MPI
type.
<br>
(Wolfgang Bangerth, 2022/03/01)
32 changes: 32 additions & 0 deletions include/deal.II/base/mpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@
#include <deal.II/base/index_set.h>
#include <deal.II/base/mpi_tags.h>
#include <deal.II/base/numbers.h>
#include <deal.II/base/template_constraints.h>

#include <boost/signals2.hpp>

#include <complex>
#include <map>
#include <numeric>
#include <set>
Expand Down Expand Up @@ -127,6 +129,36 @@ namespace Utilities
*/
namespace MPI
{
/**
* A template variable that is `true` if the template argument `T` is a data
* type that is natively supported by MPI, and `false` otherwise. This
* variable can be used together with `std::enable_if` to selectively allow
* template functions only for those data types for which the template type
* is supported by MPI. The variable is, in essence, a concept in the sense
* of C++20.
*/
template <typename T>
constexpr bool is_mpi_type = is_same_as_any_of<T,
char,
signed short,
signed int,
signed long,
signed long long,
signed char,
unsigned char,
unsigned short,
unsigned int,
unsigned long int,
unsigned long long,
float,
double,
long double,
bool,
std::complex<float>,
std::complex<double>,
std::complex<long double>,
wchar_t>::value;

/**
* Return the number of MPI processes there exist in the given
* @ref GlossMPICommunicator "communicator"
Expand Down
49 changes: 47 additions & 2 deletions include/deal.II/base/template_constraints.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,22 @@ namespace internal
{
namespace TemplateConstraints
{
// TODO: Once we are able to use DEAL_II_HAVE_CXX17, the following classes
// can be made much simpler with the help of fold expressions, see
// https://en.cppreference.com/w/cpp/language/fold

// helper struct for is_base_of_all and all_same_as
template <bool... Values>
struct BoolStorage;


/**
* A helper class whose `value` member is true or false depending on
* whether all of the given boolean template arguments are true.
* whether all of the given boolean template arguments are `true`.
* The class works by comparing the list of boolean values
* `true, Values...` with the list `Values..., true` (i.e., with
* its rotated self). The two are only the same if `Values...` is
* a list of only `true` values.
*/
template <bool... Values>
struct all_true
Expand All @@ -179,6 +187,28 @@ namespace internal
std::is_same<BoolStorage<Values..., true>,
BoolStorage<true, Values...>>::value;
};


/**
* A class whose `value` member is set to `true` if any of the
* boolean template arguments are true.
*/
template <bool... Values>
struct any_true;


template <bool V1, bool... Values>
struct any_true<V1, Values...>
{
static constexpr bool value = V1 || any_true<Values...>::value;
};


template <>
struct any_true<>
{
static constexpr bool value = false;
};
} // namespace TemplateConstraints
} // namespace internal

Expand All @@ -201,7 +231,7 @@ struct is_base_of_all
* This struct is a generalization of std::is_same to template
* parameter packs and tests if all of the types in the `Types...`
* parameter pack are equal to the `Type` given as first template
* argument. The result is stored in the member variable value.
* argument. The result is stored in the member variable `value`.
*/
template <class Type, class... Types>
struct all_same_as
Expand All @@ -212,6 +242,21 @@ struct all_same_as



/**
* This struct is a generalization of std::is_same to template
* parameter packs and tests if any of the types in the `Types...`
* parameter pack are equal to the `Type` given as first template
* argument. The result is stored in the member variable `value`.
*/
template <class Type, class... Types>
struct is_same_as_any_of
{
static constexpr bool value = internal::TemplateConstraints::any_true<
std::is_same<Type, Types>::value...>::value;
};



/*
* A generalization of `std::enable_if` that only works if
* <i>all</i> of the given boolean template parameters are
Expand Down
67 changes: 67 additions & 0 deletions tests/mpi/is_mpi_type.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// ---------------------------------------------------------------------
//
// Copyright (C) 2020 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE.md at
// the top level directory of deal.II.
//
// ---------------------------------------------------------------------


// Test the Utilities::MPI::is_mpi_type template variable.

#include <deal.II/base/mpi.h>

#include "../tests.h"

using namespace dealii;

void
test()
{
deallog << std::boolalpha;

// Verify that the following types are all supported:
deallog << Utilities::MPI::is_mpi_type<char> << std::endl;
deallog << Utilities::MPI::is_mpi_type<signed short> << std::endl;
deallog << Utilities::MPI::is_mpi_type<signed int> << std::endl;
deallog << Utilities::MPI::is_mpi_type<signed long> << std::endl;
deallog << Utilities::MPI::is_mpi_type<signed long long> << std::endl;
deallog << Utilities::MPI::is_mpi_type<signed char> << std::endl;
deallog << Utilities::MPI::is_mpi_type<unsigned char> << std::endl;
deallog << Utilities::MPI::is_mpi_type<unsigned short> << std::endl;
deallog << Utilities::MPI::is_mpi_type<unsigned int> << std::endl;
deallog << Utilities::MPI::is_mpi_type<unsigned long int> << std::endl;
deallog << Utilities::MPI::is_mpi_type<unsigned long long> << std::endl;
deallog << Utilities::MPI::is_mpi_type<float> << std::endl;
deallog << Utilities::MPI::is_mpi_type<double> << std::endl;
deallog << Utilities::MPI::is_mpi_type<long double> << std::endl;
deallog << Utilities::MPI::is_mpi_type<bool> << std::endl;
deallog << Utilities::MPI::is_mpi_type<std::complex<float>> << std::endl;
deallog << Utilities::MPI::is_mpi_type<std::complex<double>> << std::endl;
deallog
<< Utilities::MPI::is_mpi_type<std::complex<long double>> << std::endl;
deallog << Utilities::MPI::is_mpi_type<wchar_t> << std::endl;


// Then also check a non-native type:
struct X
{};
deallog << Utilities::MPI::is_mpi_type<X> << std::endl;
}


int
main(int argc, char *argv[])
{
Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);
MPILogInitAll all;

test();
}
21 changes: 21 additions & 0 deletions tests/mpi/is_mpi_type.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::true
DEAL:0::false

0 comments on commit 0fe3491

Please sign in to comment.