Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a template variable that can be used to query whether T is a natively supported MPI type. #13473

Merged
merged 5 commits into from
Mar 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -139,6 +141,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