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 https://www.boost.org/LICENSE_1_0.txt
6 #ifndef BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP
7 #define BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP
10 namespace multiprecision {
14 template <class Backend, class Unsigned>
15 void assign_bits(Backend& val, Unsigned bits, unsigned bit_location, unsigned chunk_bits, const mpl::false_& tag)
17 unsigned limb = bit_location / (sizeof(limb_type) * CHAR_BIT);
18 unsigned shift = bit_location % (sizeof(limb_type) * CHAR_BIT);
20 limb_type mask = chunk_bits >= sizeof(limb_type) * CHAR_BIT ? ~static_cast<limb_type>(0u) : (static_cast<limb_type>(1u) << chunk_bits) - 1;
22 limb_type value = static_cast<limb_type>(bits & mask) << shift;
25 if (val.size() == limb)
27 val.resize(limb + 1, limb + 1);
28 if (val.size() > limb)
29 val.limbs()[limb] = value;
31 else if (val.size() > limb)
32 val.limbs()[limb] |= value;
34 if (chunk_bits > sizeof(limb_type) * CHAR_BIT - shift)
36 shift = sizeof(limb_type) * CHAR_BIT - shift;
38 bit_location += shift;
41 assign_bits(val, bits, bit_location, chunk_bits, tag);
44 template <class Backend, class Unsigned>
45 void assign_bits(Backend& val, Unsigned bits, unsigned bit_location, unsigned chunk_bits, const mpl::true_&)
47 typedef typename Backend::local_limb_type local_limb_type;
49 // Check for possible overflow, this may trigger an exception, or have no effect
50 // depending on whether this is a checked integer or not:
52 if ((bit_location >= sizeof(local_limb_type) * CHAR_BIT) && bits)
56 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;
57 local_limb_type value = (static_cast<local_limb_type>(bits) & mask) << bit_location;
58 *val.limbs() |= value;
60 // Check for overflow bits:
62 bit_location = sizeof(local_limb_type) * CHAR_BIT - bit_location;
63 if ((bit_location < sizeof(bits) * CHAR_BIT) && (bits >>= bit_location))
64 val.resize(2, 2); // May throw!
68 template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
69 inline void resize_to_bit_size(cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& newval, unsigned bits, const mpl::false_&)
71 unsigned limb_count = static_cast<unsigned>(bits / (sizeof(limb_type) * CHAR_BIT));
72 if (bits % (sizeof(limb_type) * CHAR_BIT))
74 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)();
75 if (limb_count > max_limbs)
76 limb_count = max_limbs;
77 newval.resize(limb_count, limb_count);
78 std::memset(newval.limbs(), 0, newval.size() * sizeof(limb_type));
80 template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
81 inline void resize_to_bit_size(cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& newval, unsigned, const mpl::true_&)
86 template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class Iterator>
87 number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
89 number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, Iterator i, Iterator j, unsigned chunk_size = 0, bool msv_first = true)
91 typename number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>::backend_type newval;
93 typedef typename std::iterator_traits<Iterator>::value_type value_type;
94 typedef typename boost::make_unsigned<value_type>::type unsigned_value_type;
95 typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
96 typedef typename boost::make_unsigned<difference_type>::type size_type;
97 typedef typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::trivial_tag tag_type;
100 chunk_size = std::numeric_limits<value_type>::digits;
102 size_type limbs = std::distance(i, j);
103 size_type bits = limbs * chunk_size;
105 detail::resize_to_bit_size(newval, static_cast<unsigned>(bits), tag_type());
107 difference_type bit_location = msv_first ? bits - chunk_size : 0;
108 difference_type bit_location_change = msv_first ? -static_cast<difference_type>(chunk_size) : chunk_size;
112 detail::assign_bits(newval, static_cast<unsigned_value_type>(*i), static_cast<unsigned>(bit_location), chunk_size, tag_type());
114 bit_location += bit_location_change;
119 val.backend().swap(newval);
123 template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T>
124 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
126 number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0)
128 std::size_t byte_len = (j - i) * (chunk_size ? chunk_size / CHAR_BIT : sizeof(*i));
129 std::size_t limb_len = byte_len / sizeof(limb_type);
130 if (byte_len % sizeof(limb_type))
132 cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& result = val.backend();
133 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!
134 result.limbs()[result.size() - 1] = 0u;
135 std::memcpy(result.limbs(), i, (std::min)(byte_len, result.size() * sizeof(limb_type)));
136 result.normalize(); // In case data has leading zeros.
139 template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T>
140 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
142 number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0)
144 cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& result = val.backend();
145 std::size_t byte_len = (j - i) * (chunk_size ? chunk_size / CHAR_BIT : sizeof(*i));
146 std::size_t limb_len = byte_len / sizeof(result.limbs()[0]);
147 if (byte_len % sizeof(result.limbs()[0]))
149 result.limbs()[0] = 0u;
150 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!
151 std::memcpy(result.limbs(), i, (std::min)(byte_len, result.size() * sizeof(result.limbs()[0])));
152 result.normalize(); // In case data has leading zeros.
155 } // namespace detail
157 template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class Iterator>
158 inline number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
160 number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, Iterator i, Iterator j, unsigned chunk_size = 0, bool msv_first = true)
162 return detail::import_bits_generic(val, i, j, chunk_size, msv_first);
165 template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T>
166 inline number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
168 number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0, bool msv_first = true)
170 #if BOOST_ENDIAN_LITTLE_BYTE
171 if (((chunk_size % CHAR_BIT) == 0) && !msv_first)
172 return detail::import_bits_fast(val, i, j, chunk_size);
174 return detail::import_bits_generic(val, i, j, chunk_size, msv_first);
179 template <class Backend>
180 boost::uintmax_t extract_bits(const Backend& val, unsigned location, unsigned count, const mpl::false_& tag)
182 unsigned limb = location / (sizeof(limb_type) * CHAR_BIT);
183 unsigned shift = location % (sizeof(limb_type) * CHAR_BIT);
184 boost::uintmax_t result = 0;
185 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;
186 if (count > (sizeof(limb_type) * CHAR_BIT - shift))
188 result = extract_bits(val, location + sizeof(limb_type) * CHAR_BIT - shift, count - sizeof(limb_type) * CHAR_BIT + shift, tag);
189 result <<= sizeof(limb_type) * CHAR_BIT - shift;
191 if (limb < val.size())
192 result |= (val.limbs()[limb] >> shift) & mask;
196 template <class Backend>
197 inline boost::uintmax_t extract_bits(const Backend& val, unsigned location, unsigned count, const mpl::true_&)
199 typename Backend::local_limb_type result = *val.limbs();
200 typename Backend::local_limb_type mask = count >= std::numeric_limits<typename Backend::local_limb_type>::digits ? ~static_cast<typename Backend::local_limb_type>(0) : (static_cast<typename Backend::local_limb_type>(1u) << count) - 1;
201 return (result >> location) & mask;
204 } // namespace detail
206 template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class OutputIterator>
207 OutputIterator export_bits(
208 const number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, OutputIterator out, unsigned chunk_size, bool msv_first = true)
211 #pragma warning(push)
212 #pragma warning(disable : 4244)
214 typedef typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::trivial_tag tag_type;
221 unsigned bitcount = boost::multiprecision::backends::eval_msb_imp(val.backend()) + 1;
222 unsigned chunks = bitcount / chunk_size;
223 if (bitcount % chunk_size)
226 int bit_location = msv_first ? bitcount - chunk_size : 0;
227 int bit_step = msv_first ? -static_cast<int>(chunk_size) : chunk_size;
228 while (bit_location % bit_step)
233 *out = detail::extract_bits(val.backend(), bit_location, chunk_size, tag_type());
235 bit_location += bit_step;
236 } while ((bit_location >= 0) && (bit_location < (int)bitcount));
245 } // namespace boost::multiprecision
247 #endif // BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP