szconv.hpp (1918B)
1 #ifndef _C4_SZCONV_HPP_ 2 #define _C4_SZCONV_HPP_ 3 4 /** @file szconv.hpp utilities to deal safely with narrowing conversions */ 5 6 #include "c4/config.hpp" 7 #include "c4/error.hpp" 8 9 #include <limits> 10 11 namespace c4 { 12 13 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast") 14 15 /** @todo this would be so much easier with calls to numeric_limits::max()... */ 16 template<class SizeOut, class SizeIn> 17 struct is_narrower_size : std::conditional 18 < 19 (std::is_signed<SizeOut>::value == std::is_signed<SizeIn>::value) 20 ? 21 (sizeof(SizeOut) < sizeof(SizeIn)) 22 : 23 ( 24 (sizeof(SizeOut) < sizeof(SizeIn)) 25 || 26 ( 27 (sizeof(SizeOut) == sizeof(SizeIn)) 28 && 29 (std::is_signed<SizeOut>::value && std::is_unsigned<SizeIn>::value) 30 ) 31 ), 32 std::true_type, 33 std::false_type 34 >::type 35 { 36 static_assert(std::is_integral<SizeIn >::value, "must be integral type"); 37 static_assert(std::is_integral<SizeOut>::value, "must be integral type"); 38 }; 39 40 41 /** when SizeOut is wider than SizeIn, assignment can occur without reservations */ 42 template<class SizeOut, class SizeIn> 43 C4_ALWAYS_INLINE 44 typename std::enable_if< ! is_narrower_size<SizeOut, SizeIn>::value, SizeOut>::type 45 szconv(SizeIn sz) noexcept 46 { 47 return static_cast<SizeOut>(sz); 48 } 49 50 /** when SizeOut is narrower than SizeIn, narrowing will occur, so we check 51 * for overflow. Note that this check is done only if C4_XASSERT is enabled. 52 * @see C4_XASSERT */ 53 template<class SizeOut, class SizeIn> 54 C4_ALWAYS_INLINE 55 typename std::enable_if<is_narrower_size<SizeOut, SizeIn>::value, SizeOut>::type 56 szconv(SizeIn sz) C4_NOEXCEPT_X 57 { 58 C4_XASSERT(sz >= 0); 59 C4_XASSERT_MSG((SizeIn)sz <= (SizeIn)std::numeric_limits<SizeOut>::max(), "size conversion overflow: in=%zu", (size_t)sz); 60 SizeOut szo = static_cast<SizeOut>(sz); 61 return szo; 62 } 63 64 C4_SUPPRESS_WARNING_GCC_CLANG_POP 65 66 } // namespace c4 67 68 #endif /* _C4_SZCONV_HPP_ */