cmath: Skip Libc for integral types in isinf, etc.
For std::isinf, the standard requires effectively calling isinf as
double from Libc for integral types. But integral types are never
infinite; we don't need to call Libc to return false.
Also short-circuit other functions where Libc won't have interesting
answers: signbit, fpclassify, isfinite, isnan, and isnormal.
I added correctness tests for integral types since we're no longer
deferring to Libc.
In review it was pointed out that in future revisions of the C++
standard we may add more types to std::is_arithmetic (e.g.,
std::is_fixed_point). I'll leave it to a future commit to hack this to
allow using math functions on those. We'll need to change things like
__libcpp_fpclassify anyway, so I'm not sure anything here would really
be future-proof.
https://reviews.llvm.org/D31561
rdar://problem/31361223
llvm-svn: 301060
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: 42f8eee150bbe361eb5f7a9acfa5838e0661177b
diff --git a/include/math.h b/include/math.h
index 79ebf2f..8c30ba8 100644
--- a/include/math.h
+++ b/include/math.h
@@ -307,6 +307,7 @@
extern "C++" {
#include <type_traits>
+#include <limits>
// signbit
@@ -324,22 +325,50 @@
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
+typename std::enable_if<std::is_floating_point<_A1>::value, bool>::type
signbit(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_signbit((typename std::__promote<_A1>::type)__lcpp_x);
}
+template <class _A1>
+inline _LIBCPP_INLINE_VISIBILITY
+typename std::enable_if<
+ std::is_integral<_A1>::value && std::is_signed<_A1>::value, bool>::type
+signbit(_A1 __lcpp_x) _NOEXCEPT
+{ return __lcpp_x < 0; }
+
+template <class _A1>
+inline _LIBCPP_INLINE_VISIBILITY
+typename std::enable_if<
+ std::is_integral<_A1>::value && !std::is_signed<_A1>::value, bool>::type
+signbit(_A1) _NOEXCEPT
+{ return false; }
+
#elif defined(_LIBCPP_MSVCRT)
template <typename _A1>
inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
+typename std::enable_if<std::is_floating_point<_A1>::value, bool>::type
signbit(_A1 __lcpp_x) _NOEXCEPT
{
return ::signbit(static_cast<typename std::__promote<_A1>::type>(__lcpp_x));
}
+template <class _A1>
+inline _LIBCPP_INLINE_VISIBILITY
+typename std::enable_if<
+ std::is_integral<_A1>::value && std::is_signed<_A1>::value, bool>::type
+signbit(_A1 __lcpp_x) _NOEXCEPT
+{ return __lcpp_x < 0; }
+
+template <class _A1>
+inline _LIBCPP_INLINE_VISIBILITY
+typename std::enable_if<
+ std::is_integral<_A1>::value && !std::is_signed<_A1>::value, bool>::type
+signbit(_A1) _NOEXCEPT
+{ return false; }
+
#endif // signbit
// fpclassify
@@ -358,22 +387,34 @@
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, int>::type
+typename std::enable_if<std::is_floating_point<_A1>::value, int>::type
fpclassify(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_fpclassify((typename std::__promote<_A1>::type)__lcpp_x);
}
+template <class _A1>
+inline _LIBCPP_INLINE_VISIBILITY
+typename std::enable_if<std::is_integral<_A1>::value, int>::type
+fpclassify(_A1 __lcpp_x) _NOEXCEPT
+{ return __lcpp_x == 0 ? FP_ZERO : FP_NORMAL; }
+
#elif defined(_LIBCPP_MSVCRT)
template <typename _A1>
inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, int>::type
+typename std::enable_if<std::is_floating_point<_A1>::value, bool>::type
fpclassify(_A1 __lcpp_x) _NOEXCEPT
{
return ::fpclassify(static_cast<typename std::__promote<_A1>::type>(__lcpp_x));
}
+template <class _A1>
+inline _LIBCPP_INLINE_VISIBILITY
+typename std::enable_if<std::is_integral<_A1>::value, int>::type
+fpclassify(_A1 __lcpp_x) _NOEXCEPT
+{ return __lcpp_x == 0 ? FP_ZERO : FP_NORMAL; }
+
#endif // fpclassify
// isfinite
@@ -392,12 +433,22 @@
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
+typename std::enable_if<
+ std::is_arithmetic<_A1>::value && std::numeric_limits<_A1>::has_infinity,
+ bool>::type
isfinite(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_isfinite((typename std::__promote<_A1>::type)__lcpp_x);
}
+template <class _A1>
+inline _LIBCPP_INLINE_VISIBILITY
+typename std::enable_if<
+ std::is_arithmetic<_A1>::value && !std::numeric_limits<_A1>::has_infinity,
+ bool>::type
+isfinite(_A1) _NOEXCEPT
+{ return true; }
+
#endif // isfinite
// isinf
@@ -416,12 +467,22 @@
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
+typename std::enable_if<
+ std::is_arithmetic<_A1>::value && std::numeric_limits<_A1>::has_infinity,
+ bool>::type
isinf(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_isinf((typename std::__promote<_A1>::type)__lcpp_x);
}
+template <class _A1>
+inline _LIBCPP_INLINE_VISIBILITY
+typename std::enable_if<
+ std::is_arithmetic<_A1>::value && !std::numeric_limits<_A1>::has_infinity,
+ bool>::type
+isinf(_A1) _NOEXCEPT
+{ return false; }
+
#endif // isinf
// isnan
@@ -440,12 +501,18 @@
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
+typename std::enable_if<std::is_floating_point<_A1>::value, bool>::type
isnan(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_isnan((typename std::__promote<_A1>::type)__lcpp_x);
}
+template <class _A1>
+inline _LIBCPP_INLINE_VISIBILITY
+typename std::enable_if<std::is_integral<_A1>::value, bool>::type
+isnan(_A1) _NOEXCEPT
+{ return false; }
+
#endif // isnan
// isnormal
@@ -464,12 +531,18 @@
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
+typename std::enable_if<std::is_floating_point<_A1>::value, bool>::type
isnormal(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_isnormal((typename std::__promote<_A1>::type)__lcpp_x);
}
+template <class _A1>
+inline _LIBCPP_INLINE_VISIBILITY
+typename std::enable_if<std::is_integral<_A1>::value, bool>::type
+isnormal(_A1 __lcpp_x) _NOEXCEPT
+{ return __lcpp_x != 0; }
+
#endif // isnormal
// isgreater