Fenix @develop
 
Loading...
Searching...
No Matches
serialize.h
1#ifndef FENIX_LOGGING_SERIALIZE_H
2#define FENIX_LOGGING_SERIALIZE_H
3#include <cassert>
4#include <cstdio>
5#include <vector>
6#include <set>
7#include <type_traits>
8#include <concepts>
9#include <istream>
10#include <ostream>
11#include <optional>
12#include <mpi.h>
13
14namespace fenix::logging::serialize {
15// Helpers for understanding container types
16template <template <typename...> typename Base, typename T>
17struct container_type : std::false_type {
18 using type = void;
19};
20template <template <typename...> typename Base, typename T, typename... U>
21struct container_type<Base, Base<T, U...>> : std::true_type {
22 using type = T;
23};
24
25template <template <typename...> typename Base, typename T>
26constexpr bool container_type_v = container_type<Base, T>::value;
27
28template <template <typename...> typename Base, typename T>
29using container_type_t = typename container_type<Base, T>::type;
30
31// Helpers for understanding if a type is readable/writeable
32template <typename T>
33struct writable;
34template <typename T>
35constexpr bool writable_v = writable<T>::value;
36
37template <typename T>
38struct readable;
39template <typename T>
40constexpr bool readable_v = readable<T>::value;
41
42template <typename T>
43concept TriviallyCopyable = std::is_trivially_copyable_v<T>;
44
45template <template <typename...> typename Base, typename T>
47 container_type_v<Base, T> && writable_v<container_type_t<Base, T>>;
48template <template <typename...> typename Base, typename T>
50 container_type_v<Base, T> && readable_v<container_type_t<Base, T>>;
51
52// Convenience functions that convert to the definitions below
53template <typename T>
54void write(std::ostream& s, const T* t, int n);
55template <typename T>
56void write(std::ostream& s, const T&& t);
57
58template <typename T>
59void read(std::istream& s, T* t, int n);
60template <typename T>
61T read(std::istream& s);
62
63// Base read/write functions
64template <typename T>
66 requires(const T t, std::ostream& o) { t.serialize(o); };
67template <typename T>
69template <Serializable T>
70void write(std::ostream& s, const T& t) {
71 if constexpr (FunctionSerializable<T>) {
72 t.serialize(s);
73 } else {
74 s.write(static_cast<const char*>(static_cast<const void*>(&t)), sizeof(T));
75 }
76}
77
78template <typename T>
79concept FunctionDeserializable = requires(T t, std::istream& i) {
80 T(i);
81 t = std::move(t);
82};
83template <typename T>
85template <Deserializable T>
86void read(std::istream& s, T& t) {
87 if constexpr (FunctionDeserializable<T>) {
88 t = T(s);
89 } else {
90 s.read(static_cast<char*>(static_cast<void*>(&t)), sizeof(T));
91 }
92}
93
94// Vector read/write
95template <typename T>
97template <typename T>
99
100template <SerializableVector T>
101void write(std::ostream& s, const T& t) {
102 write<int>(s, t.size());
103 write(s, t.data(), t.size());
104}
105template <DeserializableVector T>
106void read(std::istream& s, T& t) {
107 t.resize(read<int>(s));
108 read(s, t.data(), t.size());
109}
110
111// Set read/write
112template <typename T>
114template <typename T>
116
117template <SerializableSet T>
118void write(std::ostream& s, const T& st) {
119 write<int>(s, st.size());
120 for (auto& t : st) write(s, t);
121}
122template <DeserializableSet T>
123void read(std::istream& s, T& st) {
124 assert(st.empty());
125 int size = read<int>(s);
126 for (int i = 0; i < size; i++) {
127 auto [it, inserted] = st.insert(read<container_type_t<std::set, T>>(s));
128 assert(inserted);
129 }
130}
131
132// Optional read/write
133template <typename T>
135template <typename T>
137
138template <SerializableOptional T>
139void write(std::ostream& s, const T& t) {
140 write<bool>(s, t);
141 if (t) write(s, *t);
142}
143template <DeserializableOptional T>
144void read(std::istream& s, T& t) {
145 if (read<bool>(s)) {
146 t.emplace(read<container_type_t<std::optional, T>>(s));
147 } else {
148 t.reset();
149 }
150}
151
152// MPI_Datatype read/write
153void write(std::ostream& s, const MPI_Datatype& d);
154void read(std::istream& s, MPI_Datatype& d);
155
156// MPI_Op read/write
157void write(std::ostream& s, const MPI_Op& d);
158void read(std::istream& s, MPI_Op& d);
159
160// Read/write helper structs and convenience functions
161template <typename T>
162struct writable {
163 static constexpr bool value = Serializable<T> ||
164 std::is_same_v<T, MPI_Datatype> || std::is_same_v<T, MPI_Op>;
165};
166template <template <typename...> typename Base, typename T, typename... Args>
167struct writable<Base<T, Args...>> {
168 static constexpr bool value =
170};
171
172template <typename T>
173struct readable {
174 static constexpr bool value = Deserializable<T> ||
175 std::is_same_v<T, MPI_Datatype> || std::is_same_v<T, MPI_Op>;
176};
177template <template <typename...> typename Base, typename T, typename... Args>
178struct readable<Base<T, Args...>> {
179 static constexpr bool value = DeserializableVector<T> ||
181};
182
183template <typename T>
184void write(std::ostream& s, const T* t, int n) {
186 // shortcut for trivial types
187 s.write(
188 static_cast<const char*>(static_cast<const void*>(t)), sizeof(T) * n
189 );
190 } else {
191 for (int i = 0; i < n; i++) write(s, t[i]);
192 }
193}
194template <typename T>
195void write(std::ostream& s, const T&& t) {
196 write(s, t);
197}
198
199template <typename T>
200void read(std::istream& s, T* t, int n) {
201 if constexpr (!FunctionDeserializable<T> && TriviallyCopyable<T>) {
202 // shortcut for trivial types
203 s.read(static_cast<char*>(static_cast<void*>(t)), sizeof(T) * n);
204 } else {
205 for (int i = 0; i < n; i++) read(s, t[i]);
206 }
207}
208template <typename T>
209T read(std::istream& s) {
210 if constexpr (FunctionDeserializable<T>) {
211 // force copy elision when possible
212 return T(s);
213 } else {
214 T t;
215 read(s, t);
216 return t;
217 }
218}
219
220} //namespace fenix::logging::serialize
221
222#endif
Definition serialize.h:173
Definition serialize.h:162