import_export.hpp 12 KB

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