|
12 | 12 |
|
13 | 13 | #include <string>
|
14 | 14 | #include <iosfwd>
|
| 15 | +#include <limits> |
15 | 16 |
|
16 | 17 | #include "big-int/bigint.hh"
|
| 18 | +#include "optional.h" |
17 | 19 |
|
18 | 20 | // NOLINTNEXTLINE(readability/identifiers)
|
19 | 21 | typedef BigInt mp_integer;
|
@@ -48,9 +50,83 @@ const std::string integer2string(const mp_integer &, unsigned base=10);
|
48 | 50 | const mp_integer string2integer(const std::string &, unsigned base=10);
|
49 | 51 | const std::string integer2binary(const mp_integer &, std::size_t width);
|
50 | 52 | const mp_integer binary2integer(const std::string &, bool is_signed);
|
| 53 | + |
| 54 | +/// \deprecated use numeric_cast<unsigned long long> instead |
51 | 55 | mp_integer::ullong_t integer2ulong(const mp_integer &);
|
| 56 | + |
| 57 | +/// \deprecated use numeric_cast<std::size_t> instead |
52 | 58 | std::size_t integer2size_t(const mp_integer &);
|
| 59 | + |
| 60 | +/// \deprecated use numeric_cast<unsigned> instead |
53 | 61 | unsigned integer2unsigned(const mp_integer &);
|
| 62 | + |
54 | 63 | const mp_integer mp_zero=string2integer("0");
|
55 | 64 |
|
| 65 | +/// Numerical cast provides a unified way of converting from one numerical type |
| 66 | +/// to another. |
| 67 | +/// Generic case doesn't exist, this has to be specialized for different types. |
| 68 | +template <typename T, typename = void> |
| 69 | +struct numeric_castt final |
| 70 | +{ |
| 71 | +}; |
| 72 | + |
| 73 | +/// Convert mp_integer to any signed type |
| 74 | +/// \tparam T: type to convert to |
| 75 | +/// \param mpi: mp_integer to convert |
| 76 | +/// \return optional integer of type T if conversion is possible, |
| 77 | +/// empty optional otherwise. |
| 78 | +template <typename T> |
| 79 | +struct numeric_castt<T, |
| 80 | + typename std::enable_if<std::is_integral<T>::value && |
| 81 | + std::is_signed<T>::value>::type> |
| 82 | +{ |
| 83 | + static optionalt<T> numeric_cast(const mp_integer &mpi) |
| 84 | + { |
| 85 | + static_assert( |
| 86 | + std::numeric_limits<T>::max() <= |
| 87 | + std::numeric_limits<decltype(mpi.to_long())>::max() && |
| 88 | + std::numeric_limits<T>::min() >= |
| 89 | + std::numeric_limits<decltype(mpi.to_long())>::min(), |
| 90 | + "Numeric cast only works for types smaller than long long"); |
| 91 | + if( |
| 92 | + mpi <= std::numeric_limits<T>::max() && |
| 93 | + mpi >= std::numeric_limits<T>::min()) |
| 94 | + // to_long converts to long long which is the largest signed numeric type |
| 95 | + return {static_cast<T>(mpi.to_long())}; |
| 96 | + else |
| 97 | + return {}; |
| 98 | + } |
| 99 | +}; |
| 100 | + |
| 101 | +/// Convert mp_integer to any unsigned type |
| 102 | +/// \tparam T: type to convert to |
| 103 | +/// \param mpi: mp_integer to convert |
| 104 | +/// \return optional integer of type T if conversion is possible, |
| 105 | +/// empty optional otherwise. |
| 106 | +template <typename T> |
| 107 | +struct numeric_castt<T, |
| 108 | + typename std::enable_if<std::is_integral<T>::value && |
| 109 | + !std::is_signed<T>::value>::type> |
| 110 | +{ |
| 111 | + static optionalt<T> numeric_cast(const mp_integer &mpi) |
| 112 | + { |
| 113 | + static_assert( |
| 114 | + std::numeric_limits<T>::max() <= |
| 115 | + std::numeric_limits<decltype(mpi.to_ulong())>::max() && |
| 116 | + std::numeric_limits<T>::min() >= |
| 117 | + std::numeric_limits<decltype(mpi.to_ulong())>::min(), |
| 118 | + "Numeric cast only works for types smaller than unsigned long long"); |
| 119 | + if(mpi <= std::numeric_limits<T>::max() && mpi >= 0) |
| 120 | + return {static_cast<T>(mpi.to_ulong())}; |
| 121 | + else |
| 122 | + return {}; |
| 123 | + } |
| 124 | +}; |
| 125 | + |
| 126 | +template <typename T> |
| 127 | +optionalt<T> numeric_cast(const mp_integer &mpi) |
| 128 | +{ |
| 129 | + return numeric_castt<T>::numeric_cast(mpi); |
| 130 | +} |
| 131 | + |
56 | 132 | #endif // CPROVER_UTIL_MP_ARITH_H
|
0 commit comments