10eae32dcSDimitry Andric //===----------------------------------------------------------------------===// 20eae32dcSDimitry Andric // 30eae32dcSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40eae32dcSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50eae32dcSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60eae32dcSDimitry Andric // 70eae32dcSDimitry Andric //===----------------------------------------------------------------------===// 80eae32dcSDimitry Andric 90eae32dcSDimitry Andric #ifndef _LIBCPP___RANDOM_CLAMP_TO_INTEGRAL_H 100eae32dcSDimitry Andric #define _LIBCPP___RANDOM_CLAMP_TO_INTEGRAL_H 110eae32dcSDimitry Andric 120eae32dcSDimitry Andric #include <__config> 130eae32dcSDimitry Andric #include <cmath> 140eae32dcSDimitry Andric #include <limits> 150eae32dcSDimitry Andric 160eae32dcSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 170eae32dcSDimitry Andric # pragma GCC system_header 180eae32dcSDimitry Andric #endif 190eae32dcSDimitry Andric 200eae32dcSDimitry Andric _LIBCPP_PUSH_MACROS 210eae32dcSDimitry Andric #include <__undef_macros> 220eae32dcSDimitry Andric 230eae32dcSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 240eae32dcSDimitry Andric 25*cb14a3feSDimitry Andric template <class _IntT, 26*cb14a3feSDimitry Andric class _FloatT, 270eae32dcSDimitry Andric bool _FloatBigger = (numeric_limits<_FloatT>::digits > numeric_limits<_IntT>::digits), 280eae32dcSDimitry Andric int _Bits = (numeric_limits<_IntT>::digits - numeric_limits<_FloatT>::digits)> 29*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _IntT __max_representable_int_for_float() _NOEXCEPT { 300eae32dcSDimitry Andric static_assert(is_floating_point<_FloatT>::value, "must be a floating point type"); 310eae32dcSDimitry Andric static_assert(is_integral<_IntT>::value, "must be an integral type"); 320eae32dcSDimitry Andric static_assert(numeric_limits<_FloatT>::radix == 2, "FloatT has incorrect radix"); 33*cb14a3feSDimitry Andric static_assert( 34*cb14a3feSDimitry Andric (_IsSame<_FloatT, float>::value || _IsSame<_FloatT, double>::value || _IsSame<_FloatT, long double>::value), 35*cb14a3feSDimitry Andric "unsupported floating point type"); 360eae32dcSDimitry Andric return _FloatBigger ? numeric_limits<_IntT>::max() : (numeric_limits<_IntT>::max() >> _Bits << _Bits); 370eae32dcSDimitry Andric } 380eae32dcSDimitry Andric 390eae32dcSDimitry Andric // Convert a floating point number to the specified integral type after 400eae32dcSDimitry Andric // clamping to the integral type's representable range. 410eae32dcSDimitry Andric // 420eae32dcSDimitry Andric // The behavior is undefined if `__r` is NaN. 430eae32dcSDimitry Andric template <class _IntT, class _RealT> 44*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _IntT __clamp_to_integral(_RealT __r) _NOEXCEPT { 450eae32dcSDimitry Andric using _Lim = numeric_limits<_IntT>; 4606c3fb27SDimitry Andric const _IntT __max_val = __max_representable_int_for_float<_IntT, _RealT>(); 4706c3fb27SDimitry Andric if (__r >= ::nextafter(static_cast<_RealT>(__max_val), INFINITY)) { 480eae32dcSDimitry Andric return _Lim::max(); 490eae32dcSDimitry Andric } else if (__r <= _Lim::lowest()) { 500eae32dcSDimitry Andric return _Lim::min(); 510eae32dcSDimitry Andric } 520eae32dcSDimitry Andric return static_cast<_IntT>(__r); 530eae32dcSDimitry Andric } 540eae32dcSDimitry Andric 550eae32dcSDimitry Andric _LIBCPP_END_NAMESPACE_STD 560eae32dcSDimitry Andric 570eae32dcSDimitry Andric _LIBCPP_POP_MACROS 580eae32dcSDimitry Andric 590eae32dcSDimitry Andric #endif // _LIBCPP___RANDOM_CLAMP_TO_INTEGRAL_H 60