]>
Commit | Line | Data |
---|---|---|
1 | /////////////////////////////////////////////////////////////// | |
2 | // Copyright 2015 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_IMPORT_EXPORT_HPP | |
7 | #define BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP | |
8 | ||
9 | ||
10 | namespace boost { | |
11 | namespace multiprecision { | |
12 | ||
13 | namespace detail { | |
14 | ||
15 | template <class Backend, class Unsigned> | |
16 | void assign_bits(Backend& val, Unsigned bits, unsigned bit_location, unsigned chunk_bits, const mpl::false_& tag) | |
17 | { | |
18 | unsigned limb = bit_location / (sizeof(limb_type) * CHAR_BIT); | |
19 | unsigned shift = bit_location % (sizeof(limb_type) * CHAR_BIT); | |
20 | ||
21 | limb_type mask = chunk_bits >= sizeof(limb_type) * CHAR_BIT ? ~static_cast<limb_type>(0u) : (static_cast<limb_type>(1u) << chunk_bits) - 1; | |
22 | ||
23 | limb_type value = static_cast<limb_type>(bits & mask) << shift; | |
24 | if(value) | |
25 | { | |
26 | if(val.size() == limb) | |
27 | { | |
28 | val.resize(limb + 1, limb + 1); | |
29 | if(val.size() > limb) | |
30 | val.limbs()[limb] = value; | |
31 | } | |
32 | else if(val.size() > limb) | |
33 | val.limbs()[limb] |= value; | |
34 | } | |
35 | if(chunk_bits > sizeof(limb_type) * CHAR_BIT - shift) | |
36 | { | |
37 | shift = sizeof(limb_type) * CHAR_BIT - shift; | |
38 | chunk_bits -= shift; | |
39 | bit_location += shift; | |
40 | bits >>= shift; | |
41 | if(bits) | |
42 | assign_bits(val, bits, bit_location, chunk_bits, tag); | |
43 | } | |
44 | } | |
45 | template <class Backend, class Unsigned> | |
46 | void assign_bits(Backend& val, Unsigned bits, unsigned bit_location, unsigned chunk_bits, const mpl::true_&) | |
47 | { | |
48 | typedef typename Backend::local_limb_type local_limb_type; | |
49 | // | |
50 | // Check for possible overflow, this may trigger an exception, or have no effect | |
51 | // depending on whether this is a checked integer or not: | |
52 | // | |
53 | if((bit_location >= sizeof(local_limb_type) * CHAR_BIT) && bits) | |
54 | val.resize(2, 2); | |
55 | else | |
56 | { | |
57 | local_limb_type mask = chunk_bits >= sizeof(local_limb_type) * CHAR_BIT ? ~static_cast<local_limb_type>(0u) : (static_cast<local_limb_type>(1u) << chunk_bits) - 1; | |
58 | local_limb_type value = (static_cast<local_limb_type>(bits) & mask) << bit_location; | |
59 | *val.limbs() |= value; | |
60 | // | |
61 | // Check for overflow bits: | |
62 | // | |
63 | bit_location = sizeof(local_limb_type) * CHAR_BIT - bit_location; | |
64 | bits >>= bit_location; | |
65 | if(bits) | |
66 | val.resize(2, 2); // May throw! | |
67 | } | |
68 | } | |
69 | ||
70 | template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator> | |
71 | inline void resize_to_bit_size(cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& newval, unsigned bits, const mpl::false_&) | |
72 | { | |
73 | unsigned limb_count = static_cast<unsigned>(bits / (sizeof(limb_type) * CHAR_BIT)); | |
74 | if(bits % (sizeof(limb_type) * CHAR_BIT)) | |
75 | ++limb_count; | |
76 | static const unsigned max_limbs = MaxBits ? MaxBits / (CHAR_BIT * sizeof(limb_type)) + ((MaxBits % (CHAR_BIT * sizeof(limb_type))) ? 1 : 0) : (std::numeric_limits<unsigned>::max)(); | |
77 | if(limb_count > max_limbs) | |
78 | limb_count = max_limbs; | |
79 | newval.resize(limb_count, limb_count); | |
80 | std::memset(newval.limbs(), 0, newval.size() * sizeof(limb_type)); | |
81 | } | |
82 | template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator> | |
83 | inline void resize_to_bit_size(cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& newval, unsigned, const mpl::true_&) | |
84 | { | |
85 | *newval.limbs() = 0; | |
86 | } | |
87 | ||
88 | template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class Iterator> | |
89 | number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& | |
90 | import_bits_generic( | |
91 | number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, Iterator i, Iterator j, unsigned chunk_size = 0, bool msv_first = true) | |
92 | { | |
93 | typename number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>::backend_type newval; | |
94 | ||
95 | typedef typename std::iterator_traits<Iterator>::value_type value_type; | |
96 | typedef typename boost::make_unsigned<value_type>::type unsigned_value_type; | |
97 | typedef typename std::iterator_traits<Iterator>::difference_type difference_type; | |
98 | typedef typename boost::make_unsigned<difference_type>::type size_type; | |
99 | typedef typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::trivial_tag tag_type; | |
100 | ||
101 | if(!chunk_size) | |
102 | chunk_size = std::numeric_limits<value_type>::digits; | |
103 | ||
104 | size_type limbs = std::distance(i, j); | |
105 | size_type bits = limbs * chunk_size; | |
106 | ||
107 | detail::resize_to_bit_size(newval, static_cast<unsigned>(bits), tag_type()); | |
108 | ||
109 | difference_type bit_location = msv_first ? bits - chunk_size : 0; | |
110 | difference_type bit_location_change = msv_first ? -static_cast<difference_type>(chunk_size) : chunk_size; | |
111 | ||
112 | while(i != j) | |
113 | { | |
114 | detail::assign_bits(newval, static_cast<unsigned_value_type>(*i), static_cast<unsigned>(bit_location), chunk_size, tag_type()); | |
115 | ++i; | |
116 | bit_location += bit_location_change; | |
117 | } | |
118 | ||
119 | newval.normalize(); | |
120 | ||
121 | val.backend().swap(newval); | |
122 | return val; | |
123 | } | |
124 | ||
125 | template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T> | |
126 | inline typename boost::disable_if_c<boost::multiprecision::backends::is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value, number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&>::type | |
127 | import_bits_fast( | |
128 | number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0) | |
129 | { | |
130 | std::size_t byte_len = (j - i) * (chunk_size ? chunk_size / CHAR_BIT : sizeof(*i)); | |
131 | std::size_t limb_len = byte_len / sizeof(limb_type); | |
132 | if(byte_len % sizeof(limb_type)) | |
133 | ++limb_len; | |
134 | cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& result = val.backend(); | |
135 | result.resize(static_cast<unsigned>(limb_len), static_cast<unsigned>(limb_len)); // checked types may throw here if they're not large enough to hold the data! | |
136 | result.limbs()[result.size() - 1] = 0u; | |
137 | std::memcpy(result.limbs(), i, std::min(byte_len, result.size() * sizeof(limb_type))); | |
138 | result.normalize(); // In case data has leading zeros. | |
139 | return val; | |
140 | } | |
141 | template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T> | |
142 | inline typename boost::enable_if_c<boost::multiprecision::backends::is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value, number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&>::type | |
143 | import_bits_fast( | |
144 | number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0) | |
145 | { | |
146 | cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& result = val.backend(); | |
147 | std::size_t byte_len = (j - i) * (chunk_size ? chunk_size / CHAR_BIT : sizeof(*i)); | |
148 | std::size_t limb_len = byte_len / sizeof(result.limbs()[0]); | |
149 | if(byte_len % sizeof(result.limbs()[0])) | |
150 | ++limb_len; | |
151 | result.limbs()[0] = 0u; | |
152 | result.resize(static_cast<unsigned>(limb_len), static_cast<unsigned>(limb_len)); // checked types may throw here if they're not large enough to hold the data! | |
153 | std::memcpy(result.limbs(), i, std::min(byte_len, result.size() * sizeof(result.limbs()[0]))); | |
154 | result.normalize(); // In case data has leading zeros. | |
155 | return val; | |
156 | } | |
157 | } | |
158 | ||
159 | ||
160 | template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class Iterator> | |
161 | inline number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& | |
162 | import_bits( | |
163 | number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, Iterator i, Iterator j, unsigned chunk_size = 0, bool msv_first = true) | |
164 | { | |
165 | return detail::import_bits_generic(val, i, j, chunk_size, msv_first); | |
166 | } | |
167 | ||
168 | template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T> | |
169 | inline number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& | |
170 | import_bits( | |
171 | number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0, bool msv_first = true) | |
172 | { | |
173 | #ifdef BOOST_LITTLE_ENDIAN | |
174 | if(((chunk_size % CHAR_BIT) == 0) && !msv_first) | |
175 | return detail::import_bits_fast(val, i, j, chunk_size); | |
176 | #endif | |
177 | return detail::import_bits_generic(val, i, j, chunk_size, msv_first); | |
178 | } | |
179 | ||
180 | namespace detail { | |
181 | ||
182 | template <class Backend> | |
183 | boost::uintmax_t extract_bits(const Backend& val, unsigned location, unsigned count, const mpl::false_& tag) | |
184 | { | |
185 | unsigned limb = location / (sizeof(limb_type) * CHAR_BIT); | |
186 | unsigned shift = location % (sizeof(limb_type) * CHAR_BIT); | |
187 | boost::uintmax_t result = 0; | |
188 | boost::uintmax_t mask = count == std::numeric_limits<boost::uintmax_t>::digits ? ~static_cast<boost::uintmax_t>(0) : (static_cast<boost::uintmax_t>(1u) << count) - 1; | |
189 | if(count > (sizeof(limb_type) * CHAR_BIT - shift)) | |
190 | { | |
191 | result = extract_bits(val, location + sizeof(limb_type) * CHAR_BIT - shift, count - sizeof(limb_type) * CHAR_BIT + shift, tag); | |
192 | result <<= sizeof(limb_type) * CHAR_BIT - shift; | |
193 | } | |
194 | if(limb < val.size()) | |
195 | result |= (val.limbs()[limb] >> shift) & mask; | |
196 | return result; | |
197 | } | |
198 | ||
199 | template <class Backend> | |
200 | inline boost::uintmax_t extract_bits(const Backend& val, unsigned location, unsigned count, const mpl::true_&) | |
201 | { | |
202 | boost::uintmax_t result = *val.limbs(); | |
203 | boost::uintmax_t mask = count == std::numeric_limits<boost::uintmax_t>::digits ? ~static_cast<boost::uintmax_t>(0) : (static_cast<boost::uintmax_t>(1u) << count) - 1; | |
204 | return (result >> location) & mask; | |
205 | } | |
206 | ||
207 | } | |
208 | ||
209 | template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class OutputIterator> | |
210 | OutputIterator export_bits( | |
211 | const number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, OutputIterator out, unsigned chunk_size, bool msv_first = true) | |
212 | { | |
213 | #ifdef _MSC_VER | |
214 | #pragma warning(push) | |
215 | #pragma warning(disable:4244) | |
216 | #endif | |
217 | typedef typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::trivial_tag tag_type; | |
218 | if(!val) | |
219 | { | |
220 | *out = 0; | |
221 | ++out; | |
222 | return out; | |
223 | } | |
224 | unsigned bitcount = boost::multiprecision::backends::eval_msb_imp(val.backend()) + 1; | |
225 | unsigned chunks = bitcount / chunk_size; | |
226 | if(bitcount % chunk_size) | |
227 | ++chunks; | |
228 | ||
229 | int bit_location = msv_first ? bitcount - chunk_size : 0; | |
230 | int bit_step = msv_first ? -static_cast<int>(chunk_size) : chunk_size; | |
231 | while(bit_location % bit_step) ++bit_location; | |
232 | ||
233 | do | |
234 | { | |
235 | *out = detail::extract_bits(val.backend(), bit_location, chunk_size, tag_type()); | |
236 | ++out; | |
237 | bit_location += bit_step; | |
238 | } while((bit_location >= 0) && (bit_location < (int)bitcount)); | |
239 | ||
240 | return out; | |
241 | #ifdef _MSC_VER | |
242 | #pragma warning(pop) | |
243 | #endif | |
244 | } | |
245 | ||
246 | } | |
247 | } | |
248 | ||
249 | ||
250 | ||
251 | #endif // BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP | |
252 |