[libcxx-commits] [libcxx] [libc++][numeric] P4052R0: Renaming saturation arithmetic functions (PR #189574)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Wed Apr 1 01:05:43 PDT 2026


================
@@ -0,0 +1,177 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <numeric>
+
+// template<class T>
+// constexpr T saturating_mul(T x, T y) noexcept;                     // freestanding
+
+#include <cassert>
+#include <concepts>
+#include <limits>
+#include <numeric>
+
+#include "test_macros.h"
+
+template <typename IntegerT>
+constexpr bool test_signed() {
+  constexpr auto minVal = std::numeric_limits<IntegerT>::min();
+  constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
+
+  std::same_as<IntegerT> decltype(auto) _ = std::saturating_mul(minVal, maxVal);
+
+  static_assert(noexcept(std::saturating_mul(minVal, maxVal)));
+
+  // clang-format off
+
+  // Limit values (-1, 0, 1, min, max)
+
+  assert(std::saturating_mul(IntegerT{-1}, IntegerT{-1}) == IntegerT{ 1});
+  assert(std::saturating_mul(IntegerT{-1}, IntegerT{ 0}) == IntegerT{ 0});
+  assert(std::saturating_mul(IntegerT{-1}, IntegerT{ 1}) == IntegerT{-1});
+  assert(std::saturating_mul(IntegerT{-1},       minVal) == maxVal); // saturated
+  assert(std::saturating_mul(IntegerT{-1},       maxVal) == -maxVal);
+
+  assert(std::saturating_mul(IntegerT{ 0}, IntegerT{-1}) == IntegerT{ 0});
+  assert(std::saturating_mul(IntegerT{ 0}, IntegerT{ 0}) == IntegerT{ 0});
+  assert(std::saturating_mul(IntegerT{ 0}, IntegerT{ 1}) == IntegerT{ 0});
+  assert(std::saturating_mul(IntegerT{ 0},       minVal) == IntegerT{ 0});
+  assert(std::saturating_mul(IntegerT{ 0},       maxVal) == IntegerT{ 0});
+
+  assert(std::saturating_mul(IntegerT{ 1}, IntegerT{-1}) == IntegerT{-1});
+  assert(std::saturating_mul(IntegerT{ 1}, IntegerT{ 0}) == IntegerT{ 0});
+  assert(std::saturating_mul(IntegerT{ 1}, IntegerT{ 1}) == IntegerT{ 1});
+  assert(std::saturating_mul(IntegerT{ 1},       minVal) == minVal);
+  assert(std::saturating_mul(IntegerT{ 1},       maxVal) == maxVal);
+
+  assert(std::saturating_mul(      minVal, IntegerT{-1}) == maxVal); // saturated
+  assert(std::saturating_mul(      minVal, IntegerT{ 0}) == IntegerT{ 0});
+  assert(std::saturating_mul(      minVal, IntegerT{ 1}) == minVal);
+  assert(std::saturating_mul(      minVal,       minVal) == maxVal); // saturated
+  assert(std::saturating_mul(      minVal,       maxVal) == minVal); // saturated
+
+  assert(std::saturating_mul(      maxVal, IntegerT{-1}) == -maxVal);
+  assert(std::saturating_mul(      maxVal, IntegerT{ 0}) == IntegerT{ 0});
+  assert(std::saturating_mul(      maxVal, IntegerT{ 1}) == maxVal); // saturated
+  assert(std::saturating_mul(      maxVal,       minVal) == minVal); // saturated
+  assert(std::saturating_mul(      maxVal,       maxVal) == maxVal); // saturated
+
+  // No saturation (no limit values)
+
+  assert(std::saturating_mul(IntegerT{27}, IntegerT{ 2}) == IntegerT{54});
+  assert(std::saturating_mul(IntegerT{ 2}, IntegerT{28}) == IntegerT{56});
+
+  // Saturation (no limit values)
+
+  {
+    constexpr IntegerT x = minVal / IntegerT{2} + IntegerT{27};
+    constexpr IntegerT y = minVal / IntegerT{2} + IntegerT{28};
+    assert(std::saturating_mul(x, y) == maxVal); // saturated
+  }
+  {
+    constexpr IntegerT x = minVal / IntegerT{2} + IntegerT{27};
+    constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28};
+    assert(std::saturating_mul(x, y) == minVal); // saturated
+  }
+  {
+    constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27};
+    constexpr IntegerT y = minVal / IntegerT{2} + IntegerT{28};
+    assert(std::saturating_mul(x, y) == minVal); // saturated
+  }
+  {
+    constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27};
+    constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28};
+    assert(std::saturating_mul(x, y) == maxVal); // saturated
+  }
+
+  // clang-format on
+
+  return true;
+}
+
+template <typename IntegerT>
+constexpr bool test_unsigned() {
+  constexpr auto minVal = std::numeric_limits<IntegerT>::min();
+  constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
+
+  std::same_as<IntegerT> decltype(auto) _ = std::saturating_mul(minVal, maxVal);
+
+  static_assert(noexcept(std::saturating_mul(minVal, maxVal)));
+
+  // clang-format off
+
+  // No saturation (0, 1)
+
+  assert(std::saturating_mul(IntegerT{0}, IntegerT{0}) == IntegerT{0});
+  assert(std::saturating_mul(IntegerT{0}, IntegerT{1}) == IntegerT{0});
+  assert(std::saturating_mul(IntegerT{0},      minVal) == IntegerT{0});
+  assert(std::saturating_mul(IntegerT{0},      maxVal) == IntegerT{0});
+
+  assert(std::saturating_mul(IntegerT{1}, IntegerT{0}) == IntegerT{0});
+  assert(std::saturating_mul(IntegerT{1}, IntegerT{1}) == IntegerT{1});
+  assert(std::saturating_mul(IntegerT{1},      minVal) == minVal);
+  assert(std::saturating_mul(IntegerT{1},      maxVal) == maxVal);
+
+  assert(std::saturating_mul(     minVal, IntegerT{0}) == IntegerT{0});
+  assert(std::saturating_mul(     minVal, IntegerT{1}) == minVal);
+  assert(std::saturating_mul(     minVal,      maxVal) == minVal);
+  assert(std::saturating_mul(     minVal,      maxVal) == minVal);
+
+  assert(std::saturating_mul(     maxVal, IntegerT{0}) == IntegerT{0});
+  assert(std::saturating_mul(     maxVal, IntegerT{1}) == maxVal);
+  assert(std::saturating_mul(     maxVal,      minVal) == IntegerT{0});
+  assert(std::saturating_mul(     maxVal,      maxVal) == maxVal); // saturated
+
+  // No saturation (no limit values)
+
+  assert(std::saturating_mul(IntegerT{28}, IntegerT{2}) == IntegerT{56});
+
+  // Saturation (no limit values
----------------
H-G-Hristov wrote:

```suggestion
  // Saturation (no limit values)
```

https://github.com/llvm/llvm-project/pull/189574


More information about the libcxx-commits mailing list