1 ///////////////////////////////////////////////////////////////
2 //  Copyright 2013 John Maddock. Distributed under the Boost
3 //  Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
5 
6 #ifndef BOOST_MP_CPP_INT_SERIALIZE_HPP
7 #define BOOST_MP_CPP_INT_SERIALIZE_HPP
8 
9 namespace boost {
10 
11 namespace archive{
12 
13 class binary_oarchive;
14 class binary_iarchive;
15 
16 }
17 
18 namespace serialization {
19 
20 namespace mp = boost::multiprecision;
21 
22 namespace cpp_int_detail{
23 
24 using namespace boost::multiprecision;
25 using namespace boost::multiprecision::backends;
26 
27 template <class T>
28 struct is_binary_archive : public mpl::false_ {};
29 template <>
30 struct is_binary_archive<boost::archive::binary_oarchive> : public mpl::true_ {};
31 template <>
32 struct is_binary_archive<boost::archive::binary_iarchive> : public mpl::true_ {};
33 
34 //
35 // We have 8 serialization methods to fill out (and test), they are all permutations of:
36 // Load vs Store.
37 // Trivial or non-trivial cpp_int type.
38 // Binary or not archive.
39 //
40 template <class Archive, class Int>
do_serialize(Archive & ar,Int & val,mpl::false_ const &,mpl::false_ const &,mpl::false_ const &)41 void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::false_ const&, mpl::false_ const&)
42 {
43    // Load.
44    // Non-trivial.
45    // Non binary.
46 
47    bool s;
48    ar & s;
49    std::size_t limb_count;
50    std::size_t byte_count;
51    ar & byte_count;
52    limb_count = byte_count / sizeof(limb_type) + ((byte_count % sizeof(limb_type)) ? 1 : 0);
53    val.resize(limb_count, limb_count);
54    limb_type* pl = val.limbs();
55    for(std::size_t i = 0; i < limb_count; ++i)
56    {
57       pl[i] = 0;
58       for(std::size_t j = 0; (j < sizeof(limb_type)) && byte_count; ++j)
59       {
60          unsigned char byte;
61          ar & byte;
62          pl[i] |= static_cast<limb_type>(byte) << (j * CHAR_BIT);
63          --byte_count;
64       }
65    }
66    if(s != val.sign())
67       val.negate();
68    val.normalize();
69 }
70 template <class Archive, class Int>
do_serialize(Archive & ar,Int & val,mpl::true_ const &,mpl::false_ const &,mpl::false_ const &)71 void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::false_ const&, mpl::false_ const&)
72 {
73    // Store.
74    // Non-trivial.
75    // Non binary.
76 
77    bool s = val.sign();
78    ar & s;
79    limb_type* pl = val.limbs();
80    std::size_t limb_count = val.size();
81    std::size_t byte_count = limb_count * sizeof(limb_type);
82    ar & byte_count;
83 
84    for(std::size_t i = 0; i < limb_count; ++i)
85    {
86       limb_type l = pl[i];
87       for(std::size_t j = 0; j < sizeof(limb_type); ++j)
88       {
89          unsigned char byte = static_cast<unsigned char>((l >> (j * CHAR_BIT)) & ((1u << CHAR_BIT) - 1));
90          ar & byte;
91       }
92    }
93 }
94 template <class Archive, class Int>
do_serialize(Archive & ar,Int & val,mpl::false_ const &,mpl::true_ const &,mpl::false_ const &)95 void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::true_ const&, mpl::false_ const&)
96 {
97    // Load.
98    // Trivial.
99    // Non binary.
100    bool s;
101    typename Int::local_limb_type l = 0;
102    ar & s;
103    std::size_t byte_count;
104    ar & byte_count;
105    for(std::size_t i = 0; i < byte_count; ++i)
106    {
107       unsigned char b;
108       ar & b;
109       l |= static_cast<typename Int::local_limb_type>(b) << (i * CHAR_BIT);
110    }
111    *val.limbs() = l;
112    if(s != val.sign())
113       val.negate();
114 }
115 template <class Archive, class Int>
do_serialize(Archive & ar,Int & val,mpl::true_ const &,mpl::true_ const &,mpl::false_ const &)116 void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::true_ const&, mpl::false_ const&)
117 {
118    // Store.
119    // Trivial.
120    // Non binary.
121    bool s = val.sign();
122    typename Int::local_limb_type l = *val.limbs();
123    ar & s;
124    std::size_t limb_count = sizeof(l);
125    ar & limb_count;
126    for(std::size_t i = 0; i < limb_count; ++i)
127    {
128       unsigned char b = static_cast<unsigned char>(static_cast<typename Int::local_limb_type>(l >> (i * CHAR_BIT)) & static_cast<typename Int::local_limb_type>((1u << CHAR_BIT) - 1));
129       ar & b;
130    }
131 }
132 template <class Archive, class Int>
do_serialize(Archive & ar,Int & val,mpl::false_ const &,mpl::false_ const &,mpl::true_ const &)133 void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::false_ const&, mpl::true_ const&)
134 {
135    // Load.
136    // Non-trivial.
137    // Binary.
138    bool s;
139    std::size_t c;
140    ar & s;
141    ar & c;
142    val.resize(c, c);
143    ar.load_binary(val.limbs(), c * sizeof(limb_type));
144    if(s != val.sign())
145       val.negate();
146    val.normalize();
147 }
148 template <class Archive, class Int>
do_serialize(Archive & ar,Int & val,mpl::true_ const &,mpl::false_ const &,mpl::true_ const &)149 void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::false_ const&, mpl::true_ const&)
150 {
151    // Store.
152    // Non-trivial.
153    // Binary.
154    bool s = val.sign();
155    std::size_t c = val.size();
156    ar & s;
157    ar & c;
158    ar.save_binary(val.limbs(), c * sizeof(limb_type));
159 }
160 template <class Archive, class Int>
do_serialize(Archive & ar,Int & val,mpl::false_ const &,mpl::true_ const &,mpl::true_ const &)161 void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::true_ const&, mpl::true_ const&)
162 {
163    // Load.
164    // Trivial.
165    // Binary.
166    bool s;
167    ar & s;
168    ar.load_binary(val.limbs(), sizeof(*val.limbs()));
169    if(s != val.sign())
170       val.negate();
171 }
172 template <class Archive, class Int>
do_serialize(Archive & ar,Int & val,mpl::true_ const &,mpl::true_ const &,mpl::true_ const &)173 void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::true_ const&, mpl::true_ const&)
174 {
175    // Store.
176    // Trivial.
177    // Binary.
178    bool s = val.sign();
179    ar & s;
180    ar.save_binary(val.limbs(), sizeof(*val.limbs()));
181 }
182 
183 }
184 
185 template<class Archive, unsigned MinBits, unsigned MaxBits, mp::cpp_integer_type SignType, mp::cpp_int_check_type Checked, class Allocator>
serialize(Archive & ar,mp::cpp_int_backend<MinBits,MaxBits,SignType,Checked,Allocator> & val,const unsigned int)186 void serialize(Archive & ar, mp::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& val, const unsigned int /*version*/)
187 {
188    typedef typename Archive::is_saving save_tag;
189    typedef mpl::bool_<mp::backends::is_trivial_cpp_int<mp::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value> trivial_tag;
190    typedef typename cpp_int_detail::is_binary_archive<Archive>::type binary_tag;
191 
192    // Just dispatch to the correct method:
193    cpp_int_detail::do_serialize(ar, val, save_tag(), trivial_tag(), binary_tag());
194 }
195 
196 }} // namespaces
197 
198 #endif // BOOST_MP_CPP_INT_SERIALIZE_HPP
199 
200