24#ifndef PXR_BASE_GF_NUMERIC_CAST_H
25#define PXR_BASE_GF_NUMERIC_CAST_H
29#include "pxr/base/gf/traits.h"
36PXR_NAMESPACE_OPEN_SCOPE
45template <
class T,
class U>
47GfIntegerCompareLess(T t, U u)
noexcept
49 static_assert(std::is_integral_v<T> && std::is_integral_v<U>);
51 if constexpr (std::is_signed_v<T> == std::is_signed_v<U>) {
54 else if constexpr (std::is_signed_v<T>) {
55 return t < 0 || std::make_unsigned_t<T>(t) < u;
58 return u >= 0 && t < std::make_unsigned_t<U>(u);
62enum GfNumericCastFailureType {
63 GfNumericCastPosOverflow,
64 GfNumericCastNegOverflow,
90template <
class To,
class From>
92GfNumericCast(From from, GfNumericCastFailureType *failType =
nullptr)
97 using FromLimits = std::numeric_limits<From>;
98 using ToLimits = std::numeric_limits<To>;
100 auto setFail = [&failType](GfNumericCastFailureType ft) {
107 if constexpr (std::is_integral_v<From> &&
108 std::is_integral_v<To>) {
110 if (GfIntegerCompareLess(from, ToLimits::min())) {
111 setFail(GfNumericCastNegOverflow);
114 if (GfIntegerCompareLess(ToLimits::max(), from)) {
115 setFail(GfNumericCastPosOverflow);
119 return static_cast<To
>(from);
123 std::is_integral_v<To>) {
125 if (std::isnan(from)) {
126 setFail(GfNumericCastNaN);
130 if (std::isinf(from)) {
131 setFail(std::signbit(
static_cast<double>(from))
132 ? GfNumericCastNegOverflow
133 : GfNumericCastPosOverflow);
143 From low =
static_cast<From
>(ToLimits::lowest()) -
static_cast<From
>(1);
144 From high =
static_cast<From
>(ToLimits::max()) +
static_cast<From
>(1);
147 setFail(GfNumericCastNegOverflow);
151 setFail(GfNumericCastPosOverflow);
155 return static_cast<To
>(from);
162 return static_cast<To
>(from);
166PXR_NAMESPACE_CLOSE_SCOPE
A metafunction which is equivalent to std::arithmetic but also includes any specializations from GfIs...
A metafunction which is equivalent to std::is_floating_point but allows for additional specialization...