piranha  0.10
mp_integer.hpp
1 /* Copyright 2009-2017 Francesco Biscani (bluescarni@gmail.com)
2 
3 This file is part of the Piranha library.
4 
5 The Piranha library is free software; you can redistribute it and/or modify
6 it under the terms of either:
7 
8  * the GNU Lesser General Public License as published by the Free
9  Software Foundation; either version 3 of the License, or (at your
10  option) any later version.
11 
12 or
13 
14  * the GNU General Public License as published by the Free Software
15  Foundation; either version 3 of the License, or (at your option) any
16  later version.
17 
18 or both in parallel, as here.
19 
20 The Piranha library is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 for more details.
24 
25 You should have received copies of the GNU General Public License and the
26 GNU Lesser General Public License along with the Piranha library. If not,
27 see https://www.gnu.org/licenses/. */
28 
29 #ifndef PIRANHA_MP_INTEGER_HPP
30 #define PIRANHA_MP_INTEGER_HPP
31 
32 #include <algorithm>
33 #include <cmath>
34 #include <cstddef>
35 #include <cstdint>
36 #include <stdexcept>
37 #include <string>
38 #include <type_traits>
39 #include <utility>
40 #include <vector>
41 
42 #include <piranha/config.hpp>
43 #include <piranha/detail/demangle.hpp>
44 #include <piranha/exceptions.hpp>
45 #include <piranha/is_key.hpp>
46 #include <piranha/math.hpp>
47 #define MPPP_WITH_LONG_DOUBLE
48 #include <piranha/mppp/mp++.hpp>
49 #undef MPPP_WITH_LONG_DOUBLE
50 #include <piranha/s11n.hpp>
51 #include <piranha/safe_cast.hpp>
52 #include <piranha/symbol_utils.hpp>
53 #include <piranha/type_traits.hpp>
54 
55 namespace piranha
56 {
57 
59 template <std::size_t SSize>
61 
64 
65 inline namespace impl
66 {
67 
68 // Detect if T is an instance of piranha::mp_integer.
69 // This is used in some enablers (e.g., gcd).
70 template <typename>
71 struct is_mp_integer : std::false_type {
72 };
73 
74 template <std::size_t SSize>
75 struct is_mp_integer<mp_integer<SSize>> : std::true_type {
76 };
77 
78 // Detect if T and U are both mp_integer with same SSize.
79 template <typename, typename>
80 struct is_same_mp_integer : std::false_type {
81 };
82 
83 template <std::size_t SSize>
84 struct is_same_mp_integer<mp_integer<SSize>, mp_integer<SSize>> : std::true_type {
85 };
86 }
87 
88 namespace math
89 {
90 
92 template <std::size_t SSize>
95 
103  {
104  addmul(x, y, z);
105  }
106 };
107 
109 template <std::size_t SSize>
110 struct negate_impl<mp_integer<SSize>> {
112 
118  {
119  n.neg();
120  }
121 };
122 
124 template <std::size_t SSize>
125 struct is_zero_impl<mp_integer<SSize>> {
127 
134  bool operator()(const mp_integer<SSize> &n) const
135  {
136  return n.is_zero();
137  }
138 };
139 
141 template <std::size_t SSize>
142 struct is_unitary_impl<mp_integer<SSize>> {
144 
151  bool operator()(const mp_integer<SSize> &n) const
152  {
153  return n.is_one();
154  }
155 };
156 }
157 
158 inline namespace impl
159 {
160 
161 // Avoid name clash below.
162 template <std::size_t SSize>
163 inline mp_integer<SSize> mp_integer_abs_wrapper(const mp_integer<SSize> &n)
164 {
165  return abs(n);
166 }
167 }
168 
169 namespace math
170 {
172 template <std::size_t SSize>
173 struct abs_impl<mp_integer<SSize>> {
175 
183  {
184  return mp_integer_abs_wrapper(n);
185  }
186 };
187 
189 template <std::size_t SSize>
190 struct sin_impl<mp_integer<SSize>> {
192 
200  {
201  if (is_zero(n)) {
202  return mp_integer<SSize>{};
203  }
204  piranha_throw(std::invalid_argument, "cannot compute the sine of a non-zero integer");
205  }
206 };
207 
209 template <std::size_t SSize>
210 struct cos_impl<mp_integer<SSize>> {
212 
220  {
221  if (is_zero(n)) {
222  return mp_integer<SSize>{1};
223  }
224  piranha_throw(std::invalid_argument, "cannot compute the cosine of a non-zero integer");
225  }
226 };
227 
229 template <std::size_t SSize>
230 struct partial_impl<mp_integer<SSize>> {
232 
235  mp_integer<SSize> operator()(const mp_integer<SSize> &, const std::string &) const
236  {
237  return mp_integer<SSize>{};
238  }
239 };
240 
242 
253 template <std::size_t SSize>
255 {
256  if (unlikely(sgn(n) < 0)) {
257  piranha_throw(std::domain_error, "cannot compute the factorial of the negative integer " + n.to_string());
258  }
259  mp_integer<SSize> retval;
260  fac_ui(retval, static_cast<unsigned long>(n));
261  return retval;
262 }
263 
265 
269 template <typename T, typename U, typename = void>
271 };
272 }
273 
274 inline namespace impl
275 {
276 
277 // Enabler for ipow_subs().
278 template <typename T, typename U>
279 using math_ipow_subs_t_
280  = decltype(math::ipow_subs_impl<T, U>{}(std::declval<const T &>(), std::declval<const std::string &>(),
281  std::declval<const integer &>(), std::declval<const U &>()));
282 
283 template <typename T, typename U>
284 using math_ipow_subs_t = enable_if_t<is_returnable<math_ipow_subs_t_<T, U>>::value, math_ipow_subs_t_<T, U>>;
285 }
286 
287 namespace math
288 {
289 
291 
311 template <typename T, typename U>
312 inline math_ipow_subs_t<T, U> ipow_subs(const T &x, const std::string &name, const integer &n, const U &y)
313 {
314  return ipow_subs_impl<T, U>{}(x, name, n, y);
315 }
316 
318 template <std::size_t SSize>
319 struct add3_impl<mp_integer<SSize>> {
321 
329  {
330  add(out, a, b);
331  }
332 };
333 
335 template <std::size_t SSize>
336 struct sub3_impl<mp_integer<SSize>> {
338 
346  {
347  sub(out, a, b);
348  }
349 };
350 
352 template <std::size_t SSize>
353 struct mul3_impl<mp_integer<SSize>> {
355 
363  {
364  mul(out, a, b);
365  }
366 };
367 
369 template <std::size_t SSize>
370 struct div3_impl<mp_integer<SSize>> {
372 
382  {
384  tdiv_qr(out, r, a, b);
385  }
386 };
387 }
388 
389 inline namespace impl
390 {
391 
392 // Enabler for the GCD specialisation.
393 template <typename T, typename U>
394 using math_mp_integer_gcd_enabler
395  = enable_if_t<disjunction<conjunction<std::is_integral<T>, is_mp_integer<U>, std::is_constructible<U, const T &>>,
396  conjunction<std::is_integral<U>, is_mp_integer<T>, std::is_constructible<T, const U &>>,
397  is_same_mp_integer<T, U>>::value>;
398 
399 // Wrapper to avoid clashes with piranha::math::gcd().
400 template <std::size_t SSize>
401 inline mp_integer<SSize> mp_integer_gcd_wrapper(const mp_integer<SSize> &a, const mp_integer<SSize> &b)
402 {
403  return gcd(a, b);
404 }
405 }
406 
407 namespace math
408 {
409 
411 
422 template <typename T, typename U>
423 struct gcd_impl<T, U, math_mp_integer_gcd_enabler<T, U>> {
425 
431  template <std::size_t SSize>
433  {
434  return mp_integer_gcd_wrapper(a, b);
435  }
437 
443  template <std::size_t SSize, typename T1>
444  mp_integer<SSize> operator()(const mp_integer<SSize> &a, const T1 &b) const
445  {
446  return operator()(a, mp_integer<SSize>(b));
447  }
449 
455  template <std::size_t SSize, typename T1>
456  mp_integer<SSize> operator()(const T1 &a, const mp_integer<SSize> &b) const
457  {
458  return operator()(b, a);
459  }
460 };
461 
463 template <std::size_t SSize>
464 struct gcd3_impl<mp_integer<SSize>> {
466 
475  {
476  gcd(out, a, b);
477  }
478 };
479 }
480 
481 inline namespace impl
482 {
483 
484 // Enabler for the overload below.
485 // NOTE: is_returnable is already checked by the invocation of the other overload.
486 template <typename T, typename U, typename Int>
487 using math_ipow_subs_int_t_
488  = decltype(math::ipow_subs(std::declval<const T &>(), std::declval<const std::string &>(),
489  integer{std::declval<const Int &>()}, std::declval<const U &>()));
490 
491 template <typename T, typename U, typename Int>
492 using math_ipow_subs_int_t = enable_if_t<std::is_integral<Int>::value, math_ipow_subs_int_t_<T, U, Int>>;
493 }
494 
495 namespace math
496 {
497 
499 
517 template <typename T, typename U, typename Int>
518 inline math_ipow_subs_int_t<T, U, Int> ipow_subs(const T &x, const std::string &name, const Int &n, const U &y)
519 {
520  return ipow_subs(x, name, integer{n}, y);
521 }
522 }
523 
525 
529 template <typename T, typename U>
531 {
532  template <typename T1, typename U1>
533  using ipow_subs_t = decltype(math::ipow_subs(std::declval<const T1 &>(), std::declval<std::string const &>(),
534  std::declval<integer const &>(), std::declval<const U1 &>()));
535  static const bool implementation_defined = is_detected<ipow_subs_t, T, U>::value;
536 
537 public:
539  static const bool value = implementation_defined;
540 };
541 
542 template <typename T, typename U>
543 const bool has_ipow_subs<T, U>::value;
544 
546 
556 template <typename Key, typename T>
558 {
559  PIRANHA_TT_CHECK(is_key, uncvref_t<Key>);
560  template <typename Key1, typename T1>
561  using key_ipow_subs_t = decltype(
562  std::declval<const Key1 &>().ipow_subs(std::declval<const symbol_idx &>(), std::declval<const integer &>(),
563  std::declval<const T1 &>(), std::declval<const symbol_fset &>()));
564  template <typename T1>
565  struct check_result_type : std::false_type {
566  };
567  template <typename Res>
568  struct check_result_type<std::vector<std::pair<Res, uncvref_t<Key>>>> : std::true_type {
569  };
570  static const bool implementation_defined = check_result_type<detected_t<key_ipow_subs_t, Key, T>>::value;
571 
572 public:
574  static const bool value = implementation_defined;
575 };
576 
577 // Static init.
578 template <typename Key, typename T>
580 
581 inline namespace literals
582 {
583 
585 
593 inline integer operator"" _z(const char *s)
594 {
595  return integer(s);
596 }
597 }
598 
599 inline namespace impl
600 {
601 
602 // These are a few utils useful for serialization.
603 using mpz_size_t = mppp::mppp_impl::mpz_size_t;
604 
605 inline mpz_size_t mp_integer_safe_abs_size(mpz_size_t s)
606 {
607  if (unlikely(s < -detail::safe_abs_sint<mpz_size_t>::value)) {
608  piranha_throw(std::overflow_error, "the number of limbs is too large");
609  }
610  return static_cast<mpz_size_t>(s >= 0 ? s : -s);
611 }
612 }
613 }
614 
615 namespace boost
616 {
617 namespace serialization
618 {
619 
620 template <typename Archive, std::size_t SSize,
621  piranha::enable_if_t<std::is_same<Archive, boost::archive::binary_oarchive>::value, int> = 0>
622 inline void save(Archive &ar, const piranha::mp_integer<SSize> &n, unsigned)
623 {
624  const auto &int_u = n._get_union();
625  if (n.is_static()) {
626  piranha::boost_save(ar, true);
627  // NOTE: alloc size is known for static ints.
628  const auto size = int_u.g_st()._mp_size;
629  piranha::boost_save(ar, size);
630  std::for_each(int_u.g_st().m_limbs.data(), int_u.g_st().m_limbs.data() + (size >= 0 ? size : -size),
631  [&ar](const ::mp_limb_t &l) { piranha::boost_save(ar, l); });
632  } else {
633  piranha::boost_save(ar, false);
634  // NOTE: don't record alloc size, we will reserve an adequate size on load.
635  piranha::boost_save(ar, int_u.g_dy()._mp_size);
636  std::for_each(int_u.g_dy()._mp_d, int_u.g_dy()._mp_d + ::mpz_size(&int_u.g_dy()),
637  [&ar](const ::mp_limb_t &l) { piranha::boost_save(ar, l); });
638  }
639 }
640 
641 template <typename Archive, std::size_t SSize,
642  piranha::enable_if_t<std::is_same<Archive, boost::archive::binary_iarchive>::value, int> = 0>
643 inline void load(Archive &ar, piranha::mp_integer<SSize> &n, unsigned)
644 {
645  const bool n_s = n.is_static();
646  bool s;
647  piranha::boost_load(ar, s);
648  // If the staticness of n and the serialized object differ, we have
649  // to adjust n.
650  if (s != n_s) {
651  if (n_s) {
652  // n is static, serialized is dynamic.
653  const bool pstatus = n.promote();
654  (void)pstatus;
655  assert(pstatus);
656  } else {
657  // n is dynamic, serialized is static.
659  }
660  }
661  auto &int_u = n._get_union();
662  if (s) {
663  try {
664  // NOTE: alloc is already set to the correct value.
665  piranha_assert(int_u.is_static());
666  piranha::boost_load(ar, int_u.g_st()._mp_size);
667  // Check the size from the archive is not bogus
668  auto size = int_u.g_st()._mp_size;
669  if (unlikely(size > int_u.g_st().s_size || size < -int_u.g_st().s_size)) {
670  piranha_throw(std::invalid_argument, "cannot deserialize a static integer with signed limb size "
671  + std::to_string(size) + " (the maximum static limb size is "
672  + std::to_string(int_u.g_st().s_size) + ")");
673  }
674  // Make absolute value. This is safe as we now know that size fits in the static size range.
675  size = (size >= 0) ? size : -size;
676  // Deserialize.
677  auto data = int_u.g_st().m_limbs.data();
678  std::for_each(data, data + size, [&ar](::mp_limb_t &l) { piranha::boost_load(ar, l); });
679  // Zero the limbs that were not loaded from the archive.
680  std::fill(data + size, data + int_u.g_st().s_size, 0u);
681  } catch (...) {
682  // Reset the static before re-throwing.
683  int_u.g_st()._mp_size = 0;
684  std::fill(int_u.g_st().m_limbs.begin(), int_u.g_st().m_limbs.end(), 0u);
685  throw;
686  }
687  } else {
688  piranha::mpz_size_t sz;
689  piranha::boost_load(ar, sz);
690  const auto size = piranha::mp_integer_safe_abs_size(sz);
691  // NOTE: static_cast is safe because of the type checks in mp++.
692  ::_mpz_realloc(&int_u.g_dy(), static_cast<::mp_size_t>(size));
693  try {
694  std::for_each(int_u.g_dy()._mp_d, int_u.g_dy()._mp_d + size,
695  [&ar](::mp_limb_t &l) { piranha::boost_load(ar, l); });
696  int_u.g_dy()._mp_size = sz;
697  } catch (...) {
698  // NOTE: only possible exception here is when boost_load(ar,l) throws. In this case we have successfully
699  // reallocated and possibly written some limbs, but we have not set the size yet. Just zero out the mpz.
700  ::mpz_set_ui(&int_u.g_dy(), 0u);
701  throw;
702  }
703  }
704 }
705 
706 // Portable serialization.
707 template <class Archive, std::size_t SSize,
708  piranha::enable_if_t<!std::is_same<Archive, boost::archive::binary_oarchive>::value, int> = 0>
709 inline void save(Archive &ar, const piranha::mp_integer<SSize> &n, unsigned)
710 {
711  // NOTE: here we have an unnecessary copy (but at least we are avoiding memory allocations).
712  // Maybe we should consider providing an API from mp++ to interact directly with strings
713  // rather than vectors of chars.
714  PIRANHA_MAYBE_TLS std::vector<char> tmp_v;
715  mppp::mppp_impl::mpz_to_str(tmp_v, n.get_mpz_view());
716  PIRANHA_MAYBE_TLS std::string tmp_s;
717  tmp_s.assign(tmp_v.data());
718  piranha::boost_save(ar, tmp_s);
719 }
720 
721 template <class Archive, std::size_t SSize,
722  piranha::enable_if_t<!std::is_same<Archive, boost::archive::binary_iarchive>::value, int> = 0>
723 inline void load(Archive &ar, piranha::mp_integer<SSize> &n, unsigned)
724 {
725  PIRANHA_MAYBE_TLS std::string tmp;
726  piranha::boost_load(ar, tmp);
728 }
729 
730 template <class Archive, std::size_t SSize>
731 inline void serialize(Archive &ar, piranha::mp_integer<SSize> &n, const unsigned int file_version)
732 {
733  split_free(ar, n, file_version);
734 }
735 }
736 }
737 
738 namespace piranha
739 {
740 
741 inline namespace impl
742 {
743 
744 template <typename Archive>
745 using mp_integer_boost_save_enabler
746  = enable_if_t<conjunction<has_boost_save<Archive, std::string>, has_boost_save<Archive, mpz_size_t>,
747  has_boost_save<Archive, bool>, has_boost_save<Archive, ::mp_limb_t>>::value>;
748 
749 template <typename Archive>
750 using mp_integer_boost_load_enabler
751  = enable_if_t<conjunction<has_boost_load<Archive, std::string>, has_boost_load<Archive, mpz_size_t>,
752  has_boost_load<Archive, bool>, has_boost_load<Archive, ::mp_limb_t>>::value>;
753 }
754 
756 
770 template <typename Archive, std::size_t SSize>
771 struct boost_save_impl<Archive, mp_integer<SSize>, mp_integer_boost_save_enabler<Archive>>
772  : boost_save_via_boost_api<Archive, mp_integer<SSize>> {
773 };
774 
776 
789 template <typename Archive, std::size_t SSize>
790 struct boost_load_impl<Archive, mp_integer<SSize>, mp_integer_boost_load_enabler<Archive>>
791  : boost_load_via_boost_api<Archive, mp_integer<SSize>> {
792 };
793 
794 #if defined(PIRANHA_WITH_MSGPACK)
795 
796 inline namespace impl
797 {
798 
799 // Enablers for msgpack serialization.
800 template <typename Stream>
801 using mp_integer_msgpack_pack_enabler = enable_if_t<
802  conjunction<is_msgpack_stream<Stream>, has_msgpack_pack<Stream, bool>, has_msgpack_pack<Stream, ::mp_limb_t>,
803  has_safe_cast<std::uint32_t, mpz_size_t>, has_msgpack_pack<Stream, std::string>>::value>;
804 
805 template <typename T>
806 using mp_integer_msgpack_convert_enabler
807  = enable_if_t<conjunction<is_mp_integer<T>, has_msgpack_convert<bool>, has_msgpack_convert<::mp_limb_t>,
809  has_safe_cast<mpz_size_t, typename std::vector<msgpack::object>::size_type>>::value>;
810 }
811 
813 
821 template <typename Stream, std::size_t SSize>
822 struct msgpack_pack_impl<Stream, mp_integer<SSize>, mp_integer_msgpack_pack_enabler<Stream>> {
824 
842  void operator()(msgpack::packer<Stream> &p, const mp_integer<SSize> &n, msgpack_format f) const
843  {
844  if (f == msgpack_format::binary) {
845  const auto &int_u = n._get_union();
846  // Regardless of storage type, we always pack an array of 3 elements:
847  // - staticness,
848  // - sign of size,
849  // - array of limbs.
850  p.pack_array(3);
851  if (n.is_static()) {
852  const auto size = int_u.g_st()._mp_size;
853  // No problems with the static casting here, abs(size) is guaranteed to be small.
854  const auto usize = static_cast<std::uint32_t>(size >= 0 ? size : -size);
855  piranha::msgpack_pack(p, true, f);
856  // Store whether the size is positive (true) or negative (false).
857  piranha::msgpack_pack(p, size >= 0, f);
858  p.pack_array(usize);
859  std::for_each(int_u.g_st().m_limbs.data(), int_u.g_st().m_limbs.data() + usize,
860  [&p, f](const ::mp_limb_t &l) { piranha::msgpack_pack(p, l, f); });
861  } else {
862  const auto size = int_u.g_dy()._mp_size;
863  std::uint32_t usize;
864  try {
865  usize = safe_cast<std::uint32_t>(mp_integer_safe_abs_size(size));
866  } catch (...) {
867  piranha_throw(std::overflow_error, "the number of limbs is too large");
868  }
869  piranha::msgpack_pack(p, false, f);
870  piranha::msgpack_pack(p, size >= 0, f);
871  p.pack_array(usize);
872  std::for_each(int_u.g_dy()._mp_d, int_u.g_dy()._mp_d + usize,
873  [&p, f](const ::mp_limb_t &l) { piranha::msgpack_pack(p, l, f); });
874  }
875  } else {
876  // NOTE: here we have an unnecessary copy (but at least we are avoiding memory allocations).
877  // Maybe we should consider providing an API from mp++ to interact directly with strings
878  // rather than vectors of chars.
879  PIRANHA_MAYBE_TLS std::vector<char> tmp_v;
880  mppp::mppp_impl::mpz_to_str(tmp_v, n.get_mpz_view());
881  PIRANHA_MAYBE_TLS std::string tmp_s;
882  tmp_s.assign(tmp_v.data());
883  piranha::msgpack_pack(p, tmp_s, f);
884  }
885  }
886 };
887 
889 
898 // NOTE: we need to keep the generic T param here, instead of mp_integer<SSize>, in order to trigger
899 // SFINAE in the enabler.
900 template <typename T>
901 struct msgpack_convert_impl<T, mp_integer_msgpack_convert_enabler<T>> {
903 
922  void operator()(T &n, const msgpack::object &o, msgpack_format f) const
923  {
924  if (f == msgpack_format::binary) {
925  PIRANHA_MAYBE_TLS std::array<msgpack::object, 3> vobj;
926  o.convert(vobj);
927  // Get the staticness of the serialized object.
928  bool s;
929  piranha::msgpack_convert(s, vobj[0u], f);
930  // Bring n into the same staticness as the serialized object.
931  const auto n_s = n.is_static();
932  if (s != n_s) {
933  if (n_s) {
934  const bool pstatus = n.promote();
935  (void)pstatus;
936  assert(pstatus);
937  } else {
938  n = T{};
939  }
940  }
941  auto &int_u = n._get_union();
942  // Get the size sign.
943  bool size_sign;
944  piranha::msgpack_convert(size_sign, vobj[1u], f);
945  PIRANHA_MAYBE_TLS std::vector<msgpack::object> vlimbs;
946  // Get the limbs.
947  vobj[2u].convert(vlimbs);
948  const auto size = vlimbs.size();
949  // We will need to iterate over the vector of limbs in both cases.
950  auto it = vlimbs.begin();
951  if (s) {
952  if (unlikely(size > std::size_t(int_u.g_st().s_size))) {
953  piranha_throw(std::invalid_argument,
954  "cannot deserialize a static integer with " + std::to_string(vlimbs.size())
955  + " limbs, the static size is " + std::to_string(int_u.g_st().s_size));
956  }
957  try {
958  // Fill in the limbs.
959  auto data = int_u.g_st().m_limbs.data();
960  // NOTE: for_each is guaranteed to proceed in order, so we are sure that it and l are consistent.
961  std::for_each(data, data + size, [f, &it](::mp_limb_t &l) {
962  piranha::msgpack_convert(l, *it, f);
963  ++it;
964  });
965  // Zero the limbs that were not loaded from the archive.
966  std::fill(data + size, data + int_u.g_st().s_size, 0u);
967  // Set the size, with sign.
968  int_u.g_st()._mp_size = static_cast<mpz_size_t>(size_sign ? static_cast<mpz_size_t>(size)
969  : -static_cast<mpz_size_t>(size));
970  } catch (...) {
971  // Reset the static before re-throwing.
972  int_u.g_st()._mp_size = 0;
973  std::fill(int_u.g_st().m_limbs.begin(), int_u.g_st().m_limbs.end(), 0u);
974  throw;
975  }
976  } else {
977  mpz_size_t sz;
978  try {
979  sz = safe_cast<mpz_size_t>(size);
980  // We need to be able to negate n.
981  if (unlikely(sz > detail::safe_abs_sint<mpz_size_t>::value)) {
982  throw std::overflow_error("");
983  }
984  } catch (...) {
985  piranha_throw(std::overflow_error, "the number of limbs is too large");
986  }
987  ::_mpz_realloc(&int_u.g_dy(), sz);
988  try {
989  std::for_each(int_u.g_dy()._mp_d, int_u.g_dy()._mp_d + sz, [f, &it](::mp_limb_t &l) {
990  piranha::msgpack_convert(l, *it, f);
991  ++it;
992  });
993  int_u.g_dy()._mp_size = static_cast<mpz_size_t>(size_sign ? sz : -sz);
994  } catch (...) {
995  ::mpz_set_ui(&int_u.g_dy(), 0u);
996  throw;
997  }
998  }
999  } else {
1000  PIRANHA_MAYBE_TLS std::string tmp;
1001  piranha::msgpack_convert(tmp, o, f);
1002  n = T{tmp};
1003  }
1004  }
1005 };
1006 
1007 #endif
1008 
1009 inline namespace impl
1010 {
1011 
1012 // Enabler for safe_cast specialisation.
1013 template <typename To, typename From>
1014 using mp_integer_safe_cast_enabler = enable_if_t<
1015  disjunction<conjunction<is_mp_integer<To>, std::is_floating_point<From>, std::is_constructible<To, From>>,
1016  conjunction<is_mp_integer<To>, std::is_integral<From>, std::is_constructible<To, From>>,
1017  conjunction<is_mp_integer<From>, std::is_integral<To>, std::is_constructible<To, From>>>::value>;
1018 }
1019 
1021 
1031 template <typename To, typename From>
1032 struct safe_cast_impl<To, From, mp_integer_safe_cast_enabler<To, From>> {
1033 private:
1034  template <typename T>
1035  using float_enabler = enable_if_t<std::is_floating_point<T>::value, int>;
1036  template <typename T>
1037  using mp_int_enabler = enable_if_t<is_mp_integer<T>::value, int>;
1038  template <typename T>
1039  using int_enabler = enable_if_t<std::is_integral<T>::value, int>;
1040  template <typename T, float_enabler<T> = 0>
1041  static To impl(const T &f)
1042  {
1043  if (unlikely(!std::isfinite(f))) {
1044  piranha_throw(safe_cast_failure, "the non-finite floating-point value " + std::to_string(f)
1045  + " cannot be converted to an arbitrary-precision integer");
1046  }
1047  if (unlikely(f != std::trunc(f))) {
1048  piranha_throw(safe_cast_failure, "the floating-point value with nonzero fractional part "
1049  + std::to_string(f)
1050  + " cannot be converted to an arbitrary-precision integer");
1051  }
1052  return To{f};
1053  }
1054  template <typename T, mp_int_enabler<T> = 0>
1055  static To impl(const T &n)
1056  {
1057  try {
1058  return To(n);
1059  } catch (const std::overflow_error &) {
1060  piranha_throw(safe_cast_failure, "the arbitrary-precision integer " + n.to_string()
1061  + " cannot be converted to the type '" + detail::demangle<To>()
1062  + "', as the conversion cannot preserve the original value");
1063  }
1064  }
1065  template <typename T, int_enabler<T> = 0>
1066  static To impl(const T &n)
1067  {
1068  return To{n};
1069  }
1070 
1071 public:
1073 
1083  To operator()(const From &x) const
1084  {
1085  return impl(x);
1086  }
1087 };
1088 }
1089 
1090 #endif
Default functor for the implementation of piranha::math::mul3().
Definition: math.hpp:2664
auto gcd(const T &a, const U &b) -> decltype(gcd_impl< T, U >()(a, b))
GCD.
Definition: math.hpp:2878
mp_integer< SSize > operator()(const mp_integer< SSize > &a, const T1 &b) const
Call operator, piranha::mp_integer - integral overload.
Definition: mp_integer.hpp:444
void boost_load(Archive &ar, T &x)
Load from Boost archive.
Definition: s11n.hpp:469
void operator()(mp_integer< SSize > &x, const mp_integer< SSize > &y, const mp_integer< SSize > &z) const
Call operator.
Definition: mp_integer.hpp:102
bool operator()(const mp_integer< SSize > &n) const
Call operator.
Definition: mp_integer.hpp:151
Default functor for the implementation of piranha::math::negate().
Definition: math.hpp:253
Multiprecision integer class.
Definition: mp++.hpp:869
mp_integer< SSize > operator()(const T1 &a, const mp_integer< SSize > &b) const
Call operator, integral - piranha::mp_integer overload.
Definition: mp_integer.hpp:456
bool is_zero() const
Test if the value is zero.
Definition: mp++.hpp:5104
Default implementation of piranha::boost_load().
Definition: s11n.hpp:391
Default functor for the implementation of piranha::math::div3().
Definition: math.hpp:2736
mp_integer< 1 > integer
Alias for piranha::mp_integer with 1 limb of static storage.
Definition: mp_integer.hpp:63
void msgpack_convert(T &x, const msgpack::object &o, msgpack_format f)
Convert msgpack object.
Definition: s11n.hpp:957
Default functor for the implementation of piranha::math::multiply_accumulate().
Definition: math.hpp:339
void operator()(mp_integer< SSize > &out, const mp_integer< SSize > &a, const mp_integer< SSize > &b) const
Call operator.
Definition: mp_integer.hpp:328
Key type concept check.
Definition: is_key.hpp:65
mp_integer< SSize > factorial(const mp_integer< SSize > &n)
Factorial.
Definition: mp_integer.hpp:254
void operator()(mp_integer< SSize > &out, const mp_integer< SSize > &a, const mp_integer< SSize > &b) const
Call operator.
Definition: mp_integer.hpp:381
void operator()(mp_integer< SSize > &out, const mp_integer< SSize > &a, const mp_integer< SSize > &b) const
Call operator.
Definition: mp_integer.hpp:345
Default functor for the implementation of piranha::math::is_zero().
Definition: math.hpp:69
Implementation of piranha::boost_load() via the Boost API.
Definition: s11n.hpp:363
Exceptions.
Default functor for the implementation of piranha::math::sin().
Definition: math.hpp:541
std::string to_string(int base=10) const
Conversion to string.
Definition: mp++.hpp:1350
Default implementation of piranha::boost_save().
Definition: s11n.hpp:245
void operator()(mp_integer< SSize > &out, const mp_integer< SSize > &a, const mp_integer< SSize > &b) const
Call operator.
Definition: mp_integer.hpp:362
STL namespace.
Default functor for the implementation of piranha::math::cos().
Definition: math.hpp:449
mppp_impl::integer_union< SSize > & _get_union()
Return a reference to the internal union.
Definition: mp++.hpp:5070
void operator()(msgpack::packer< Stream > &p, const mp_integer< SSize > &n, msgpack_format f) const
Call operator.
Definition: mp_integer.hpp:842
void operator()(mp_integer< SSize > &out, const mp_integer< SSize > &a, const mp_integer< SSize > &b) const
Call operator.
Definition: mp_integer.hpp:474
mp_integer< SSize > operator()(const mp_integer< SSize > &n) const
Call operator.
Definition: mp_integer.hpp:199
bool promote()
Promote to dynamic storage.
Definition: mp++.hpp:1566
Detect the presence of piranha::msgpack_convert().
Definition: s11n.hpp:610
void operator()(T &n, const msgpack::object &o, msgpack_format f) const
Call operator.
Definition: mp_integer.hpp:922
mp_integer< SSize > operator()(const mp_integer< SSize > &n) const
Call operator.
Definition: mp_integer.hpp:182
Default functor for the implementation of piranha::math::ipow_subs().
Definition: mp_integer.hpp:270
Default functor for the implementation of piranha::math::add3().
Definition: math.hpp:2520
Default functor for the implementation of piranha::msgpack_convert().
Definition: s11n.hpp:867
#define piranha_throw(exception_type,...)
Exception-throwing macro.
Definition: exceptions.hpp:118
Default functor for the implementation of piranha::math::sub3().
Definition: math.hpp:2592
Default functor for the implementation of piranha::math::gcd3().
Definition: math.hpp:2888
Default functor for the implementation of piranha::msgpack_pack().
Definition: s11n.hpp:686
msgpack_format
Serialization format for msgpack.
Definition: s11n.hpp:673
mpz_view get_mpz_view() const
Get an mpz_t view.
Definition: mp++.hpp:1652
mp_integer & neg()
Negate in-place.
Definition: mp++.hpp:1662
Default functor for the implementation of piranha::math::partial().
Definition: math.hpp:633
Default implementation of piranha::safe_cast().
Definition: safe_cast.hpp:63
mp_integer< SSize > operator()(const mp_integer< SSize > &a, const mp_integer< SSize > &b) const
Call operator, piranha::mp_integer - piranha::mp_integer overload.
Definition: mp_integer.hpp:432
Default functor for the implementation of piranha::math::gcd().
Definition: math.hpp:2837
bool is_zero(const T &x)
Zero test.
Definition: math.hpp:133
Type trait to detect the presence of the integral power substitution method in keys.
Definition: mp_integer.hpp:557
Implementation of piranha::boost_save() via the Boost API.
Definition: s11n.hpp:217
bool is_static() const
Test for static storage.
Definition: mp++.hpp:1292
bool operator()(const mp_integer< SSize > &n) const
Call operator.
Definition: mp_integer.hpp:134
Root piranha namespace.
Definition: array_key.hpp:52
void msgpack_pack(msgpack::packer< Stream > &packer, const T &x, msgpack_format f)
Pack generic object in a msgpack stream.
Definition: s11n.hpp:856
bool is_one() const
Test if the value is equal to one.
Definition: mp++.hpp:5137
Detect the presence of piranha::msgpack_pack().
Definition: s11n.hpp:607
Type traits.
mp_integer< SSize > operator()(const mp_integer< SSize > &n) const
Call operator.
Definition: mp_integer.hpp:219
Type trait to detect piranha::safe_cast().
Definition: safe_cast.hpp:237
void boost_save(Archive &ar, const T &x)
Save to Boost archive.
Definition: s11n.hpp:328
static const bool value
Value of the type trait.
Definition: mp_integer.hpp:574
static const bool value
Value of the type trait.
Definition: mp_integer.hpp:539
Default functor for the implementation of piranha::math::abs().
Definition: math.hpp:947
mp_integer< SSize > operator()(const mp_integer< SSize > &, const std::string &) const
Call operator.
Definition: mp_integer.hpp:235
Type trait to detect the availability of the piranha::math::ipow_subs() function. ...
Definition: mp_integer.hpp:530
void operator()(mp_integer< SSize > &n) const
Call operator.
Definition: mp_integer.hpp:117
math_ipow_subs_t< T, U > ipow_subs(const T &x, const std::string &name, const integer &n, const U &y)
Substitution of integral power.
Definition: mp_integer.hpp:312
Exception to signal failure in piranha::safe_cast().
Definition: safe_cast.hpp:53
Default functor for the implementation of piranha::math::is_unitary().
Definition: math.hpp:179
safe_cast_type< To, From > safe_cast(const From &x)
Safe cast.
Definition: safe_cast.hpp:219