Program Listing for File Portable.h

↰ Return to documentation for file (ADS/Portable.h)

/*--------------------------------------------------------------------------*/
/*---------------------------- File Portable.h -----------------------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*----------------------------- DEFINITIONS --------------------------------*/
/*--------------------------------------------------------------------------*/

#ifndef __ADS_Portable
 #define __ADS_Portable
                      /* self-identification: #endif constant */

/*--------------------------------------------------------------------------*/
/*------------------------------ INCLUDES ----------------------------------*/
/*--------------------------------------------------------------------------*/

#include <bit>
#include <compare>
#include <concepts>
#include <cstdint>
#include <type_traits>

#if defined( _MSC_VER ) && !defined( __clang__ )
 #include <cstdlib>
 #include <intrin.h>
#endif

/*--------------------------------------------------------------------------*/
/*--------------------------- NAMESPACE ------------------------------------*/
/*--------------------------------------------------------------------------*/

namespace ADS {

namespace detail {

/*--------------------------------------------------------------------------*/

constexpr std::uint64_t wideProduct( std::uint64_t a , std::uint64_t b ,
                                     std::uint64_t & hi )
{
#if defined( __SIZEOF_INT128__ )
 __extension__ typedef unsigned __int128 U;
 const U p = U( a ) * b;
 hi = std::uint64_t( p >> 64 );
 return( std::uint64_t( p ) );
#else
 if( ! std::is_constant_evaluated() ) {
 #if defined( _MSC_VER ) && defined( _M_X64 ) && !defined( __clang__ )
  return( _umul128( a , b , &hi ) );
 #elif defined( _MSC_VER ) && defined( _M_ARM64 ) && !defined( __clang__ )
  hi = __umulh( a , b );
  return( a * b );
 #endif
  }
 constexpr std::uint64_t LOW = 0xFFFFFFFFULL;
 const std::uint64_t a0 = a & LOW , a1 = a >> 32 , b0 = b & LOW ,
                     b1 = b >> 32;
 const std::uint64_t p00 = a0 * b0 , p01 = a0 * b1 , p10 = a1 * b0 ,
                     p11 = a1 * b1;
 const std::uint64_t mid = ( p00 >> 32 ) + ( p01 & LOW ) + ( p10 & LOW );
 hi = p11 + ( p01 >> 32 ) + ( p10 >> 32 ) + ( mid >> 32 );
 return( ( mid << 32 ) | ( p00 & LOW ) );
#endif
 }

/*--------------------------------------------------------------------------*/

constexpr std::uint64_t byteSwap( std::uint64_t x )
{
#if defined( __GNUC__ ) || defined( __clang__ )
 return( __builtin_bswap64( x ) );
#elif defined( __cpp_lib_byteswap )
 return( std::byteswap( x ) );
#else
 #if defined( _MSC_VER )
 if( ! std::is_constant_evaluated() )
  return( _byteswap_uint64( x ) );
 #endif
 x = ( ( x >> 8 ) & 0x00FF00FF00FF00FFULL ) |
     ( ( x & 0x00FF00FF00FF00FFULL ) << 8 );
 x = ( ( x >> 16 ) & 0x0000FFFF0000FFFFULL ) |
     ( ( x & 0x0000FFFF0000FFFFULL ) << 16 );
 return( ( x >> 32 ) | ( x << 32 ) );
#endif
 }

/*--------------------------------------------------------------------------*/

#if defined( __SIZEOF_INT128__ )

__extension__ typedef __int128 Int128;

#else

struct Int128 {
 std::uint64_t lo = 0;
 std::uint64_t hi = 0;

 constexpr Int128( void ) = default;

 template< std::integral I >
 constexpr Int128( I v )
  : lo( std::uint64_t( v ) ) ,
    hi( ( std::is_signed_v< I > && ( v < 0 ) ) ? ~std::uint64_t( 0 ) : 0 )
 { }

 explicit operator long double( void ) const {
  return( (long double)( std::int64_t( hi ) ) * 18446744073709551616.0L +
          (long double)( lo ) );
  }

 friend constexpr Int128 operator+( Int128 a , Int128 b ) {
  Int128 r;
  r.lo = a.lo + b.lo;
  r.hi = a.hi + b.hi + ( r.lo < a.lo ? 1 : 0 );
  return( r );
  }

 friend constexpr Int128 operator-( Int128 a , Int128 b ) {
  Int128 r;
  r.lo = a.lo - b.lo;
  r.hi = a.hi - b.hi - ( a.lo < b.lo ? 1 : 0 );
  return( r );
  }

 friend constexpr Int128 operator*( Int128 a , Int128 b ) {
  Int128 r;
  r.lo = wideProduct( a.lo , b.lo , r.hi );
  r.hi += a.lo * b.hi + a.hi * b.lo;
  return( r );
  }

 friend constexpr bool operator==( Int128 a , Int128 b ) {
  return( ( a.lo == b.lo ) && ( a.hi == b.hi ) );
  }

 friend constexpr std::strong_ordering operator<=>( Int128 a , Int128 b ) {
  if( a.hi != b.hi )
   return( std::int64_t( a.hi ) <=> std::int64_t( b.hi ) );
  return( a.lo <=> b.lo );
  }
 };

#endif

/*--------------------------------------------------------------------------*/

}  // end( namespace detail )

/*--------------------------------------------------------------------------*/

}  // end( namespace ADS )

/*--------------------------------------------------------------------------*/

#endif  /* Portable.h included */

/*--------------------------------------------------------------------------*/
/*-------------------------- End File Portable.h ---------------------------*/
/*--------------------------------------------------------------------------*/