178 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// REQUIRES: std-at-least-c++2610 11// <numeric>12 13// template<class T>14// constexpr T mul_sat(T x, T y) noexcept; // freestanding15 16#include <cassert>17#include <concepts>18#include <limits>19#include <numeric>20 21#include "test_macros.h"22 23template <typename IntegerT>24constexpr bool test_signed() {25 constexpr auto minVal = std::numeric_limits<IntegerT>::min();26 constexpr auto maxVal = std::numeric_limits<IntegerT>::max();27 28 std::same_as<IntegerT> decltype(auto) _ = std::mul_sat(minVal, maxVal);29 30 static_assert(noexcept(std::mul_sat(minVal, maxVal)));31 32 // clang-format off33 34 // Limit values (-1, 0, 1, min, max)35 36 assert(std::mul_sat(IntegerT{-1}, IntegerT{-1}) == IntegerT{ 1});37 assert(std::mul_sat(IntegerT{-1}, IntegerT{ 0}) == IntegerT{ 0});38 assert(std::mul_sat(IntegerT{-1}, IntegerT{ 1}) == IntegerT{-1});39 assert(std::mul_sat(IntegerT{-1}, minVal) == maxVal); // saturated40 assert(std::mul_sat(IntegerT{-1}, maxVal) == -maxVal);41 42 assert(std::mul_sat(IntegerT{ 0}, IntegerT{-1}) == IntegerT{ 0});43 assert(std::mul_sat(IntegerT{ 0}, IntegerT{ 0}) == IntegerT{ 0});44 assert(std::mul_sat(IntegerT{ 0}, IntegerT{ 1}) == IntegerT{ 0});45 assert(std::mul_sat(IntegerT{ 0}, minVal) == IntegerT{ 0});46 assert(std::mul_sat(IntegerT{ 0}, maxVal) == IntegerT{ 0});47 48 assert(std::mul_sat(IntegerT{ 1}, IntegerT{-1}) == IntegerT{-1});49 assert(std::mul_sat(IntegerT{ 1}, IntegerT{ 0}) == IntegerT{ 0});50 assert(std::mul_sat(IntegerT{ 1}, IntegerT{ 1}) == IntegerT{ 1});51 assert(std::mul_sat(IntegerT{ 1}, minVal) == minVal);52 assert(std::mul_sat(IntegerT{ 1}, maxVal) == maxVal);53 54 assert(std::mul_sat( minVal, IntegerT{-1}) == maxVal); // saturated55 assert(std::mul_sat( minVal, IntegerT{ 0}) == IntegerT{ 0});56 assert(std::mul_sat( minVal, IntegerT{ 1}) == minVal);57 assert(std::mul_sat( minVal, minVal) == maxVal); // saturated58 assert(std::mul_sat( minVal, maxVal) == minVal); // saturated59 60 assert(std::mul_sat( maxVal, IntegerT{-1}) == -maxVal);61 assert(std::mul_sat( maxVal, IntegerT{ 0}) == IntegerT{ 0});62 assert(std::mul_sat( maxVal, IntegerT{ 1}) == maxVal); // saturated63 assert(std::mul_sat( maxVal, minVal) == minVal); // saturated64 assert(std::mul_sat( maxVal, maxVal) == maxVal); // saturated65 66 // No saturation (no limit values)67 68 assert(std::mul_sat(IntegerT{27}, IntegerT{ 2}) == IntegerT{54});69 assert(std::mul_sat(IntegerT{ 2}, IntegerT{28}) == IntegerT{56});70 71 // Saturation (no limit values)72 73 {74 constexpr IntegerT x = minVal / IntegerT{2} + IntegerT{27};75 constexpr IntegerT y = minVal / IntegerT{2} + IntegerT{28};76 assert(std::mul_sat(x, y) == maxVal); // saturated77 }78 {79 constexpr IntegerT x = minVal / IntegerT{2} + IntegerT{27};80 constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28};81 assert(std::mul_sat(x, y) == minVal); // saturated82 }83 {84 constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27};85 constexpr IntegerT y = minVal / IntegerT{2} + IntegerT{28};86 assert(std::mul_sat(x, y) == minVal); // saturated87 }88 {89 constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27};90 constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28};91 assert(std::mul_sat(x, y) == maxVal); // saturated92 }93 94 // clang-format on95 96 return true;97}98 99template <typename IntegerT>100constexpr bool test_unsigned() {101 constexpr auto minVal = std::numeric_limits<IntegerT>::min();102 constexpr auto maxVal = std::numeric_limits<IntegerT>::max();103 104 std::same_as<IntegerT> decltype(auto) _ = std::mul_sat(minVal, maxVal);105 106 static_assert(noexcept(std::mul_sat(minVal, maxVal)));107 108 // clang-format off109 110 // No saturation (0, 1)111 112 assert(std::mul_sat(IntegerT{0}, IntegerT{0}) == IntegerT{0});113 assert(std::mul_sat(IntegerT{0}, IntegerT{1}) == IntegerT{0});114 assert(std::mul_sat(IntegerT{0}, minVal) == IntegerT{0});115 assert(std::mul_sat(IntegerT{0}, maxVal) == IntegerT{0});116 117 assert(std::mul_sat(IntegerT{1}, IntegerT{0}) == IntegerT{0});118 assert(std::mul_sat(IntegerT{1}, IntegerT{1}) == IntegerT{1});119 assert(std::mul_sat(IntegerT{1}, minVal) == minVal);120 assert(std::mul_sat(IntegerT{1}, maxVal) == maxVal);121 122 assert(std::mul_sat( minVal, IntegerT{0}) == IntegerT{0});123 assert(std::mul_sat( minVal, IntegerT{1}) == minVal);124 assert(std::mul_sat( minVal, maxVal) == minVal);125 assert(std::mul_sat( minVal, maxVal) == minVal);126 127 assert(std::mul_sat( maxVal, IntegerT{0}) == IntegerT{0});128 assert(std::mul_sat( maxVal, IntegerT{1}) == maxVal);129 assert(std::mul_sat( maxVal, minVal) == IntegerT{0});130 assert(std::mul_sat( maxVal, maxVal) == maxVal); // saturated131 132 // No saturation (no limit values)133 134 assert(std::mul_sat(IntegerT{28}, IntegerT{2}) == IntegerT{56});135 136 // Saturation (no limit values137 138 {139 constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27};140 constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28};141 assert(std::mul_sat(x, y) == maxVal); // saturated142 }143 144 // clang-format on145 146 return true;147}148 149constexpr bool test() {150 // Signed151 test_signed<signed char>();152 test_signed<short int>();153 test_signed<int>();154 test_signed<long int>();155 test_signed<long long int>();156#ifndef TEST_HAS_NO_INT128157 test_signed<__int128_t>();158#endif159 // Unsigned160 test_unsigned<unsigned char>();161 test_unsigned<unsigned short int>();162 test_unsigned<unsigned int>();163 test_unsigned<unsigned long int>();164 test_unsigned<unsigned long long int>();165#ifndef TEST_HAS_NO_INT128166 test_unsigned<__uint128_t>();167#endif168 169 return true;170}171 172int main(int, char**) {173 test();174 static_assert(test());175 176 return 0;177}178