Bonita Montero
unread,Nov 19, 2021, 12:08:57 AM11/19/21You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to
With C and C++ the compiler can assume that signed integer operations
never overflow. So I wrote a little C++20-class called sgi<T> with which
you can have overflows and you can check for them, f.e. with a + b < a.
#include <iostream>
#include <random>
#include "sgi.h"
using namespace std;
short rnd();
int main()
{
using sgis = sgi<short>;
sgis a( rnd() ), b( rnd() );
bool f = a + b < a;
cout << f << endl;
}
#if defined(_MSC_VER)
__declspec(noinline)
#elif defined(__GNUC__)
__attribute((noinline))
#endif
short rnd()
{
static mt19937_64 mt( (random_device())() );
static uniform_int_distribution<short> uid( -10, +10 );
return uid( mt );
}
The code in main results in this:
call "?rnd@@YAFXZ"
mov esi, eax
call "?rnd@@YAFXZ"
add eax, esi
cmp ax, si
setl dl
The class assumes two's complement and that you can operate on unsigned
values as they were signed values and consider the output-value as a
signed value.
This is my class:
#pragma once
#include <type_traits>
#include <concepts>
template<typename T>
concept sgi_concept = std::is_integral_v<T> && std::is_signed_v<T>;
template<typename T>
requires sgi_concept<T>
struct sgi
{
sgi() = default;
template<typename T2>
requires sgi_concept<T2>
sgi( T2 value );
template<typename T2>
sgi( sgi<T2> const &other );
template<typename T2>
requires sgi_concept<T2>
explicit operator T2() const;
template<typename T2>
sgi &operator |=( sgi<T2> const &other );
template<typename T2>
sgi &operator ^=( sgi<T2> const &other );
template<typename T2>
sgi &operator &=( sgi<T2> const &other );
sgi &operator >>=( unsigned shift );
sgi &operator <<=( unsigned shift );
template<typename T2>
sgi &operator %=( sgi<T2> const &other );
template<typename T2>
sgi &operator /=( sgi<T2> const &other );
template<typename T2>
sgi &operator *=( sgi<T2> const &other );
template<typename T2>
sgi &operator -=( sgi<T2> const &other);
template<typename T2>
sgi &operator +=( sgi<T2> const &other );
template<typename T2>
sgi &operator =( sgi<T2> const &other );
template<typename T2>
requires sgi_concept<T2>
sgi &operator =( T2 value );
template<typename T1, typename T2>
friend bool operator ||( sgi<T1> const &left, sgi<T2> const &right );
template<typename T1, typename T2>
friend bool operator &&( sgi<T1> const &left, sgi<T2> const &right );
template<typename T1, typename T2>
friend sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>
operator |( sgi<T1> const &left, sgi<T2> const &right );
template<typename T1, typename T2>
friend sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>
operator ^( sgi<T1> const &left, sgi<T2> const &right );
template<typename T1, typename T2>
friend sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>
operator &( sgi<T1> const &left, sgi<T2> const &right );
template<typename T1, typename T2>
friend bool operator !=( sgi<T1> const &left, sgi<T2> const &right );
// don't used <=> because of optimization-problems
template<typename T1, typename T2>
friend bool operator >=( sgi<T1> const &left, sgi<T2> const &right );
template<typename T1, typename T2>
friend bool operator >( sgi<T1> const &left, sgi<T2> const &right );
template<typename T1, typename T2>
friend bool operator <=( sgi<T1> const &left, sgi<T2> const &right );
template<typename T1, typename T2>
friend bool operator <( sgi<T1> const &left, sgi<T2> const &right );
template<typename T2>
friend sgi<T2> operator <<( sgi<T2> const &left, unsigned shift );
template<typename T2>
friend sgi<T2> operator >>( sgi<T> const &left, unsigned shift );
template<typename T1, typename T2>
friend sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>
operator -( sgi<T1> const &left, sgi<T2> const &right );
template<typename T1, typename T2>
friend sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>
operator +( sgi<T1> const &left, sgi<T2> const &right );
template<typename T1, typename T2>
friend sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>
operator %( sgi<T1> const &left, sgi<T2> const &right );
template<typename T1, typename T2>
friend sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>
operator /( sgi<T1> const &left, sgi<T2> const &right );
template<typename T1, typename T2>
friend sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>
operator *( sgi<T1> const &left, sgi<T2> const &right );
sgi operator ~() const;
bool operator !() const;
sgi operator +() const;
sgi operator -() const;
sgi<T> &operator --();
sgi<T> &operator ++();
sgi<T> operator --( int ) const;
sgi<T> operator ++( int ) const;
private:
using TU = std::make_unsigned_t<T>;
TU value;
};
template<typename T>
requires sgi_concept<T>
template<typename T2>
inline
sgi<T>::sgi( sgi<T2> const &other ) :
value( (T)(T2)other.value )
{
}
template<typename T>
requires sgi_concept<T>
template<typename T2>
requires sgi_concept<T2>
inline
sgi<T>::sgi( T2 value ) :
value( (T)value )
{
}
template<typename T>
requires sgi_concept<T>
template<typename T2>
requires sgi_concept<T2>
inline
sgi<T>::operator T2() const
{
return (T2)(T)value;
}
template<typename T>
requires sgi_concept<T>
template<typename T2>
inline
sgi<T> &sgi<T>::operator |=( sgi<T2> const &value )
{
value |= (T)(T2)value.value;
return *this;
}
template<typename T>
requires sgi_concept<T>
template<typename T2>
inline
sgi<T> &sgi<T>::operator ^=( sgi<T2> const &value )
{
value ^= (T)(T2)value.value;
return *this;
}
template<typename T>
requires sgi_concept<T>
template<typename T2>
inline
sgi<T> &sgi<T>::operator &=( sgi<T2> const &value )
{
value &= (T)(T2)value.value;
return *this;
}
template<typename T>
requires sgi_concept<T>
inline
sgi<T> &sgi<T>::operator >>=( unsigned shift )
{
value = (T)value >> shift;
return *this;
}
template<typename T>
requires sgi_concept<T>
inline
sgi<T> &sgi<T>::operator <<=( unsigned shift )
{
value = (T)value << shift;
return *this;
}
template<typename T>
requires sgi_concept<T>
template<typename T2>
inline
sgi<T> &sgi<T>::operator %=( sgi<T2> const &other )
{
value = (T)((T)value % (T2)other.value);
return *this;
}
template<typename T>
requires sgi_concept<T>
template<typename T2>
inline
sgi<T> &sgi<T>::operator /=( sgi<T2> const &other )
{
value = (T)((T)value / (T2)other.value);
return *this;
}
template<typename T>
requires sgi_concept<T>
template<typename T2>
inline
sgi<T> &sgi<T>::operator *=( sgi<T2> const &other )
{
value = (T)((T)value * (T2)other.value);
return *this;
}
template<typename T>
requires sgi_concept<T>
template<typename T2>
inline
sgi<T> &sgi<T>::operator -=( sgi<T2> const &other )
{
value -= (T)(T2)other.value;
return *this;
}
template<typename T>
requires sgi_concept<T>
template<typename T2>
inline
sgi<T> &sgi<T>::operator +=( sgi<T2> const &other )
{
value += (T)(T2)other.value;
return *this;
}
template<typename T>
requires sgi_concept<T>
template<typename T2>
inline
sgi<T> &sgi<T>::operator =( sgi<T2> const &other )
{
value = (T)(T2)other.value;
return *this;
}
template<typename T>
requires sgi_concept<T>
template<typename T2>
requires sgi_concept<T2>
inline
sgi<T> &sgi<T>::operator =( T2 value )
{
this->value = (T)value;
return *this;
}
template<typename T1, typename T2>
inline
bool operator ||( sgi<T1> const &left, sgi<T2> const &right )
{
return left.value || right.value;
}
template<typename T1, typename T2>
inline
bool operator &&( sgi<T1> const &left, sgi<T2> const &right )
{
return left.value && right.value;
}
template<typename T1, typename T2>
inline
sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>> operator |(
sgi<T1> const &left, sgi<T2> const &right )
{
return sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>(
(T1)left.value | (T2)right.value );
}
template<typename T1, typename T2>
inline
sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>> operator ^(
sgi<T1> const &left, sgi<T2> const &right )
{
return sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>(
(T1)left.value ^ (T2)right.value );
}
template<typename T1, typename T2>
inline
sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>> operator &(
sgi<T1> const &left, sgi<T2> const &right )
{
return sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>(
(T1)left.value & (T2)right.value );
}
template<typename T1, typename T2>
inline
bool operator !=( sgi<T1> const &left, sgi<T2> const &right )
{
return (T1)left.value != (T2)right.value;
}
template<typename T1, typename T2>
inline
bool operator >=( sgi<T1> const &left, sgi<T2> const &right )
{
return (T1)left.value >= (T2)right.value;
}
template<typename T1, typename T2>
inline
bool operator >( sgi<T1> const &left, sgi<T2> const &right )
{
return (T1)left.value > (T2)right.value;
}
template<typename T1, typename T2>
inline
bool operator <=( sgi<T1> const &left, sgi<T2> const &right )
{
return (T1)left.value <= (T2)right.value;
}
template<typename T1, typename T2>
inline
bool operator <( sgi<T1> const &left, sgi<T2> const &right )
{
return (T1)left.value < (T2)right.value;
}
template<typename T>
inline
sgi<T> operator <<( sgi<T> const &left, unsigned shift )
{
return sgi<T>( (T)left.value << shift );
}
template<typename T>
inline
sgi<T> operator >>( sgi<T> const &left, unsigned shift )
{
return sgi<T>( (T)left.value >> shift );
}
template<typename T1, typename T2>
inline
sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>> operator -(
sgi<T1> const &left, sgi<T2> const &right )
{
return sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>(
(T1)left.value - (T2)right.value );
}
template<typename T1, typename T2>
inline
sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>> operator +(
sgi<T1> const &left, sgi<T2> const &right )
{
return sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>(
(T1)left.value + (T2)right.value );
}
template<typename T1, typename T2>
inline
sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>> operator %(
sgi<T1> const &left, sgi<T2> const &right )
{
return sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>(
(T1)left.value % (T2)right.value );
}
template<typename T1, typename T2>
inline
sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>> operator /(
sgi<T1> const &left, sgi<T2> const &right )
{
return sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>(
(T1)left.value / (T2)right.value );
}
template<typename T1, typename T2>
inline
sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>> operator *(
sgi<T1> const &left, sgi<T2> const &right )
{
return sgi<std::conditional_t<sizeof(T1) >= sizeof(T2), T1, T2>>(
(T1)left.value * (T2)right.value );
}
template<typename T>
requires sgi_concept<T>
inline
sgi<T> sgi<T>::operator ~() const
{
return sgi( (T)~value );
}
template<typename T>
requires sgi_concept<T>
inline
bool sgi<T>::operator !() const
{
return !value;
}
template<typename T>
requires sgi_concept<T>
inline
sgi<T> sgi<T>::operator +() const
{
return sgi( value );
}
template<typename T>
requires sgi_concept<T>
inline
sgi<T> sgi<T>::operator -() const
{
return sgi( -(T)value );
}
template<typename T>
requires sgi_concept<T>
inline
sgi<T> &sgi<T>::operator --()
{
--value;
return *this;
}
template<typename T>
requires sgi_concept<T>
inline
sgi<T> &sgi<T>::operator ++()
{
++value;
return *this;
}
template<typename T>
requires sgi_concept<T>
inline
sgi<T> sgi<T>::operator --( int ) const
{
T initial = value;
--value;
return sgi( initial );
}
template<typename T>
requires sgi_concept<T>
inline
sgi<T> sgi<T>::operator ++( int ) const
{
T initial = value;
++value;
return sgi( initial );
}