Skip to content

Commit b23f1c6

Browse files
committed
refactor(math-overflow): reimplement; generalize for more signed types
1 parent ed7e94c commit b23f1c6

File tree

2 files changed

+8
-18
lines changed

2 files changed

+8
-18
lines changed

src/quick-lint-js/util/math-overflow.h

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,16 @@
99
#include <quick-lint-js/util/narrow-cast.h>
1010

1111
namespace quick_lint_js {
12-
// Only permit tested specializations, and disallow implicit conversions (e.g.
13-
// long -> int).
1412
template <class T>
15-
std::optional<T> checked_add(T x, T y) noexcept = delete;
16-
17-
template <>
18-
inline std::optional<int> checked_add(int x, int y) noexcept {
19-
using out = int;
20-
using wider_int = long long;
21-
constexpr out out_max = (std::numeric_limits<out>::max)();
22-
constexpr out out_min = std::numeric_limits<out>::lowest();
23-
static_assert(std::numeric_limits<wider_int>::lowest() / 2 <= out_min);
24-
static_assert(out_max <= (std::numeric_limits<wider_int>::max)() / 2);
25-
26-
wider_int sum = static_cast<wider_int>(x) + static_cast<wider_int>(y);
27-
if (in_range<out>(sum)) {
28-
return static_cast<out>(sum);
29-
} else {
13+
std::enable_if_t<std::is_signed_v<T> && std::is_integral_v<T>, std::optional<T>>
14+
checked_add(T x, T y) noexcept {
15+
// https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
16+
constexpr T t_max = (std::numeric_limits<T>::max)();
17+
constexpr T t_min = std::numeric_limits<T>::lowest();
18+
if (((y > 0) && (x > (t_max - y))) || ((y < 0) && (x < (t_min - y)))) {
3019
return std::nullopt;
3120
}
21+
return x + y;
3222
}
3323
}
3424

test/test-math-overflow.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace quick_lint_js {
1111
namespace {
1212
template <class BoolVector16>
1313
class test_math_checked_add_signed : public ::testing::Test {};
14-
using signed_types = ::testing::Types<int>;
14+
using signed_types = ::testing::Types<int, long, long long>;
1515
TYPED_TEST_SUITE(test_math_checked_add_signed, signed_types,
1616
::testing::internal::DefaultNameGenerator);
1717

0 commit comments

Comments
 (0)