Goose  Artifact [eed0f11d12]

Artifact eed0f11d12c23c08a8f6ec1b9cfa66d33f97925bc0e89405514136fcec70c851:

  • File bs/util/bigint.h — part of check-in [c44aed7937] at 2019-08-05 19:02:51 on branch trunk — llr, execute, codegen: Implemented the And, Or, Shl, LShr and AShr instructions. (user: achavasse size: 4379)

#ifndef EMPATHY_UTIL_BIGINT_H
#define EMPATHY_UTIL_BIGINT_H

namespace empathy::util
{
    using llvm::APInt;
    using llvm::APSInt;

    // This is a wrapper around llvm::APSInt used to represent compile time integer with "infinite" width.
    //
    // It wraps the various operations so that they work on integers of different sizes, where the smallest
    // one is automatically sign extended first.
    //
    // It also wraps arithmetic operations to automatically extend the size to make sure that the result
    // won't overflow.
    //
    // They are always signed.
    class BigInt
    {
        public:
            BigInt()
            {
                m_value.setIsSigned( true );
            }

            template< typename T >
            BigInt( T&& v ) :
                m_value( forward< T >( v ) )
            {
                m_value.setIsSigned( true );
            }

            static BigInt FromBinString( const string& str );
            static BigInt FromDecString( const string& str );
            static BigInt FromHexString( const string& str );

            static BigInt FromU64( uint64_t val )
            {
                auto apsint = APSInt::getUnsigned( val );
                apsint.zext( 65 );
                return move( apsint );
            }

            uint64_t ToU64() const { return m_value.getLimitedValue(); }

            const auto& getAPSInt() const { return m_value; }
            operator const APSInt&() { return m_value; }

            auto getActiveBits() const { return m_value.getActiveBits(); }
            auto getMinSignedBits() const { return m_value.getMinSignedBits(); }
            bool isNegative() const { return m_value.isNegative(); }

            auto zext( uint32_t size ) const { return m_value.zext( size ); }
            auto sext( uint32_t size ) const { return m_value.sext( size ); }

            friend ostream& operator<<( ostream& out, const BigInt& bi )
            {
                return out << bi.m_value.toString( 10 );
            }

        private:
            template< typename F >
            static auto applyOpOnMixedSizes(
                const BigInt& lhs, const BigInt& rhs, F&& func )
            {
                if( lhs.m_value.getBitWidth() < rhs.m_value.getBitWidth() )
                    return func( lhs.m_value.sext( rhs.m_value.getBitWidth() ), rhs.m_value );

                if( lhs.m_value.getBitWidth() > rhs.m_value.getBitWidth() )
                    return func( lhs.m_value, rhs.m_value.sext( lhs.m_value.getBitWidth() ) );

                return func( lhs.m_value, rhs.m_value );
            }

            template< typename F >
            static auto extendAndApplyOp( uint32_t wantedSize,
                const BigInt& lhs, const BigInt& rhs, F&& func )
            {
                return func( lhs.m_value.sext( wantedSize ), rhs.m_value.sext( wantedSize ) );
            }

        public:
            auto operator==( const BigInt& rhs ) const
            {
                return applyOpOnMixedSizes( *this, rhs,
                    []( const APInt& l, const APInt& r ) { return l == r; } );
            }

            auto operator&( const BigInt& rhs ) const
            {
                return applyOpOnMixedSizes( *this, rhs,
                    []( const APInt& l, const APInt& r ) { return l & r; } );
            }

            auto operator|( const BigInt& rhs ) const
            {
                return applyOpOnMixedSizes( *this, rhs,
                    []( const APInt& l, const APInt& r ) { return l | r; } );
            }

            auto operator^( const BigInt& rhs ) const
            {
                return applyOpOnMixedSizes( *this, rhs,
                    []( const APInt& l, const APInt& r ) { return l ^ r; } );
            }

            auto shl( const BigInt& rhs ) const
            {
                return sext( getMinSignedBits() + rhs.ToU64() ).shl( rhs.m_value );
            }

            auto ashr( const BigInt& rhs ) const
            {
                return m_value.ashr( rhs.m_value );
            }

        private:
            llvm::APSInt m_value;
    };
}

namespace std
{
    template<> struct hash< empathy::util::BigInt >
    {
        size_t operator()( const empathy::util::BigInt& x ) const
        {
            return llvm::hash_value( x.getAPSInt() );
        }
    };
}

#endif