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