Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use std::is_signed and std::enable_if #2395

Merged
merged 3 commits into from
Nov 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 8 additions & 37 deletions src/safe_op.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <limits>
#include <stdexcept>
#include <type_traits>

#ifdef _MSC_VER
#include <Intsafe.h>
Expand Down Expand Up @@ -37,35 +38,6 @@ namespace Safe {
* is available.
*/
namespace Internal {
/*!
* @brief Helper struct to determine whether a type is signed or unsigned
*
* This struct is a backport of std::is_signed from C++11. It has a public
* enum with the property VALUE which is true when the type is signed or
* false if it is unsigned.
*/
template <typename T>
struct is_signed {
enum { VALUE = static_cast<T>(-1) < static_cast<T>(0) };
};

/*!
* @brief Helper struct for SFINAE, from C++11

* This struct has a public typedef called type typedef'd to T if B is
* true. Otherwise there is no typedef.
*/
template <bool B, class T = void>
struct enable_if {};

/*!
* @brief Specialization of enable_if for the case B == true
*/
template <class T>
struct enable_if<true, T> {
using type = T;
};

/*!
* @brief Check the addition of two numbers for overflows for signed
* integer types larger than int or with the same size as int.
Expand All @@ -84,9 +56,8 @@ struct enable_if<true, T> {
* https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
*/
template <typename T>
typename enable_if<is_signed<T>::VALUE && sizeof(T) >= sizeof(int), bool>::type fallback_add_overflow(T summand_1,
T summand_2,
T& result) {
typename std::enable_if<std::is_signed<T>::value && sizeof(T) >= sizeof(int), bool>::type fallback_add_overflow(
T summand_1, T summand_2, T& result) {
if (((summand_2 >= 0) && (summand_1 > std::numeric_limits<T>::max() - summand_2)) ||
((summand_2 < 0) && (summand_1 < std::numeric_limits<T>::min() - summand_2))) {
return true;
Expand Down Expand Up @@ -116,9 +87,8 @@ typename enable_if<is_signed<T>::VALUE && sizeof(T) >= sizeof(int), bool>::type
* https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules
*/
template <typename T>
typename enable_if<is_signed<T>::VALUE && sizeof(T) < sizeof(int), bool>::type fallback_add_overflow(T summand_1,
T summand_2,
T& result) {
typename std::enable_if<std::is_signed<T>::value && sizeof(T) < sizeof(int), bool>::type fallback_add_overflow(
T summand_1, T summand_2, T& result) {
const int res = summand_1 + summand_2;
if ((res > std::numeric_limits<T>::max()) || (res < std::numeric_limits<T>::min())) {
return true;
Expand All @@ -145,7 +115,8 @@ typename enable_if<is_signed<T>::VALUE && sizeof(T) < sizeof(int), bool>::type f
* https://wiki.sei.cmu.edu/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
*/
template <typename T>
typename enable_if<!is_signed<T>::VALUE, bool>::type fallback_add_overflow(T summand_1, T summand_2, T& result) {
typename std::enable_if<!std::is_signed<T>::value, bool>::type fallback_add_overflow(T summand_1, T summand_2,
T& result) {
result = summand_1 + summand_2;
return result < summand_1;
}
Expand Down Expand Up @@ -255,7 +226,7 @@ T add(T summand_1, T summand_2) {
* when `num == std::numeric_limits<T>::min()`.
*/
template <typename T>
typename Internal::enable_if<Internal::is_signed<T>::VALUE, T>::type abs(T num) throw() {
typename std::enable_if<std::is_signed<T>::value, T>::type abs(T num) throw() {
if (num == std::numeric_limits<T>::min()) {
return std::numeric_limits<T>::max();
}
Expand Down
66 changes: 32 additions & 34 deletions unitTests/test_safe_op.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,42 +26,41 @@ struct AdditionTestValues;
* Overload for unsigned types.
*/
template <typename T>
struct AdditionTestValues<T, typename si::enable_if<!si::is_signed<T>::VALUE>::type> {
struct AdditionTestValues<T, std::enable_if_t<!std::is_signed_v<T>>> {
static const size_t case_count = 5;
static const T summand[case_count];
static const bool overflow[case_count][case_count];
};

template <typename T>
const T AdditionTestValues<T, typename si::enable_if<!si::is_signed<T>::VALUE>::type>::summand[] = {
const T AdditionTestValues<T, std::enable_if_t<!std::is_signed_v<T>>>::summand[] = {
0, 1, 2, static_cast<T>(std::numeric_limits<T>::max() - 1), std::numeric_limits<T>::max()};

template <typename T>
const bool
AdditionTestValues<T, typename si::enable_if<!si::is_signed<T>::VALUE>::type>::overflow[case_count][case_count] = {
// 0
{false, false, false, false, false},
// 1
{false, false, false, false, true},
// 2
{false, false, false, true, true},
// max - 1
{false, false, true, true, true},
// max
{false, true, true, true, true}};
const bool AdditionTestValues<T, std::enable_if_t<!std::is_signed_v<T>>>::overflow[case_count][case_count] = {
// 0
{false, false, false, false, false},
// 1
{false, false, false, false, true},
// 2
{false, false, false, true, true},
// max - 1
{false, false, true, true, true},
// max
{false, true, true, true, true}};

/*!
* Overload for signed integers
*/
template <typename T>
struct AdditionTestValues<T, typename si::enable_if<si::is_signed<T>::VALUE>::type> {
struct AdditionTestValues<T, std::enable_if_t<std::is_signed_v<T>>> {
static const size_t case_count = 8;
static const T summand[case_count];
static const bool overflow[case_count][case_count];
};

template <typename T>
const T AdditionTestValues<T, typename si::enable_if<si::is_signed<T>::VALUE>::type>::summand[] = {
const T AdditionTestValues<T, std::enable_if_t<std::is_signed_v<T>>>::summand[] = {
std::numeric_limits<T>::min(),
static_cast<T>(std::numeric_limits<T>::min() + 1),
-1,
Expand All @@ -72,24 +71,23 @@ const T AdditionTestValues<T, typename si::enable_if<si::is_signed<T>::VALUE>::t
std::numeric_limits<T>::max()};

template <typename T>
const bool
AdditionTestValues<T, typename si::enable_if<si::is_signed<T>::VALUE>::type>::overflow[case_count][case_count] = {
// min
{true, true, true, false, false, false, false, false},
// min + 1
{true, true, false, false, false, false, false, false},
// -1
{true, false, false, false, false, false, false, false},
// 0
{false, false, false, false, false, false, false, false},
// 1
{false, false, false, false, false, false, false, true},
// 2
{false, false, false, false, false, false, true, true},
// max - 1
{false, false, false, false, false, true, true, true},
// max
{false, false, false, false, true, true, true, true}};
const bool AdditionTestValues<T, std::enable_if_t<std::is_signed_v<T>>>::overflow[case_count][case_count] = {
// min
{true, true, true, false, false, false, false, false},
// min + 1
{true, true, false, false, false, false, false, false},
// -1
{true, false, false, false, false, false, false, false},
// 0
{false, false, false, false, false, false, false, false},
// 1
{false, false, false, false, false, false, false, true},
// 2
{false, false, false, false, false, false, true, true},
// max - 1
{false, false, false, false, false, true, true, true},
// max
{false, false, false, false, true, true, true, true}};

/*!
* Test the addition of all combinations of AdditionTestValues<T>::summand[i],
Expand Down