mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-11-04 05:59:32 +01:00 
			
		
		
		
	Add helpers for implementing uniform integer distribution
* Utility for extended mult n x n bits -> 2n bits * Utility to adapt output from URBG to target (unsigned) integral type * Utility to reorder signed values into unsigned type while keeping the order.
This commit is contained in:
		@@ -110,6 +110,7 @@ set(IMPL_HEADERS
 | 
				
			|||||||
  ${SOURCES_DIR}/internal/catch_preprocessor.hpp
 | 
					  ${SOURCES_DIR}/internal/catch_preprocessor.hpp
 | 
				
			||||||
  ${SOURCES_DIR}/internal/catch_preprocessor_remove_parens.hpp
 | 
					  ${SOURCES_DIR}/internal/catch_preprocessor_remove_parens.hpp
 | 
				
			||||||
  ${SOURCES_DIR}/internal/catch_random_floating_point_helpers.hpp
 | 
					  ${SOURCES_DIR}/internal/catch_random_floating_point_helpers.hpp
 | 
				
			||||||
 | 
					  ${SOURCES_DIR}/internal/catch_random_integer_helpers.hpp
 | 
				
			||||||
  ${SOURCES_DIR}/internal/catch_random_number_generator.hpp
 | 
					  ${SOURCES_DIR}/internal/catch_random_number_generator.hpp
 | 
				
			||||||
  ${SOURCES_DIR}/internal/catch_random_seed_generation.hpp
 | 
					  ${SOURCES_DIR}/internal/catch_random_seed_generation.hpp
 | 
				
			||||||
  ${SOURCES_DIR}/internal/catch_reporter_registry.hpp
 | 
					  ${SOURCES_DIR}/internal/catch_reporter_registry.hpp
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -92,6 +92,7 @@
 | 
				
			|||||||
#include <catch2/internal/catch_preprocessor_internal_stringify.hpp>
 | 
					#include <catch2/internal/catch_preprocessor_internal_stringify.hpp>
 | 
				
			||||||
#include <catch2/internal/catch_preprocessor_remove_parens.hpp>
 | 
					#include <catch2/internal/catch_preprocessor_remove_parens.hpp>
 | 
				
			||||||
#include <catch2/internal/catch_random_floating_point_helpers.hpp>
 | 
					#include <catch2/internal/catch_random_floating_point_helpers.hpp>
 | 
				
			||||||
 | 
					#include <catch2/internal/catch_random_integer_helpers.hpp>
 | 
				
			||||||
#include <catch2/internal/catch_random_number_generator.hpp>
 | 
					#include <catch2/internal/catch_random_number_generator.hpp>
 | 
				
			||||||
#include <catch2/internal/catch_random_seed_generation.hpp>
 | 
					#include <catch2/internal/catch_random_seed_generation.hpp>
 | 
				
			||||||
#include <catch2/internal/catch_reporter_registry.hpp>
 | 
					#include <catch2/internal/catch_reporter_registry.hpp>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										202
									
								
								src/catch2/internal/catch_random_integer_helpers.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								src/catch2/internal/catch_random_integer_helpers.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,202 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					//              Copyright Catch2 Authors
 | 
				
			||||||
 | 
					// Distributed under the Boost Software License, Version 1.0.
 | 
				
			||||||
 | 
					//   (See accompanying file LICENSE.txt or copy at
 | 
				
			||||||
 | 
					//        https://www.boost.org/LICENSE_1_0.txt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: BSL-1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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;
 | 
				
			||||||
 | 
					            T lower;
 | 
				
			||||||
 | 
					            friend bool operator==( ExtendedMultResult const& lhs,
 | 
				
			||||||
 | 
					                                    ExtendedMultResult const& rhs ) {
 | 
				
			||||||
 | 
					                return lhs.upper == rhs.upper && lhs.lower == rhs.lower;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Returns 128 bit result of multiplying lhs and rhs
 | 
				
			||||||
 | 
					        constexpr ExtendedMultResult<std::uint64_t>
 | 
				
			||||||
 | 
					        extendedMult( std::uint64_t lhs, std::uint64_t rhs ) {
 | 
				
			||||||
 | 
					            // We use the simple long multiplication approach for
 | 
				
			||||||
 | 
					            // correctness, we can use platform specific builtins
 | 
				
			||||||
 | 
					            // for performance later.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Split the lhs and rhs into two 32bit "digits", so that we can
 | 
				
			||||||
 | 
					            // do 64 bit arithmetic to handle carry bits.
 | 
				
			||||||
 | 
					            //            32b    32b    32b    32b
 | 
				
			||||||
 | 
					            //     lhs                  L1     L2
 | 
				
			||||||
 | 
					            //   * rhs                  R1     R2
 | 
				
			||||||
 | 
					            //            ------------------------
 | 
				
			||||||
 | 
					            //                       |  R2 * L2  |
 | 
				
			||||||
 | 
					            //                 |  R2 * L1  |
 | 
				
			||||||
 | 
					            //                 |  R1 * L2  |
 | 
				
			||||||
 | 
					            //           |  R1 * L1  |
 | 
				
			||||||
 | 
					            //           -------------------------
 | 
				
			||||||
 | 
					            //           |  a  |  b  |  c  |  d  |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CarryBits( x ) ( x >> 32 )
 | 
				
			||||||
 | 
					#define Digits( x ) ( x & 0xFF'FF'FF'FF )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            auto r2l2 = Digits( rhs ) * Digits( lhs );
 | 
				
			||||||
 | 
					            auto r2l1 = Digits( rhs ) * CarryBits( lhs );
 | 
				
			||||||
 | 
					            auto r1l2 = CarryBits( rhs ) * Digits( lhs );
 | 
				
			||||||
 | 
					            auto r1l1 = CarryBits( rhs ) * CarryBits( lhs );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Sum to columns first
 | 
				
			||||||
 | 
					            auto d = Digits( r2l2 );
 | 
				
			||||||
 | 
					            auto c = CarryBits( r2l2 ) + Digits( r2l1 ) + Digits( r1l2 );
 | 
				
			||||||
 | 
					            auto b = CarryBits( r2l1 ) + CarryBits( r1l2 ) + Digits( r1l1 );
 | 
				
			||||||
 | 
					            auto a = CarryBits( r1l1 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Propagate carries between columns
 | 
				
			||||||
 | 
					            c += CarryBits( d );
 | 
				
			||||||
 | 
					            b += CarryBits( c );
 | 
				
			||||||
 | 
					            a += CarryBits( b );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Remove the used carries
 | 
				
			||||||
 | 
					            c = Digits( c );
 | 
				
			||||||
 | 
					            b = Digits( b );
 | 
				
			||||||
 | 
					            a = Digits( a );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef CarryBits
 | 
				
			||||||
 | 
					#undef Digits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                a << 32 | b, // upper 64 bits
 | 
				
			||||||
 | 
					                c << 32 | d  // lower 64 bits
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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 ) ) };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        template <typename TargetType,
 | 
				
			||||||
 | 
					                  typename Generator>
 | 
				
			||||||
 | 
					            std::enable_if_t<sizeof(typename Generator::result_type) >= sizeof(TargetType),
 | 
				
			||||||
 | 
					            TargetType> fillBitsFrom(Generator& gen) {
 | 
				
			||||||
 | 
					            using gresult_type = typename Generator::result_type;
 | 
				
			||||||
 | 
					            static_assert( std::is_unsigned<TargetType>::value, "Only unsigned integers are supported" );
 | 
				
			||||||
 | 
					            static_assert( Generator::min() == 0 &&
 | 
				
			||||||
 | 
					                           Generator::max() == static_cast<gresult_type>( -1 ),
 | 
				
			||||||
 | 
					                           "Generator must be able to output all numbers in its result type (effectively it must be a random bit generator)" );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // We want to return the top bits from a generator, as they are
 | 
				
			||||||
 | 
					            // usually considered higher quality.
 | 
				
			||||||
 | 
					            constexpr auto generated_bits = sizeof( gresult_type ) * CHAR_BIT;
 | 
				
			||||||
 | 
					            constexpr auto return_bits = sizeof( TargetType ) * CHAR_BIT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return static_cast<TargetType>( gen() >>
 | 
				
			||||||
 | 
					                                            ( generated_bits - return_bits) );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        template <typename TargetType,
 | 
				
			||||||
 | 
					                  typename Generator>
 | 
				
			||||||
 | 
					            std::enable_if_t<sizeof(typename Generator::result_type) < sizeof(TargetType),
 | 
				
			||||||
 | 
					            TargetType> fillBitsFrom(Generator& gen) {
 | 
				
			||||||
 | 
					            using gresult_type = typename Generator::result_type;
 | 
				
			||||||
 | 
					            static_assert( std::is_unsigned<TargetType>::value,
 | 
				
			||||||
 | 
					                           "Only unsigned integers are supported" );
 | 
				
			||||||
 | 
					            static_assert( Generator::min() == 0 &&
 | 
				
			||||||
 | 
					                           Generator::max() == static_cast<gresult_type>( -1 ),
 | 
				
			||||||
 | 
					                           "Generator must be able to output all numbers in its result type (effectively it must be a random bit generator)" );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            constexpr auto generated_bits = sizeof( gresult_type ) * CHAR_BIT;
 | 
				
			||||||
 | 
					            constexpr auto return_bits = sizeof( TargetType ) * CHAR_BIT;
 | 
				
			||||||
 | 
					            std::size_t filled_bits = 0;
 | 
				
			||||||
 | 
					            TargetType ret = 0;
 | 
				
			||||||
 | 
					            do {
 | 
				
			||||||
 | 
					                ret <<= generated_bits;
 | 
				
			||||||
 | 
					                ret |= gen();
 | 
				
			||||||
 | 
					                filled_bits += generated_bits;
 | 
				
			||||||
 | 
					            } while ( filled_bits < return_bits );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * Transposes numbers into unsigned type while keeping their ordering
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * This means that signed types are changed so that the ordering is
 | 
				
			||||||
 | 
					         * [INT_MIN, ..., -1, 0, ..., INT_MAX], rather than order we would
 | 
				
			||||||
 | 
					         * get by simple casting ([0, ..., INT_MAX, INT_MIN, ..., -1])
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        template <typename OriginalType, typename UnsignedType>
 | 
				
			||||||
 | 
					        std::enable_if_t<std::is_signed<OriginalType>::value, UnsignedType>
 | 
				
			||||||
 | 
					        transposeToNaturalOrder( UnsignedType in ) {
 | 
				
			||||||
 | 
					            static_assert(
 | 
				
			||||||
 | 
					                sizeof( OriginalType ) == sizeof( UnsignedType ),
 | 
				
			||||||
 | 
					                "reordering requires the same sized types on both sides" );
 | 
				
			||||||
 | 
					            static_assert( std::is_unsigned<UnsignedType>::value,
 | 
				
			||||||
 | 
					                           "Input type must be unsigned" );
 | 
				
			||||||
 | 
					            // Assuming 2s complement (standardized in current C++), the
 | 
				
			||||||
 | 
					            // positive and negative numbers are already internally ordered,
 | 
				
			||||||
 | 
					            // and their difference is in the top bit. Swapping it orders
 | 
				
			||||||
 | 
					            // them the desired way.
 | 
				
			||||||
 | 
					            constexpr auto highest_bit =
 | 
				
			||||||
 | 
					                UnsignedType( 1 ) << ( sizeof( UnsignedType ) * CHAR_BIT - 1 );
 | 
				
			||||||
 | 
					            return static_cast<UnsignedType>( in ^ highest_bit );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        template <typename OriginalType,
 | 
				
			||||||
 | 
					                  typename UnsignedType>
 | 
				
			||||||
 | 
					        std::enable_if_t<std::is_unsigned<OriginalType>::value, UnsignedType>
 | 
				
			||||||
 | 
					            transposeToNaturalOrder(UnsignedType in) {
 | 
				
			||||||
 | 
					            static_assert(
 | 
				
			||||||
 | 
					                sizeof( OriginalType ) == sizeof( UnsignedType ),
 | 
				
			||||||
 | 
					                "reordering requires the same sized types on both sides" );
 | 
				
			||||||
 | 
					            static_assert( std::is_unsigned<UnsignedType>::value, "Input type must be unsigned" );
 | 
				
			||||||
 | 
					            // No reordering is needed for unsigned -> unsigned
 | 
				
			||||||
 | 
					            return in;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } // namespace Detail
 | 
				
			||||||
 | 
					} // namespace Catch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED
 | 
				
			||||||
@@ -116,6 +116,7 @@ internal_headers = [
 | 
				
			|||||||
  'internal/catch_preprocessor_internal_stringify.hpp',
 | 
					  'internal/catch_preprocessor_internal_stringify.hpp',
 | 
				
			||||||
  'internal/catch_preprocessor_remove_parens.hpp',
 | 
					  'internal/catch_preprocessor_remove_parens.hpp',
 | 
				
			||||||
  'internal/catch_random_floating_point_helpers.hpp',
 | 
					  'internal/catch_random_floating_point_helpers.hpp',
 | 
				
			||||||
 | 
					  'internal/catch_random_integer_helpers.hpp',
 | 
				
			||||||
  'internal/catch_random_number_generator.hpp',
 | 
					  'internal/catch_random_number_generator.hpp',
 | 
				
			||||||
  'internal/catch_random_seed_generation.hpp',
 | 
					  'internal/catch_random_seed_generation.hpp',
 | 
				
			||||||
  'internal/catch_reporter_registry.hpp',
 | 
					  'internal/catch_reporter_registry.hpp',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -86,6 +86,7 @@ set(TEST_SOURCES
 | 
				
			|||||||
        ${SELF_TEST_DIR}/IntrospectiveTests/Details.tests.cpp
 | 
					        ${SELF_TEST_DIR}/IntrospectiveTests/Details.tests.cpp
 | 
				
			||||||
        ${SELF_TEST_DIR}/IntrospectiveTests/FloatingPoint.tests.cpp
 | 
					        ${SELF_TEST_DIR}/IntrospectiveTests/FloatingPoint.tests.cpp
 | 
				
			||||||
        ${SELF_TEST_DIR}/IntrospectiveTests/GeneratorsImpl.tests.cpp
 | 
					        ${SELF_TEST_DIR}/IntrospectiveTests/GeneratorsImpl.tests.cpp
 | 
				
			||||||
 | 
					        ${SELF_TEST_DIR}/IntrospectiveTests/Integer.tests.cpp
 | 
				
			||||||
        ${SELF_TEST_DIR}/IntrospectiveTests/InternalBenchmark.tests.cpp
 | 
					        ${SELF_TEST_DIR}/IntrospectiveTests/InternalBenchmark.tests.cpp
 | 
				
			||||||
        ${SELF_TEST_DIR}/IntrospectiveTests/Json.tests.cpp
 | 
					        ${SELF_TEST_DIR}/IntrospectiveTests/Json.tests.cpp
 | 
				
			||||||
        ${SELF_TEST_DIR}/IntrospectiveTests/Parse.tests.cpp
 | 
					        ${SELF_TEST_DIR}/IntrospectiveTests/Parse.tests.cpp
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										150
									
								
								tests/SelfTest/IntrospectiveTests/Integer.tests.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								tests/SelfTest/IntrospectiveTests/Integer.tests.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,150 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					//              Copyright Catch2 Authors
 | 
				
			||||||
 | 
					// Distributed under the Boost Software License, Version 1.0.
 | 
				
			||||||
 | 
					//   (See accompanying file LICENSE.txt or copy at
 | 
				
			||||||
 | 
					//        https://www.boost.org/LICENSE_1_0.txt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: BSL-1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <catch2/catch_test_macros.hpp>
 | 
				
			||||||
 | 
					#include <catch2/internal/catch_random_integer_helpers.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace {
 | 
				
			||||||
 | 
					    template <typename Int>
 | 
				
			||||||
 | 
					    static void
 | 
				
			||||||
 | 
					    CommutativeMultCheck( Int a, Int b, Int upper_result, Int lower_result ) {
 | 
				
			||||||
 | 
					        using Catch::Detail::extendedMult;
 | 
				
			||||||
 | 
					        using Catch::Detail::ExtendedMultResult;
 | 
				
			||||||
 | 
					        CHECK( extendedMult( a, b ) ==
 | 
				
			||||||
 | 
					               ExtendedMultResult<Int>{ upper_result, lower_result } );
 | 
				
			||||||
 | 
					        CHECK( extendedMult( b, a ) ==
 | 
				
			||||||
 | 
					               ExtendedMultResult<Int>{ upper_result, lower_result } );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					} // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE( "extendedMult 64x64", "[Integer][approvals]" ) {
 | 
				
			||||||
 | 
					    // a x 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 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // bits in upper half on one side, bits in lower half on other side
 | 
				
			||||||
 | 
					    CommutativeMultCheck<uint64_t>( 0xcdcd'dcdc'0000'0000,
 | 
				
			||||||
 | 
					                                    0x0000'0000'aeae'aeae,
 | 
				
			||||||
 | 
					                                    0x0000'0000'8c6e'5a77,
 | 
				
			||||||
 | 
					                                    0x7391'a588'0000'0000 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Some input numbers without interesting patterns
 | 
				
			||||||
 | 
					    CommutativeMultCheck<uint64_t>( 0xaaaa'aaaa'aaaa'aaaa,
 | 
				
			||||||
 | 
					                                    0xbbbb'bbbb'bbbb'bbbb,
 | 
				
			||||||
 | 
					                                    0x7d27'd27d'27d2'7d26,
 | 
				
			||||||
 | 
					                                    0xd82d'82d8'2d82'd82e );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CommutativeMultCheck<uint64_t>( 0x7d27'd27d'27d2'7d26,
 | 
				
			||||||
 | 
					                                    0xd82d'82d8'2d82'd82e,
 | 
				
			||||||
 | 
					                                    0x69af'd991'8256'b953,
 | 
				
			||||||
 | 
					                                    0x8724'8909'fcb6'8cd4 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CommutativeMultCheck<uint64_t>( 0xdead'beef'dead'beef,
 | 
				
			||||||
 | 
					                                    0xfeed'feed'feed'feef,
 | 
				
			||||||
 | 
					                                    0xddbf'680b'2b0c'b558,
 | 
				
			||||||
 | 
					                                    0x7a36'b06f'2ce9'6321 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CommutativeMultCheck<uint64_t>( 0xddbf'680b'2b0c'b558,
 | 
				
			||||||
 | 
					                                    0x7a36'b06f'2ce9'6321,
 | 
				
			||||||
 | 
					                                    0x69dc'96c9'294b'fc7f,
 | 
				
			||||||
 | 
					                                    0xd038'39fa'a3dc'6858 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CommutativeMultCheck<uint64_t>( 0x61c8'8646'80b5'83eb,
 | 
				
			||||||
 | 
					                                    0x61c8'8646'80b5'83eb,
 | 
				
			||||||
 | 
					                                    0x2559'92d3'8220'8bbe,
 | 
				
			||||||
 | 
					                                    0xdf44'2d22'ce48'59b9 );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE( "SizedUnsignedType helpers", "[integer][approvals]" ) {
 | 
				
			||||||
 | 
					    using Catch::Detail::SizedUnsignedType_t;
 | 
				
			||||||
 | 
					    using Catch::Detail::DoubleWidthUnsignedType_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    STATIC_REQUIRE( sizeof( SizedUnsignedType_t<1> ) == 1 );
 | 
				
			||||||
 | 
					    STATIC_REQUIRE( sizeof( SizedUnsignedType_t<2> ) == 2 );
 | 
				
			||||||
 | 
					    STATIC_REQUIRE( sizeof( SizedUnsignedType_t<4> ) == 4 );
 | 
				
			||||||
 | 
					    STATIC_REQUIRE( sizeof( SizedUnsignedType_t<8> ) == 8 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    STATIC_REQUIRE( sizeof( DoubleWidthUnsignedType_t<std::uint8_t> ) == 2 );
 | 
				
			||||||
 | 
					    STATIC_REQUIRE( std::is_unsigned<DoubleWidthUnsignedType_t<std::uint8_t>>::value );
 | 
				
			||||||
 | 
					    STATIC_REQUIRE( sizeof( DoubleWidthUnsignedType_t<std::uint16_t> ) == 4 );
 | 
				
			||||||
 | 
					    STATIC_REQUIRE( std::is_unsigned<DoubleWidthUnsignedType_t<std::uint16_t>>::value );
 | 
				
			||||||
 | 
					    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 );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE( "negative and positive signed integers keep their order after transposeToNaturalOrder",
 | 
				
			||||||
 | 
					                    "[integer][approvals]") {
 | 
				
			||||||
 | 
					    using Catch::Detail::transposeToNaturalOrder;
 | 
				
			||||||
 | 
					    int32_t negative( -1 );
 | 
				
			||||||
 | 
					    int32_t positive( 1 );
 | 
				
			||||||
 | 
					    uint32_t adjusted_negative =
 | 
				
			||||||
 | 
					        transposeToNaturalOrder<int32_t>( static_cast<uint32_t>( negative ) );
 | 
				
			||||||
 | 
					    uint32_t adjusted_positive =
 | 
				
			||||||
 | 
					        transposeToNaturalOrder<int32_t>( static_cast<uint32_t>( positive ) );
 | 
				
			||||||
 | 
					    REQUIRE( adjusted_negative < adjusted_positive );
 | 
				
			||||||
 | 
					    REQUIRE( adjusted_positive - adjusted_negative == 2 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Conversion has to be reversible
 | 
				
			||||||
 | 
					    REQUIRE( negative == static_cast<int32_t>( transposeToNaturalOrder<int32_t>(
 | 
				
			||||||
 | 
					                             adjusted_negative ) ) );
 | 
				
			||||||
 | 
					    REQUIRE( positive == static_cast<int32_t>( transposeToNaturalOrder<int32_t>(
 | 
				
			||||||
 | 
					                             adjusted_positive ) ) );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE( "unsigned integers are unchanged by transposeToNaturalOrder",
 | 
				
			||||||
 | 
					           "[integer][approvals]") {
 | 
				
			||||||
 | 
					    using Catch::Detail::transposeToNaturalOrder;
 | 
				
			||||||
 | 
					    uint32_t max = std::numeric_limits<uint32_t>::max();
 | 
				
			||||||
 | 
					    uint32_t zero = 0;
 | 
				
			||||||
 | 
					    REQUIRE( max == transposeToNaturalOrder<uint32_t>( max ) );
 | 
				
			||||||
 | 
					    REQUIRE( zero == transposeToNaturalOrder<uint32_t>( zero ) );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -8,6 +8,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <catch2/catch_test_macros.hpp>
 | 
					#include <catch2/catch_test_macros.hpp>
 | 
				
			||||||
#include <catch2/catch_template_test_macros.hpp>
 | 
					#include <catch2/catch_template_test_macros.hpp>
 | 
				
			||||||
 | 
					#include <catch2/internal/catch_random_integer_helpers.hpp>
 | 
				
			||||||
#include <catch2/internal/catch_random_number_generator.hpp>
 | 
					#include <catch2/internal/catch_random_number_generator.hpp>
 | 
				
			||||||
#include <catch2/internal/catch_random_seed_generation.hpp>
 | 
					#include <catch2/internal/catch_random_seed_generation.hpp>
 | 
				
			||||||
#include <catch2/internal/catch_uniform_floating_point_distribution.hpp>
 | 
					#include <catch2/internal/catch_uniform_floating_point_distribution.hpp>
 | 
				
			||||||
@@ -77,3 +78,29 @@ TEMPLATE_TEST_CASE("uniform_floating_point_distribution never returns infs from
 | 
				
			|||||||
        REQUIRE_FALSE( std::isnan( ret ) );
 | 
					        REQUIRE_FALSE( std::isnan( ret ) );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE( "fillBitsFrom - shortening and stretching", "[rng][approvals]" ) {
 | 
				
			||||||
 | 
					    using Catch::Detail::fillBitsFrom;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The seed is not important, but the numbers below have to be repeatable.
 | 
				
			||||||
 | 
					    // They should also exhibit the same general pattern of being prefixes
 | 
				
			||||||
 | 
					    Catch::SimplePcg32 pcg( 0xaabb'ccdd );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SECTION( "Shorten to 8 bits" ) {
 | 
				
			||||||
 | 
					        // We cast the result to avoid dealing with char-like type in uint8_t
 | 
				
			||||||
 | 
					        auto shortened = static_cast<uint32_t>( fillBitsFrom<uint8_t>( pcg ) );
 | 
				
			||||||
 | 
					        REQUIRE( shortened == 0xcc );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    SECTION( "Shorten to 16 bits" ) {
 | 
				
			||||||
 | 
					        auto shortened = fillBitsFrom<uint16_t>( pcg );
 | 
				
			||||||
 | 
					        REQUIRE( shortened == 0xccbe );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    SECTION( "Keep at 32 bits" ) {
 | 
				
			||||||
 | 
					        auto n = fillBitsFrom<uint32_t>( pcg );
 | 
				
			||||||
 | 
					        REQUIRE( n == 0xccbe'5f04 );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    SECTION( "Stretch to 64 bits" ) {
 | 
				
			||||||
 | 
					        auto stretched = fillBitsFrom<uint64_t>( pcg );
 | 
				
			||||||
 | 
					        REQUIRE( stretched == 0xccbe'5f04'a424'a486 );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@ self_test_sources = files(
 | 
				
			|||||||
  'SelfTest/IntrospectiveTests/Details.tests.cpp',
 | 
					  'SelfTest/IntrospectiveTests/Details.tests.cpp',
 | 
				
			||||||
  'SelfTest/IntrospectiveTests/FloatingPoint.tests.cpp',
 | 
					  'SelfTest/IntrospectiveTests/FloatingPoint.tests.cpp',
 | 
				
			||||||
  'SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp',
 | 
					  'SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp',
 | 
				
			||||||
 | 
					  'SelfTest/IntrospectiveTests/Integer.tests.cpp',
 | 
				
			||||||
  'SelfTest/IntrospectiveTests/InternalBenchmark.tests.cpp',
 | 
					  'SelfTest/IntrospectiveTests/InternalBenchmark.tests.cpp',
 | 
				
			||||||
  'SelfTest/IntrospectiveTests/Parse.tests.cpp',
 | 
					  'SelfTest/IntrospectiveTests/Parse.tests.cpp',
 | 
				
			||||||
  'SelfTest/IntrospectiveTests/PartTracker.tests.cpp',
 | 
					  'SelfTest/IntrospectiveTests/PartTracker.tests.cpp',
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user