piranha  0.10
s11n.hpp
1 /* Copyright 2009-2017 Francesco Biscani (bluescarni@gmail.com)
2 
3 This file is part of the Piranha library.
4 
5 The Piranha library is free software; you can redistribute it and/or modify
6 it under the terms of either:
7 
8  * the GNU Lesser General Public License as published by the Free
9  Software Foundation; either version 3 of the License, or (at your
10  option) any later version.
11 
12 or
13 
14  * the GNU General Public License as published by the Free Software
15  Foundation; either version 3 of the License, or (at your option) any
16  later version.
17 
18 or both in parallel, as here.
19 
20 The Piranha library is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 for more details.
24 
25 You should have received copies of the GNU General Public License and the
26 GNU Lesser General Public License along with the Piranha library. If not,
27 see https://www.gnu.org/licenses/. */
28 
29 #ifndef PIRANHA_S11N_HPP
30 #define PIRANHA_S11N_HPP
31 
32 // Common headers for serialization.
33 #include <boost/algorithm/string/predicate.hpp>
34 #include <boost/archive/binary_iarchive.hpp>
35 #include <boost/archive/binary_oarchive.hpp>
36 #include <boost/archive/text_iarchive.hpp>
37 #include <boost/archive/text_oarchive.hpp>
38 #include <boost/iostreams/filtering_stream.hpp>
39 #include <boost/mpl/bool.hpp>
40 #include <boost/serialization/split_free.hpp>
41 #include <boost/serialization/split_member.hpp>
42 #include <boost/serialization/string.hpp>
43 #include <boost/version.hpp>
44 #include <cstddef>
45 #include <fstream>
46 #include <ios>
47 #include <memory>
48 #include <stdexcept>
49 #include <string>
50 #include <type_traits>
51 #include <utility>
52 
53 #include <piranha/detail/demangle.hpp>
54 #include <piranha/exceptions.hpp>
55 #include <piranha/is_key.hpp>
56 #include <piranha/safe_cast.hpp>
57 #include <piranha/symbol_utils.hpp>
58 #include <piranha/type_traits.hpp>
59 
60 namespace piranha
61 {
62 
63 inline namespace impl
64 {
65 
66 // Scalar types directly supported by the all serialization libraries.
67 template <typename T>
68 using is_serialization_scalar
69  = disjunction<std::is_same<char, T>, std::is_same<signed char, T>, std::is_same<unsigned char, T>,
70  std::is_same<short, T>, std::is_same<unsigned short, T>, std::is_same<int, T>,
71  std::is_same<unsigned, T>, std::is_same<long, T>, std::is_same<unsigned long, T>,
72  std::is_same<long long, T>, std::is_same<unsigned long long, T>, std::is_same<float, T>,
73  std::is_same<double, T>, std::is_same<bool, T>>;
74 
75 // Implementation of the detection of boost saving archives.
76 namespace ibsa_impl
77 {
78 
79 template <typename A>
80 using is_saving_t = typename A::is_saving;
81 
82 template <typename A>
83 using is_loading_t = typename A::is_loading;
84 
85 template <typename A, typename T>
86 using lshift_t = decltype(std::declval<A &>() << std::declval<const T &>());
87 
88 template <typename A, typename T>
89 using and_t = decltype(std::declval<A &>() & std::declval<const T &>());
90 
91 // NOTE: here it does not make much sense that the pointer is non-const, but we are going by the literal
92 // description in the boost archive concept.
93 template <typename A, typename T>
94 using save_binary_t = decltype(std::declval<A &>().save_binary(std::declval<T *>(), std::declval<std::size_t>()));
95 
96 template <typename A, typename T>
97 using register_type_t = decltype(std::declval<A &>().template register_type<T>());
98 
99 template <typename A>
100 using get_library_version_t = decltype(std::declval<const A &>().get_library_version());
101 
102 struct helper;
103 
104 template <typename A>
105 using get_helper_t_1 = decltype(std::declval<A &>().template get_helper<helper>());
106 
107 template <typename A>
108 using get_helper_t_2 = decltype(std::declval<A &>().template get_helper<helper>(static_cast<void *>(nullptr)));
109 
110 template <typename Archive, typename T>
111 using impl
112  = conjunction<std::is_same<detected_t<is_saving_t, uncvref_t<Archive>>, boost::mpl::bool_<true>>,
113  std::is_same<detected_t<is_loading_t, uncvref_t<Archive>>, boost::mpl::bool_<false>>,
114  // NOTE: add lvalue ref instead of using Archive &, so we avoid a hard
115  // error if Archive is void.
116  std::is_same<detected_t<lshift_t, Archive, T>, addlref_t<Archive>>,
117  std::is_same<detected_t<and_t, Archive, T>, addlref_t<Archive>>,
118  is_detected<save_binary_t, Archive, unref_t<T>>, is_detected<register_type_t, Archive, uncvref_t<T>>,
119  // NOTE: the docs here mention that get_library_version() is supposed to
120  // return an unsigned integral type, but the boost archives apparently
121  // return a type which is implicitly convertible to some unsigned int.
122  // This seems to work and it should cover also the cases in which the
123  // return type is a real unsigned int.
124  std::is_convertible<detected_t<get_library_version_t, Archive>, unsigned long long>
125 #if BOOST_VERSION >= 105700
126  // Helper support is available since 1.57.
127  ,
128  is_detected<get_helper_t_1, Archive>, is_detected<get_helper_t_2, Archive>
129 #endif
130  >;
131 }
132 }
133 
135 
140 template <typename Archive, typename T>
142 {
143  static const bool implementation_defined = ibsa_impl::impl<Archive, T>::value;
144 
145 public:
147  static const bool value = implementation_defined;
148 };
149 
150 template <typename Archive, typename T>
152 
153 inline namespace impl
154 {
155 
156 // Implementation of boost loading archive concept. We reuse some types from the ibsa_impl namespace.
157 namespace ibla_impl
158 {
159 
160 template <typename A, typename T>
161 using rshift_t = decltype(std::declval<A &>() >> std::declval<T &>());
162 
163 template <typename A, typename T>
164 using and_t = decltype(std::declval<A &>() & std::declval<T &>());
165 
166 template <typename A, typename T>
167 using load_binary_t = decltype(std::declval<A &>().load_binary(std::declval<T *>(), std::declval<std::size_t>()));
168 
169 template <typename A, typename T>
170 using reset_object_address_t
171  = decltype(std::declval<A &>().reset_object_address(std::declval<T *>(), std::declval<T *>()));
172 
173 template <typename A>
174 using delete_created_pointers_t = decltype(std::declval<A &>().delete_created_pointers());
175 
176 template <typename Archive, typename T>
177 using impl = conjunction<
178  std::is_same<detected_t<ibsa_impl::is_saving_t, uncvref_t<Archive>>, boost::mpl::bool_<false>>,
179  std::is_same<detected_t<ibsa_impl::is_loading_t, uncvref_t<Archive>>, boost::mpl::bool_<true>>,
180  std::is_same<detected_t<rshift_t, Archive, T>, addlref_t<Archive>>,
181  std::is_same<detected_t<and_t, Archive, T>, addlref_t<Archive>>, is_detected<load_binary_t, Archive, unref_t<T>>,
182  is_detected<ibsa_impl::register_type_t, Archive, uncvref_t<T>>,
183  std::is_convertible<detected_t<ibsa_impl::get_library_version_t, Archive>, unsigned long long>,
184  is_detected<reset_object_address_t, Archive, unref_t<T>>, is_detected<delete_created_pointers_t, Archive>
185 #if BOOST_VERSION >= 105700
186  ,
187  is_detected<ibsa_impl::get_helper_t_1, Archive>, is_detected<ibsa_impl::get_helper_t_2, Archive>
188 #endif
189  >;
190 }
191 }
192 
194 
199 template <typename Archive, typename T>
201 {
202  static const bool implementation_defined = ibla_impl::impl<Archive, T>::value;
203 
204 public:
206  static const bool value = implementation_defined;
207 };
208 
209 template <typename Archive, typename T>
211 
213 
216 template <typename Archive, typename T>
219 
233  void operator()(Archive &ar, const T &x) const
234  {
235  ar << x;
236  }
237 };
238 
240 
244 template <typename Archive, typename T, typename = void>
246 };
247 
248 inline namespace impl
249 {
250 
251 // Enabler for the arithmetic specialisation of boost_save().
252 template <typename Archive, typename T>
253 using boost_save_arithmetic_enabler =
254  // NOTE: the check for non-constness of Archive is implicit in the saving archive concept.
255  // NOTE: here we are relying on the fact that the Archive class correctly advertises the capability
256  // to serialize arithmetic types. This is for instance *not* the case for Boost archives, which
257  // accept every type (at the signature level), but since here we are concerned only with arithmetic
258  // types (for which serialization is always available in Boost archives), it should not matter.
259  enable_if_t<conjunction<is_boost_saving_archive<Archive, T>,
260  disjunction<is_serialization_scalar<T>, std::is_same<T, long double>>>::value>;
261 }
262 
264 
274 template <typename Archive, typename T>
275 struct boost_save_impl<Archive, T, boost_save_arithmetic_enabler<Archive, T>> : boost_save_via_boost_api<Archive, T> {
276 };
277 
278 inline namespace impl
279 {
280 
281 // Enabler for boost_save() for strings.
282 template <typename Archive>
283 using boost_save_string_enabler = enable_if_t<is_boost_saving_archive<Archive, std::string>::value>;
284 }
285 
287 
292 template <typename Archive>
293 struct boost_save_impl<Archive, std::string, boost_save_string_enabler<Archive>>
294  : boost_save_via_boost_api<Archive, std::string> {
295 };
296 
297 inline namespace impl
298 {
299 
300 template <typename Archive, typename T>
301 using boost_save_impl_t = decltype(boost_save_impl<Archive, T>{}(std::declval<Archive &>(), std::declval<const T &>()));
302 
303 // Enabler for boost_save().
304 template <typename Archive, typename T>
305 using boost_save_enabler
306  = enable_if_t<conjunction<is_boost_saving_archive<Archive, T>, is_detected<boost_save_impl_t, Archive, T>>::value,
307  int>;
308 }
309 
311 
327 template <typename Archive, typename T, boost_save_enabler<Archive, T> = 0>
328 inline void boost_save(Archive &ar, const T &x)
329 {
331 }
332 
333 inline namespace impl
334 {
335 
336 template <typename A, typename T>
337 using boost_save_t = decltype(piranha::boost_save(std::declval<A &>(), std::declval<const T &>()));
338 }
339 
341 
345 template <typename Archive, typename T>
347 {
348  static const bool implementation_defined = is_detected<boost_save_t, Archive, T>::value;
349 
350 public:
352  static const bool value = implementation_defined;
353 };
354 
355 template <typename Archive, typename T>
357 
359 
362 template <typename Archive, typename T>
365 
379  void operator()(Archive &ar, T &x) const
380  {
381  ar >> x;
382  }
383 };
384 
386 
390 template <typename Archive, typename T, typename = void>
392 };
393 
394 inline namespace impl
395 {
396 
397 // Enabler for the arithmetic specialisation of boost_load().
398 template <typename Archive, typename T>
399 using boost_load_arithmetic_enabler
400  = enable_if_t<conjunction<is_boost_loading_archive<Archive, T>,
401  disjunction<is_serialization_scalar<T>, std::is_same<T, long double>>>::value>;
402 }
403 
405 
415 template <typename Archive, typename T>
416 struct boost_load_impl<Archive, T, boost_load_arithmetic_enabler<Archive, T>> : boost_load_via_boost_api<Archive, T> {
417 };
418 
419 inline namespace impl
420 {
421 
422 // Enabler for boost_load for strings.
423 template <typename Archive>
424 using boost_load_string_enabler = enable_if_t<is_boost_loading_archive<Archive, std::string>::value>;
425 }
426 
428 
433 template <typename Archive>
434 struct boost_load_impl<Archive, std::string, boost_load_string_enabler<Archive>>
435  : boost_load_via_boost_api<Archive, std::string> {
436 };
437 
438 inline namespace impl
439 {
440 
441 template <typename Archive, typename T>
442 using boost_load_impl_t = decltype(boost_load_impl<Archive, T>{}(std::declval<Archive &>(), std::declval<T &>()));
443 
444 // Enabler for boost_load().
445 template <typename Archive, typename T>
446 using boost_load_enabler
447  = enable_if_t<conjunction<is_boost_loading_archive<Archive, T>, is_detected<boost_load_impl_t, Archive, T>>::value,
448  int>;
449 }
450 
452 
468 template <typename Archive, typename T, boost_load_enabler<Archive, T> = 0>
469 inline void boost_load(Archive &ar, T &x)
470 {
472 }
473 
474 inline namespace impl
475 {
476 
477 template <typename A, typename T>
478 using boost_load_t = decltype(piranha::boost_load(std::declval<A &>(), std::declval<T &>()));
479 }
480 
482 
486 template <typename Archive, typename T>
488 {
489  static const bool implementation_defined = is_detected<boost_load_t, Archive, T>::value;
490 
491 public:
493  static const bool value = implementation_defined;
494 };
495 
496 template <typename Archive, typename T>
498 
500 
513 template <typename Key>
515 private:
516  PIRANHA_TT_CHECK(is_key, Key);
517 
518 public:
520 
524  explicit boost_s11n_key_wrapper(Key &k, const symbol_fset &ss)
525  : m_key_m(std::addressof(k)), m_key_c(m_key_m), m_ss(ss)
526  {
527  }
529 
533  explicit boost_s11n_key_wrapper(const Key &k, const symbol_fset &ss)
534  : m_key_m(nullptr), m_key_c(std::addressof(k)), m_ss(ss)
535  {
536  }
538 
546  Key &key()
547  {
548  if (unlikely(!m_key_m)) {
549  piranha_throw(std::runtime_error, "trying to access the mutable key instance of a boost_s11n_key_wrapper "
550  "that was constructed with a const key");
551  }
552  return *m_key_m;
553  }
555 
558  const Key &key() const
559  {
560  return *m_key_c;
561  }
563 
566  const symbol_fset &ss() const
567  {
568  return m_ss;
569  }
570 
571 private:
572  Key *m_key_m;
573  const Key *m_key_c;
574  const symbol_fset &m_ss;
575 };
576 }
577 
578 #include <piranha/config.hpp>
579 
580 #if defined(PIRANHA_WITH_MSGPACK)
581 
582 #include <msgpack.hpp>
583 
584 #if MSGPACK_VERSION_MAJOR < 2
585 
586 #error The minimum msgpack-c version supported is 2.
587 
588 #endif
589 
590 #include <algorithm>
591 #include <array>
592 #include <boost/iostreams/device/mapped_file.hpp>
593 #include <cmath>
594 #include <cstdint>
595 #include <ios>
596 #include <iterator>
597 #include <limits>
598 #include <locale>
599 #include <sstream>
600 #include <vector>
601 
602 namespace piranha
603 {
604 
605 // Fwd decls.
606 template <typename, typename>
608 
609 template <typename>
611 
612 inline namespace impl
613 {
614 
615 // Wrapper for std stream classes for use in msgpack. The reason for this wrapper is that msgpack expects
616 // streams with a write(const char *, std::size_t) method, but in std streams the second param is std::streamsize
617 // (which is a signed int). Hence we wrap the write method to do the safe conversion from size_t to streamsize.
618 template <typename Stream>
619 struct msgpack_stream_wrapper : Stream {
620  // Inherit ctors.
621  using Stream::Stream;
622  auto write(const typename Stream::char_type *p, std::size_t count)
623  -> decltype(std::declval<Stream &>().write(p, std::streamsize(0)))
624  {
625  return static_cast<Stream *>(this)->write(p, safe_cast<std::streamsize>(count));
626  }
627 };
628 
629 template <typename T>
630 using msgpack_stream_write_t
631  = decltype(std::declval<T &>().write(std::declval<const char *>(), std::declval<std::size_t>()));
632 }
633 
635 
644 template <typename T>
646 {
647  static const bool implementation_defined
648  = conjunction<is_detected<msgpack_stream_write_t, T>, negation<std::is_reference<T>>,
649  negation<std::is_const<T>>>::value;
650 
651 public:
653  static const bool value = implementation_defined;
654 };
655 
656 template <typename T>
657 const bool is_msgpack_stream<T>::value;
658 
660 
673 enum class msgpack_format {
675  portable,
677  binary
678 };
679 
681 
685 template <typename Stream, typename T, typename = void>
687 };
688 
689 inline namespace impl
690 {
691 
692 template <typename Stream, typename T>
693 using msgpack_scalar_enabler = enable_if_t<conjunction<is_msgpack_stream<Stream>, is_serialization_scalar<T>>::value>;
694 }
695 
697 
710 template <typename Stream, typename T>
711 struct msgpack_pack_impl<Stream, T, msgpack_scalar_enabler<Stream, T>> {
713 
719  void operator()(msgpack::packer<Stream> &packer, const T &x, msgpack_format) const
720  {
721  packer.pack(x);
722  }
723 };
724 
725 inline namespace impl
726 {
727 
728 template <typename Stream>
729 using msgpack_ld_enabler
730  = enable_if_t<conjunction<is_msgpack_stream<Stream>, has_msgpack_pack<Stream, std::string>>::value>;
731 }
732 
734 
740 template <typename Stream>
741 struct msgpack_pack_impl<Stream, long double, msgpack_ld_enabler<Stream>> {
743 
755  void operator()(msgpack::packer<Stream> &packer, const long double &x, msgpack_format f) const
756  {
757  if (f == msgpack_format::binary) {
758  packer.pack_bin(sizeof(long double));
759  packer.pack_bin_body(reinterpret_cast<const char *>(&x), sizeof(long double));
760  } else {
761  if (std::isnan(x)) {
762  if (std::signbit(x)) {
763  msgpack_pack(packer, std::string("-nan"), f);
764  } else {
765  msgpack_pack(packer, std::string("+nan"), f);
766  }
767  } else if (std::isinf(x)) {
768  if (std::signbit(x)) {
769  msgpack_pack(packer, std::string("-inf"), f);
770  } else {
771  msgpack_pack(packer, std::string("+inf"), f);
772  }
773  } else {
774  std::ostringstream oss;
775  // Make sure we are using the C locale.
776  oss.imbue(std::locale::classic());
777  // Use scientific format.
778  oss << std::scientific;
779  // http://stackoverflow.com/questions/554063/how-do-i-print-a-double-value-with-full-precision-using-cout
780  // NOTE: this does not mean that the *exact* value of the long double is printed, just that the
781  // value is recovered exactly if reloaded on the same machine. This is a compromise, as the exact
782  // printing of the value in string form would take up hundreds of digits. On the other hand, there is a
783  // similar situation also for float and double, as there is not guarantee that they conform to IEEE. In
784  // the end it seems the only practical approach is to consider all floating-point types as approximate
785  // values, subject to various platform/architecture vagaries.
786  oss.precision(std::numeric_limits<long double>::max_digits10);
787  oss << x;
788  msgpack_pack(packer, oss.str(), f);
789  }
790  }
791  }
792 };
793 
794 inline namespace impl
795 {
796 
797 template <typename Stream>
798 using msgpack_string_enabler = enable_if_t<is_msgpack_stream<Stream>::value>;
799 }
800 
802 
808 template <typename Stream>
809 struct msgpack_pack_impl<Stream, std::string, msgpack_string_enabler<Stream>> {
811 
817  void operator()(msgpack::packer<Stream> &packer, const std::string &s, msgpack_format) const
818  {
819  packer.pack(s);
820  }
821 };
822 
823 inline namespace impl
824 {
825 
826 template <typename Stream, typename T>
827 using msgpack_pack_impl_t = decltype(msgpack_pack_impl<Stream, T>{}(
828  std::declval<msgpack::packer<Stream> &>(), std::declval<const T &>(), std::declval<msgpack_format>()));
829 
830 // Enabler for msgpack_pack.
831 template <typename Stream, typename T>
832 using msgpack_pack_enabler
833  = enable_if_t<conjunction<is_msgpack_stream<Stream>, is_detected<msgpack_pack_impl_t, Stream, T>>::value, int>;
834 }
835 
837 
855 template <typename Stream, typename T, msgpack_pack_enabler<Stream, T> = 0>
856 inline void msgpack_pack(msgpack::packer<Stream> &packer, const T &x, msgpack_format f)
857 {
858  msgpack_pack_impl<Stream, T>{}(packer, x, f);
859 }
860 
862 
866 template <typename T, typename = void>
868 };
869 
870 inline namespace impl
871 {
872 
873 template <typename T>
874 using msgpack_convert_scalar_enabler = enable_if_t<is_serialization_scalar<T>::value>;
875 }
876 
878 
890 template <typename T>
891 struct msgpack_convert_impl<T, msgpack_convert_scalar_enabler<T>> {
893 
899  void operator()(T &x, const msgpack::object &o, msgpack_format) const
900  {
901  o.convert(x);
902  }
903 };
904 
906 
909 template <>
910 struct msgpack_convert_impl<std::string> {
912 
918  void operator()(std::string &s, const msgpack::object &o, msgpack_format) const
919  {
920  o.convert(s);
921  }
922 };
923 
924 inline namespace impl
925 {
926 
927 template <typename T>
928 using msgpack_convert_impl_t = decltype(msgpack_convert_impl<T>{}(
929  std::declval<T &>(), std::declval<const msgpack::object &>(), std::declval<msgpack_format>()));
930 
931 // Enabler for msgpack_convert.
932 template <typename T>
933 using msgpack_convert_enabler
934  = enable_if_t<conjunction<negation<std::is_const<T>>, is_detected<msgpack_convert_impl_t, T>>::value, int>;
935 }
936 
938 
956 template <typename T, msgpack_convert_enabler<T> = 0>
957 inline void msgpack_convert(T &x, const msgpack::object &o, msgpack_format f)
958 {
959  msgpack_convert_impl<T>{}(x, o, f);
960 }
961 
962 inline namespace impl
963 {
964 
965 template <typename T>
966 using msgpack_convert_ld_enabler
967  = enable_if_t<conjunction<std::is_same<T, long double>, has_msgpack_convert<std::string>>::value>;
968 }
969 
971 
976 template <typename T>
977 struct msgpack_convert_impl<T, msgpack_convert_ld_enabler<T>> {
979 
990  void operator()(long double &x, const msgpack::object &o, msgpack_format f) const
991  {
992  using lim = std::numeric_limits<long double>;
993  if (f == msgpack_format::binary) {
994  std::array<char, sizeof(long double)> tmp;
995  o.convert(tmp);
996  std::copy(tmp.begin(), tmp.end(), reinterpret_cast<char *>(&x));
997  } else {
998  PIRANHA_MAYBE_TLS std::string tmp;
999  msgpack_convert(tmp, o, f);
1000  if (tmp == "+nan") {
1001  if (lim::has_quiet_NaN) {
1002  x = std::copysign(lim::quiet_NaN(), 1.l);
1003  } else {
1004  piranha_throw(std::invalid_argument, "cannot deserialize a NaN if the platform does not support "
1005  "quiet NaNs");
1006  }
1007  } else if (tmp == "-nan") {
1008  if (lim::has_quiet_NaN) {
1009  x = std::copysign(lim::quiet_NaN(), -1.l);
1010  } else {
1011  piranha_throw(std::invalid_argument, "cannot deserialize a NaN if the platform does not support "
1012  "quiet NaNs");
1013  }
1014  } else if (tmp == "+inf") {
1015  if (lim::has_infinity) {
1016  x = lim::infinity();
1017  } else {
1018  piranha_throw(std::invalid_argument, "infinities are not supported by the platform");
1019  }
1020  } else if (tmp == "-inf") {
1021  if (lim::has_infinity) {
1022  x = std::copysign(lim::infinity(), -1.l);
1023  } else {
1024  piranha_throw(std::invalid_argument, "infinities are not supported by the platform");
1025  }
1026  } else {
1027  std::istringstream iss;
1028  iss.imbue(std::locale::classic());
1029  // NOTE: is seems like the std::scientific format flag has an effect on input
1030  // streams as well. See the example here:
1031  // http://en.cppreference.com/w/cpp/io/manip/fixed
1032  iss >> std::scientific;
1033  iss.str(tmp);
1034  iss >> x;
1035  if (unlikely(iss.fail())) {
1036  piranha_throw(std::invalid_argument, "failed to parse the string '" + tmp + "' as a long double");
1037  }
1038  }
1039  }
1040  }
1041 };
1042 
1043 inline namespace impl
1044 {
1045 
1046 template <typename Stream, typename T>
1047 using msgpack_pack_t = decltype(piranha::msgpack_pack(std::declval<msgpack::packer<Stream> &>(),
1048  std::declval<const T &>(), std::declval<msgpack_format>()));
1049 }
1050 
1052 
1056 template <typename Stream, typename T>
1057 class has_msgpack_pack
1058 {
1059  static const bool implementation_defined = is_detected<msgpack_pack_t, Stream, T>::value;
1060 
1061 public:
1063  static const bool value = implementation_defined;
1064 };
1065 
1066 template <typename Stream, typename T>
1068 
1069 inline namespace impl
1070 {
1071 
1072 template <typename T>
1073 using msgpack_convert_t = decltype(piranha::msgpack_convert(
1074  std::declval<T &>(), std::declval<const msgpack::object &>(), std::declval<msgpack_format>()));
1075 }
1076 
1078 
1081 template <typename T>
1082 class has_msgpack_convert
1083 {
1084  static const bool implementation_defined = is_detected<msgpack_convert_t, T>::value;
1085 
1086 public:
1088  static const bool value = implementation_defined;
1089 };
1090 
1091 template <typename T>
1093 
1094 inline namespace impl
1095 {
1096 
1097 template <typename Stream, typename Key>
1098 using key_msgpack_pack_t = decltype(std::declval<const Key &>().msgpack_pack(
1099  std::declval<msgpack::packer<Stream> &>(), std::declval<msgpack_format>(), std::declval<const symbol_fset &>()));
1100 }
1101 
1103 
1114 template <typename Stream, typename Key>
1116 {
1117  PIRANHA_TT_CHECK(is_key, uncvref_t<Key>);
1118  static const bool implementation_defined
1119  = conjunction<is_detected<key_msgpack_pack_t, Stream, Key>, is_msgpack_stream<Stream>>::value;
1120 
1121 public:
1123  static const bool value = implementation_defined;
1124 };
1125 
1126 template <typename Stream, typename Key>
1128 
1129 inline namespace impl
1130 {
1131 
1132 template <typename Key>
1133 using key_msgpack_convert_t = decltype(std::declval<Key &>().msgpack_convert(
1134  std::declval<const msgpack::object &>(), std::declval<msgpack_format>(), std::declval<const symbol_fset &>()));
1135 }
1136 
1138 
1148 template <typename Key>
1150 {
1151  PIRANHA_TT_CHECK(is_key, uncvref_t<Key>);
1152  static const bool implementation_defined = is_detected<key_msgpack_convert_t, Key>::value;
1153 
1154 public:
1156  static const bool value = implementation_defined;
1157 };
1158 
1159 template <typename Key>
1161 }
1162 
1163 #endif
1164 
1165 #if defined(PIRANHA_WITH_ZLIB)
1166 
1167 #include <boost/iostreams/filter/gzip.hpp>
1168 #include <boost/iostreams/filter/zlib.hpp>
1169 
1170 #define PIRANHA_ZLIB_CONDITIONAL(expr) expr
1171 
1172 #else
1173 
1174 #define PIRANHA_ZLIB_CONDITIONAL(expr) piranha_throw(not_implemented_error, "zlib support is not enabled")
1175 
1176 #endif
1177 
1178 #if defined(PIRANHA_WITH_BZIP2)
1179 
1180 #include <boost/iostreams/filter/bzip2.hpp>
1181 
1182 #define PIRANHA_BZIP2_CONDITIONAL(expr) expr
1183 
1184 #else
1185 
1186 #define PIRANHA_BZIP2_CONDITIONAL(expr) piranha_throw(not_implemented_error, "bzip2 support is not enabled")
1187 
1188 #endif
1189 
1190 namespace piranha
1191 {
1192 
1194 
1205 enum class data_format {
1207 
1210  boost_binary,
1212 
1217 
1222 
1226 };
1227 
1229 
1232 enum class compression {
1234  none,
1236  bzip2,
1238  gzip,
1240  zlib
1241 };
1242 
1243 inline namespace impl
1244 {
1245 
1246 // NOTE: no need for ifdefs guards here, as the compression-specific stuff is hidden in the CompressionFilter type.
1247 template <typename CompressionFilter, typename T>
1248 inline void save_file_boost_compress_impl(const T &x, std::ofstream &ofile, data_format f)
1249 {
1250  piranha_assert(f == data_format::boost_binary || f == data_format::boost_portable);
1251  // NOTE: there seem to be 2 choices here: stream or streambuf. The first does some formatting, while the second
1252  // one is "raw" but does not provide the stream interface (which is used, e.g., by msgpack). Since we always
1253  // open files in binary mode (as suggested by the Boost serialization library), this should not matter in the end.
1254  // Some resources:
1255  // http://stackoverflow.com/questions/1753469/how-to-hook-up-boost-serialization-iostreams-to-serialize-gzip-an-object-to
1256  // https://code.google.com/p/cloudobserver/wiki/TutorialsBoostIOstreams
1257  // http://stackoverflow.com/questions/8116541/what-exactly-is-streambuf-how-do-i-use-it
1258  // http://www.boost.org/doc/libs/1_46_1/libs/serialization/doc/special.html
1259  boost::iostreams::filtering_ostream out;
1260  out.push(CompressionFilter{});
1261  out.push(ofile);
1262  if (f == data_format::boost_binary) {
1263  boost::archive::binary_oarchive oa(out);
1264  boost_save(oa, x);
1265  } else {
1266  boost::archive::text_oarchive oa(out);
1267  boost_save(oa, x);
1268  }
1269 }
1270 
1271 // NOTE: the implementation is the specular of the above.
1272 template <typename DecompressionFilter, typename T>
1273 inline void load_file_boost_compress_impl(T &x, std::ifstream &ifile, data_format f)
1274 {
1275  piranha_assert(f == data_format::boost_binary || f == data_format::boost_portable);
1276  boost::iostreams::filtering_istream in;
1277  in.push(DecompressionFilter{});
1278  in.push(ifile);
1279  if (f == data_format::boost_binary) {
1280  boost::archive::binary_iarchive ia(in);
1281  boost_load(ia, x);
1282  } else {
1283  boost::archive::text_iarchive ia(in);
1284  boost_load(ia, x);
1285  }
1286 }
1287 
1288 // Main save/load functions for Boost format.
1289 template <typename T, enable_if_t<conjunction<has_boost_save<boost::archive::binary_oarchive, T>,
1290  has_boost_save<boost::archive::text_oarchive, T>>::value,
1291  int> = 0>
1292 inline void save_file_boost_impl(const T &x, const std::string &filename, data_format f, compression c)
1293 {
1294  namespace bi = boost::iostreams;
1295  // NOTE: always open in binary mode in order to avoid problems with special formatting in streams.
1296  std::ofstream ofile(filename, std::ios::out | std::ios::binary | std::ios::trunc);
1297  if (unlikely(!ofile.good())) {
1298  piranha_throw(std::runtime_error, "file '" + filename + "' could not be opened for saving");
1299  }
1300  switch (c) {
1301  case compression::bzip2:
1302  PIRANHA_BZIP2_CONDITIONAL(save_file_boost_compress_impl<bi::bzip2_compressor>(x, ofile, f));
1303  break;
1304  case compression::gzip:
1305  PIRANHA_ZLIB_CONDITIONAL(save_file_boost_compress_impl<bi::gzip_compressor>(x, ofile, f));
1306  break;
1307  case compression::zlib:
1308  PIRANHA_ZLIB_CONDITIONAL(save_file_boost_compress_impl<bi::zlib_compressor>(x, ofile, f));
1309  break;
1310  case compression::none:
1311  if (f == data_format::boost_binary) {
1312  boost::archive::binary_oarchive oa(ofile);
1313  boost_save(oa, x);
1314  } else {
1315  boost::archive::text_oarchive oa(ofile);
1316  boost_save(oa, x);
1317  }
1318  }
1319 }
1320 
1321 template <typename T, enable_if_t<disjunction<negation<has_boost_save<boost::archive::binary_oarchive, T>>,
1322  negation<has_boost_save<boost::archive::text_oarchive, T>>>::value,
1323  int> = 0>
1324 inline void save_file_boost_impl(const T &, const std::string &, data_format, compression)
1325 {
1326  piranha_throw(not_implemented_error,
1327  "type '" + detail::demangle<T>() + "' does not support serialization via Boost");
1328 }
1329 
1330 template <typename T, enable_if_t<conjunction<has_boost_load<boost::archive::binary_iarchive, T>,
1331  has_boost_load<boost::archive::text_iarchive, T>>::value,
1332  int> = 0>
1333 inline void load_file_boost_impl(T &x, const std::string &filename, data_format f, compression c)
1334 {
1335  namespace bi = boost::iostreams;
1336  std::ifstream ifile(filename, std::ios::in | std::ios::binary);
1337  if (unlikely(!ifile.good())) {
1338  piranha_throw(std::runtime_error, "file '" + filename + "' could not be opened for loading");
1339  }
1340  switch (c) {
1341  case compression::bzip2:
1342  PIRANHA_BZIP2_CONDITIONAL(load_file_boost_compress_impl<bi::bzip2_decompressor>(x, ifile, f));
1343  break;
1344  case compression::gzip:
1345  PIRANHA_ZLIB_CONDITIONAL(load_file_boost_compress_impl<bi::gzip_decompressor>(x, ifile, f));
1346  break;
1347  case compression::zlib:
1348  PIRANHA_ZLIB_CONDITIONAL(load_file_boost_compress_impl<bi::zlib_decompressor>(x, ifile, f));
1349  break;
1350  case compression::none:
1351  if (f == data_format::boost_binary) {
1352  boost::archive::binary_iarchive ia(ifile);
1353  boost_load(ia, x);
1354  } else {
1355  boost::archive::text_iarchive ia(ifile);
1356  boost_load(ia, x);
1357  }
1358  }
1359 }
1360 
1361 template <typename T, enable_if_t<disjunction<negation<has_boost_load<boost::archive::binary_iarchive, T>>,
1362  negation<has_boost_load<boost::archive::text_iarchive, T>>>::value,
1363  int> = 0>
1364 inline void load_file_boost_impl(T &, const std::string &, data_format, compression)
1365 {
1366  piranha_throw(not_implemented_error,
1367  "type '" + detail::demangle<T>() + "' does not support deserialization via Boost");
1368 }
1369 
1370 #if defined(PIRANHA_WITH_MSGPACK)
1371 
1372 // Compressed load/save for msgpack.
1373 template <typename CompressionFilter, typename T>
1374 inline void save_file_msgpack_compress_impl(const T &x, msgpack_stream_wrapper<std::ofstream> &ofile, msgpack_format mf)
1375 {
1376  msgpack_stream_wrapper<boost::iostreams::filtering_ostream> out;
1377  out.push(CompressionFilter{});
1378  out.push(ofile);
1379  msgpack::packer<decltype(out)> packer(out);
1380  msgpack_pack(packer, x, mf);
1381 }
1382 
1383 template <typename DecompressionFilter, typename T>
1384 inline void load_file_msgpack_compress_impl(T &x, const std::string &filename, msgpack_format mf)
1385 {
1386  std::ifstream ifile(filename, std::ios::in | std::ios::binary);
1387  if (unlikely(!ifile.good())) {
1388  piranha_throw(std::runtime_error, "file '" + filename + "' could not be opened for loading");
1389  }
1390  std::vector<char> vchar;
1391  boost::iostreams::filtering_istream in;
1392  in.push(DecompressionFilter{});
1393  in.push(ifile);
1394  std::copy(std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>(), std::back_inserter(vchar));
1395  auto oh = msgpack::unpack(vchar.data(), safe_cast<std::size_t>(vchar.size()));
1396  msgpack_convert(x, oh.get(), mf);
1397 }
1398 
1399 // Main msgpack load/save functions.
1400 template <
1401  typename T,
1402  enable_if_t<conjunction<has_msgpack_pack<msgpack_stream_wrapper<std::ofstream>, T>,
1403  has_msgpack_pack<msgpack_stream_wrapper<boost::iostreams::filtering_ostream>, T>>::value,
1404  int> = 0>
1405 inline void save_file_msgpack_impl(const T &x, const std::string &filename, data_format f, compression c)
1406 {
1407  namespace bi = boost::iostreams;
1409  msgpack_stream_wrapper<std::ofstream> ofile(filename, std::ios::out | std::ios::binary | std::ios::trunc);
1410  if (unlikely(!ofile.good())) {
1411  piranha_throw(std::runtime_error, "file '" + filename + "' could not be opened for saving");
1412  }
1413  switch (c) {
1414  case compression::bzip2:
1415  PIRANHA_BZIP2_CONDITIONAL(save_file_msgpack_compress_impl<bi::bzip2_compressor>(x, ofile, mf));
1416  break;
1417  case compression::gzip:
1418  PIRANHA_ZLIB_CONDITIONAL(save_file_msgpack_compress_impl<bi::gzip_compressor>(x, ofile, mf));
1419  break;
1420  case compression::zlib:
1421  PIRANHA_ZLIB_CONDITIONAL(save_file_msgpack_compress_impl<bi::zlib_compressor>(x, ofile, mf));
1422  break;
1423  case compression::none: {
1424  msgpack::packer<decltype(ofile)> packer(ofile);
1425  msgpack_pack(packer, x, mf);
1426  }
1427  }
1428 }
1429 
1430 template <
1431  typename T,
1432  enable_if_t<
1433  disjunction<negation<has_msgpack_pack<msgpack_stream_wrapper<std::ofstream>, T>>,
1434  negation<has_msgpack_pack<msgpack_stream_wrapper<boost::iostreams::filtering_ostream>, T>>>::value,
1435  int> = 0>
1436 inline void save_file_msgpack_impl(const T &, const std::string &, data_format, compression)
1437 {
1438  piranha_throw(not_implemented_error,
1439  "type '" + detail::demangle<T>() + "' does not support serialization via msgpack");
1440 }
1441 
1442 template <typename T, enable_if_t<has_msgpack_convert<T>::value, int> = 0>
1443 inline void load_file_msgpack_impl(T &x, const std::string &filename, data_format f, compression c)
1444 {
1445  namespace bi = boost::iostreams;
1447  switch (c) {
1448  case compression::bzip2:
1449  PIRANHA_BZIP2_CONDITIONAL(load_file_msgpack_compress_impl<bi::bzip2_decompressor>(x, filename, mf));
1450  break;
1451  case compression::gzip:
1452  PIRANHA_ZLIB_CONDITIONAL(load_file_msgpack_compress_impl<bi::gzip_decompressor>(x, filename, mf));
1453  break;
1454  case compression::zlib:
1455  PIRANHA_ZLIB_CONDITIONAL(load_file_msgpack_compress_impl<bi::zlib_decompressor>(x, filename, mf));
1456  break;
1457  case compression::none: {
1458  // NOTE: two-stage construction for exception handling.
1459  std::unique_ptr<bi::mapped_file> mmap;
1460  try {
1461  mmap.reset(new bi::mapped_file(filename, bi::mapped_file::readonly));
1462  } catch (...) {
1463  // NOTE: this is just to beautify a bit the error message, and we assume any error in the line
1464  // above results from being unable to open the file.
1465  piranha_throw(std::runtime_error, "file '" + filename + "' could not be opened for loading");
1466  }
1467  // NOTE: this might be superfluous, but better safe than sorry.
1468  if (unlikely(!mmap->is_open())) {
1469  piranha_throw(std::runtime_error, "file '" + filename + "' could not be opened for loading");
1470  }
1471  auto oh = msgpack::unpack(mmap->const_data(), safe_cast<std::size_t>(mmap->size()));
1472  msgpack_convert(x, oh.get(), mf);
1473  }
1474  }
1475 }
1476 
1477 template <typename T, enable_if_t<!has_msgpack_convert<T>::value, int> = 0>
1478 inline void load_file_msgpack_impl(T &, const std::string &, data_format, compression)
1479 {
1480  piranha_throw(not_implemented_error,
1481  "type '" + detail::demangle<T>() + "' does not support deserialization via msgpack");
1482 }
1483 
1484 #else
1485 
1486 // If msgpack is not available, just error out.
1487 template <typename T>
1488 inline void save_file_msgpack_impl(const T &, const std::string &, data_format, compression)
1489 {
1490  piranha_throw(not_implemented_error, "msgpack support is not enabled");
1491 }
1492 
1493 template <typename T>
1494 inline void load_file_msgpack_impl(T &, const std::string &, data_format, compression)
1495 {
1496  piranha_throw(not_implemented_error, "msgpack support is not enabled");
1497 }
1498 
1499 #endif
1500 
1501 // General enabler for load_file().
1502 template <typename T>
1503 using load_file_enabler = enable_if_t<!std::is_const<T>::value, int>;
1504 
1505 // Utility to deduce compression and data format from a filename.
1506 inline std::pair<compression, data_format> get_cdf_from_filename(std::string filename)
1507 {
1508  const auto orig_fname = filename;
1510  if (boost::ends_with(filename, ".bz2")) {
1511  c = compression::bzip2;
1512  filename.erase(filename.end() - 4, filename.end());
1513  } else if (boost::ends_with(filename, ".gz")) {
1514  c = compression::gzip;
1515  filename.erase(filename.end() - 3, filename.end());
1516  } else if (boost::ends_with(filename, ".zip")) {
1517  c = compression::zlib;
1518  filename.erase(filename.end() - 4, filename.end());
1519  }
1520  data_format f;
1521  if (boost::ends_with(filename, ".boostb")) {
1523  } else if (boost::ends_with(filename, ".boostp")) {
1525  } else if (boost::ends_with(filename, ".mpackb")) {
1527  } else if (boost::ends_with(filename, ".mpackp")) {
1529  } else {
1530  piranha_throw(std::invalid_argument,
1531  "unable to deduce the data format from the filename '" + orig_fname
1532  + "'. The filename must end with one of ['.boostb','.boostp','.mpackb','.mpackp'], "
1533  "optionally followed by one of ['.bz2','gz','zip'].");
1534  }
1535  return std::make_pair(c, f);
1536 }
1537 }
1538 
1540 
1564 template <typename T>
1565 inline void save_file(const T &x, const std::string &filename, data_format f, compression c)
1566 {
1568  save_file_boost_impl(x, filename, f, c);
1570  save_file_msgpack_impl(x, filename, f, c);
1571  }
1572 }
1573 
1575 
1600 template <typename T>
1601 inline void save_file(const T &x, const std::string &filename)
1602 {
1603  const auto p = get_cdf_from_filename(filename);
1604  save_file(x, filename, p.second, p.first);
1605 }
1606 
1608 
1637 template <typename T, load_file_enabler<T> = 0>
1638 inline void load_file(T &x, const std::string &filename, data_format f, compression c)
1639 {
1641  load_file_boost_impl(x, filename, f, c);
1643  load_file_msgpack_impl(x, filename, f, c);
1644  }
1645 }
1646 
1648 
1662 template <typename T, load_file_enabler<T> = 0>
1663 inline void load_file(T &x, const std::string &filename)
1664 {
1665  const auto p = get_cdf_from_filename(filename);
1666  load_file(x, filename, p.second, p.first);
1667 }
1668 
1669 inline namespace impl
1670 {
1671 
1672 #if defined(PIRANHA_WITH_MSGPACK)
1673 
1674 // These typedefs are useful when checking the availability of boost save/load member functions, which
1675 // we use fairly often to implement the _impl functors.
1676 template <typename Stream, typename T>
1677 using msgpack_pack_member_t = decltype(
1678  std::declval<const T &>().msgpack_pack(std::declval<msgpack::packer<Stream> &>(), std::declval<msgpack_format>()));
1679 
1680 template <typename T>
1681 using msgpack_convert_member_t = decltype(
1682  std::declval<T &>().msgpack_convert(std::declval<const msgpack::object &>(), std::declval<msgpack_format>()));
1683 
1684 #endif
1685 
1686 // Utility functions to serialize ranges and vector-like types.
1687 template <typename Archive, typename It>
1688 inline void boost_save_range(Archive &ar, It begin, It end)
1689 {
1690  for (; begin != end; ++begin) {
1691  boost_save(ar, *begin);
1692  }
1693 }
1694 
1695 template <typename Archive, typename V>
1696 inline void boost_save_vector(Archive &ar, const V &v)
1697 {
1698  boost_save(ar, v.size());
1699  boost_save_range(ar, v.begin(), v.end());
1700 }
1701 
1702 template <typename Archive, typename It>
1703 inline void boost_load_range(Archive &ar, It begin, It end)
1704 {
1705  for (; begin != end; ++begin) {
1706  boost_load(ar, *begin);
1707  }
1708 }
1709 
1710 template <typename Archive, typename V>
1711 inline void boost_load_vector(Archive &ar, V &v)
1712 {
1713  typename V::size_type size;
1714  boost_load(ar, size);
1715  v.resize(size);
1716  boost_load_range(ar, v.begin(), v.end());
1717 }
1718 
1719 // Introduce also enablers to detect when we can use the vector save/load functions.
1720 template <typename Archive, typename V, typename T = void>
1721 using boost_save_vector_enabler = enable_if_t<
1722  conjunction<has_boost_save<Archive, typename V::value_type>, has_boost_save<Archive, typename V::size_type>>::value,
1723  T>;
1724 
1725 template <typename Archive, typename V, typename T = void>
1726 using boost_load_vector_enabler = enable_if_t<
1727  conjunction<has_boost_load<Archive, typename V::value_type>, has_boost_load<Archive, typename V::size_type>>::value,
1728  T>;
1729 
1730 #if defined(PIRANHA_WITH_MSGPACK)
1731 
1732 template <typename Stream, typename It, typename Size>
1733 inline void msgpack_pack_range(msgpack::packer<Stream> &p, It begin, It end, Size s, msgpack_format f)
1734 {
1735  p.pack_array(safe_cast<std::uint32_t>(s));
1736  for (; begin != end; ++begin) {
1737  msgpack_pack(p, *begin, f);
1738  }
1739 }
1740 
1741 template <typename Stream, typename V>
1742 inline void msgpack_pack_vector(msgpack::packer<Stream> &p, const V &v, msgpack_format f)
1743 {
1744  msgpack_pack_range(p, v.begin(), v.end(), v.size(), f);
1745 }
1746 
1747 // Convert the msgpack array in o to a vector of type V.
1748 template <typename V>
1749 inline void msgpack_convert_array(const msgpack::object &o, V &v, msgpack_format f)
1750 {
1751  // First extract a vector of objects from o.
1752  PIRANHA_MAYBE_TLS std::vector<msgpack::object> tmp_obj;
1753  o.convert(tmp_obj);
1754  v.resize(safe_cast<decltype(v.size())>(tmp_obj.size()));
1755  for (decltype(v.size()) i = 0; i < v.size(); ++i) {
1756  piranha::msgpack_convert(v[i], tmp_obj[static_cast<decltype(v.size())>(i)], f);
1757  }
1758 }
1759 
1760 template <typename Stream, typename V, typename T = void>
1761 using msgpack_pack_vector_enabler
1762  = enable_if_t<conjunction<is_msgpack_stream<Stream>, has_msgpack_pack<Stream, typename V::value_type>,
1763  has_safe_cast<std::uint32_t, typename V::size_type>>::value,
1764  T>;
1765 
1766 template <typename V, typename T = void>
1767 using msgpack_convert_array_enabler
1768  = enable_if_t<conjunction<has_safe_cast<typename V::size_type, typename std::vector<msgpack::object>::size_type>,
1769  has_msgpack_convert<typename V::value_type>>::value,
1770  T>;
1771 
1772 #endif
1773 }
1774 }
1775 
1776 #undef PIRANHA_ZLIB_CONDITIONAL
1777 
1778 #undef PIRANHA_BZIP2_CONDITIONAL
1779 
1780 #endif
static const bool value
Value of the type trait.
Definition: s11n.hpp:206
void operator()(msgpack::packer< Stream > &packer, const T &x, msgpack_format) const
Call operator.
Definition: s11n.hpp:719
static const bool value
Value of the type trait.
Definition: s11n.hpp:1156
Detect msgpack stream.
Definition: s11n.hpp:645
boost_s11n_key_wrapper(const Key &k, const symbol_fset &ss)
Constructor from const key and piranha::symbol_fset.
Definition: s11n.hpp:533
void operator()(long double &x, const msgpack::object &o, msgpack_format f) const
Call operator.
Definition: s11n.hpp:990
void boost_load(Archive &ar, T &x)
Load from Boost archive.
Definition: s11n.hpp:469
Detect Boost saving archives.
Definition: s11n.hpp:141
Default implementation of piranha::boost_load().
Definition: s11n.hpp:391
data_format
Data format.
Definition: s11n.hpp:1205
void msgpack_convert(T &x, const msgpack::object &o, msgpack_format f)
Convert msgpack object.
Definition: s11n.hpp:957
Key type concept check.
Definition: is_key.hpp:65
void save_file(const T &x, const std::string &filename, data_format f, compression c)
Save to file.
Definition: s11n.hpp:1565
static const bool value
Value of the type trait.
Definition: s11n.hpp:147
Implementation of piranha::boost_load() via the Boost API.
Definition: s11n.hpp:363
Exceptions.
Default implementation of piranha::boost_save().
Definition: s11n.hpp:245
STL namespace.
Detect Boost loading archives.
Definition: s11n.hpp:200
Detect the presence of piranha::boost_load().
Definition: s11n.hpp:487
static const bool value
Value of the type trait.
Definition: s11n.hpp:653
Detect the presence of piranha::msgpack_convert().
Definition: s11n.hpp:610
Detect the presence of the msgpack_convert() method in keys.
Definition: s11n.hpp:1149
void load_file(T &x, const std::string &filename, data_format f, compression c)
Load from file.
Definition: s11n.hpp:1638
Default functor for the implementation of piranha::msgpack_convert().
Definition: s11n.hpp:867
void operator()(std::string &s, const msgpack::object &o, msgpack_format) const
Call operator.
Definition: s11n.hpp:918
#define piranha_throw(exception_type,...)
Exception-throwing macro.
Definition: exceptions.hpp:118
boost::container::flat_set< std::string > symbol_fset
Flat set of symbols.
Detect the presence of piranha::boost_save().
Definition: s11n.hpp:346
const Key & key() const
Const reference to the key.
Definition: s11n.hpp:558
Default functor for the implementation of piranha::msgpack_pack().
Definition: s11n.hpp:686
Wrapper for the serialization of keys via Boost.
Definition: s11n.hpp:514
msgpack_format
Serialization format for msgpack.
Definition: s11n.hpp:673
void operator()(msgpack::packer< Stream > &packer, const std::string &s, msgpack_format) const
Call operator.
Definition: s11n.hpp:817
static const bool value
Value of the type trait.
Definition: s11n.hpp:1063
boost_s11n_key_wrapper(Key &k, const symbol_fset &ss)
Constructor from key and piranha::symbol_fset.
Definition: s11n.hpp:524
static const bool value
Value of the type trait.
Definition: s11n.hpp:1123
zlib compression.
Key & key()
Reference to the key.
Definition: s11n.hpp:546
static const bool value
Value of the type trait.
Definition: s11n.hpp:352
Implementation of piranha::boost_save() via the Boost API.
Definition: s11n.hpp:217
Root piranha namespace.
Definition: array_key.hpp:52
void msgpack_pack(msgpack::packer< Stream > &packer, const T &x, msgpack_format f)
Pack generic object in a msgpack stream.
Definition: s11n.hpp:856
Detect the presence of piranha::msgpack_pack().
Definition: s11n.hpp:607
void operator()(Archive &ar, T &x) const
Call operator.
Definition: s11n.hpp:379
Type traits.
Detect the presence of the msgpack_pack() method in keys.
Definition: s11n.hpp:1115
void operator()(Archive &ar, const T &x) const
Call operator.
Definition: s11n.hpp:233
static const bool value
Value of the type trait.
Definition: s11n.hpp:493
void operator()(msgpack::packer< Stream > &packer, const long double &x, msgpack_format f) const
Call operator.
Definition: s11n.hpp:755
bzip2 compression.
gzip compression.
void boost_save(Archive &ar, const T &x)
Save to Boost archive.
Definition: s11n.hpp:328
static const bool value
Value of the type trait.
Definition: s11n.hpp:1088
compression
Compression format.
Definition: s11n.hpp:1232
const symbol_fset & ss() const
Const reference to the symbol set.
Definition: s11n.hpp:566
void operator()(T &x, const msgpack::object &o, msgpack_format) const
Call operator.
Definition: s11n.hpp:899
safe_cast_type< To, From > safe_cast(const From &x)
Safe cast.
Definition: safe_cast.hpp:219