class sgi
From
Bonita Montero@21:1/5 to
All on Fri Nov 19 06:08:40 2021
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 );
}
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)