master
  1// -*- C++ -*-
  2//===----------------------------------------------------------------------===//
  3//
  4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  5// See https://llvm.org/LICENSE.txt for license information.
  6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  7//
  8//===----------------------------------------------------------------------===//
  9
 10#ifndef _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H
 11#define _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H
 12
 13#include <__assert>
 14#include <__config>
 15#include <__memory/addressof.h>
 16#include <__type_traits/integer_traits.h>
 17#include <__utility/cmp.h>
 18#include <limits>
 19
 20#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 21#  pragma GCC system_header
 22#endif
 23
 24_LIBCPP_PUSH_MACROS
 25#include <__undef_macros>
 26
 27_LIBCPP_BEGIN_NAMESPACE_STD
 28
 29#if _LIBCPP_STD_VER >= 20
 30
 31template <__signed_or_unsigned_integer _Tp>
 32_LIBCPP_HIDE_FROM_ABI constexpr _Tp __add_sat(_Tp __x, _Tp __y) noexcept {
 33  if (_Tp __sum; !__builtin_add_overflow(__x, __y, std::addressof(__sum)))
 34    return __sum;
 35  // Handle overflow
 36  if constexpr (__unsigned_integer<_Tp>) {
 37    return std::numeric_limits<_Tp>::max();
 38  } else {
 39    // Signed addition overflow
 40    if (__x > 0)
 41      // Overflows if (x > 0 && y > 0)
 42      return std::numeric_limits<_Tp>::max();
 43    else
 44      // Overflows if  (x < 0 && y < 0)
 45      return std::numeric_limits<_Tp>::min();
 46  }
 47}
 48
 49template <__signed_or_unsigned_integer _Tp>
 50_LIBCPP_HIDE_FROM_ABI constexpr _Tp __sub_sat(_Tp __x, _Tp __y) noexcept {
 51  if (_Tp __sub; !__builtin_sub_overflow(__x, __y, std::addressof(__sub)))
 52    return __sub;
 53  // Handle overflow
 54  if constexpr (__unsigned_integer<_Tp>) {
 55    // Overflows if (x < y)
 56    return std::numeric_limits<_Tp>::min();
 57  } else {
 58    // Signed subtration overflow
 59    if (__x >= 0)
 60      // Overflows if (x >= 0 && y < 0)
 61      return std::numeric_limits<_Tp>::max();
 62    else
 63      // Overflows if (x < 0 && y > 0)
 64      return std::numeric_limits<_Tp>::min();
 65  }
 66}
 67
 68template <__signed_or_unsigned_integer _Tp>
 69_LIBCPP_HIDE_FROM_ABI constexpr _Tp __mul_sat(_Tp __x, _Tp __y) noexcept {
 70  if (_Tp __mul; !__builtin_mul_overflow(__x, __y, std::addressof(__mul)))
 71    return __mul;
 72  // Handle overflow
 73  if constexpr (__unsigned_integer<_Tp>) {
 74    return std::numeric_limits<_Tp>::max();
 75  } else {
 76    // Signed multiplication overflow
 77    if ((__x > 0 && __y > 0) || (__x < 0 && __y < 0))
 78      return std::numeric_limits<_Tp>::max();
 79    // Overflows if (x < 0 && y > 0) || (x > 0 && y < 0)
 80    return std::numeric_limits<_Tp>::min();
 81  }
 82}
 83
 84template <__signed_or_unsigned_integer _Tp>
 85_LIBCPP_HIDE_FROM_ABI constexpr _Tp __div_sat(_Tp __x, _Tp __y) noexcept {
 86  _LIBCPP_ASSERT_UNCATEGORIZED(__y != 0, "Division by 0 is undefined");
 87  if constexpr (__unsigned_integer<_Tp>) {
 88    return __x / __y;
 89  } else {
 90    // Handle signed division overflow
 91    if (__x == std::numeric_limits<_Tp>::min() && __y == _Tp{-1})
 92      return std::numeric_limits<_Tp>::max();
 93    return __x / __y;
 94  }
 95}
 96
 97template <__signed_or_unsigned_integer _Rp, __signed_or_unsigned_integer _Tp>
 98_LIBCPP_HIDE_FROM_ABI constexpr _Rp __saturate_cast(_Tp __x) noexcept {
 99  // Saturation is impossible edge case when ((min _Rp) < (min _Tp) && (max _Rp) > (max _Tp)) and it is expected to be
100  // optimized out by the compiler.
101
102  // Handle overflow
103  if (std::cmp_less(__x, std::numeric_limits<_Rp>::min()))
104    return std::numeric_limits<_Rp>::min();
105  if (std::cmp_greater(__x, std::numeric_limits<_Rp>::max()))
106    return std::numeric_limits<_Rp>::max();
107  // No overflow
108  return static_cast<_Rp>(__x);
109}
110
111#endif // _LIBCPP_STD_VER >= 20
112
113#if _LIBCPP_STD_VER >= 26
114
115template <__signed_or_unsigned_integer _Tp>
116_LIBCPP_HIDE_FROM_ABI constexpr _Tp add_sat(_Tp __x, _Tp __y) noexcept {
117  return std::__add_sat(__x, __y);
118}
119
120template <__signed_or_unsigned_integer _Tp>
121_LIBCPP_HIDE_FROM_ABI constexpr _Tp sub_sat(_Tp __x, _Tp __y) noexcept {
122  return std::__sub_sat(__x, __y);
123}
124
125template <__signed_or_unsigned_integer _Tp>
126_LIBCPP_HIDE_FROM_ABI constexpr _Tp mul_sat(_Tp __x, _Tp __y) noexcept {
127  return std::__mul_sat(__x, __y);
128}
129
130template <__signed_or_unsigned_integer _Tp>
131_LIBCPP_HIDE_FROM_ABI constexpr _Tp div_sat(_Tp __x, _Tp __y) noexcept {
132  return std::__div_sat(__x, __y);
133}
134
135template <__signed_or_unsigned_integer _Rp, __signed_or_unsigned_integer _Tp>
136_LIBCPP_HIDE_FROM_ABI constexpr _Rp saturate_cast(_Tp __x) noexcept {
137  return std::__saturate_cast<_Rp>(__x);
138}
139
140#endif // _LIBCPP_STD_VER >= 26
141
142_LIBCPP_END_NAMESPACE_STD
143
144_LIBCPP_POP_MACROS
145
146#endif // _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H