@@ -12,8 +12,10 @@ Author: Daniel Kroening, kroening@kroening.com
1212
1313#include < string>
1414#include < iosfwd>
15+ #include < limits>
1516
1617#include " big-int/bigint.hh"
18+ #include " optional.h"
1719
1820// NOLINTNEXTLINE(readability/identifiers)
1921typedef BigInt mp_integer;
@@ -48,9 +50,83 @@ const std::string integer2string(const mp_integer &, unsigned base=10);
4850const mp_integer string2integer (const std::string &, unsigned base=10 );
4951const std::string integer2binary (const mp_integer &, std::size_t width);
5052const mp_integer binary2integer (const std::string &, bool is_signed);
53+
54+ // / \deprecated use numeric_cast<unsigned long long> instead
5155mp_integer::ullong_t integer2ulong (const mp_integer &);
56+
57+ // / \deprecated use numeric_cast<std::size_t> instead
5258std::size_t integer2size_t (const mp_integer &);
59+
60+ // / \deprecated use numeric_cast<unsigned> instead
5361unsigned integer2unsigned (const mp_integer &);
62+
5463const mp_integer mp_zero=string2integer(" 0" );
5564
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+
56132#endif // CPROVER_UTIL_MP_ARITH_H
0 commit comments