Line data Source code
1 : // Copyright (c) 2021-2023 Made to Order Software Corp. All Rights Reserved 2 : // 3 : // https://snapwebsites.org/project/snapdev 4 : // contact@m2osw.com 5 : // 6 : // This program is free software: you can redistribute it and/or modify 7 : // it under the terms of the GNU General Public License as published by 8 : // the Free Software Foundation, either version 3 of the License, or 9 : // (at your option) any later version. 10 : // 11 : // This program is distributed in the hope that it will be useful, 12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 : // GNU General Public License for more details. 15 : // 16 : // You should have received a copy of the GNU General Public License 17 : // along with this program. If not, see <https://www.gnu.org/licenses/>. 18 : 19 : /** \file 20 : * \brief Verify the saturated_subtract() function. 21 : * 22 : * This file implements tests to verify that the saturated_subtract() function 23 : * will indeed saturate the result on an underflow. 24 : */ 25 : 26 : // self 27 : // 28 : #include "catch_main.h" 29 : 30 : 31 : 32 : // snapdev 33 : // 34 : #include <snapdev/math.h> 35 : #include <snapdev/ostream_int128.h> 36 : 37 : 38 : // last include 39 : // 40 : #include <snapdev/poison.h> 41 : 42 : 43 : // __int128 is not ISO C++ yet 44 : #pragma GCC diagnostic ignored "-Wpedantic" 45 : 46 : 47 5 : CATCH_TEST_CASE("saturated_subtract_uint", "[math]") 48 : { 49 5 : CATCH_START_SECTION("saturated_subtract_uint8: test all possible cases with 8 bits") 50 : { 51 257 : for(std::uint32_t n(0); n < 256; ++n) 52 : { 53 65792 : for(std::uint32_t m(0); m < 256; ++m) 54 : { 55 65536 : std::int32_t expected(n - m); 56 65536 : if(expected < 0) // easy to test in this case 57 : { 58 32640 : expected = 0; 59 : } 60 65536 : std::int32_t const result(snapdev::saturated_subtract( 61 : static_cast<std::uint8_t>(n) 62 65536 : , static_cast<std::uint8_t>(m))); 63 65536 : CATCH_REQUIRE(result == expected); 64 : } 65 : } 66 : } 67 5 : CATCH_END_SECTION() 68 : 69 5 : CATCH_START_SECTION("saturated_subtract_uint16: test many possible cases with 16 bits") 70 : { 71 1311 : for(std::uint32_t n(0); n < 65536; n += rand() % 100) 72 : { 73 1735894 : for(std::uint32_t m(0); m < 65536; m += rand() % 100) 74 : { 75 1734584 : std::int32_t expected(n - m); 76 1734584 : if(expected < 0) // easy to test in this case 77 : { 78 861063 : expected = 0; 79 : } 80 1734584 : std::int32_t const result(snapdev::saturated_subtract( 81 : static_cast<std::uint16_t>(n) 82 1734584 : , static_cast<std::uint16_t>(m))); 83 1734584 : CATCH_REQUIRE(result == expected); 84 : } 85 : } 86 : } 87 5 : CATCH_END_SECTION() 88 : 89 5 : CATCH_START_SECTION("saturated_subtract: test a few possible cases with 32 bits") 90 : { 91 : // no underflow at all 92 : { 93 1 : std::uint32_t const result(snapdev::saturated_subtract( 94 : static_cast<std::uint32_t>(32'000) 95 : , static_cast<std::uint32_t>(1'000))); 96 1 : CATCH_REQUIRE(result == 31'000UL); 97 : } 98 : 99 : // no underflow, but close 100 : { 101 1 : std::uint32_t const result(snapdev::saturated_subtract( 102 : static_cast<std::uint32_t>(1'000) 103 : , static_cast<std::uint32_t>(1'000))); 104 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::min()); 105 : } 106 : 107 : // underflow by 1 108 : { 109 1 : std::uint32_t const result(snapdev::saturated_subtract( 110 : static_cast<std::uint32_t>(1'000) 111 : , static_cast<std::uint32_t>(1'001))); 112 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::min()); 113 : } 114 : 115 : // definitive underflow 116 : { 117 1 : std::uint32_t const result(snapdev::saturated_subtract( 118 : static_cast<std::uint32_t>(1'000) 119 : , static_cast<std::uint32_t>(3'501))); 120 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::min()); 121 : } 122 : 123 : // max. underflow 124 : { 125 1 : std::uint32_t const result(snapdev::saturated_subtract( 126 : std::numeric_limits<std::uint32_t>::min() 127 : , std::numeric_limits<std::uint32_t>::max())); 128 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::min()); 129 : } 130 : } 131 5 : CATCH_END_SECTION() 132 : 133 5 : CATCH_START_SECTION("saturated_subtract_uint64: test a few possible cases with 64 bits") 134 : { 135 : // no underflow at all 136 : { 137 1 : std::uint64_t const result(snapdev::saturated_subtract( 138 : static_cast<std::uint64_t>(32'000) 139 : , static_cast<std::uint64_t>(1'000))); 140 1 : CATCH_REQUIRE(result == 31'000UL); 141 : } 142 : 143 : // no underflow, but close 144 : { 145 1 : std::uint64_t const result(snapdev::saturated_subtract( 146 : static_cast<std::uint64_t>(1'000) 147 : , static_cast<std::uint64_t>(1'000))); 148 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::min()); 149 : } 150 : 151 : // underflow by 1 152 : { 153 1 : std::uint64_t const result(snapdev::saturated_subtract( 154 : static_cast<std::uint64_t>(1'000) 155 : , static_cast<std::uint64_t>(1'001))); 156 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::min()); 157 : } 158 : 159 : // definitive underflow 160 : { 161 1 : std::uint64_t const result(snapdev::saturated_subtract( 162 : static_cast<std::uint64_t>(1'000) 163 : , static_cast<std::uint64_t>(3'501))); 164 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::min()); 165 : } 166 : 167 : // max. underflow 168 : { 169 1 : std::uint64_t const result(snapdev::saturated_subtract( 170 : std::numeric_limits<std::uint64_t>::min() 171 : , std::numeric_limits<std::uint64_t>::max())); 172 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::min()); 173 : } 174 : } 175 5 : CATCH_END_SECTION() 176 : 177 5 : CATCH_START_SECTION("saturated_subtract_uint128: test a few possible cases with 128 bits") 178 : { 179 : #pragma GCC diagnostic push 180 : #pragma GCC diagnostic ignored "-Wpedantic" 181 : // no underflow at all 182 : { 183 1 : unsigned __int128 const result(snapdev::saturated_subtract( 184 : static_cast<unsigned __int128>(32'000) 185 : , static_cast<unsigned __int128>(1'000))); 186 1 : CATCH_REQUIRE(result == 31'000UL); 187 : } 188 : 189 : // no underflow, but close 190 : { 191 1 : unsigned __int128 const result(snapdev::saturated_subtract( 192 : static_cast<unsigned __int128>(1'000) 193 : , static_cast<unsigned __int128>(1'000))); 194 1 : CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::min()); 195 : } 196 : 197 : // underflow by 1 198 : { 199 1 : unsigned __int128 const result(snapdev::saturated_subtract( 200 : static_cast<unsigned __int128>(1'000) 201 : , static_cast<unsigned __int128>(1'001))); 202 1 : CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::min()); 203 : } 204 : 205 : // definitive underflow 206 : { 207 1 : unsigned __int128 const result(snapdev::saturated_subtract( 208 : static_cast<unsigned __int128>(3'501) 209 1 : , std::numeric_limits<unsigned __int128>::max() - 1'000)); 210 1 : CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::min()); 211 : } 212 : 213 : // max. underflow 214 : { 215 1 : unsigned __int128 const result(snapdev::saturated_subtract( 216 : std::numeric_limits<unsigned __int128>::min() 217 : , std::numeric_limits<unsigned __int128>::max())); 218 1 : CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::min()); 219 : } 220 : #pragma GCC diagnostic pop 221 : } 222 5 : CATCH_END_SECTION() 223 5 : } 224 : 225 : 226 : // vim: ts=4 sw=4 et