xref: /freebsd/contrib/llvm-project/libcxx/include/__random/clamp_to_integral.h (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
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