My Project
Serializer.hpp
1 /*
2  This file is part of the Open Porous Media project (OPM).
3 
4  OPM is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 2 of the License, or
7  (at your option) any later version.
8 
9  OPM is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with OPM. If not, see <http://www.gnu.org/licenses/>.
16 
17  Consult the COPYING file in the top-level source directory of this
18  module for the precise wording of the license and the list of
19  copyright holders.
20 */
21 #ifndef SERIALIZER_HPP
22 #define SERIALIZER_HPP
23 
24 #include <algorithm>
25 #include <functional>
26 #include <map>
27 #include <memory>
28 #include <optional>
29 #include <set>
30 #include <type_traits>
31 #include <utility>
32 #include <unordered_map>
33 #include <unordered_set>
34 #include <variant>
35 #include <vector>
36 
37 namespace Opm {
38 namespace detail {
39 
40 template<typename ...Ts>
42 {
43 
44 template<std::size_t Index, typename, typename ...Rest>
45 static decltype(auto) make_variant(std::size_t index)
46 {
47  if(Index == index)
48  return std::variant<Ts...>{std::in_place_index_t<Index>{}};
49 
50  if constexpr(sizeof...(Rest) != 0)
51  return make_variant<Index + 1, Rest...>(index);
52  else
53  throw std::runtime_error("Invalid variant index");
54 }
55 
56 };
57 
58 template<typename ...Ts>
59 decltype(auto) make_variant(std::size_t index)
60 {
61  return detail::MakeVariantImpl<Ts...>::template make_variant<0, Ts...>(index);
62 }
63 
64 template<class T>
65 using remove_cvr_t = std::remove_cv_t<std::remove_reference_t<T>>;
66 
67 } // namespace detail
68 
74 template<class Packer>
75 class Serializer {
76 public:
79  explicit Serializer(const Packer& packer) :
80  m_packer(packer)
81  {}
82 
84  template<class T>
85  void operator()(const T& data)
86  {
87  if constexpr (is_ptr<T>::value) {
88  ptr(data);
89  } else if constexpr (is_pair_or_tuple<T>::value) {
90  tuple(data);
91  } else if constexpr (is_variant<T>::value) {
92  variant(data);
93  } else if constexpr (is_optional<T>::value) {
94  optional(data);
95  } else if constexpr (is_vector<T>::value) {
96  vector(data);
97  } else if constexpr (is_map<T>::value) {
98  map(data);
99  } else if constexpr (is_array<T>::value) {
100  array(data);
101  } else if constexpr (is_set<T>::value) {
102  set(data);
103  } else if constexpr (has_serializeOp<detail::remove_cvr_t<T>>::value) {
104  const_cast<T&>(data).serializeOp(*this);
105  } else {
106  if (m_op == Operation::PACKSIZE)
107  m_packSize += m_packer.packSize(data);
108  else if (m_op == Operation::PACK)
109  m_packer.pack(data, m_buffer, m_position);
110  else if (m_op == Operation::UNPACK)
111  m_packer.unpack(const_cast<T&>(data), m_buffer, m_position);
112  }
113  }
114 
118  template<class T>
119  void pack(const T& data)
120  {
122  m_packSize = 0;
123  (*this)(data);
124  m_position = 0;
125  m_buffer.resize(m_packSize);
127  (*this)(data);
128  }
129 
133  template<class... Args>
134  void pack(const Args&... data)
135  {
137  m_packSize = 0;
138  variadic_call(data...);
139  m_position = 0;
140  m_buffer.resize(m_packSize);
142  variadic_call(data...);
143  }
144 
148  template<class T>
149  void unpack(T& data)
150  {
151  m_position = 0;
153  (*this)(data);
154  }
155 
159  template<class... Args>
160  void unpack(Args&... data)
161  {
162  m_position = 0;
164  variadic_call(data...);
165  }
166 
168  size_t position() const
169  {
170  return m_position;
171  }
172 
174  bool isSerializing() const
175  {
176  return m_op != Operation::UNPACK;
177  }
178 
179 protected:
183  template <typename T>
184  void vector(const std::vector<T>& data)
185  {
186  if constexpr (std::is_pod_v<T>) {
187  if (m_op == Operation::PACKSIZE) {
188  (*this)(data.size());
189  m_packSize += m_packer.packSize(data.data(), data.size());
190  } else if (m_op == Operation::PACK) {
191  (*this)(data.size());
192  m_packer.pack(data.data(), data.size(), m_buffer, m_position);
193  } else if (m_op == Operation::UNPACK) {
194  std::size_t size = 0;
195  (*this)(size);
196  auto& data_mut = const_cast<std::vector<T>&>(data);
197  data_mut.resize(size);
198  m_packer.unpack(data_mut.data(), size, m_buffer, m_position);
199  }
200  } else {
201  if (m_op == Operation::UNPACK) {
202  std::size_t size = 0;
203  (*this)(size);
204  auto& data_mut = const_cast<std::vector<T>&>(data);
205  data_mut.resize(size);
206  std::for_each(data_mut.begin(), data_mut.end(), std::ref(*this));
207  } else {
208  (*this)(data.size());
209  std::for_each(data.begin(), data.end(), std::ref(*this));
210  }
211  }
212  }
213 
216  void vector(const std::vector<bool>& data)
217  {
218  if (m_op == Operation::UNPACK) {
219  std::size_t size = 0;
220  (*this)(size);
221  auto& data_mut = const_cast<std::vector<bool>&>(data);
222  data_mut.clear();
223  data_mut.reserve(size);
224  for (size_t i = 0; i < size; ++i) {
225  bool entry = false;
226  (*this)(entry);
227  data_mut.push_back(entry);
228  }
229  } else {
230  (*this)(data.size());
231  for (const auto entry : data) { // Not a reference: vector<bool> range
232  bool b = entry;
233  (*this)(b);
234  }
235  }
236  }
237 
240  template <class Array>
241  void array(const Array& data)
242  {
243  using T = typename Array::value_type;
244 
245  if constexpr (std::is_pod_v<T>) {
246  if (m_op == Operation::PACKSIZE)
247  m_packSize += m_packer.packSize(data.data(), data.size());
248  else if (m_op == Operation::PACK)
249  m_packer.pack(data.data(), data.size(), m_buffer, m_position);
250  else if (m_op == Operation::UNPACK) {
251  auto& data_mut = const_cast<Array&>(data);
252  m_packer.unpack(data_mut.data(), data_mut.size(), m_buffer, m_position);
253  }
254  } else {
255  std::for_each(data.begin(), data.end(), std::ref(*this));
256  }
257  }
258 
261  template<class... Args>
262  void variant(const std::variant<Args...>& data)
263  {
264  if (m_op == Operation::UNPACK) {
265  std::size_t index = 0;
266  (*this)(index);
267  auto& data_mut = const_cast<std::variant<Args...>&>(data);
268  data_mut = detail::make_variant<Args...>(index);
269  std::visit(std::ref(*this), data_mut);
270  } else {
271  (*this)(data.index());
272  std::visit(std::ref(*this), data);
273  }
274  }
275 
279  template<class T>
280  void optional(const std::optional<T>& data)
281  {
282  if (m_op == Operation::UNPACK) {
283  bool has = false;
284  (*this)(has);
285  if (has) {
286  T res;
287  (*this)(res);
288  const_cast<std::optional<T>&>(data) = res;
289  }
290  } else {
291  (*this)(data.has_value());
292  if (data.has_value()) {
293  (*this)(*data);
294  }
295  }
296  }
297 
300  template<class Tuple>
301  void tuple(const Tuple& data)
302  {
303  tuple_call(data);
304  }
305 
309  template<class Map>
310  void map(const Map& data)
311  {
312  if (m_op == Operation::UNPACK) {
313  std::size_t size = 0;
314  (*this)(size);
315  auto& data_mut = const_cast<Map&>(data);
316  for (size_t i = 0; i < size; ++i) {
317  typename Map::value_type entry;
318  (*this)(entry);
319  data_mut.insert(entry);
320  }
321  } else {
322  (*this)(data.size());
323  std::for_each(data.begin(), data.end(), std::ref(*this));
324  }
325  }
326 
330  template<class Set>
331  void set(const Set& data)
332  {
333  if (m_op == Operation::UNPACK) {
334  std::size_t size = 0;
335  (*this)(size);
336  auto& data_mut = const_cast<Set&>(data);
337  for (size_t i = 0; i < size; ++i) {
338  typename Set::value_type entry;
339  (*this)(entry);
340  data_mut.insert(entry);
341  }
342  } else {
343  (*this)(data.size());
344  std::for_each(data.begin(), data.end(), std::ref(*this));
345  }
346  }
347 
348  template<typename T, typename... Args>
349  void variadic_call(T& first,
350  Args&&... args)
351  {
352  (*this)(first);
353  if constexpr (sizeof...(args) > 0)
354  variadic_call(std::forward<Args>(args)...);
355  }
356 
357  template<std::size_t I = 0, typename Tuple>
358  typename std::enable_if<I == std::tuple_size<Tuple>::value, void>::type
359  tuple_call(const Tuple&)
360  {
361  }
362 
363  template<std::size_t I = 0, typename Tuple>
364  typename std::enable_if<I != std::tuple_size<Tuple>::value, void>::type
365  tuple_call(const Tuple& tuple)
366  {
367  (*this)(std::get<I>(tuple));
368  tuple_call<I+1>(tuple);
369  }
370 
372  enum class Operation {
373  PACKSIZE,
374  PACK,
375  UNPACK
376  };
377 
379  template<class T>
380  struct is_vector {
381  constexpr static bool value = false;
382  };
383 
384  template<class T1, class Allocator>
385  struct is_vector<std::vector<T1,Allocator>> {
386  constexpr static bool value = true;
387  };
388 
390  template<class T>
391  struct is_variant {
392  constexpr static bool value = false;
393  };
394 
395  template<class... Ts>
396  struct is_variant<std::variant<Ts...>> {
397  constexpr static bool value = true;
398  };
399 
401  template<class T>
403  constexpr static bool value = false;
404  };
405 
406  template<class... Ts>
407  struct is_pair_or_tuple<std::tuple<Ts...>> {
408  constexpr static bool value = true;
409  };
410 
411  template<class T1, class T2>
412  struct is_pair_or_tuple<std::pair<T1,T2>> {
413  constexpr static bool value = true;
414  };
415 
417  template<class T>
418  struct is_ptr {
419  constexpr static bool value = false;
420  };
421 
422  template<class T1>
423  struct is_ptr<std::shared_ptr<T1>> {
424  constexpr static bool value = true;
425  };
426 
427  template<class T1, class Deleter>
428  struct is_ptr<std::unique_ptr<T1, Deleter>> {
429  constexpr static bool value = true;
430  };
431 
433  template<class T>
434  struct is_optional {
435  constexpr static bool value = false;
436  };
437 
438  template<class T1>
439  struct is_optional<std::optional<T1>> {
440  constexpr static bool value = true;
441  };
442 
444  template<class T>
445  struct is_map {
446  constexpr static bool value = false;
447  };
448 
449  template<class Key, class T, class Compare, class Allocator>
450  struct is_map<std::map<Key,T,Compare,Allocator>> {
451  constexpr static bool value = true;
452  };
453 
454  template<class Key, class T, class Hash, class KeyEqual, class Allocator>
455  struct is_map<std::unordered_map<Key,T,Hash,KeyEqual,Allocator>> {
456  constexpr static bool value = true;
457  };
458 
460  template<class T>
461  struct is_set {
462  constexpr static bool value = false;
463  };
464 
465  template<class Key, class Compare, class Allocator>
466  struct is_set<std::set<Key,Compare,Allocator>> {
467  constexpr static bool value = true;
468  };
469 
470  template<class Key, class Hash, class KeyEqual, class Allocator>
471  struct is_set<std::unordered_set<Key,Hash,KeyEqual,Allocator>> {
472  constexpr static bool value = true;
473  };
474 
476  template<class T>
477  struct is_array {
478  constexpr static bool value = false;
479  };
480 
481  template<class T, std::size_t N>
482  struct is_array<std::array<T,N>> {
483  constexpr static bool value = true;
484  };
485 
489  template <typename, class = void>
490  struct has_serializeOp : public std::false_type {};
491 
496  template <typename T>
498  T, std::void_t<decltype(std::declval<T>().serializeOp(std::declval<Serializer<Packer>&>()))>
499  > : public std::true_type {};
500 
502  template<class PtrType>
503  void ptr(const PtrType& data)
504  {
505  using T1 = typename PtrType::element_type;
506  bool value = data ? true : false;
507  (*this)(value);
508  if (m_op == Operation::UNPACK && value) {
509  const_cast<PtrType&>(data).reset(new T1);
510  }
511  if (data) {
512  (*this)(*data);
513  }
514  }
515 
516  const Packer& m_packer;
518  size_t m_packSize = 0;
519  int m_position = 0;
520  std::vector<char> m_buffer;
521 };
522 
523 }
524 
525 #endif
Class for (de-)serializing.
Definition: Serializer.hpp:75
void ptr(const PtrType &data)
Handler for smart pointers.
Definition: Serializer.hpp:503
void array(const Array &data)
Handler for arrays.
Definition: Serializer.hpp:241
void operator()(const T &data)
Applies current serialization op to the passed data.
Definition: Serializer.hpp:85
bool isSerializing() const
Returns true if we are currently doing a serialization operation.
Definition: Serializer.hpp:174
const Packer & m_packer
Packer to use.
Definition: Serializer.hpp:516
void tuple(const Tuple &data)
Handler for std::tuple.
Definition: Serializer.hpp:301
void set(const Set &data)
Handler for sets.
Definition: Serializer.hpp:331
Operation
Enumeration of operations.
Definition: Serializer.hpp:372
@ UNPACK
Performing de-serialization.
@ PACKSIZE
Calculating serialization buffer size.
@ PACK
Performing serialization.
void unpack(T &data)
Call this to de-serialize data.
Definition: Serializer.hpp:149
size_t position() const
Returns current position in buffer.
Definition: Serializer.hpp:168
void vector(const std::vector< T > &data)
Handler for vectors.
Definition: Serializer.hpp:184
size_t m_packSize
Required buffer size after PACKSIZE has been done.
Definition: Serializer.hpp:518
void pack(const Args &... data)
Call this to serialize data.
Definition: Serializer.hpp:134
void unpack(Args &... data)
Call this to de-serialize data.
Definition: Serializer.hpp:160
void vector(const std::vector< bool > &data)
Handler for bool vectors.
Definition: Serializer.hpp:216
Serializer(const Packer &packer)
Constructor.
Definition: Serializer.hpp:79
void variant(const std::variant< Args... > &data)
Handler for std::variant.
Definition: Serializer.hpp:262
void map(const Map &data)
Handler for maps.
Definition: Serializer.hpp:310
void pack(const T &data)
Call this to serialize data.
Definition: Serializer.hpp:119
Operation m_op
Current operation.
Definition: Serializer.hpp:517
void optional(const std::optional< T > &data)
Handler for std::optional.
Definition: Serializer.hpp:280
int m_position
Current position in buffer.
Definition: Serializer.hpp:519
std::vector< char > m_buffer
Buffer for serialized data.
Definition: Serializer.hpp:520
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition: Exceptions.hpp:29
Detect existence of serializeOp member function.
Definition: Serializer.hpp:490
Predicate for arrays.
Definition: Serializer.hpp:477
Predicate for maps.
Definition: Serializer.hpp:445
Predicate for std::optional.
Definition: Serializer.hpp:434
Predicate for detecting pairs and tuples.
Definition: Serializer.hpp:402
Predicate for smart pointers.
Definition: Serializer.hpp:418
Predicate for sets.
Definition: Serializer.hpp:461
Predicate for detecting variants.
Definition: Serializer.hpp:391
Predicate for detecting vectors.
Definition: Serializer.hpp:380
Definition: Serializer.hpp:42