| 64 | #if DEBUG |
| 65 | template<typename Out, typename In> |
| 66 | static Out narrow_cast (In val) { |
| 67 | static_assert(::std::is_arithmetic<In>::value && ::std::is_arithmetic<Out>::value, "Only numeric types are valid for narrow_cast"); |
| 68 | if(sizeof(In) <= sizeof(Out) && ::std::is_signed<In>::value == ::std::is_signed<Out>::value) { |
| 69 | return (Out)val; |
| 70 | } |
| 71 | |
| 72 | // Comparing an unsigned number against a signed minimum causes issues, at least on Windows, |
| 73 | // but if the output is signed and the input is unsigned then there is never a case where |
| 74 | // the input could underflow the output. The reverse situation does not appear to be true. |
| 75 | // the input could underflow the output. The reverse situation does not appear to be true. |
| 76 | bool min_ok = std::is_signed<Out>::value && !std::is_signed<In>::value; |
| 77 | |
| 78 | #ifdef Assert |
| 79 | if(::std::is_floating_point<In>::value) { |
| 80 | Assert(val >= std::numeric_limits<Out>::min() && val <= ::std::numeric_limits<Out>::max(), |
| 81 | "Invalid narrow_cast %g -> %s", (double)val, typeid(Out).name()); |
| 82 | } else if(::std::is_signed<In>::value) { |
| 83 | Assert((min_ok || val >= std::numeric_limits<Out>::min()) && val <= ::std::numeric_limits<Out>::max(), |
| 84 | "Invalid narrow_cast %" PRIi64 " -> %s", (int64_t)val, typeid(Out).name()); |
| 85 | } else { |
| 86 | Assert((min_ok || val >= std::numeric_limits<Out>::min()) && val <= ::std::numeric_limits<Out>::max(), |
| 87 | "Invalid narrow_cast %" PRIu64 " -> %s", (uint64_t)val, typeid(Out).name()); |
| 88 | } |
| 89 | #else |
| 90 | char message[256]; |
| 91 | if(::std::is_floating_point<In>::value) { |
| 92 | sprintf(message, "Invalid narrow_cast %g -> %s", (double)val, typeid(Out).name()); |
| 93 | throwIf(val < std::numeric_limits<Out>::min() || val > std::numeric_limits<Out>::max(), InternalError, message); |
| 94 | } else if(::std::is_signed<In>::value) { |
| 95 | sprintf(message, "Invalid narrow_cast %" PRIi64 " -> %s", (int64_t)val, typeid(Out).name()); |
| 96 | throwIf((!min_ok && val < std::numeric_limits<Out>::min()) || val > std::numeric_limits<Out>::max(), |
| 97 | InternalError, message); |
| 98 | } else { |
| 99 | sprintf(message, "Invalid narrow_cast %" PRIu64 " -> %s", (uint64_t)val, typeid(Out).name()); |
| 100 | throwIf((!min_ok && val < std::numeric_limits<Out>::min()) || val > std::numeric_limits<Out>::max(), |
| 101 | InternalError, message); |
| 102 | } |
| 103 | #endif |
| 104 | return (Out)val; |
| 105 | } |
| 106 | #else |
| 107 | template<typename Out, typename In> |
| 108 | static inline Out narrow_cast(In val) { |
nothing calls this directly
no outgoing calls
no test coverage detected