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>)
98 template <
typename T,
typename =
void>
constexpr bool has_mpi_type =
false;
109 struct serialize_checker {
110 template <
typename T>
122 template <
typename T>
123 concept Serializable =
requires(
const T ac, T a, detail::serialize_checker ar) {
124 { ac.serialize(ar) } -> std::same_as<void>;
125 { a.deserialize(ar) } -> std::same_as<void>;
140 template <
typename... Ts> [[nodiscard]] MPI_Datatype
get_mpi_type(std::tuple<Ts...> tup) {
141 static constexpr int N =
sizeof...(Ts);
145 std::array<int, N> blocklen;
146 for (
int i = 0; i < N; ++i) { blocklen[i] = 1; }
149 std::array<MPI_Aint, N> disp;
151 []<
size_t... Is>(std::index_sequence<Is...>,
auto &t, MPI_Aint *d) {
152 ((d[Is] = (
char *)&std::get<Is>(t) - (
char *)&std::get<0>(t)), ...);
154 auto min_el = *std::min_element(d, d +
sizeof...(Ts));
155 ((d[Is] -= min_el), ...);
156 }(std::index_sequence_for<Ts...>{}, tup, disp.data());
160 check_mpi_call(MPI_Type_create_struct(N, blocklen.data(), disp.data(), types.data(), &cty),
"MPI_Type_create_struct");
169 template <
typename... Ts>
struct mpi_type<std::tuple<Ts...>> {
170 [[nodiscard]]
static MPI_Datatype get()
noexcept {
171 static MPI_Datatype type =
get_mpi_type(std::tuple<Ts...>{});
197 template <
typename U>
200 [[nodiscard]]
static MPI_Datatype get()
noexcept {
210 std::vector<int> block_lengths{};
211 std::vector<MPI_Aint> displacements{};
212 std::vector<MPI_Datatype> types{};
213 MPI_Aint base_address{};
216 explicit mpi_archive(
const void *base) { MPI_Get_address(base, &base_address); }
219 template <
typename T>
221 mpi_archive &
operator&(
const T &member) {
222 types.push_back(mpi_type<T>::get());
224 MPI_Get_address(&member, &address);
225 displacements.push_back(MPI_Aint_diff(address, base_address));
226 block_lengths.push_back(1);
250 template <Serializable T> [[nodiscard]] MPI_Datatype
get_mpi_type(
const T &obj) {
251 detail::mpi_archive ar(&obj);
254 MPI_Type_create_struct(
static_cast<int>(ar.block_lengths.size()), ar.block_lengths.data(), ar.displacements.data(), ar.types.data(), &
mpi_type);
264 [[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.