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> ||
165 std::is_same_v<T, MPI_Op>;
166};
167template <template <typename...> typename Base, typename T, typename... Args>
168struct writable<Base<T, Args...>> {
169 static constexpr bool value =
171};
172
173template <typename T>
174struct readable {
175 static constexpr bool value = Deserializable<T> ||
176 std::is_same_v<T, MPI_Datatype> ||
177 std::is_same_v<T, MPI_Op>;
178};
179template <template <typename...> typename Base, typename T, typename... Args>
180struct readable<Base<T, Args...>> {
181 static constexpr bool value = DeserializableVector<T> ||
184};
185
186template <typename T>
187void write(std::ostream& s, const T* t, int n) {
189 // shortcut for trivial types
190 s.write(
191 static_cast<const char*>(static_cast<const void*>(t)), sizeof(T) * n
192 );
193 } else {
194 for (int i = 0; i < n; i++) write(s, t[i]);
195 }
196}
197template <typename T>
198void write(std::ostream& s, const T&& t) {
199 write(s, t);
200}
201
202template <typename T>
203void read(std::istream& s, T* t, int n) {
204 if constexpr (!FunctionDeserializable<T> && TriviallyCopyable<T>) {
205 // shortcut for trivial types
206 s.read(static_cast<char*>(static_cast<void*>(t)), sizeof(T) * n);
207 } else {
208 for (int i = 0; i < n; i++) read(s, t[i]);
209 }
210}
211template <typename T>
212T read(std::istream& s) {
213 if constexpr (FunctionDeserializable<T>) {
214 // force copy elision when possible
215 return T(s);
216 } else {
217 T t;
218 read(s, t);
219 return t;
220 }
221}
222
223} //namespace fenix::logging::serialize
224
225#endif
Definition serialize.h:174
Definition serialize.h:162