Interface Documentation
Version: invalid
serialize.hh
1 /*
2  @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@
3  /@@///// /@@ @@////@@ @@////// /@@
4  /@@ /@@ @@@@@ @@ // /@@ /@@
5  /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@
6  /@@//// /@@/@@@@@@@/@@ ////////@@/@@
7  /@@ /@@/@@//// //@@ @@ /@@/@@
8  /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@
9  // /// ////// ////// //////// //
10 
11  Copyright (c) 2016, Triad National Security, LLC
12  All rights reserved.
13  */
14 #pragma once
15 
16 #include <cstddef>
17 #include <cstring> // memcpy
18 #include <map>
19 #include <set>
20 #include <tuple>
21 #include <type_traits>
22 #include <unordered_map>
23 #include <utility> // declval
24 #include <vector>
25 
26 #include "type_traits.hh"
27 #include <flecsi/flog.hh>
28 
29 namespace flecsi {
30 namespace util {
31 
32 // Similar to that in GNU libc. NB: memcpy has no alignment requirements.
33 inline void
34 mempcpy(std::byte *& d, const void * s, std::size_t n) {
35  std::memcpy(d, s, n);
36  d += n;
37 }
38 // For size precalculation:
39 inline void
40 mempcpy(std::size_t & x, const void *, std::size_t n) {
41  x += n;
42 }
43 
44 template<class, class = void>
45 struct serial;
46 
47 template<class T, class P>
48 void
49 serial_put(P & p, const T & t) {
51 }
52 template<class T>
53 std::size_t
54 serial_size(const T & t) {
55  std::size_t ret = 0;
56  serial_put(ret, t);
57  return ret;
58 }
59 template<class T>
60 T
61 serial_get(const std::byte *& p) {
62  return serial<std::remove_const_t<T>>::get(p);
63 }
64 
65 template<class T>
66 auto serial_put(const T & t) { // for a single object
67  std::vector<std::byte> ret(serial_size(t));
68  auto *const p0 = ret.data(), *p = p0;
69  serial_put(p, t);
70  flog_assert(p == p0 + ret.size(), "Wrong serialization size");
71  return ret;
72 }
73 template<class T>
74 T serial_get1(const std::byte * p) { // for a single object
75  return serial_get<T>(p);
76 }
77 
78 namespace detail {
79 template<class T>
81  template<class P>
82  static void put(P & p, const T & c) {
83  serial_put(p, c.size());
84  for(auto & t : c)
85  serial_put(p, t);
86  }
87  static T get(const std::byte *& p) {
88  T ret;
89  for(auto n = serial_get<typename T::size_type>(p); n--;)
90  ret.insert(serial_get<typename T::value_type>(p));
91  return ret;
92  }
93 };
94 } // namespace detail
95 
96 template<class T>
97 constexpr bool memcpyable_v =
98  std::is_default_constructible_v<T> && std::is_trivially_move_assignable_v<T>;
99 
100 template<class T>
101 struct serial<T, std::enable_if_t<memcpyable_v<T>>> {
102  static_assert(!std::is_pointer_v<T>, "Cannot serialize pointers");
103  template<class P>
104  static void put(P & p, const T & t) {
105  mempcpy(p, &t, sizeof t);
106  }
107  static T get(const std::byte *& p) {
108  T ret;
109  // Suppress -Wclass-memaccess: the default constructor needn't be trivial!
110  std::memcpy(static_cast<void *>(&ret), p, sizeof ret);
111  p += sizeof ret;
112  return ret;
113  }
114 };
115 // To allow convenient serial_put(std::tie(...)), it is part of the interface
116 // that pair and tuple elements are just concatenated.
117 template<class T, class U>
118 struct serial<std::pair<T, U>,
119  std::enable_if_t<!memcpyable_v<std::pair<T, U>>>> {
120  using type = std::pair<T, U>;
121  template<class P>
122  static void put(P & p, const type & v) {
123  serial_put(p, v.first);
124  serial_put(p, v.second);
125  }
126  static type get(const std::byte *& p) {
127  return {serial_get<T>(p), serial_get<U>(p)};
128  }
129 };
130 template<class... TT>
131 struct serial<std::tuple<TT...>,
132  std::enable_if_t<!memcpyable_v<std::tuple<TT...>>>> {
133  using type = std::tuple<TT...>;
134  template<class P>
135  static void put(P & p, const type & t) {
136  std::apply([&p](const TT &... xx) { (serial_put(p, xx), ...); }, t);
137  }
138  static type get(const std::byte *& p) {
139  return type{serial_get<TT>(p)...};
140  }
141 };
142 template<class T>
143 struct serial<std::vector<T>> {
144  using type = std::vector<T>;
145  template<class P>
146  static void put(P & p, const type & v) {
147  serial_put(p, v.size());
148  for(auto & t : v)
149  serial_put(p, t);
150  }
151  static type get(const std::byte *& p) {
152  auto n = serial_get<typename type::size_type>(p);
153  type ret;
154  ret.reserve(n);
155  while(n--)
156  ret.push_back(serial_get<T>(p));
157  return ret;
158  }
159 };
160 template<class T>
161 struct serial<std::set<T>> : detail::serial_container<std::set<T>> {};
162 template<class K, class V>
163 struct serial<std::map<K, V>> : detail::serial_container<std::map<K, V>> {};
164 template<class K, class V>
165 struct serial<std::unordered_map<K, V>>
166  : detail::serial_container<std::unordered_map<K, V>> {};
167 template<>
168 struct serial<std::string> {
169  template<class P>
170  static void put(P & p, const std::string & s) {
171  const auto n = s.size();
172  serial_put(p, n);
173  mempcpy(p, s.data(), n);
174  }
175  static std::string get(const std::byte *& p) {
176  const auto n = serial_get<std::string::size_type>(p);
177  const auto d = p;
178  p += n;
179  return {reinterpret_cast<const char *>(d), n};
180  }
181 };
182 
183 // Adapters for other protocols:
184 
185 // This works even without Legion:
186 template<class T>
187 struct serial<T,
188  voided<decltype(&T::legion_buffer_size),
189  std::enable_if_t<!memcpyable_v<T>>>> {
190  template<class P>
191  static void put(P & p, const T & t) {
192  if constexpr(std::is_pointer_v<P>)
193  p += t.legion_serialize(p);
194  else
195  p += t.legion_buffer_size();
196  }
197  static T get(const std::byte *& p) {
198  T ret;
199  p += ret.legion_deserialize(p);
200  return ret;
201  }
202 };
203 
204 // Should define put and get and optionally size:
205 template<class>
207 template<class T, class = void>
209  static std::size_t size(const T & t) {
210  return serial_size(serial_convert<T>::put(t));
211  }
212 };
213 template<class T>
214 struct serial_convert_traits<T, decltype(void(serial_convert<T>::size))>
215  : serial_convert<T> {};
216 template<class T>
217 struct serial<T, decltype(void(serial_convert<T>::put))> {
219  template<class P>
220  static void put(P & p, const T & t) {
221  if constexpr(std::is_pointer_v<P>)
222  serial_put(p, Convert::put(t));
223  else
224  p += Convert::size(t);
225  }
226  static T get(const std::byte *& p) {
227  return Convert::get(
228  serial_get<std::decay_t<decltype(Convert::put(std::declval<T>()))>>(p));
229  }
230 };
231 
232 } // namespace util
233 } // namespace flecsi
Definition: serialize.hh:45
Definition: serialize.hh:206
#define flog_assert(test, message)
Definition: flog.hh:411
Definition: serialize.hh:80
Definition: serialize.hh:208
Definition: control.hh:31