• 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)
  • From Bonita Montero@21:1/5 to All on Fri Nov 19 06:23:08 2021
    Am 19.11.2021 um 06:08 schrieb Bonita Montero:
    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;

    Eh:
    bool f = a + sgis( 1 ) < a;


    call "?rnd@@YAFXZ"
    movzx eax, ax
    cmp eax, 32767
    sete dl

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)