mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-24 14:45:41 +00:00
69 lines
1.9 KiB
C++
69 lines
1.9 KiB
C++
|
#ifndef _C4_SZCONV_HPP_
|
||
|
#define _C4_SZCONV_HPP_
|
||
|
|
||
|
/** @file szconv.hpp utilities to deal safely with narrowing conversions */
|
||
|
|
||
|
#include "c4/config.hpp"
|
||
|
#include "c4/error.hpp"
|
||
|
|
||
|
#include <limits>
|
||
|
|
||
|
namespace c4 {
|
||
|
|
||
|
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||
|
|
||
|
/** @todo this would be so much easier with calls to numeric_limits::max()... */
|
||
|
template<class SizeOut, class SizeIn>
|
||
|
struct is_narrower_size : std::conditional
|
||
|
<
|
||
|
(std::is_signed<SizeOut>::value == std::is_signed<SizeIn>::value)
|
||
|
?
|
||
|
(sizeof(SizeOut) < sizeof(SizeIn))
|
||
|
:
|
||
|
(
|
||
|
(sizeof(SizeOut) < sizeof(SizeIn))
|
||
|
||
|
||
|
(
|
||
|
(sizeof(SizeOut) == sizeof(SizeIn))
|
||
|
&&
|
||
|
(std::is_signed<SizeOut>::value && std::is_unsigned<SizeIn>::value)
|
||
|
)
|
||
|
),
|
||
|
std::true_type,
|
||
|
std::false_type
|
||
|
>::type
|
||
|
{
|
||
|
static_assert(std::is_integral<SizeIn >::value, "must be integral type");
|
||
|
static_assert(std::is_integral<SizeOut>::value, "must be integral type");
|
||
|
};
|
||
|
|
||
|
|
||
|
/** when SizeOut is wider than SizeIn, assignment can occur without reservations */
|
||
|
template<class SizeOut, class SizeIn>
|
||
|
C4_ALWAYS_INLINE
|
||
|
typename std::enable_if< ! is_narrower_size<SizeOut, SizeIn>::value, SizeOut>::type
|
||
|
szconv(SizeIn sz) noexcept
|
||
|
{
|
||
|
return static_cast<SizeOut>(sz);
|
||
|
}
|
||
|
|
||
|
/** when SizeOut is narrower than SizeIn, narrowing will occur, so we check
|
||
|
* for overflow. Note that this check is done only if C4_XASSERT is enabled.
|
||
|
* @see C4_XASSERT */
|
||
|
template<class SizeOut, class SizeIn>
|
||
|
C4_ALWAYS_INLINE
|
||
|
typename std::enable_if<is_narrower_size<SizeOut, SizeIn>::value, SizeOut>::type
|
||
|
szconv(SizeIn sz) C4_NOEXCEPT_X
|
||
|
{
|
||
|
C4_XASSERT(sz >= 0);
|
||
|
C4_XASSERT_MSG((SizeIn)sz <= (SizeIn)std::numeric_limits<SizeOut>::max(), "size conversion overflow: in=%zu", (size_t)sz);
|
||
|
SizeOut szo = static_cast<SizeOut>(sz);
|
||
|
return szo;
|
||
|
}
|
||
|
|
||
|
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||
|
|
||
|
} // namespace c4
|
||
|
|
||
|
#endif /* _C4_SZCONV_HPP_ */
|