diff --git a/libcxx/include/__numeric/clamp_to_integral.h b/libcxx/include/__numeric/clamp_to_integral.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__numeric/clamp_to_integral.h @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___NUMERIC_CLAMP_TO_INTEGRAL_H +#define _LIBCPP___NUMERIC_CLAMP_TO_INTEGRAL_H + +#include <__config> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template ::digits > numeric_limits<_IntT>::digits), + int _Bits = (numeric_limits<_IntT>::digits - numeric_limits<_FloatT>::digits)> +_LIBCPP_INLINE_VISIBILITY +_LIBCPP_CONSTEXPR _IntT __max_representable_int_for_float() _NOEXCEPT { + static_assert(is_floating_point<_FloatT>::value, "must be a floating point type"); + static_assert(is_integral<_IntT>::value, "must be an integral type"); + static_assert(numeric_limits<_FloatT>::radix == 2, "FloatT has incorrect radix"); + static_assert((_IsSame<_FloatT, float>::value || _IsSame<_FloatT, double>::value + || _IsSame<_FloatT,long double>::value), "unsupported floating point type"); + return _FloatBigger ? numeric_limits<_IntT>::max() : (numeric_limits<_IntT>::max() >> _Bits << _Bits); +} + +// Convert a floating point number to the specified integral type after +// clamping to the integral types representable range. +// +// The behavior is undefined if `__r` is NaN. +template +_LIBCPP_INLINE_VISIBILITY +_IntT __clamp_to_integral(_RealT __r) _NOEXCEPT { + using _Lim = numeric_limits<_IntT>; + const _IntT _MaxVal = __max_representable_int_for_float<_IntT, _RealT>(); + if (__r >= ::nextafter(static_cast<_RealT>(_MaxVal), INFINITY)) { + return _Lim::max(); + } else if (__r <= _Lim::lowest()) { + return _Lim::min(); + } + return static_cast<_IntT>(__r); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___NUMERIC_CLAMP_TO_INTEGRAL_H diff --git a/libcxx/include/__random/poisson_distribution.h b/libcxx/include/__random/poisson_distribution.h --- a/libcxx/include/__random/poisson_distribution.h +++ b/libcxx/include/__random/poisson_distribution.h @@ -10,6 +10,7 @@ #define _LIBCPP___RANDOM_POISSON_DISTRIBUTION_H #include <__config> +#include <__numeric/clamp_to_integral.h> #include <__random/exponential_distribution.h> #include <__random/normal_distribution.h> #include <__random/uniform_real_distribution.h> diff --git a/libcxx/include/cmath b/libcxx/include/cmath --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -638,36 +638,6 @@ #endif // _LIBCPP_STD_VER > 17 -template ::digits > numeric_limits<_IntT>::digits), - int _Bits = (numeric_limits<_IntT>::digits - numeric_limits<_FloatT>::digits)> -_LIBCPP_INLINE_VISIBILITY -_LIBCPP_CONSTEXPR _IntT __max_representable_int_for_float() _NOEXCEPT { - static_assert(is_floating_point<_FloatT>::value, "must be a floating point type"); - static_assert(is_integral<_IntT>::value, "must be an integral type"); - static_assert(numeric_limits<_FloatT>::radix == 2, "FloatT has incorrect radix"); - static_assert((_IsSame<_FloatT, float>::value || _IsSame<_FloatT, double>::value - || _IsSame<_FloatT,long double>::value), "unsupported floating point type"); - return _FloatBigger ? numeric_limits<_IntT>::max() : (numeric_limits<_IntT>::max() >> _Bits << _Bits); -} - -// Convert a floating point number to the specified integral type after -// clamping to the integral types representable range. -// -// The behavior is undefined if `__r` is NaN. -template -_LIBCPP_INLINE_VISIBILITY -_IntT __clamp_to_integral(_RealT __r) _NOEXCEPT { - using _Lim = numeric_limits<_IntT>; - const _IntT _MaxVal = __max_representable_int_for_float<_IntT, _RealT>(); - if (__r >= ::nextafter(static_cast<_RealT>(_MaxVal), INFINITY)) { - return _Lim::max(); - } else if (__r <= _Lim::lowest()) { - return _Lim::min(); - } - return static_cast<_IntT>(__r); -} - _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -667,6 +667,7 @@ module __numeric { module accumulate { private header "__numeric/accumulate.h" } module adjacent_difference { private header "__numeric/adjacent_difference.h" } + module clamp_to_integral { private header "__numeric/clamp_to_integral.h" } module exclusive_scan { private header "__numeric/exclusive_scan.h" } module gcd_lcm { private header "__numeric/gcd_lcm.h" } module inclusive_scan { private header "__numeric/inclusive_scan.h" } diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/numeric/clamp_to_integral.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/numeric/clamp_to_integral.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/numeric/clamp_to_integral.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__numeric/clamp_to_integral.h'}} +#include <__numeric/clamp_to_integral.h> diff --git a/libcxx/test/libcxx/numerics/clamp_to_integral.pass.cpp b/libcxx/test/libcxx/numerics/clamp_to_integral.pass.cpp --- a/libcxx/test/libcxx/numerics/clamp_to_integral.pass.cpp +++ b/libcxx/test/libcxx/numerics/clamp_to_integral.pass.cpp @@ -12,9 +12,10 @@ // closest representable value for the specified integer type, or // numeric_limits::max()/min() if the value isn't representable. -#include #include #include +#include +#include template void test() {