Skip to content

Commit

Permalink
ExtendedMult for generic unsigned int types
Browse files Browse the repository at this point in the history
  • Loading branch information
horenmar committed Nov 29, 2023
1 parent 9207780 commit 6c9807f
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 24 deletions.
56 changes: 36 additions & 20 deletions src/catch2/internal/catch_random_integer_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,34 @@
#ifndef CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED
#define CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED

#include <climits>
#include <cstddef>
#include <cstdint>
#include <type_traits>

namespace Catch {
namespace Detail {

template <std::size_t>
struct SizedUnsignedType;
#define SizedUnsignedTypeHelper( TYPE ) \
template <> \
struct SizedUnsignedType<sizeof( TYPE )> { \
using type = TYPE; \
}

SizedUnsignedTypeHelper( std::uint8_t );
SizedUnsignedTypeHelper( std::uint16_t );
SizedUnsignedTypeHelper( std::uint32_t );
SizedUnsignedTypeHelper( std::uint64_t );
#undef SizedUnsignedTypeHelper

template <std::size_t sz>
using SizedUnsignedType_t = typename SizedUnsignedType<sz>::type;

template <typename T>
using DoubleWidthUnsignedType_t = SizedUnsignedType_t<2 * sizeof( T )>;

template <typename T>
struct ExtendedMultResult {
T upper;
Expand Down Expand Up @@ -77,27 +100,20 @@ namespace Catch {
};
}

template <std::size_t>
struct SizedUnsignedType;
#define SizedUnsignedTypeHelper( TYPE ) \
template <> \
struct SizedUnsignedType<sizeof( TYPE )> { \
using type = TYPE; \
}

SizedUnsignedTypeHelper( std::uint8_t );
SizedUnsignedTypeHelper( std::uint16_t );
SizedUnsignedTypeHelper( std::uint32_t );
SizedUnsignedTypeHelper( std::uint64_t );
#undef SizedUnsignedTypeHelper

template <std::size_t sz>
using SizedUnsignedType_t = typename SizedUnsignedType<sz>::type;

template <typename T>
using DoubleWidthUnsignedType_t = SizedUnsignedType_t<2 * sizeof(T)>;

template <typename UInt>
constexpr ExtendedMultResult<UInt> ExtendedMult( UInt lhs, UInt rhs ) {
static_assert( std::is_unsigned<UInt>::value,
"ExtendedMult can only handle unsigned integers" );
static_assert( sizeof( UInt ) < sizeof( std::uint64_t ),
"Generic extendedMult can only handle types smaller "
"than uint64_t" );
using WideType = DoubleWidthUnsignedType_t<UInt>;

auto result = WideType( lhs ) * WideType( rhs );
return {
static_cast<UInt>( result >> ( CHAR_BIT * sizeof( UInt ) ) ),
static_cast<UInt>( result & UInt( -1 ) ) };
}

} // namespace Detail
} // namespace Catch
Expand Down
46 changes: 42 additions & 4 deletions tests/SelfTest/IntrospectiveTests/Integer.tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,8 @@ namespace {
} // namespace

TEST_CASE( "ExtendedMult 64x64", "[Integer][approvals]" ) {
using Catch::Detail::ExtendedMult;
using Catch::Detail::ExtendedMultResult;

// a x 0 == 0
CommutativeMultCheck<uint64_t>( 0x12345678, 0, 0, 0 );
CommutativeMultCheck<uint64_t>( 0x1234'5678'9ABC'DEFF, 0, 0, 0 );

// bit carried from low half to upper half
CommutativeMultCheck<uint64_t>( uint64_t( 1 ) << 63, 2, 1, 0 );
Expand Down Expand Up @@ -81,3 +78,44 @@ TEST_CASE( "SizedUnsignedType helpers", "[integer][approvals]" ) {
STATIC_REQUIRE( sizeof( DoubleWidthUnsignedType_t<std::uint32_t> ) == 8 );
STATIC_REQUIRE( std::is_unsigned<DoubleWidthUnsignedType_t<std::uint32_t>>::value );
}

TEST_CASE( "ExtendedMult 32x32", "[integer][approvals]" ) {
// a x 0 == 0
CommutativeMultCheck<uint32_t>( 0x1234'5678, 0, 0, 0 );

// bit carried from low half to upper half
CommutativeMultCheck<uint32_t>( uint32_t(1) << 31, 2, 1, 0 );

// bits in upper half on one side, bits in lower half on other side
CommutativeMultCheck<uint32_t>( 0xdcdc'0000, 0x0000'aabb, 0x0000'934b, 0x6cb4'0000 );

// Some input numbers without interesting patterns
CommutativeMultCheck<uint32_t>(
0xaaaa'aaaa, 0xbbbb'bbbb, 0x7d27'd27c, 0x2d82'd82e );

CommutativeMultCheck<uint32_t>(
0x7d27'd27c, 0x2d82'd82e, 0x163f'f7e8, 0xc5b8'7248 );

CommutativeMultCheck<uint32_t>(
0xdead'beef, 0xfeed'feed, 0xddbf'6809, 0x6f8d'e543 );

CommutativeMultCheck<uint32_t>(
0xddbf'6809, 0x6f8d'e543, 0x60a0'e71e, 0x751d'475b );
}

TEST_CASE( "ExtendedMult 8x8", "[integer][approvals]" ) {
// a x 0 == 0
CommutativeMultCheck<uint8_t>( 0xcd, 0, 0, 0 );

// bit carried from low half to upper half
CommutativeMultCheck<uint8_t>( uint8_t( 1 ) << 7, 2, 1, 0 );

// bits in upper half on one side, bits in lower half on other side
CommutativeMultCheck<uint8_t>( 0x80, 0x03, 0x01, 0x80 );

// Some input numbers without interesting patterns
CommutativeMultCheck<uint8_t>( 0xaa, 0xbb, 0x7c, 0x2e );
CommutativeMultCheck<uint8_t>( 0x7c, 0x2e, 0x16, 0x48 );
CommutativeMultCheck<uint8_t>( 0xdc, 0xcd, 0xb0, 0x2c );
CommutativeMultCheck<uint8_t>( 0xb0, 0x2c, 0x1e, 0x40 );
}

0 comments on commit 6c9807f

Please sign in to comment.