Skip to content

Commit

Permalink
update the checked_multiply template to deal with mismatched sign in …
Browse files Browse the repository at this point in the history
…signed numbers and min val correctly. This involved adding to templates to clear up warnings
  • Loading branch information
phlptp committed Jul 26, 2019
1 parent c8da413 commit 7e99462
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 6 deletions.
24 changes: 18 additions & 6 deletions include/CLI/Validators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,12 +509,24 @@ auto search(const T &set, const V &val, const std::function<V(V)> &filter_functi
});
return {(it != std::end(setref)), it};
}
/// Generate the absolute value of a number
template <typename T> inline typename std::enable_if<std::is_signed<T>::value, T>::type absval(T a) {
return static_cast<T>((std::abs)(a));

// the following suggestion was made by Nikita Ofitserov(@himikof)
// done in templates to prevent compiler warnings on negation of unsigned numbers

/// Do a check for overflow on signed numbers
template <typename T>
inline typename std::enable_if<std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
if((a > 0) == (b > 0)) {
return ((std::numeric_limits<T>::max)() / (std::abs)(a) < (std::abs)(b));
} else {
return ((std::numeric_limits<T>::min)() / (std::abs)(a) > -(std::abs)(b));
}
}
/// Do a check for overflow on unsigned numbers
template <typename T>
inline typename std::enable_if<!std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
return ((std::numeric_limits<T>::max)() / a < b);
}
/// unsigned values just return the value
template <typename T> inline typename std::enable_if<!std::is_signed<T>::value, T>::type absval(T a) { return a; }

/// Performs a *= b; if it doesn't cause integer overflow. Returns false otherwise.
template <typename T> typename std::enable_if<std::is_integral<T>::value, bool>::type checked_multiply(T &a, T b) {
Expand All @@ -525,7 +537,7 @@ template <typename T> typename std::enable_if<std::is_integral<T>::value, bool>:
if(a == (std::numeric_limits<T>::min)() || b == (std::numeric_limits<T>::min)()) {
return false;
}
if((std::numeric_limits<T>::max)() / absval(a) < absval(b)) {
if(overflowCheck(a, b)) {
return false;
}
a *= b;
Expand Down
14 changes: 14 additions & 0 deletions tests/HelpersTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,20 @@ TEST(CheckedMultiply, Int) {
b = -101;
ASSERT_FALSE(CLI::detail::checked_multiply(a, b));
ASSERT_EQ(a, std::numeric_limits<int>::min() / 100);
a = 2;
b = std::numeric_limits<int>::min() / 2;
ASSERT_TRUE(CLI::detail::checked_multiply(a, b));
a = std::numeric_limits<int>::min() / 2;
b = 2;
ASSERT_TRUE(CLI::detail::checked_multiply(a, b));

a = 4;
b = std::numeric_limits<int>::min() / 4;
ASSERT_TRUE(CLI::detail::checked_multiply(a, b));

a = 48;
b = std::numeric_limits<int>::min() / 48;
ASSERT_TRUE(CLI::detail::checked_multiply(a, b));
}

TEST(CheckedMultiply, SizeT) {
Expand Down

0 comments on commit 7e99462

Please sign in to comment.