/////////////////////////////////////////////////////////////// // Copyright 2013 John Maddock. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt #ifndef BOOST_MP_CPP_INT_SERIALIZE_HPP #define BOOST_MP_CPP_INT_SERIALIZE_HPP namespace boost { namespace archive { class binary_oarchive; class binary_iarchive; } // namespace archive namespace serialization { namespace mp = boost::multiprecision; namespace cpp_int_detail { using namespace boost::multiprecision; using namespace boost::multiprecision::backends; template struct is_binary_archive : public std::integral_constant {}; template <> struct is_binary_archive : public std::integral_constant {}; template <> struct is_binary_archive : public std::integral_constant {}; // // We have 8 serialization methods to fill out (and test), they are all permutations of: // Load vs Store. // Trivial or non-trivial cpp_int type. // Binary or not archive. // template void do_serialize(Archive& ar, Int& val, std::integral_constant const&, std::integral_constant const&, std::integral_constant const&) { // Load. // Non-trivial. // Non binary. using boost::make_nvp; bool s; ar& make_nvp("sign", s); std::size_t limb_count; std::size_t byte_count; ar& make_nvp("byte-count", byte_count); limb_count = byte_count / sizeof(limb_type) + ((byte_count % sizeof(limb_type)) ? 1 : 0); val.resize(limb_count, limb_count); limb_type* pl = val.limbs(); for (std::size_t i = 0; i < limb_count; ++i) { pl[i] = 0; for (std::size_t j = 0; (j < sizeof(limb_type)) && byte_count; ++j) { unsigned char byte; ar& make_nvp("byte", byte); pl[i] |= static_cast(byte) << (j * CHAR_BIT); --byte_count; } } if (s != val.sign()) val.negate(); val.normalize(); } template void do_serialize(Archive& ar, Int& val, std::integral_constant const&, std::integral_constant const&, std::integral_constant const&) { // Store. // Non-trivial. // Non binary. using boost::make_nvp; bool s = val.sign(); ar& make_nvp("sign", s); limb_type* pl = val.limbs(); std::size_t limb_count = val.size(); std::size_t byte_count = limb_count * sizeof(limb_type); ar& make_nvp("byte-count", byte_count); for (std::size_t i = 0; i < limb_count; ++i) { limb_type l = pl[i]; for (std::size_t j = 0; j < sizeof(limb_type); ++j) { unsigned char byte = static_cast((l >> (j * CHAR_BIT)) & ((1u << CHAR_BIT) - 1)); ar& make_nvp("byte", byte); } } } template void do_serialize(Archive& ar, Int& val, std::integral_constant const&, std::integral_constant const&, std::integral_constant const&) { // Load. // Trivial. // Non binary. using boost::make_nvp; bool s; typename Int::local_limb_type l = 0; ar& make_nvp("sign", s); std::size_t byte_count; ar& make_nvp("byte-count", byte_count); for (std::size_t i = 0; i < byte_count; ++i) { unsigned char b; ar& make_nvp("byte", b); l |= static_cast(b) << (i * CHAR_BIT); } *val.limbs() = l; if (s != val.sign()) val.negate(); } template void do_serialize(Archive& ar, Int& val, std::integral_constant const&, std::integral_constant const&, std::integral_constant const&) { // Store. // Trivial. // Non binary. using boost::make_nvp; bool s = val.sign(); typename Int::local_limb_type l = *val.limbs(); ar& make_nvp("sign", s); std::size_t limb_count = sizeof(l); ar& make_nvp("byte-count", limb_count); for (std::size_t i = 0; i < limb_count; ++i) { unsigned char b = static_cast(static_cast(l >> (i * CHAR_BIT)) & static_cast((1u << CHAR_BIT) - 1)); ar& make_nvp("byte", b); } } template void do_serialize(Archive& ar, Int& val, std::integral_constant const&, std::integral_constant const&, std::integral_constant const&) { // Load. // Non-trivial. // Binary. bool s; std::size_t c; ar& s; ar& c; val.resize(c, c); ar.load_binary(val.limbs(), c * sizeof(limb_type)); if (s != val.sign()) val.negate(); val.normalize(); } template void do_serialize(Archive& ar, Int& val, std::integral_constant const&, std::integral_constant const&, std::integral_constant const&) { // Store. // Non-trivial. // Binary. bool s = val.sign(); std::size_t c = val.size(); ar& s; ar& c; ar.save_binary(val.limbs(), c * sizeof(limb_type)); } template void do_serialize(Archive& ar, Int& val, std::integral_constant const&, std::integral_constant const&, std::integral_constant const&) { // Load. // Trivial. // Binary. bool s; ar& s; ar.load_binary(val.limbs(), sizeof(*val.limbs())); if (s != val.sign()) val.negate(); } template void do_serialize(Archive& ar, Int& val, std::integral_constant const&, std::integral_constant const&, std::integral_constant const&) { // Store. // Trivial. // Binary. bool s = val.sign(); ar& s; ar.save_binary(val.limbs(), sizeof(*val.limbs())); } } // namespace cpp_int_detail template void serialize(Archive& ar, mp::cpp_int_backend& val, const unsigned int /*version*/) { using archive_save_tag = typename Archive::is_saving ; using save_tag = std::integral_constant ; using trivial_tag = std::integral_constant >::value>; using binary_tag = typename cpp_int_detail::is_binary_archive::type ; // Just dispatch to the correct method: cpp_int_detail::do_serialize(ar, val, save_tag(), trivial_tag(), binary_tag()); } } // namespace serialization } // namespace boost #endif // BOOST_MP_CPP_INT_SERIALIZE_HPP