From 9ff48e09598f9270fe8cbb23952c225a9fb90180 Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Mon, 13 Nov 2017 17:32:20 +0000 Subject: [PATCH] Add numeric_cast template for numeric conversion This is for now only applied to mp_integer but could be extended to other numerical types. --- src/util/mp_arith.h | 76 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/util/mp_arith.h b/src/util/mp_arith.h index 7cc4dd7dfad..4cdabf9326f 100644 --- a/src/util/mp_arith.h +++ b/src/util/mp_arith.h @@ -12,8 +12,10 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include "big-int/bigint.hh" +#include "optional.h" // NOLINTNEXTLINE(readability/identifiers) typedef BigInt mp_integer; @@ -48,9 +50,83 @@ const std::string integer2string(const mp_integer &, unsigned base=10); const mp_integer string2integer(const std::string &, unsigned base=10); const std::string integer2binary(const mp_integer &, std::size_t width); const mp_integer binary2integer(const std::string &, bool is_signed); + +/// \deprecated use numeric_cast instead mp_integer::ullong_t integer2ulong(const mp_integer &); + +/// \deprecated use numeric_cast instead std::size_t integer2size_t(const mp_integer &); + +/// \deprecated use numeric_cast instead unsigned integer2unsigned(const mp_integer &); + const mp_integer mp_zero=string2integer("0"); +/// Numerical cast provides a unified way of converting from one numerical type +/// to another. +/// Generic case doesn't exist, this has to be specialized for different types. +template +struct numeric_castt final +{ +}; + +/// Convert mp_integer to any signed type +/// \tparam T: type to convert to +/// \param mpi: mp_integer to convert +/// \return optional integer of type T if conversion is possible, +/// empty optional otherwise. +template +struct numeric_castt::value && + std::is_signed::value>::type> +{ + static optionalt numeric_cast(const mp_integer &mpi) + { + static_assert( + std::numeric_limits::max() <= + std::numeric_limits::max() && + std::numeric_limits::min() >= + std::numeric_limits::min(), + "Numeric cast only works for types smaller than long long"); + if( + mpi <= std::numeric_limits::max() && + mpi >= std::numeric_limits::min()) + // to_long converts to long long which is the largest signed numeric type + return {static_cast(mpi.to_long())}; + else + return {}; + } +}; + +/// Convert mp_integer to any unsigned type +/// \tparam T: type to convert to +/// \param mpi: mp_integer to convert +/// \return optional integer of type T if conversion is possible, +/// empty optional otherwise. +template +struct numeric_castt::value && + !std::is_signed::value>::type> +{ + static optionalt numeric_cast(const mp_integer &mpi) + { + static_assert( + std::numeric_limits::max() <= + std::numeric_limits::max() && + std::numeric_limits::min() >= + std::numeric_limits::min(), + "Numeric cast only works for types smaller than unsigned long long"); + if(mpi <= std::numeric_limits::max() && mpi >= 0) + return {static_cast(mpi.to_ulong())}; + else + return {}; + } +}; + +template +optionalt numeric_cast(const mp_integer &mpi) +{ + return numeric_castt::numeric_cast(mpi); +} + #endif // CPROVER_UTIL_MP_ARITH_H