[libc++][math] Add constexpr to std::fpclassify (#210993)
Adds `constexpr` to `std::fpclassify` as required by
[P0533R9](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0533r9.pdf).
Towards https://github.com/llvm/llvm-project/issues/105174. Follows-up
8889a3d3b5.
This commit is contained in:
parent
3fd07e3235
commit
4eeff3e309
5 changed files with 118 additions and 15 deletions
|
|
@ -138,7 +138,7 @@ long double tanhl(long double x);
|
|||
|
||||
bool signbit(arithmetic x);
|
||||
|
||||
int fpclassify(arithmetic x);
|
||||
int fpclassify(arithmetic x); // constexpr since C++23
|
||||
|
||||
bool isfinite(arithmetic x);
|
||||
bool isinf(arithmetic x);
|
||||
|
|
|
|||
|
|
@ -387,26 +387,50 @@ namespace __math {
|
|||
|
||||
// fpclassify
|
||||
|
||||
// template on non-double overloads to make them weaker than same overloads from MSVC runtime
|
||||
template <class = int>
|
||||
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI int fpclassify(float __x) _NOEXCEPT {
|
||||
# ifdef _LIBCPP_PREFERRED_OVERLOAD
|
||||
[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD int fpclassify(float __x) _NOEXCEPT {
|
||||
return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x);
|
||||
}
|
||||
|
||||
template <class = int>
|
||||
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI int fpclassify(double __x) _NOEXCEPT {
|
||||
[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD int
|
||||
fpclassify(double __x) _NOEXCEPT {
|
||||
return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x);
|
||||
}
|
||||
|
||||
template <class = int>
|
||||
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI int fpclassify(long double __x) _NOEXCEPT {
|
||||
[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD int
|
||||
fpclassify(long double __x) _NOEXCEPT {
|
||||
return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x);
|
||||
}
|
||||
|
||||
template <class _A1, std::__enable_if_t<std::is_integral<_A1>::value, int> = 0>
|
||||
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI int fpclassify(_A1 __x) _NOEXCEPT {
|
||||
[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD int
|
||||
fpclassify(_A1 __x) _NOEXCEPT {
|
||||
return __x == 0 ? FP_ZERO : FP_NORMAL;
|
||||
}
|
||||
# else
|
||||
|
||||
// template on non-double overloads to make them weaker than same overloads from MSVC runtime
|
||||
template <class = int>
|
||||
[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int fpclassify(float __x) _NOEXCEPT {
|
||||
return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x);
|
||||
}
|
||||
|
||||
template <class = int>
|
||||
[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int fpclassify(double __x) _NOEXCEPT {
|
||||
return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x);
|
||||
}
|
||||
|
||||
template <class = int>
|
||||
[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int fpclassify(long double __x) _NOEXCEPT {
|
||||
return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x);
|
||||
}
|
||||
|
||||
template <class _A1, std::__enable_if_t<std::is_integral<_A1>::value, int> = 0>
|
||||
[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int fpclassify(_A1 __x) _NOEXCEPT {
|
||||
return __x == 0 ? FP_ZERO : FP_NORMAL;
|
||||
}
|
||||
# endif
|
||||
|
||||
} // namespace __math
|
||||
|
||||
|
|
|
|||
|
|
@ -203,9 +203,9 @@ int main(int, char**) {
|
|||
ASSERT_NOT_CONSTEXPR_CXX23(std::fmaf(1.0f, 1.0f, 1.0f) == 2.0f);
|
||||
ASSERT_NOT_CONSTEXPR_CXX23(std::fmal(1.0L, 1.0L, 1.0L) == 2.0L);
|
||||
|
||||
ASSERT_NOT_CONSTEXPR_CXX23(std::fpclassify(-1.0f) == FP_NORMAL);
|
||||
ASSERT_NOT_CONSTEXPR_CXX23(std::fpclassify(-1.0) == FP_NORMAL);
|
||||
ASSERT_NOT_CONSTEXPR_CXX23(std::fpclassify(-1.0L) == FP_NORMAL);
|
||||
ASSERT_CONSTEXPR_CXX23(std::fpclassify(-1.0f) == FP_NORMAL);
|
||||
ASSERT_CONSTEXPR_CXX23(std::fpclassify(-1.0) == FP_NORMAL);
|
||||
ASSERT_CONSTEXPR_CXX23(std::fpclassify(-1.0L) == FP_NORMAL);
|
||||
|
||||
ASSERT_CONSTEXPR_CXX23(std::isfinite(-1.0f) == 1);
|
||||
ASSERT_CONSTEXPR_CXX23(std::isfinite(-1.0) == 1);
|
||||
|
|
|
|||
|
|
@ -197,9 +197,9 @@ int main(int, char**) {
|
|||
ASSERT_CONSTEXPR_CXX23(std::fmaf(1.0f, 1.0f, 1.0f) == 2.0f);
|
||||
ASSERT_CONSTEXPR_CXX23(std::fmal(1.0L, 1.0L, 1.0L) == 2.0L);
|
||||
|
||||
ASSERT_NOT_CONSTEXPR_CXX23(std::fpclassify(-1.0f) == FP_NORMAL);
|
||||
ASSERT_NOT_CONSTEXPR_CXX23(std::fpclassify(-1.0) == FP_NORMAL);
|
||||
ASSERT_NOT_CONSTEXPR_CXX23(std::fpclassify(-1.0L) == FP_NORMAL);
|
||||
ASSERT_CONSTEXPR_CXX23(std::fpclassify(-1.0f) == FP_NORMAL);
|
||||
ASSERT_CONSTEXPR_CXX23(std::fpclassify(-1.0) == FP_NORMAL);
|
||||
ASSERT_CONSTEXPR_CXX23(std::fpclassify(-1.0L) == FP_NORMAL);
|
||||
|
||||
ASSERT_CONSTEXPR_CXX23(std::isfinite(-1.0f) == 1);
|
||||
ASSERT_CONSTEXPR_CXX23(std::isfinite(-1.0) == 1);
|
||||
|
|
|
|||
79
libcxx/test/std/numerics/c.math/fpclassify.pass.cpp
Normal file
79
libcxx/test/std/numerics/c.math/fpclassify.pass.cpp
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// bool fpclassify(floating-point-type x); // constexpr since C++23
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "type_algorithms.h"
|
||||
|
||||
struct TestFloat {
|
||||
template <class T>
|
||||
TEST_CONSTEXPR_CXX23 void operator()() const {
|
||||
using lim = std::numeric_limits<T>;
|
||||
TEST_CONSTEXPR_CXX23 T max = lim::max();
|
||||
TEST_CONSTEXPR_CXX23 T min = lim::min();
|
||||
TEST_CONSTEXPR_CXX23 T d_min = lim::denorm_min();
|
||||
TEST_CONSTEXPR_CXX23 T inf = lim::infinity();
|
||||
TEST_CONSTEXPR_CXX23 T nan = lim::quiet_NaN();
|
||||
TEST_CONSTEXPR_CXX23 T s_nan = lim::signaling_NaN();
|
||||
|
||||
assert(std::fpclassify(nan) == FP_NAN);
|
||||
assert(std::fpclassify(s_nan) == FP_NAN);
|
||||
|
||||
assert(std::fpclassify(inf) == FP_INFINITE);
|
||||
assert(std::fpclassify(-inf) == FP_INFINITE);
|
||||
|
||||
assert(std::fpclassify(T(1)) == FP_NORMAL);
|
||||
assert(std::fpclassify(T(-1)) == FP_NORMAL);
|
||||
assert(std::fpclassify(max) == FP_NORMAL);
|
||||
assert(std::fpclassify(min) == FP_NORMAL);
|
||||
|
||||
assert(std::fpclassify(d_min) == FP_SUBNORMAL);
|
||||
|
||||
assert(std::fpclassify(T(0)) == FP_ZERO);
|
||||
assert(std::fpclassify(T(-0.0)) == FP_ZERO);
|
||||
}
|
||||
};
|
||||
|
||||
struct TestInt {
|
||||
template <class T>
|
||||
TEST_CONSTEXPR_CXX23 void operator()() const {
|
||||
using lim = std::numeric_limits<T>;
|
||||
TEST_CONSTEXPR_CXX23 T max = lim::max();
|
||||
TEST_CONSTEXPR_CXX23 T low = lim::lowest();
|
||||
|
||||
assert(std::fpclassify(T(0)) == FP_ZERO);
|
||||
assert(std::fpclassify(T(1)) == FP_NORMAL);
|
||||
assert(std::fpclassify(max) == FP_NORMAL);
|
||||
|
||||
if (std::is_signed<T>::value) {
|
||||
assert(std::fpclassify(low) == FP_NORMAL);
|
||||
assert(std::fpclassify(T(-1)) == FP_NORMAL);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CONSTEXPR_CXX23 bool test() {
|
||||
types::for_each(types::floating_point_types(), TestFloat());
|
||||
types::for_each(types::integral_types(), TestInt());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
#if TEST_STD_VER >= 23
|
||||
static_assert(test());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in a new issue