103c19e91SHristo Hristov // -*- C++ -*-
203c19e91SHristo Hristov //===----------------------------------------------------------------------===//
303c19e91SHristo Hristov //
403c19e91SHristo Hristov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
503c19e91SHristo Hristov // See https://llvm.org/LICENSE.txt for license information.
603c19e91SHristo Hristov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
703c19e91SHristo Hristov //
803c19e91SHristo Hristov //===----------------------------------------------------------------------===//
903c19e91SHristo Hristov
1003c19e91SHristo Hristov #ifndef _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H
1103c19e91SHristo Hristov #define _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H
1203c19e91SHristo Hristov
1337dca605SLouis Dionne #include <__assert>
1403c19e91SHristo Hristov #include <__concepts/arithmetic.h>
1503c19e91SHristo Hristov #include <__config>
1603c19e91SHristo Hristov #include <__utility/cmp.h>
1703c19e91SHristo Hristov #include <limits>
1803c19e91SHristo Hristov
1903c19e91SHristo Hristov #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2003c19e91SHristo Hristov # pragma GCC system_header
2103c19e91SHristo Hristov #endif
2203c19e91SHristo Hristov
237b462251SLouis Dionne _LIBCPP_PUSH_MACROS
247b462251SLouis Dionne #include <__undef_macros>
257b462251SLouis Dionne
2603c19e91SHristo Hristov _LIBCPP_BEGIN_NAMESPACE_STD
2703c19e91SHristo Hristov
28*31e769cfSMark de Wever #if _LIBCPP_STD_VER >= 20
2903c19e91SHristo Hristov
3003c19e91SHristo Hristov template <__libcpp_integer _Tp>
__add_sat(_Tp __x,_Tp __y)31*31e769cfSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr _Tp __add_sat(_Tp __x, _Tp __y) noexcept {
3203c19e91SHristo Hristov if (_Tp __sum; !__builtin_add_overflow(__x, __y, &__sum))
3303c19e91SHristo Hristov return __sum;
3403c19e91SHristo Hristov // Handle overflow
3503c19e91SHristo Hristov if constexpr (__libcpp_unsigned_integer<_Tp>) {
3603c19e91SHristo Hristov return std::numeric_limits<_Tp>::max();
3703c19e91SHristo Hristov } else {
3803c19e91SHristo Hristov // Signed addition overflow
3903c19e91SHristo Hristov if (__x > 0)
4003c19e91SHristo Hristov // Overflows if (x > 0 && y > 0)
4103c19e91SHristo Hristov return std::numeric_limits<_Tp>::max();
4203c19e91SHristo Hristov else
4303c19e91SHristo Hristov // Overflows if (x < 0 && y < 0)
4403c19e91SHristo Hristov return std::numeric_limits<_Tp>::min();
4503c19e91SHristo Hristov }
4603c19e91SHristo Hristov }
4703c19e91SHristo Hristov
4803c19e91SHristo Hristov template <__libcpp_integer _Tp>
__sub_sat(_Tp __x,_Tp __y)49*31e769cfSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr _Tp __sub_sat(_Tp __x, _Tp __y) noexcept {
5003c19e91SHristo Hristov if (_Tp __sub; !__builtin_sub_overflow(__x, __y, &__sub))
5103c19e91SHristo Hristov return __sub;
5203c19e91SHristo Hristov // Handle overflow
5303c19e91SHristo Hristov if constexpr (__libcpp_unsigned_integer<_Tp>) {
5403c19e91SHristo Hristov // Overflows if (x < y)
5503c19e91SHristo Hristov return std::numeric_limits<_Tp>::min();
5603c19e91SHristo Hristov } else {
5703c19e91SHristo Hristov // Signed subtration overflow
5803c19e91SHristo Hristov if (__x >= 0)
5903c19e91SHristo Hristov // Overflows if (x >= 0 && y < 0)
6003c19e91SHristo Hristov return std::numeric_limits<_Tp>::max();
6103c19e91SHristo Hristov else
6203c19e91SHristo Hristov // Overflows if (x < 0 && y > 0)
6303c19e91SHristo Hristov return std::numeric_limits<_Tp>::min();
6403c19e91SHristo Hristov }
6503c19e91SHristo Hristov }
6603c19e91SHristo Hristov
6703c19e91SHristo Hristov template <__libcpp_integer _Tp>
__mul_sat(_Tp __x,_Tp __y)68*31e769cfSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr _Tp __mul_sat(_Tp __x, _Tp __y) noexcept {
6903c19e91SHristo Hristov if (_Tp __mul; !__builtin_mul_overflow(__x, __y, &__mul))
7003c19e91SHristo Hristov return __mul;
7103c19e91SHristo Hristov // Handle overflow
7203c19e91SHristo Hristov if constexpr (__libcpp_unsigned_integer<_Tp>) {
7303c19e91SHristo Hristov return std::numeric_limits<_Tp>::max();
7403c19e91SHristo Hristov } else {
7503c19e91SHristo Hristov // Signed multiplication overflow
7603c19e91SHristo Hristov if ((__x > 0 && __y > 0) || (__x < 0 && __y < 0))
7703c19e91SHristo Hristov return std::numeric_limits<_Tp>::max();
7803c19e91SHristo Hristov // Overflows if (x < 0 && y > 0) || (x > 0 && y < 0)
7903c19e91SHristo Hristov return std::numeric_limits<_Tp>::min();
8003c19e91SHristo Hristov }
8103c19e91SHristo Hristov }
8203c19e91SHristo Hristov
8303c19e91SHristo Hristov template <__libcpp_integer _Tp>
__div_sat(_Tp __x,_Tp __y)84*31e769cfSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr _Tp __div_sat(_Tp __x, _Tp __y) noexcept {
8503c19e91SHristo Hristov _LIBCPP_ASSERT_UNCATEGORIZED(__y != 0, "Division by 0 is undefined");
8603c19e91SHristo Hristov if constexpr (__libcpp_unsigned_integer<_Tp>) {
8703c19e91SHristo Hristov return __x / __y;
8803c19e91SHristo Hristov } else {
8903c19e91SHristo Hristov // Handle signed division overflow
9003c19e91SHristo Hristov if (__x == std::numeric_limits<_Tp>::min() && __y == _Tp{-1})
9103c19e91SHristo Hristov return std::numeric_limits<_Tp>::max();
9203c19e91SHristo Hristov return __x / __y;
9303c19e91SHristo Hristov }
9403c19e91SHristo Hristov }
9503c19e91SHristo Hristov
9603c19e91SHristo Hristov template <__libcpp_integer _Rp, __libcpp_integer _Tp>
__saturate_cast(_Tp __x)97*31e769cfSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr _Rp __saturate_cast(_Tp __x) noexcept {
9803c19e91SHristo Hristov // Saturation is impossible edge case when ((min _Rp) < (min _Tp) && (max _Rp) > (max _Tp)) and it is expected to be
9903c19e91SHristo Hristov // optimized out by the compiler.
10003c19e91SHristo Hristov
10103c19e91SHristo Hristov // Handle overflow
10203c19e91SHristo Hristov if (std::cmp_less(__x, std::numeric_limits<_Rp>::min()))
10303c19e91SHristo Hristov return std::numeric_limits<_Rp>::min();
10403c19e91SHristo Hristov if (std::cmp_greater(__x, std::numeric_limits<_Rp>::max()))
10503c19e91SHristo Hristov return std::numeric_limits<_Rp>::max();
10603c19e91SHristo Hristov // No overflow
10703c19e91SHristo Hristov return static_cast<_Rp>(__x);
10803c19e91SHristo Hristov }
10903c19e91SHristo Hristov
110*31e769cfSMark de Wever #endif // _LIBCPP_STD_VER >= 20
111*31e769cfSMark de Wever
112*31e769cfSMark de Wever #if _LIBCPP_STD_VER >= 26
113*31e769cfSMark de Wever
114*31e769cfSMark de Wever template <__libcpp_integer _Tp>
add_sat(_Tp __x,_Tp __y)115*31e769cfSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr _Tp add_sat(_Tp __x, _Tp __y) noexcept {
116*31e769cfSMark de Wever return std::__add_sat(__x, __y);
117*31e769cfSMark de Wever }
118*31e769cfSMark de Wever
119*31e769cfSMark de Wever template <__libcpp_integer _Tp>
sub_sat(_Tp __x,_Tp __y)120*31e769cfSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr _Tp sub_sat(_Tp __x, _Tp __y) noexcept {
121*31e769cfSMark de Wever return std::__sub_sat(__x, __y);
122*31e769cfSMark de Wever }
123*31e769cfSMark de Wever
124*31e769cfSMark de Wever template <__libcpp_integer _Tp>
mul_sat(_Tp __x,_Tp __y)125*31e769cfSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr _Tp mul_sat(_Tp __x, _Tp __y) noexcept {
126*31e769cfSMark de Wever return std::__mul_sat(__x, __y);
127*31e769cfSMark de Wever }
128*31e769cfSMark de Wever
129*31e769cfSMark de Wever template <__libcpp_integer _Tp>
div_sat(_Tp __x,_Tp __y)130*31e769cfSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr _Tp div_sat(_Tp __x, _Tp __y) noexcept {
131*31e769cfSMark de Wever return std::__div_sat(__x, __y);
132*31e769cfSMark de Wever }
133*31e769cfSMark de Wever
134*31e769cfSMark de Wever template <__libcpp_integer _Rp, __libcpp_integer _Tp>
saturate_cast(_Tp __x)135*31e769cfSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr _Rp saturate_cast(_Tp __x) noexcept {
136*31e769cfSMark de Wever return std::__saturate_cast<_Rp>(__x);
137*31e769cfSMark de Wever }
138*31e769cfSMark de Wever
13903c19e91SHristo Hristov #endif // _LIBCPP_STD_VER >= 26
14003c19e91SHristo Hristov
14103c19e91SHristo Hristov _LIBCPP_END_NAMESPACE_STD
14203c19e91SHristo Hristov
1437b462251SLouis Dionne _LIBCPP_POP_MACROS
1447b462251SLouis Dionne
14503c19e91SHristo Hristov #endif // _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H
146