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

source code of boost/libs/multiprecision/include/boost/multiprecision/cpp_int/import_export.hpp