1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// REQUIRES: std-at-least-c++26
10
11// The test uses "Placeholder variables with no name"
12// UNSUPPORTED: apple-clang-15, apple-clang-16
13
14// <numeric>
15
16// template<class T>
17// constexpr T mul_sat(T x, T y) noexcept; // freestanding
18
19#include <cassert>
20#include <concepts>
21#include <limits>
22#include <numeric>
23
24#include "test_macros.h"
25
26template <typename IntegerT>
27constexpr bool test_signed() {
28 constexpr auto minVal = std::numeric_limits<IntegerT>::min();
29 constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
30
31 std::same_as<IntegerT> decltype(auto) _ = std::mul_sat(minVal, maxVal);
32
33 static_assert(noexcept(std::mul_sat(minVal, maxVal)));
34
35 // clang-format off
36
37 // Limit values (-1, 0, 1, min, max)
38
39 assert(std::mul_sat(IntegerT{-1}, IntegerT{-1}) == IntegerT{ 1});
40 assert(std::mul_sat(IntegerT{-1}, IntegerT{ 0}) == IntegerT{ 0});
41 assert(std::mul_sat(IntegerT{-1}, IntegerT{ 1}) == IntegerT{-1});
42 assert(std::mul_sat(IntegerT{-1}, minVal) == maxVal); // saturated
43 assert(std::mul_sat(IntegerT{-1}, maxVal) == -maxVal);
44
45 assert(std::mul_sat(IntegerT{ 0}, IntegerT{-1}) == IntegerT{ 0});
46 assert(std::mul_sat(IntegerT{ 0}, IntegerT{ 0}) == IntegerT{ 0});
47 assert(std::mul_sat(IntegerT{ 0}, IntegerT{ 1}) == IntegerT{ 0});
48 assert(std::mul_sat(IntegerT{ 0}, minVal) == IntegerT{ 0});
49 assert(std::mul_sat(IntegerT{ 0}, maxVal) == IntegerT{ 0});
50
51 assert(std::mul_sat(IntegerT{ 1}, IntegerT{-1}) == IntegerT{-1});
52 assert(std::mul_sat(IntegerT{ 1}, IntegerT{ 0}) == IntegerT{ 0});
53 assert(std::mul_sat(IntegerT{ 1}, IntegerT{ 1}) == IntegerT{ 1});
54 assert(std::mul_sat(IntegerT{ 1}, minVal) == minVal);
55 assert(std::mul_sat(IntegerT{ 1}, maxVal) == maxVal);
56
57 assert(std::mul_sat( minVal, IntegerT{-1}) == maxVal); // saturated
58 assert(std::mul_sat( minVal, IntegerT{ 0}) == IntegerT{ 0});
59 assert(std::mul_sat( minVal, IntegerT{ 1}) == minVal);
60 assert(std::mul_sat( minVal, minVal) == maxVal); // saturated
61 assert(std::mul_sat( minVal, maxVal) == minVal); // saturated
62
63 assert(std::mul_sat( maxVal, IntegerT{-1}) == -maxVal);
64 assert(std::mul_sat( maxVal, IntegerT{ 0}) == IntegerT{ 0});
65 assert(std::mul_sat( maxVal, IntegerT{ 1}) == maxVal); // saturated
66 assert(std::mul_sat( maxVal, minVal) == minVal); // saturated
67 assert(std::mul_sat( maxVal, maxVal) == maxVal); // saturated
68
69 // No saturation (no limit values)
70
71 assert(std::mul_sat(IntegerT{27}, IntegerT{ 2}) == IntegerT{54});
72 assert(std::mul_sat(IntegerT{ 2}, IntegerT{28}) == IntegerT{56});
73
74 // Saturation (no limit values)
75
76 {
77 constexpr IntegerT x = minVal / IntegerT{2} + IntegerT{27};
78 constexpr IntegerT y = minVal / IntegerT{2} + IntegerT{28};
79 assert(std::mul_sat(x, y) == maxVal); // saturated
80 }
81 {
82 constexpr IntegerT x = minVal / IntegerT{2} + IntegerT{27};
83 constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28};
84 assert(std::mul_sat(x, y) == minVal); // saturated
85 }
86 {
87 constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27};
88 constexpr IntegerT y = minVal / IntegerT{2} + IntegerT{28};
89 assert(std::mul_sat(x, y) == minVal); // saturated
90 }
91 {
92 constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27};
93 constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28};
94 assert(std::mul_sat(x, y) == maxVal); // saturated
95 }
96
97 // clang-format on
98
99 return true;
100}
101
102template <typename IntegerT>
103constexpr bool test_unsigned() {
104 constexpr auto minVal = std::numeric_limits<IntegerT>::min();
105 constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
106
107 std::same_as<IntegerT> decltype(auto) _ = std::mul_sat(minVal, maxVal);
108
109 static_assert(noexcept(std::mul_sat(minVal, maxVal)));
110
111 // clang-format off
112
113 // No saturation (0, 1)
114
115 assert(std::mul_sat(IntegerT{0}, IntegerT{0}) == IntegerT{0});
116 assert(std::mul_sat(IntegerT{0}, IntegerT{1}) == IntegerT{0});
117 assert(std::mul_sat(IntegerT{0}, minVal) == IntegerT{0});
118 assert(std::mul_sat(IntegerT{0}, maxVal) == IntegerT{0});
119
120 assert(std::mul_sat(IntegerT{1}, IntegerT{0}) == IntegerT{0});
121 assert(std::mul_sat(IntegerT{1}, IntegerT{1}) == IntegerT{1});
122 assert(std::mul_sat(IntegerT{1}, minVal) == minVal);
123 assert(std::mul_sat(IntegerT{1}, maxVal) == maxVal);
124
125 assert(std::mul_sat( minVal, IntegerT{0}) == IntegerT{0});
126 assert(std::mul_sat( minVal, IntegerT{1}) == minVal);
127 assert(std::mul_sat( minVal, maxVal) == minVal);
128 assert(std::mul_sat( minVal, maxVal) == minVal);
129
130 assert(std::mul_sat( maxVal, IntegerT{0}) == IntegerT{0});
131 assert(std::mul_sat( maxVal, IntegerT{1}) == maxVal);
132 assert(std::mul_sat( maxVal, minVal) == IntegerT{0});
133 assert(std::mul_sat( maxVal, maxVal) == maxVal); // saturated
134
135 // No saturation (no limit values)
136
137 assert(std::mul_sat(IntegerT{28}, IntegerT{2}) == IntegerT{56});
138
139 // Saturation (no limit values
140
141 {
142 constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27};
143 constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28};
144 assert(std::mul_sat(x, y) == maxVal); // saturated
145 }
146
147 // clang-format on
148
149 return true;
150}
151
152constexpr bool test() {
153 // Signed
154 test_signed<signed char>();
155 test_signed<short int>();
156 test_signed<int>();
157 test_signed<long int>();
158 test_signed<long long int>();
159#ifndef TEST_HAS_NO_INT128
160 test_signed<__int128_t>();
161#endif
162 // Unsigned
163 test_unsigned<unsigned char>();
164 test_unsigned<unsigned short int>();
165 test_unsigned<unsigned int>();
166 test_unsigned<unsigned long int>();
167 test_unsigned<unsigned long long int>();
168#ifndef TEST_HAS_NO_INT128
169 test_unsigned<__uint128_t>();
170#endif
171
172 return true;
173}
174
175int main(int, char**) {
176 test();
177 static_assert(test());
178
179 return 0;
180}
181

source code of libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.pass.cpp