archive.h
Go to the documentation of this file.
1 //
2 // Created by Eduard Valeyev on 5/17/21.
3 //
4 
5 #ifndef TTG_SERIALIZATION_BACKENDS_BOOST_ARCHIVE_H
6 #define TTG_SERIALIZATION_BACKENDS_BOOST_ARCHIVE_H
7 
8 #include <boost/archive/binary_iarchive.hpp>
9 #include <boost/archive/binary_oarchive.hpp>
10 #include <boost/iostreams/device/array.hpp>
11 #include <boost/iostreams/stream.hpp>
12 
13 // explicitly instantiate for this type of binary stream
14 #include <boost/archive/impl/basic_binary_iarchive.ipp>
15 #include <boost/archive/impl/basic_binary_iprimitive.ipp>
16 #include <boost/archive/impl/basic_binary_oarchive.ipp>
17 #include <boost/archive/impl/basic_binary_oprimitive.ipp>
18 
19 namespace ttg::detail {
20 
21  // used to serialize data only
22  template <typename Archive, typename T>
23  void oarchive_save_override_optimized_dispatch(Archive& ar, const T& t) {
24  if constexpr (boost::is_array<T>::value) {
25  boost::archive::detail::save_array_type<Archive>::invoke(ar, t);
26  return;
27  } else if constexpr (boost::is_enum<T>::value) {
28  boost::archive::detail::save_enum_type<Archive>::invoke(ar, t);
29  return;
30  } else {
31  std::conditional_t<boost::is_pointer<T>::value, T, std::add_pointer_t<const T>> tptr;
32  if constexpr (boost::is_pointer<T>::value) {
33  static_assert(!std::is_polymorphic_v<T>,
34  "oarchive_save_override does not support serialization of polymorphic types");
35  tptr = t;
36  } else
37  tptr = &t;
38  if constexpr (boost::mpl::equal_to<boost::serialization::implementation_level<T>,
39  boost::mpl::int_<boost::serialization::primitive_type>>::value) {
40  boost::archive::detail::save_non_pointer_type<Archive>::save_primitive::invoke(ar, *tptr);
41  } else
42  boost::archive::detail::save_non_pointer_type<Archive>::save_only::invoke(ar, *tptr);
43  }
44  }
45 
46  // used to serialize data only
47  template <typename Archive, typename T>
49  if constexpr (boost::is_array<T>::value) {
50  boost::archive::detail::load_array_type<Archive>::invoke(ar, t);
51  return;
52  } else if constexpr (boost::is_enum<T>::value) {
53  boost::archive::detail::load_enum_type<Archive>::invoke(ar, t);
54  return;
55  } else {
56  std::conditional_t<boost::is_pointer<T>::value, T, std::add_pointer_t<T>> tptr;
57  if constexpr (boost::is_pointer<T>::value) {
58  static_assert(!std::is_polymorphic_v<T>,
59  "iarchive_load_override_optimized_dispatch does not support serialization of polymorphic types");
60  using Value = std::remove_pointer_t<T>;
61  std::allocator<Value> alloc; // instead use the allocator associated with the archive?
62  auto* buf = alloc.allocate(sizeof(Value));
63  t = new (buf) Value;
64  tptr = t;
65  } else
66  tptr = &t;
67  if constexpr (boost::mpl::equal_to<boost::serialization::implementation_level<T>,
68  boost::mpl::int_<boost::serialization::primitive_type>>::value) {
69  boost::archive::detail::load_non_pointer_type<Archive>::load_primitive::invoke(ar, *tptr);
70  } else
71  boost::archive::detail::load_non_pointer_type<Archive>::load_only::invoke(ar, *tptr);
72  }
73  }
74 
76 
90  template <typename StreamOrStreambuf>
92  : private StreamOrStreambuf,
93  public boost::archive::binary_oarchive_impl<boost_optimized_oarchive<StreamOrStreambuf>,
94  std::ostream::char_type, std::ostream::traits_type> {
95  public:
96  using pbase_type = StreamOrStreambuf;
97  using base_type = boost::archive::binary_oarchive_impl<boost_optimized_oarchive<StreamOrStreambuf>,
98  std::ostream::char_type, std::ostream::traits_type>;
99  // if pbase_type is derived from std::streambuf can use this information to avoid virtual function calls and inline
100  static constexpr bool pbase_derived_from_stdstreambuf = std::is_base_of_v<std::streambuf, pbase_type>;
101 
102  private:
104  friend class boost::archive::detail::common_oarchive<StreamOrStreambuf>;
105  friend base_type;
106 
107  const auto& pbase() const { return static_cast<const pbase_type&>(*this); }
108  auto& pbase() { return static_cast<pbase_type&>(*this); }
109  const auto& base() const { return static_cast<const base_type&>(*this); }
110  auto& base() { return static_cast<base_type&>(*this); }
111 
112  public:
114  : pbase_type{}, base_type(this->pbase(), boost::archive::no_header | boost::archive::no_codecvt){};
115 
116  boost_optimized_oarchive(StreamOrStreambuf sbuf)
117  : pbase_type(std::move(sbuf))
118  , base_type(this->pbase(), boost::archive::no_header | boost::archive::no_codecvt){};
119 
120  template <typename Arg>
122  : pbase_type(std::forward<Arg>(arg))
123  , base_type(this->pbase(), boost::archive::no_header | boost::archive::no_codecvt){};
124 
127 
128  template <class T>
129  void save_override(const T& t) {
131  }
132 
133  void save_override(const boost::archive::class_id_optional_type& /* t */) {}
134 
135  void save_override(const boost::archive::version_type& t) {}
136  void save_override(const boost::serialization::item_version_type& t) {}
137 
138  void save_override(const boost::archive::class_id_type& t) {}
139  void save_override(const boost::archive::class_id_reference_type& t) {}
140 
142 
143  void save_object(const void* x, const boost::archive::detail::basic_oserializer& bos) { abort(); }
144 
147 
148  // default saving of primitives.
149  template<class T>
150  void save(const T & t)
151  {
152  save_binary(& t, sizeof(T));
153  }
154 
155  // trap usage of invalid uninitialized boolean which would
156  // otherwise crash on load.
157  void save(const bool t){
158  BOOST_ASSERT(0 == static_cast<int>(t) || 1 == static_cast<int>(t));
159  save_binary(& t, sizeof(t));
160  }
161 
162  public:
163 
164  // the optimized save_array dispatches to save_binary
165  template <class ValueType>
166  void save_array(boost::serialization::array_wrapper<ValueType> const& a, unsigned int)
167  {
168  save_binary(a.address(),a.count()*sizeof(ValueType));
169  }
170 
171  void save_binary(const void *address, std::size_t count) {
172  if constexpr (pbase_derived_from_stdstreambuf) { // if we were given a streambuf use it directly ...
173  using Elem = std::ostream::char_type;
174  static_assert(sizeof(Elem) == 1);
175  count = (count + sizeof(Elem) - 1) / sizeof(Elem);
176  std::streamsize scount = static_cast<StreamOrStreambuf&>(this->pbase())
177  .sputn(static_cast<const Elem*>(address), static_cast<std::streamsize>(count));
178  assert(count == static_cast<std::size_t>(scount));
179  }
180  else { // ... else let boost::archive::basic_binary_oprimitive handle via std::stringbuf
181  // (and associated virtual function calls ... no inlining for you)
182  this->base().save_binary(address, count);
183  }
184  }
185 
187 
188  template <class T>
189  auto& operator<<(const T& t) {
190  this->save_override(t);
191  return *this;
192  }
193 
194  // the & operator
195  template <class T>
196  auto& operator&(const T& t) {
197  return *this << t;
198  }
199 
200  const auto& streambuf() const {
201  if constexpr (pbase_derived_from_stdstreambuf) {
202  return static_cast<const StreamOrStreambuf&>(this->pbase());
203  }
204  else {
205  return this->pbase();
206  }
207  }
208  const auto& stream() const { return this->pbase(); }
209  };
210 
213 
216 
220 
223 
225 
230  inline auto make_boost_buffer_oarchive(void* const buf, std::size_t size, std::size_t buf_offset = 0) {
231  assert(buf_offset <= size);
232  return ttg::detail::boost_byte_oarchive(ttg::detail::byte_ostreambuf(static_cast<char*>(buf) + buf_offset, size - buf_offset));
233  }
234 
236 
241  template <std::size_t N>
242  inline auto make_boost_buffer_oarchive(char (&buf)[N], std::size_t buf_offset = 0) {
243  assert(buf_offset <= N);
244  return ttg::detail::boost_byte_oarchive(ttg::detail::byte_ostreambuf(&(buf[buf_offset], N - buf_offset)));
245  }
246 
248  template <typename StreamOrStreambuf>
250  : private StreamOrStreambuf,
251  public boost::archive::binary_iarchive_impl<boost_optimized_iarchive<StreamOrStreambuf>,
252  std::ostream::char_type, std::ostream::traits_type> {
253  public:
254  using pbase_type = StreamOrStreambuf;
255  using base_type = boost::archive::binary_iarchive_impl<boost_optimized_iarchive, std::ostream::char_type,
256  std::ostream::traits_type>;
257  // if pbase_type is derived from std::streambuf can use this information to avoid virtual function calls and inline
258  static constexpr bool pbase_derived_from_stdstreambuf = std::is_base_of_v<std::streambuf, pbase_type>;
259 
260  private:
262  friend class boost::archive::detail::common_iarchive<boost_optimized_iarchive>;
263  friend base_type;
264 
265  const auto& pbase() const { return static_cast<const pbase_type&>(*this); }
266  auto& pbase() { return static_cast<pbase_type&>(*this); }
267  const auto& base() const { return static_cast<const base_type&>(*this); }
268  auto& base() { return static_cast<base_type&>(*this); }
269 
270  public:
272  : pbase_type{}, base_type(this->pbase(), boost::archive::no_header | boost::archive::no_codecvt){};
273 
274  boost_optimized_iarchive(StreamOrStreambuf sbuf)
275  : pbase_type(std::move(sbuf))
276  , base_type(this->pbase(), boost::archive::no_header | boost::archive::no_codecvt){};
277 
278  template <typename Arg>
280  : pbase_type(std::forward<Arg>(arg))
281  , base_type(this->pbase(), boost::archive::no_header | boost::archive::no_codecvt){};
282 
285 
286  template <class T>
287  void load_override(T& t) {
289  }
290 
291  void load_override(boost::archive::class_id_optional_type& /* t */) {}
292 
293  void load_override(boost::archive::version_type& t) {}
294  void load_override(boost::serialization::item_version_type& t) {}
295 
296  void load_override(boost::archive::class_id_type& t) {}
297  void load_override(boost::archive::class_id_reference_type& t) {}
298 
300 
301  void load_object(void* x, const boost::archive::detail::basic_oserializer& bos) { abort(); }
302 
305 
306  // main template for serialization of primitive types
307  template<class T>
308  void load(T & t){
309  load_binary(& t, sizeof(T));
310  }
311 
313  // fundamental types that need special treatment
314 
315  // trap usage of invalid uninitialized boolean
316  void load(bool & t){
317  load_binary(& t, sizeof(t));
318  int i = t;
319  BOOST_ASSERT(0 == i || 1 == i);
320  (void)i; // warning suppression for release builds.
321  }
322 
323  public:
324 
325  // the optimized load_array dispatches to load_binary
326  template <class ValueType>
327  void load_array(boost::serialization::array_wrapper<ValueType>& a, unsigned int)
328  {
329  load_binary(a.address(),a.count()*sizeof(ValueType));
330  }
331 
333  void *address,
334  std::size_t count
335  ) {
336  if constexpr (pbase_derived_from_stdstreambuf) { // if we were given a streambuf use it directly ...
337  using Elem = std::ostream::char_type;
338  static_assert(sizeof(Elem) == 1);
339  std::streamsize s = static_cast<std::streamsize>(count);
340  std::streamsize scount = static_cast<StreamOrStreambuf&>(this->pbase()).sgetn(static_cast<Elem*>(address), s);
341  assert(scount == count);
342  }
343  else { // ... else let boost::archive::basic_binary_iprimitive handle via std::stringbuf
344  // (and associated virtual function calls ... no inlining for you)
345  this->base().load_binary(address, count);
346  }
347  }
348 
350 
351  template <class T>
352  auto& operator>>(T& t) {
353  this->load_override(t);
354  return *this;
355  }
356 
357  // the & operator
358  template <class T>
359  auto& operator&(T& t) {
360  return *this >> t;
361  }
362 
363  const auto& streambuf() const {
364  if constexpr (pbase_derived_from_stdstreambuf) {
365  return static_cast<const StreamOrStreambuf&>(this->pbase());
366  }
367  else {
368  return this->pbase();
369  }
370  }
371  const auto& stream() const { return this->pbase(); }
372  };
373 
376 
380 
383 
385 
390  inline auto make_boost_buffer_iarchive(const void* const buf, std::size_t size, std::size_t buf_offset = 0) {
391  assert(buf_offset <= size);
392  return ttg::detail::boost_byte_iarchive(ttg::detail::byte_istreambuf(static_cast<const char*>(buf) + buf_offset, size - buf_offset));
393  }
394 
396 
401  template <std::size_t N>
402  inline auto make_boost_buffer_iarchive(const char (&buf)[N], std::size_t buf_offset = 0) {
403  assert(buf_offset <= N);
404  return ttg::detail::boost_byte_iarchive(ttg::detail::byte_istreambuf((&(buf[buf_offset]), N - buf_offset)));
405  }
406 
407 } // namespace ttg::detail
408 
409 // for some reason need to use array optimization for the base as well ... dispatch to optimized version in
410 // array_wrapper.hpp:serializer(ar,version) for some reason uses Archive::base_type using apple clang 12.0.5.12050022
411 #define BOOST_SERIALIZATION_USE_ARRAY_OPTIMIZATION_FOR_THIS_AND_BASE(x) \
412  BOOST_SERIALIZATION_USE_ARRAY_OPTIMIZATION(x); \
413  BOOST_SERIALIZATION_USE_ARRAY_OPTIMIZATION(x::base_type);
414 
429 
430 #undef BOOST_SERIALIZATION_USE_ARRAY_OPTIMIZATION_FOR_THIS_AND_BASE
431 
432 #endif // TTG_SERIALIZATION_BACKENDS_BOOST_ARCHIVE_H
BOOST_SERIALIZATION_REGISTER_ARCHIVE(ttg::detail::boost_counting_oarchive)
#define BOOST_SERIALIZATION_USE_ARRAY_OPTIMIZATION_FOR_THIS_AND_BASE(x)
Definition: archive.h:411
optimized data-only deserializer for boost_optimized_oarchive
Definition: archive.h:252
void load_override(boost::archive::class_id_type &t)
Definition: archive.h:296
void load_binary(void *address, std::size_t count)
Definition: archive.h:332
boost::archive::binary_iarchive_impl< boost_optimized_iarchive, std::ostream::char_type, std::ostream::traits_type > base_type
Definition: archive.h:256
void load_override(boost::archive::version_type &t)
Definition: archive.h:293
void load_array(boost::serialization::array_wrapper< ValueType > &a, unsigned int)
Definition: archive.h:327
const auto & stream() const
Definition: archive.h:371
boost_optimized_iarchive(StreamOrStreambuf sbuf)
Definition: archive.h:274
void load_object(void *x, const boost::archive::detail::basic_oserializer &bos)
Definition: archive.h:301
void load_override(boost::serialization::item_version_type &t)
Definition: archive.h:294
void load_override(boost::archive::class_id_reference_type &t)
Definition: archive.h:297
friend class boost::archive::save_access
Definition: archive.h:261
void load_override(boost::archive::class_id_optional_type &)
Definition: archive.h:291
const auto & streambuf() const
Definition: archive.h:363
static constexpr bool pbase_derived_from_stdstreambuf
Definition: archive.h:258
optimized data-only serializer
Definition: archive.h:94
const auto & streambuf() const
Definition: archive.h:200
void save_binary(const void *address, std::size_t count)
Definition: archive.h:171
void save_override(const boost::archive::version_type &t)
Definition: archive.h:135
const auto & stream() const
Definition: archive.h:208
static constexpr bool pbase_derived_from_stdstreambuf
Definition: archive.h:100
void save_override(const boost::archive::class_id_reference_type &t)
Definition: archive.h:139
void save_override(const boost::serialization::item_version_type &t)
Definition: archive.h:136
void save_override(const boost::archive::class_id_type &t)
Definition: archive.h:138
void save_override(const boost::archive::class_id_optional_type &)
Definition: archive.h:133
boost_optimized_oarchive(StreamOrStreambuf sbuf)
Definition: archive.h:116
void save_object(const void *x, const boost::archive::detail::basic_oserializer &bos)
Definition: archive.h:143
friend class boost::archive::save_access
Definition: archive.h:103
boost::archive::binary_oarchive_impl< boost_optimized_oarchive< StreamOrStreambuf >, std::ostream::char_type, std::ostream::traits_type > base_type
Definition: archive.h:98
void save_array(boost::serialization::array_wrapper< ValueType > const &a, unsigned int)
Definition: archive.h:166
streambuf that writes bytes to a buffer in memory
Definition: stream.h:101
streambuf that writes bytes to a buffer in memory
Definition: stream.h:71
void oarchive_save_override_optimized_dispatch(Archive &ar, const T &t)
Definition: archive.h:23
auto make_boost_buffer_iarchive(const void *const buf, std::size_t size, std::size_t buf_offset=0)
constructs a boost_buffer_iarchive object
Definition: archive.h:390
boost_optimized_oarchive< byte_ostreambuf > boost_byte_oarchive
an archive that constructs serialized representation of an object in a memory buffer,...
Definition: archive.h:222
auto make_boost_buffer_oarchive(void *const buf, std::size_t size, std::size_t buf_offset=0)
constructs a boost_buffer_oarchive object
Definition: archive.h:230
void iarchive_load_override_optimized_dispatch(Archive &ar, T &t)
Definition: archive.h:48
boost_optimized_iarchive< byte_istreambuf > boost_byte_iarchive
the deserializer for boost_byte_oarchive
Definition: archive.h:382
int size(World world=default_execution_context())
Definition: run.h:89
void abort()
Aborts the TTG program using the default backend's ttg_abort method.
Definition: run.h:62