import_export.hpp 12 KB

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