Loading...
Searching...
No Matches
safe_op.hpp
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2021 Exiv2 authors
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
#ifndef SAFE_OP_HPP_
#define SAFE_OP_HPP_
#include <limits>
#include <stdexcept>
#ifdef _MSC_VER
#include <Intsafe.h>
#endif
namespace Safe
{
namespace Internal
{
template <typename T>
struct is_signed
{
enum
{
VALUE = T(-1) < T(0)
};
};
template <bool B, class T = void>
struct enable_if
{
};
template <class T>
struct enable_if<true, T>
{
typedef T type;
};
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)
{
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;
} else {
result = summand_1 + summand_2;
return false;
}
}
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)
{
const int res = summand_1 + summand_2;
if ((res > std::numeric_limits<T>::max()) || (res < std::numeric_limits<T>::min())) {
return true;
} else {
result = static_cast<T>(res);
return false;
}
}
template <typename T>
typename enable_if<!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;
}
template <typename T>
bool builtin_add_overflow(T summand_1, T summand_2, T& result)
{
return fallback_add_overflow(summand_1, summand_2, result);
}
#if defined(__GNUC__) || defined(__clang__)
#if __GNUC__ >= 5 || __clang_major__ >= 3
#define SPECIALIZE_builtin_add_overflow(type, builtin_name) \
/* Full specialization of builtin_add_overflow for type using the */ \
/* builtin_name intrinsic */ \
template <> \
inline bool builtin_add_overflow<type>(type summand_1, type summand_2, type & result) \
{ \
return builtin_name(summand_1, summand_2, &result); \
}
SPECIALIZE_builtin_add_overflow(int, __builtin_sadd_overflow);
SPECIALIZE_builtin_add_overflow(long, __builtin_saddl_overflow);
SPECIALIZE_builtin_add_overflow(long long, __builtin_saddll_overflow);
SPECIALIZE_builtin_add_overflow(unsigned int, __builtin_uadd_overflow);
SPECIALIZE_builtin_add_overflow(unsigned long, __builtin_uaddl_overflow);
SPECIALIZE_builtin_add_overflow(unsigned long long, __builtin_uaddll_overflow);
#undef SPECIALIZE_builtin_add_overflow
#endif // __GNUC__ >= 5 || __clang_major >= 3
#elif defined(_MSC_VER)
// intrinsics are not in available in MSVC 2005 and earlier
#if _MSC_VER >= 1400
#define SPECIALIZE_builtin_add_overflow_WIN(type, builtin_name) \
template <> \
inline bool builtin_add_overflow(type summand_1, type summand_2, type& result) \
{ \
return builtin_name(summand_1, summand_2, &result) != S_OK; \
}
SPECIALIZE_builtin_add_overflow_WIN(unsigned int, UIntAdd);
SPECIALIZE_builtin_add_overflow_WIN(unsigned long, ULongAdd);
SPECIALIZE_builtin_add_overflow_WIN(unsigned long long, ULongLongAdd);
#undef SPECIALIZE_builtin_add_overflow_WIN
#endif // _MSC_VER >= 1400
#endif // defined(_MSC_VER)
} // namespace Internal
template <typename T>
T add(T summand_1, T summand_2)
{
T res = 0;
if (Internal::builtin_add_overflow(summand_1, summand_2, res)) {
throw std::overflow_error("Overflow in addition");
}
return res;
}
template <typename T>
typename Internal::enable_if<Internal::is_signed<T>::VALUE, T>::type abs(T num) throw()
{
if (num == std::numeric_limits<T>::min()) {
return std::numeric_limits<T>::max();
}
return num < 0 ? -num : num;
}
} // namespace Safe
#endif // SAFE_OP_HPP_
Safe
Arithmetic operations with overflow checks.
Definition safe_op.hpp:35
Safe::abs
Internal::enable_if< Internal::is_signed< T >::VALUE, T >::type abs(T num)
Calculates the absolute value of a number without producing negative values.
Definition safe_op.hpp:320
Safe::Internal::enable_if
Helper struct for SFINAE, from C++11.
Definition safe_op.hpp:84
Safe::Internal::is_signed
Helper struct to determine whether a type is signed or unsigned.
Definition safe_op.hpp:69