Fenix @develop
 
Loading...
Searching...
No Matches
datatype.hpp
1#ifndef FENIX_MPIXX_DATATYPE_HPP
2#define FENIX_MPIXX_DATATYPE_HPP
3
4#include <mpi.h>
5
6#include <cstddef>
7#include <cstdint>
8#include <utility>
9#include <vector>
10
11#include "fenix/mpixx/util.hpp"
12
13namespace fenix::mpixx {
14
15// RAII wrapper for MPI_Datatype with move-only semantics
16// Owns an MPI_Datatype handle and automatically frees it on destruction.
17// Does NOT free builtin MPI datatypes (MPI_INT, MPI_DOUBLE, etc.).
18// Accessors check MPI initialization state and return MPI_DATATYPE_NULL
19// if MPI is not initialized or has been finalized.
20class Datatype {
21 public:
22 // Construct from existing MPI_Datatype (takes ownership)
23 explicit Datatype(MPI_Datatype type) noexcept : type_(type) {}
24
25 // Default constructor creates MPI_DATATYPE_NULL
26 Datatype() noexcept : Datatype(MPI_DATATYPE_NULL) {}
27
28 // Destructor automatically frees non-builtin types
29 virtual ~Datatype() { free(); }
30
31 // Move semantics (frees old type before taking ownership)
32 Datatype& operator=(Datatype&& o) noexcept;
33 Datatype& operator=(MPI_Datatype type) { return *this = Datatype(type); }
34 Datatype(Datatype&& o) noexcept { *this = std::move(o); }
35
36 // Delete copy operations (move-only)
37 Datatype(const Datatype&) = delete;
38 Datatype& operator=(const Datatype&) = delete;
39
40 // Accessors
41 MPI_Datatype get() const noexcept {
42 return mpi_active() ? type_ : MPI_DATATYPE_NULL;
43 }
44
45 // Implicit conversion to MPI_Datatype
46 operator MPI_Datatype() const noexcept { return get(); }
47
48 explicit operator bool() const noexcept { return get() != MPI_DATATYPE_NULL; }
49
50 // Release ownership without freeing
51 MPI_Datatype release() noexcept;
52
53 // MPI datatype operations
54 void commit();
55 int size() const;
56 int extent() const;
57 void get_extent(MPI_Aint* lb, MPI_Aint* extent) const;
58 void get_true_extent(MPI_Aint* true_lb, MPI_Aint* true_extent) const;
59
60 // Check if this is a builtin type
61 bool is_builtin() const noexcept;
62
63 // Free the datatype (safe even if type_ is MPI_DATATYPE_NULL or builtin)
64 virtual void free();
65
66 // ========== Type Construction Factory Methods ==========
67
68 // Create contiguous type
69 static Datatype contiguous(int count, MPI_Datatype oldtype);
70
71 // Create vector type (regular strided pattern with element strides)
72 static Datatype vector(
73 int count, int blocklength, int stride, MPI_Datatype oldtype
74 );
75
76 // Create hvector (vector with byte stride)
77 static Datatype hvector(
78 int count, int blocklength, MPI_Aint stride, MPI_Datatype oldtype
79 );
80
81 // Create indexed type (variable blocks and displacements in element units)
82 static Datatype indexed(
83 int count, const int* array_of_blocklengths,
84 const int* array_of_displacements, MPI_Datatype oldtype
85 );
86
87 // Create hindexed (indexed with byte displacements)
88 static Datatype hindexed(
89 int count, const int* array_of_blocklengths,
90 const MPI_Aint* array_of_displacements, MPI_Datatype oldtype
91 );
92
93 // Create indexed_block (all blocks same length, element displacements)
94 static Datatype indexed_block(
95 int count, int blocklength, const int* array_of_displacements,
96 MPI_Datatype oldtype
97 );
98
99 // Create hindexed_block (indexed_block with byte displacements)
100 static Datatype hindexed_block(
101 int count, int blocklength, const MPI_Aint* array_of_displacements,
102 MPI_Datatype oldtype
103 );
104
105 // Create struct type (heterogeneous)
106 static Datatype create_struct(
107 int count, const int* array_of_blocklengths,
108 const MPI_Aint* array_of_displacements, const MPI_Datatype* array_of_types
109 );
110
111 // Create subarray type (multidimensional subarray)
112 static Datatype subarray(
113 int ndims, const int* array_of_sizes, const int* array_of_subsizes,
114 const int* array_of_starts, int order, MPI_Datatype oldtype
115 );
116
117 // Create darray (distributed array) type
118 static Datatype darray(
119 int size, int rank, int ndims, const int* array_of_gsizes,
120 const int* array_of_distribs, const int* array_of_dargs,
121 const int* array_of_psizes, int order, MPI_Datatype oldtype
122 );
123
124 // Create resized type (change lower bound and extent)
125 static Datatype resized(MPI_Datatype oldtype, MPI_Aint lb, MPI_Aint extent);
126
127 // Create duplicate type
128 static Datatype dup(MPI_Datatype oldtype);
129
130 // ========== Serialization ==========
131
132 // Serialize this datatype to a portable byte buffer
133 // Returns vector of bytes that can be sent to another rank
134 std::vector<uint8_t> serialize() const;
135
136 // Deserialize from byte buffer to reconstruct datatype
137 // Throws if buffer is invalid or deserialization fails
138 static Datatype deserialize(const std::vector<uint8_t>& buffer);
139 static Datatype deserialize(const uint8_t* data, size_t size);
140
141 private:
142 MPI_Datatype type_ = MPI_DATATYPE_NULL;
143
144 // Helper: Check if a given MPI_Datatype is builtin
145 static bool is_builtin_type(MPI_Datatype type) noexcept;
146
147 // Serialization helpers (implementation details in .cpp)
148 struct TypeInfo;
149 static TypeInfo introspect(MPI_Datatype type);
150 static void serialize_recursive(
151 MPI_Datatype type, std::vector<uint8_t>& buffer
152 );
153 static Datatype deserialize_recursive(
154 const uint8_t*& ptr, const uint8_t* end
155 );
156};
157
158// Non-owning reference to an MPI_Datatype
159// Does not free the datatype on destruction, only releases ownership.
160// Useful for storing datatypes that are owned elsewhere (e.g., builtins).
161// Unlike Datatype, DatatypeRef is copyable since it doesn't own the resource.
162class DatatypeRef : public Datatype {
163 public:
164 // Implicit constructor from MPI_Datatype
165 DatatypeRef(MPI_Datatype type = MPI_DATATYPE_NULL) : Datatype(type) {}
166 DatatypeRef(const Datatype& dt) : Datatype(dt.get()) {}
167 DatatypeRef(const DatatypeRef& other) : Datatype(other.get()) {}
168
169 DatatypeRef& operator=(const DatatypeRef& other) {
170 *this = other.get();
171 return *this;
172 }
173 DatatypeRef& operator=(const Datatype& dt) {
174 *this = dt.get();
175 return *this;
176 }
177 DatatypeRef& operator=(DatatypeRef&& other) {
178 if (this != &other) {
179 (void)release();
180 *this = other.release();
181 }
182 return *this;
183 }
184 DatatypeRef& operator=(MPI_Datatype type) {
185 (void)release();
186 // Directly assign to base class via Datatype's assignment operator
187 Datatype::operator=(Datatype(type));
188 return *this;
189 }
190
191 ~DatatypeRef() override { (void)release(); }
192};
193
194} // namespace fenix::mpixx
195
196#endif // FENIX_MPIXX_DATATYPE_HPP
Definition datatype.hpp:162
Definition datatype.hpp:20
Definition datatype.cpp:409