62 template <> struct mpi_type<T> { \
63 [[nodiscard]] static MPI_Datatype get() noexcept { return MPI_TY; } \
71 D(
long long, MPI_LONG_LONG);
72 D(
double, MPI_DOUBLE);
74 D(std::complex<double>, MPI_C_DOUBLE_COMPLEX);
75 D(
unsigned long, MPI_UNSIGNED_LONG);
76 D(
unsigned int, MPI_UNSIGNED);
77 D(
unsigned long long, MPI_UNSIGNED_LONG_LONG);
85 requires(std::is_enum_v<E>)
99 template <
typename T,
typename =
void>
constexpr bool has_mpi_type =
false;
110 struct serialize_checker {
111 template <
typename T>
123 template <
typename T>
124 concept Serializable =
requires(
const T ac, T a, detail::serialize_checker ar) {
125 { ac.serialize(ar) } -> std::same_as<void>;
126 { a.deserialize(ar) } -> std::same_as<void>;
141 template <
typename... Ts> [[nodiscard]] MPI_Datatype
get_mpi_type(std::tuple<Ts...> tup) {
142 static constexpr int N =
sizeof...(Ts);
146 std::array<int, N> blocklen;
147 for (
int i = 0; i < N; ++i) { blocklen[i] = 1; }
150 std::array<MPI_Aint, N> disp;
152 []<
size_t... Is>(std::index_sequence<Is...>,
auto &t, MPI_Aint *d) {
153 ((d[Is] = (
char *)&std::get<Is>(t) - (
char *)&std::get<0>(t)), ...);
155 auto min_el = *std::min_element(d, d +
sizeof...(Ts));
156 ((d[Is] -= min_el), ...);
157 }(std::index_sequence_for<Ts...>{}, tup, disp.data());
161 check_mpi_call(MPI_Type_create_struct(N, blocklen.data(), disp.data(), types.data(), &cty),
"MPI_Type_create_struct");
170 template <
typename... Ts>
struct mpi_type<std::tuple<Ts...>> {
171 [[nodiscard]]
static MPI_Datatype get()
noexcept {
172 static MPI_Datatype type =
get_mpi_type(std::tuple<Ts...>{});
198 template <
typename U>
201 [[nodiscard]]
static MPI_Datatype get()
noexcept {
211 std::vector<int> block_lengths{};
212 std::vector<MPI_Aint> displacements{};
213 std::vector<MPI_Datatype> types{};
214 MPI_Aint base_address{};
217 explicit mpi_archive(
const void *base) { MPI_Get_address(base, &base_address); }
220 template <
typename T>
222 mpi_archive &
operator&(
const T &member) {
223 types.push_back(mpi_type<T>::get());
225 MPI_Get_address(&member, &address);
226 displacements.push_back(MPI_Aint_diff(address, base_address));
227 block_lengths.push_back(1);
251 template <Serializable T> [[nodiscard]] MPI_Datatype
get_mpi_type(
const T &obj) {
252 detail::mpi_archive ar(&obj);
255 MPI_Type_create_struct(
static_cast<int>(ar.block_lengths.size()), ar.block_lengths.data(), ar.displacements.data(), ar.types.data(), &
mpi_type);
265 [[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.