diff options
-rw-r--r-- | include/o3tl/strong_int.hxx | 50 |
1 files changed, 47 insertions, 3 deletions
diff --git a/include/o3tl/strong_int.hxx b/include/o3tl/strong_int.hxx index ce5466e45167..8a9d91dbfb8c 100644 --- a/include/o3tl/strong_int.hxx +++ b/include/o3tl/strong_int.hxx @@ -23,10 +23,52 @@ #include <sal/config.h> #include <limits> #include <cassert> +#include <type_traits> namespace o3tl { +#if HAVE_CXX14_CONSTEXPR + +namespace detail { + +template<typename T1, typename T2> constexpr +typename std::enable_if< + std::is_signed<T1>::value && std::is_signed<T2>::value, bool>::type +isInRange(T2 value) { + return value >= std::numeric_limits<T1>::min() + && value <= std::numeric_limits<T1>::max(); +} + +template<typename T1, typename T2> constexpr +typename std::enable_if< + std::is_signed<T1>::value && std::is_unsigned<T2>::value, bool>::type +isInRange(T2 value) { + return value + <= static_cast<typename std::make_unsigned<T1>::type>( + std::numeric_limits<T1>::max()); +} + +template<typename T1, typename T2> constexpr +typename std::enable_if< + std::is_unsigned<T1>::value && std::is_signed<T2>::value, bool>::type +isInRange(T2 value) { + return value >= 0 + && (static_cast<typename std::make_unsigned<T2>::type>(value) + <= std::numeric_limits<T1>::max()); +} + +template<typename T1, typename T2> constexpr +typename std::enable_if< + std::is_unsigned<T1>::value && std::is_unsigned<T2>::value, bool>::type +isInRange(T2 value) { + return value <= std::numeric_limits<T1>::max(); +} + +} + +#endif + /// /// Wrap up an integer type so that we prevent accidental conversion to other integer types. /// @@ -42,12 +84,14 @@ template <typename UNDERLYING_TYPE, typename PHANTOM_TYPE> struct strong_int { public: - explicit constexpr strong_int(long value) : m_value(value) + template<typename T> explicit constexpr strong_int( + T value, + typename std::enable_if<std::is_integral<T>::value, int>::type = 0): + m_value(value) { #if HAVE_CXX14_CONSTEXPR // catch attempts to pass in out-of-range values early - assert(value >= std::numeric_limits<UNDERLYING_TYPE>::min() - && value <= std::numeric_limits<UNDERLYING_TYPE>::max() + assert(detail::isInRange<UNDERLYING_TYPE>(value) && "out of range"); #endif } |