template <std::integral I> I ConvertWithOverflowTo(double f)
{
f = rtl::math::round(f); if (!o3tl::convertsToAtMost(f, std::numeric_limits<I>::max()))
{
SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW); return std::numeric_limits<I>::max();
} if (!o3tl::convertsToAtLeast(f, std::numeric_limits<I>::min()))
{
SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW); return std::numeric_limits<I>::min();
} return f;
}
template <std::integral To, std::integral From> To ConvertWithOverflowTo(From n)
{ using ValidRange = o3tl::ValidRange<To>; if (ValidRange::isAbove(n))
{
SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW); return std::numeric_limits<To>::max();
} if (ValidRange::isBelow(n))
{
SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW); return std::numeric_limits<To>::min();
} return n;
}
template <std::floating_point To, std::floating_point From> inline To ConvertWithOverflowTo(From n)
{ if constexpr (std::numeric_limits<From>::max() > std::numeric_limits<To>::max())
{ if (n > std::numeric_limits<To>::max())
{
SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW); return std::numeric_limits<To>::max();
}
} if constexpr (std::numeric_limits<From>::lowest() < std::numeric_limits<To>::lowest())
{ if (n < std::numeric_limits<To>::lowest())
{
SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW); return std::numeric_limits<To>::lowest();
}
} // tests for underflow - storing value too small for precision of single if constexpr (std::numeric_limits<From>::min() < std::numeric_limits<To>::min())
{ if (n > 0 && n < std::numeric_limits<To>::min())
{
SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW); return std::numeric_limits<To>::min();
} if (n < 0 && n > -std::numeric_limits<To>::min())
{
SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW); return -std::numeric_limits<To>::min();
}
} return n;
}
template <std::floating_point To, std::integral From> inline To ConvertWithOverflowTo(From n)
{ // No integral types overflow floats returnstatic_cast<To>(n);
}