61 template <> struct mpi_type<T> { \
62 [[nodiscard]] static MPI_Datatype get() noexcept { return MPI_TY; } \
70 D(
long long, MPI_LONG_LONG);
71 D(
double, MPI_DOUBLE);
73 D(std::complex<double>, MPI_C_DOUBLE_COMPLEX);
74 D(
unsigned long, MPI_UNSIGNED_LONG);
75 D(
unsigned int, MPI_UNSIGNED);
76 D(
unsigned long long, MPI_UNSIGNED_LONG_LONG);
84 requires(std::is_enum_v<E>)
97 template <
typename T,
typename =
void>
constexpr bool has_mpi_type =
false;
108 struct serialize_checker {
109 template <
typename T>
121 template <
typename T>
122 concept Serializable =
requires(
const T ac, T a, detail::serialize_checker ar) {
123 { ac.serialize(ar) } -> std::same_as<void>;
124 { a.deserialize(ar) } -> std::same_as<void>;
139 template <
typename... Ts> [[nodiscard]] MPI_Datatype
get_mpi_type(std::tuple<Ts...> tup) {
140 static constexpr int N =
sizeof...(Ts);
144 std::array<int, N> blocklen;
145 for (
int i = 0; i < N; ++i) { blocklen[i] = 1; }
148 std::array<MPI_Aint, N> disp;
150 []<
size_t... Is>(std::index_sequence<Is...>,
auto &t, MPI_Aint *d) {
151 ((d[Is] = (
char *)&std::get<Is>(t) - (
char *)&std::get<0>(t)), ...);
153 auto min_el = *std::min_element(d, d +
sizeof...(Ts));
154 ((d[Is] -= min_el), ...);
155 }(std::index_sequence_for<Ts...>{}, tup, disp.data());
159 check_mpi_call(MPI_Type_create_struct(N, blocklen.data(), disp.data(), types.data(), &cty),
"MPI_Type_create_struct");
168 template <
typename... Ts>
struct mpi_type<std::tuple<Ts...>> {
169 [[nodiscard]]
static MPI_Datatype get()
noexcept {
170 static MPI_Datatype type =
get_mpi_type(std::tuple<Ts...>{});
196 template <
typename U>
199 [[nodiscard]]
static MPI_Datatype get()
noexcept {
209 std::vector<int> block_lengths{};
210 std::vector<MPI_Aint> displacements{};
211 std::vector<MPI_Datatype> types{};
212 MPI_Aint base_address{};
215 explicit mpi_archive(
const void *base) { MPI_Get_address(base, &base_address); }
218 template <
typename T>
220 mpi_archive &
operator&(
const T &member) {
221 types.push_back(mpi_type<T>::get());
223 MPI_Get_address(&member, &address);
224 displacements.push_back(MPI_Aint_diff(address, base_address));
225 block_lengths.push_back(1);
249 template <Serializable T> [[nodiscard]] MPI_Datatype
get_mpi_type(
const T &obj) {
250 detail::mpi_archive ar(&obj);
253 MPI_Type_create_struct(
static_cast<int>(ar.block_lengths.size()), ar.block_lengths.data(), ar.displacements.data(), ar.types.data(), &
mpi_type);
263 [[nodiscard]]
static MPI_Datatype get()
noexcept {
A concept that checks if objects of a type can be serialized and deserialized.
MPI_Datatype get_mpi_type(std::tuple< Ts... > tup)
Create a new MPI_Datatype from a tuple.
constexpr bool has_mpi_type
Type trait to check if a type T has a corresponding MPI datatype, i.e. if mpi::mpi_type has been spec...
void check_mpi_call(int errcode, const std::string &mpi_routine)
Check the success of an MPI call.
Map C++ datatypes to the corresponding MPI datatypes.
Provides general utilities related to MPI.