opm-common
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 3 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 <cstddef>
26 #include <cstdint>
27 #include <functional>
28 #include <map>
29 #include <memory>
30 #include <optional>
31 #include <set>
32 #include <stdexcept>
33 #include <type_traits>
34 #include <unordered_map>
35 #include <unordered_set>
36 #include <utility>
37 #include <variant>
38 #include <vector>
39 
40 #if HAVE_DUNE_COMMON
41 namespace Dune { template<typename,int> class FieldVector; }
42 #endif
43 
44 #if HAVE_DUNE_ISTL
45 namespace Dune { template<typename,typename> class BlockVector; }
46 #endif
47 
48 namespace Opm {
49 namespace detail {
50 
51 template<typename ...Ts>
53 {
54 
55 template<std::size_t Index, typename, typename ...Rest>
56 static decltype(auto) make_variant(std::size_t index)
57 {
58  if(Index == index)
59  return std::variant<Ts...>{std::in_place_index_t<Index>{}};
60 
61  if constexpr(sizeof...(Rest) != 0)
62  return make_variant<Index + 1, Rest...>(index);
63  else
64  throw std::runtime_error("Invalid variant index");
65 }
66 
67 };
68 
69 template<typename ...Ts>
70 decltype(auto) make_variant(std::size_t index)
71 {
72  return detail::MakeVariantImpl<Ts...>::template make_variant<0, Ts...>(index);
73 }
74 
75 template<class T>
76 using remove_cvr_t = std::remove_cv_t<std::remove_reference_t<T>>;
77 
78 template <typename T>
79 struct is_unique_ptr : std::false_type {};
80 
81 template <typename T>
82 struct is_unique_ptr<std::unique_ptr<T>> : std::true_type {};
83 
84 template <typename T>
85 constexpr bool is_pod_v = std::is_standard_layout_v<T> && std::is_trivial_v<T>;
86 
87 } // namespace detail
88 
94 template<class Packer>
95 class Serializer {
96 public:
99  explicit Serializer(const Packer& packer) :
100  m_packer(packer)
101  {}
102 
104  template<class T>
105  void operator()(const T& data)
106  {
107  if constexpr (is_ptr<T>::value) {
108  if constexpr (detail::is_unique_ptr<T>::value) {
109  unique_ptr(data);
110  } else {
111  shared_ptr(data);
112  }
113  } else if constexpr (is_pair_or_tuple<T>::value) {
114  tuple(data);
115  } else if constexpr (is_variant<T>::value) {
116  variant(data);
117  } else if constexpr (is_optional<T>::value) {
118  optional(data);
119  } else if constexpr (is_vector<T>::value) {
120  vector(data);
121  } else if constexpr (is_map<T>::value) {
122  map(data);
123  } else if constexpr (is_array<T>::value) {
124  array(data);
125  } else if constexpr (is_set<T>::value) {
126  set(data);
127  } else if constexpr (has_serializeOp<detail::remove_cvr_t<T>>::value) {
128  const_cast<T&>(data).serializeOp(*this);
129  } else {
130  if (m_op == Operation::PACKSIZE)
131  m_packSize += m_packer.packSize(data);
132  else if (m_op == Operation::PACK)
133  m_packer.pack(data, m_buffer, m_position);
134  else if (m_op == Operation::UNPACK)
135  m_packer.unpack(const_cast<T&>(data), m_buffer, m_position);
136  }
137  }
138 
142  template<class T>
143  void pack(const T& data)
144  {
145  m_ptrmap.clear();
147  m_packSize = 0;
148  (*this)(data);
149  m_position = 0;
150  m_buffer.resize(m_packSize);
151  m_ptrmap.clear();
153  (*this)(data);
154  m_ptrmap.clear();
155  }
156 
160  template<class... Args>
161  void pack(const Args&... data)
162  {
163  m_ptrmap.clear();
165  m_packSize = 0;
166  variadic_call(data...);
167  m_position = 0;
168  m_buffer.resize(m_packSize);
169  m_ptrmap.clear();
171  variadic_call(data...);
172  m_ptrmap.clear();
173  }
174 
178  template<class T>
179  void unpack(T& data)
180  {
181  m_position = 0;
182  m_ptrmap.clear();
184  (*this)(data);
185  m_ptrmap.clear();
186  }
187 
191  template<class... Args>
192  void unpack(Args&... data)
193  {
194  m_position = 0;
195  m_ptrmap.clear();
197  variadic_call(data...);
198  m_ptrmap.clear();
199  }
200 
202  std::size_t position() const
203  {
204  return m_position;
205  }
206 
208  bool isSerializing() const
209  {
210  return m_op != Operation::UNPACK;
211  }
212 
213 protected:
217  template <typename Vector>
218  void vector(const Vector& data)
219  {
220  if constexpr (detail::is_pod_v<typename Vector::value_type>) {
221  if (m_op == Operation::PACKSIZE) {
222  (*this)(data.size());
223  if (data.size() > 0) {
224  m_packSize += m_packer.packSize(data.data(), data.size());
225  }
226  } else if (m_op == Operation::PACK) {
227  (*this)(data.size());
228  if (data.size() > 0) {
229  m_packer.pack(data.data(), data.size(), m_buffer, m_position);
230  }
231  } else if (m_op == Operation::UNPACK) {
232  std::size_t size = 0;
233  (*this)(size);
234  auto& data_mut = const_cast<Vector&>(data);
235  data_mut.resize(size);
236  if (size > 0) {
237  m_packer.unpack(data_mut.data(), size, m_buffer, m_position);
238  }
239  }
240  } else {
241  if (m_op == Operation::UNPACK) {
242  std::size_t size = 0;
243  (*this)(size);
244  auto& data_mut = const_cast<Vector&>(data);
245  data_mut.resize(size);
246  std::ranges::for_each(data_mut, std::ref(*this));
247  } else {
248  (*this)(data.size());
249  std::ranges::for_each(data, std::ref(*this));
250  }
251  }
252  }
253 
256  void vector(const std::vector<bool>& data)
257  {
258  if (m_op == Operation::UNPACK) {
259  std::size_t size = 0;
260  (*this)(size);
261  auto& data_mut = const_cast<std::vector<bool>&>(data);
262  data_mut.clear();
263  data_mut.reserve(size);
264  for (std::size_t i = 0; i < size; ++i) {
265  bool entry = false;
266  (*this)(entry);
267  data_mut.push_back(entry);
268  }
269  } else {
270  (*this)(data.size());
271  for (const auto entry : data) { // Not a reference: vector<bool> range
272  bool b = entry;
273  (*this)(b);
274  }
275  }
276  }
277 
280  template <class Array>
281  void array(const Array& data)
282  {
283  using T = typename Array::value_type;
284 
285  if constexpr (detail::is_pod_v<T>) {
286  if (m_op == Operation::PACKSIZE)
287  m_packSize += m_packer.packSize(data.data(), data.size());
288  else if (m_op == Operation::PACK)
289  m_packer.pack(data.data(), data.size(), m_buffer, m_position);
290  else if (m_op == Operation::UNPACK) {
291  auto& data_mut = const_cast<Array&>(data);
292  m_packer.unpack(data_mut.data(), data_mut.size(), m_buffer, m_position);
293  }
294  } else {
295  std::ranges::for_each(data, std::ref(*this));
296  }
297  }
298 
301  template<class... Args>
302  void variant(const std::variant<Args...>& data)
303  {
304  if (m_op == Operation::UNPACK) {
305  std::size_t index = 0;
306  (*this)(index);
307  auto& data_mut = const_cast<std::variant<Args...>&>(data);
308  data_mut = detail::make_variant<Args...>(index);
309  std::visit(std::ref(*this), data_mut);
310  } else {
311  (*this)(data.index());
312  std::visit(std::ref(*this), data);
313  }
314  }
315 
319  template<class T>
320  void optional(const std::optional<T>& data)
321  {
322  if (m_op == Operation::UNPACK) {
323  bool has = false;
324  (*this)(has);
325  if (has) {
326  T res{};
327  (*this)(res);
328  const_cast<std::optional<T>&>(data) = res;
329  } else {
330  const_cast<std::optional<T>&>(data) = std::nullopt;
331  }
332  } else {
333  (*this)(data.has_value());
334  if (data.has_value()) {
335  (*this)(*data);
336  }
337  }
338  }
339 
342  template<class Tuple>
343  void tuple(const Tuple& data)
344  {
345  tuple_call(data);
346  }
347 
351  template<class Map>
352  void map(const Map& data)
353  {
354  if (m_op == Operation::UNPACK) {
355  std::size_t size = 0;
356  (*this)(size);
357  auto& data_mut = const_cast<Map&>(data);
358  for (std::size_t i = 0; i < size; ++i) {
359  typename Map::value_type entry;
360  (*this)(entry);
361  data_mut.insert(std::move(entry));
362  }
363  } else {
364  (*this)(data.size());
365  std::ranges::for_each(data, std::ref(*this));
366  }
367  }
368 
372  template<class Set>
373  void set(const Set& data)
374  {
375  if (m_op == Operation::UNPACK) {
376  std::size_t size = 0;
377  (*this)(size);
378  auto& data_mut = const_cast<Set&>(data);
379  for (std::size_t i = 0; i < size; ++i) {
380  typename Set::value_type entry{};
381  (*this)(entry);
382  data_mut.insert(entry);
383  }
384  } else {
385  (*this)(data.size());
386  std::ranges::for_each(data, std::ref(*this));
387  }
388  }
389 
390  template<typename T, typename... Args>
391  void variadic_call(T& first,
392  Args&&... args)
393  {
394  (*this)(first);
395  if constexpr (sizeof...(args) > 0)
396  variadic_call(std::forward<Args>(args)...);
397  }
398 
399  template<std::size_t I = 0, typename Tuple>
400  typename std::enable_if<I == std::tuple_size<Tuple>::value, void>::type
401  tuple_call(const Tuple&)
402  {
403  }
404 
405  template<std::size_t I = 0, typename Tuple>
406  typename std::enable_if<I != std::tuple_size<Tuple>::value, void>::type
407  tuple_call(const Tuple& tuple)
408  {
409  (*this)(std::get<I>(tuple));
410  tuple_call<I+1>(tuple);
411  }
412 
414  enum class Operation {
415  PACKSIZE,
416  PACK,
417  UNPACK
418  };
419 
421  template<class T>
422  struct is_vector {
423  constexpr static bool value = false;
424  };
425 
426  template<class T1, class Allocator>
427  struct is_vector<std::vector<T1,Allocator>> {
428  constexpr static bool value = true;
429  };
430 
431 #if HAVE_DUNE_ISTL
432  template<class T1, class Allocator>
433  struct is_vector<Dune::BlockVector<T1,Allocator>> {
434  constexpr static bool value = true;
435  };
436 #endif
437 
439  template<class T>
440  struct is_variant {
441  constexpr static bool value = false;
442  };
443 
444  template<class... Ts>
445  struct is_variant<std::variant<Ts...>> {
446  constexpr static bool value = true;
447  };
448 
450  template<class T>
452  constexpr static bool value = false;
453  };
454 
455  template<class... Ts>
456  struct is_pair_or_tuple<std::tuple<Ts...>> {
457  constexpr static bool value = true;
458  };
459 
460  template<class T1, class T2>
461  struct is_pair_or_tuple<std::pair<T1,T2>> {
462  constexpr static bool value = true;
463  };
464 
466  template<class T>
467  struct is_ptr {
468  constexpr static bool value = false;
469  };
470 
471  template<class T1>
472  struct is_ptr<std::shared_ptr<T1>> {
473  constexpr static bool value = true;
474  };
475 
476  template<class T1, class Deleter>
477  struct is_ptr<std::unique_ptr<T1, Deleter>> {
478  constexpr static bool value = true;
479  };
480 
482  template<class T>
483  struct is_optional {
484  constexpr static bool value = false;
485  };
486 
487  template<class T1>
488  struct is_optional<std::optional<T1>> {
489  constexpr static bool value = true;
490  };
491 
493  template<class T>
494  struct is_map {
495  constexpr static bool value = false;
496  };
497 
498  template<class Key, class T, class Compare, class Allocator>
499  struct is_map<std::map<Key,T,Compare,Allocator>> {
500  constexpr static bool value = true;
501  };
502 
503  template<class Key, class T, class Hash, class KeyEqual, class Allocator>
504  struct is_map<std::unordered_map<Key,T,Hash,KeyEqual,Allocator>> {
505  constexpr static bool value = true;
506  };
507 
509  template<class T>
510  struct is_set {
511  constexpr static bool value = false;
512  };
513 
514  template<class Key, class Compare, class Allocator>
515  struct is_set<std::set<Key,Compare,Allocator>> {
516  constexpr static bool value = true;
517  };
518 
519  template<class Key, class Hash, class KeyEqual, class Allocator>
520  struct is_set<std::unordered_set<Key,Hash,KeyEqual,Allocator>> {
521  constexpr static bool value = true;
522  };
523 
525  template<class T>
526  struct is_array {
527  constexpr static bool value = false;
528  };
529 
530  template<class T, std::size_t N>
531  struct is_array<std::array<T,N>> {
532  constexpr static bool value = true;
533  };
534 
535 #if HAVE_DUNE_COMMON
536  template<class T, int N>
537  struct is_array<Dune::FieldVector<T,N>> {
538  constexpr static bool value = true;
539  };
540 #endif
541 
545  template <typename, class = void>
546  struct has_serializeOp : public std::false_type {};
547 
552  template <typename T>
554  T, std::void_t<decltype(std::declval<T>().serializeOp(std::declval<Serializer<Packer>&>()))>
555  > : public std::true_type {};
556 
558  template<class PtrType>
559  void shared_ptr(const PtrType& data)
560  {
561  using T1 = typename PtrType::element_type;
562  std::uintptr_t data_ptr = reinterpret_cast<std::uintptr_t>(data.get());
563  (*this)(data_ptr);
564  if (!data_ptr)
565  return;
567  if (m_ptrmap.count(data_ptr) == 0) {
568  (*this)(*data);
569  m_ptrmap[data_ptr].reset();
570  }
571  } else { // m_op == Operation::UNPACK
572  if (m_ptrmap.count(data_ptr) == 0) {
573  const_cast<PtrType&>(data) = std::make_shared<T1>();
574  m_ptrmap[data_ptr] = std::static_pointer_cast<void>(data);
575  (*this)(*data);
576  } else {
577  const_cast<PtrType&>(data) = std::static_pointer_cast<T1>(m_ptrmap[data_ptr]);
578  }
579  }
580  }
581 
582  template<class PtrType>
583  void unique_ptr(const PtrType& data)
584  {
585  using T1 = typename PtrType::element_type;
586 
587  if (m_op != Operation::UNPACK) {
588  (*this)(data ? 1 : 0);
589  if (data) {
590  (*this)(*data);
591  }
592  } else {
593  int ptr = 0;
594  (*this)(ptr);
595  if (ptr == 1) {
596  const_cast<PtrType&>(data) = std::make_unique<T1>();
597  (*this)(*data);
598  }
599  }
600  }
601 
602  const Packer& m_packer;
604  std::size_t m_packSize = 0;
605  std::size_t m_position = 0;
606  std::vector<char> m_buffer;
607  std::map<std::uintptr_t, std::shared_ptr<void>> m_ptrmap;
608 };
609 
610 }
611 
612 #endif
std::size_t m_packSize
Required buffer size after PACKSIZE has been done.
Definition: Serializer.hpp:604
Calculating serialization buffer size.
std::size_t position() const
Returns current position in buffer.
Definition: Serializer.hpp:202
Definition: SymmTensor.hpp:23
void operator()(const T &data)
Applies current serialization op to the passed data.
Definition: Serializer.hpp:105
Predicate for arrays.
Definition: Serializer.hpp:526
void vector(const std::vector< bool > &data)
Handler for bool vectors.
Definition: Serializer.hpp:256
Performing de-serialization.
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition: Exceptions.hpp:30
Predicate for detecting pairs and tuples.
Definition: Serializer.hpp:451
void set(const Set &data)
Handler for sets.
Definition: Serializer.hpp:373
Definition: CriticalError.hpp:115
Operation
Enumeration of operations.
Definition: Serializer.hpp:414
void tuple(const Tuple &data)
Handler for std::tuple.
Definition: Serializer.hpp:343
void pack(const Args &... data)
Call this to serialize data.
Definition: Serializer.hpp:161
Predicate for std::optional.
Definition: Serializer.hpp:483
void unpack(Args &... data)
Call this to de-serialize data.
Definition: Serializer.hpp:192
Operation m_op
Current operation.
Definition: Serializer.hpp:603
std::size_t m_position
Current position in buffer.
Definition: Serializer.hpp:605
Predicate for detecting vectors.
Definition: Serializer.hpp:422
void shared_ptr(const PtrType &data)
Handler for shared pointers.
Definition: Serializer.hpp:559
Serializer(const Packer &packer)
Constructor.
Definition: Serializer.hpp:99
std::map< std::uintptr_t, std::shared_ptr< void > > m_ptrmap
Map to keep track of which pointer data has been serialized and actual pointers during unpacking...
Definition: Serializer.hpp:607
Predicate for detecting variants.
Definition: Serializer.hpp:440
std::vector< char > m_buffer
Buffer for serialized data.
Definition: Serializer.hpp:606
void variant(const std::variant< Args... > &data)
Handler for std::variant.
Definition: Serializer.hpp:302
void vector(const Vector &data)
Handler for vectors.
Definition: Serializer.hpp:218
Definition: Serializer.hpp:52
Predicate for maps.
Definition: Serializer.hpp:494
Predicate for sets.
Definition: Serializer.hpp:510
void unpack(T &data)
Call this to de-serialize data.
Definition: Serializer.hpp:179
Predicate for smart pointers.
Definition: Serializer.hpp:467
bool isSerializing() const
Returns true if we are currently doing a serialization operation.
Definition: Serializer.hpp:208
void array(const Array &data)
Handler for arrays.
Definition: Serializer.hpp:281
const Packer & m_packer
Packer to use.
Definition: Serializer.hpp:602
Class for (de-)serializing.
Definition: Serializer.hpp:95
Definition: Serializer.hpp:79
void map(const Map &data)
Handler for maps.
Definition: Serializer.hpp:352
void optional(const std::optional< T > &data)
Handler for std::optional.
Definition: Serializer.hpp:320
Detect existence of serializeOp member function.
Definition: Serializer.hpp:546
void pack(const T &data)
Call this to serialize data.
Definition: Serializer.hpp:143
Performing serialization.