diff --git a/doc/hash2/reference/hash_append_fwd.adoc b/doc/hash2/reference/hash_append_fwd.adoc index 8b7c5c7..45849b8 100644 --- a/doc/hash2/reference/hash_append_fwd.adoc +++ b/doc/hash2/reference/hash_append_fwd.adoc @@ -35,3 +35,55 @@ struct hash_append_tag; } // namespace boost ``` +The header `boost/hash2/hash_append_fwd.hpp` declares the functions implemented in `boost/hash2/hash_append.hpp`. + +It can be used when code wishes to implement `hash_append` support for a user-defined type without physically depending on the implementation of `hash_append`. + +## Example + +.X.hpp +[source] +---- +#include +#include + +class X +{ +private: + + int a = -1; + std::vector b{ 1, 2, 3 }; + + template + friend void tag_invoke( + boost::hash2::hash_append_tag const&, Hash& h, Flavor const& f, X const& v ) + { + boost::hash2::hash_append( h, f, v.a ); + boost::hash2::hash_append( h, f, v.b ); + } + +public: + + X() = default; +}; +---- + +.main.cpp +[source] +---- +#include "X.hpp" +#include +#include +#include + +int main() +{ + X x; + + boost::hash2::md5_128 hash; + boost::hash2::hash_append( hash, {}, x ); + + std::cout << "MD5 digest of x: " << hash.result() << std::endl; +} +---- + diff --git a/include/boost/hash2/detail/reverse.hpp b/include/boost/hash2/detail/reverse.hpp deleted file mode 100644 index bfab480..0000000 --- a/include/boost/hash2/detail/reverse.hpp +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef BOOST_HASH2_DETAIL_REVERSE_HPP_INCLUDED -#define BOOST_HASH2_DETAIL_REVERSE_HPP_INCLUDED - -// Copyright 2024 Peter Dimov. -// Distributed under the Boost Software License, Version 1.0. -// https://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include - -namespace boost -{ -namespace hash2 -{ -namespace detail -{ - -template void reverse( unsigned char (&d)[ N ], void const* s ) -{ - unsigned char const* s2 = static_cast( s ); - - for( std::size_t i = 0; i < N; ++i ) - { - d[ i ] = s2[ N-1-i ]; - } -} - -#if defined(__GNUC__) || defined(__clang__) - -inline void reverse( unsigned char (&d)[ 2 ], void const* s ) -{ - std::uint16_t tmp; - std::memcpy( &tmp, s, 2 ); - tmp = __builtin_bswap16( tmp ); - std::memcpy( d, &tmp, 2 ); -} - -inline void reverse( unsigned char (&d)[ 4 ], void const* s ) -{ - std::uint32_t tmp; - std::memcpy( &tmp, s, 4 ); - tmp = __builtin_bswap32( tmp ); - std::memcpy( d, &tmp, 4 ); -} - -inline void reverse( unsigned char (&d)[ 8 ], void const* s ) -{ - std::uint64_t tmp; - std::memcpy( &tmp, s, 8 ); - tmp = __builtin_bswap64( tmp ); - std::memcpy( d, &tmp, 8 ); -} - -inline void reverse( unsigned char (&d)[ 16 ], void const* s ) -{ - std::uint64_t tmp[ 2 ]; - std::memcpy( tmp, s, 16 ); - - std::uint64_t tmp2[ 2 ] = { __builtin_bswap64( tmp[1] ), __builtin_bswap64( tmp[0] ) }; - std::memcpy( d, tmp2, 16 ); -} - -#elif defined(_MSC_VER) - -inline void reverse( unsigned char (&d)[ 2 ], void const* s ) -{ - unsigned short tmp; - std::memcpy( &tmp, s, 2 ); - tmp = _byteswap_ushort( tmp ); - std::memcpy( d, &tmp, 2 ); -} - -inline void reverse( unsigned char (&d)[ 4 ], void const* s ) -{ - unsigned long tmp; - std::memcpy( &tmp, s, 4 ); - tmp = _byteswap_ulong( tmp ); - std::memcpy( d, &tmp, 4 ); -} - -inline void reverse( unsigned char (&d)[ 8 ], void const* s ) -{ - unsigned long long tmp; - std::memcpy( &tmp, s, 8 ); - tmp = _byteswap_uint64( tmp ); - std::memcpy( d, &tmp, 8 ); -} - -inline void reverse( unsigned char (&d)[ 16 ], void const* s ) -{ - unsigned long long tmp[ 2 ]; - std::memcpy( tmp, s, 16 ); - - unsigned long long tmp2[ 2 ] = { _byteswap_uint64( tmp[1] ), _byteswap_uint64( tmp[0] ) }; - std::memcpy( d, tmp2, 16 ); -} - -#endif - -} // namespace detail -} // namespace hash2 -} // namespace boost - -#endif // #ifndef BOOST_HASH2_DETAIL_REVERSE_HPP_INCLUDED diff --git a/include/boost/hash2/get_integral_result.hpp b/include/boost/hash2/get_integral_result.hpp index 7ccef06..c6742f4 100644 --- a/include/boost/hash2/get_integral_result.hpp +++ b/include/boost/hash2/get_integral_result.hpp @@ -5,10 +5,9 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include #include -#include #include +#include #include namespace boost @@ -16,33 +15,167 @@ namespace boost namespace hash2 { -template - typename std::enable_if::value && (sizeof(R) >= sizeof(T)), T>::type - get_integral_result( R const & r ) +namespace detail { - typedef typename std::make_unsigned::type U; - return static_cast( static_cast( r ) ); + +// identity + +template + constexpr typename std::enable_if::type + get_result_multiplier() +{ + return 1; } +// contraction + +// 2 -> 1 +template + constexpr typename std::enable_if::type + get_result_multiplier() +{ + return 0xBF01; +} + +// 4 -> 1 +template + constexpr typename std::enable_if::type + get_result_multiplier() +{ + return 0x7F7F7F7Fu; +} + +// 8 -> 1 +template + constexpr typename std::enable_if::type + get_result_multiplier() +{ + return 0x7F7F7F7F7F7F7F7Full; +} + +// 4 -> 2 +template + constexpr typename std::enable_if::type + get_result_multiplier() +{ + return 0xBFFF0001u; +} + +// 8 -> 2 +template + constexpr typename std::enable_if::type + get_result_multiplier() +{ + return 0xBFFFBFFFBFFFBFFFull; +} + +// 8 -> 4 +template + constexpr typename std::enable_if::type + get_result_multiplier() +{ + return 0xBFFFFFFF00000001ull; +} + +// expansion + +// 1 -> 2 +template + constexpr typename std::enable_if::type + get_result_multiplier() +{ + return 0x7F7F; +} + +// 1 -> 4 +template + constexpr typename std::enable_if::type + get_result_multiplier() +{ + return 0xBFBFBFBFu; +} + +// 1 -> 8 +template + constexpr typename std::enable_if::type + get_result_multiplier() +{ + return 0xDFDFDFDFDFDFDFDFull; +} + +// 2 -> 4 +template + constexpr typename std::enable_if::type + get_result_multiplier() +{ + return 0x7FFF7FFFu; +} + +// 2 -> 8 +template + constexpr typename std::enable_if::type + get_result_multiplier() +{ + return 0x7FFF7FFF7FFF7FFFull; +} + +// 4 -> 8 +template + constexpr typename std::enable_if::type + get_result_multiplier() +{ + return 0x7FFFFFFF7FFFFFFFull; +} + +} // namespace detail + +// contraction + template - typename std::enable_if::value && sizeof(R) == 4 && sizeof(T) == 8, T>::type + typename std::enable_if::value && (sizeof(R) > sizeof(T)), T>::type get_integral_result( R const & r ) { + static_assert( std::is_integral::value, "T must be integral" ); + static_assert( !std::is_same::type, bool>::value, "T must not be bool" ); + + static_assert( std::is_unsigned::value, "R must be unsigned" ); + typedef typename std::make_unsigned::type U; - return static_cast( ( static_cast( r ) << 32 ) + r ); + + constexpr auto m = detail::get_result_multiplier(); + + return static_cast( static_cast( ( r * m ) >> ( std::numeric_limits::digits - std::numeric_limits::digits ) ) ); } -template - T get_integral_result( std::array const & r ) +// identity or expansion + +template + typename std::enable_if::value && (sizeof(R) <= sizeof(T)), T>::type + get_integral_result( R const & r ) { - static_assert( N >= 8, "Array result type is too short" ); - return static_cast( detail::read64le( r.data() ) ); + static_assert( std::is_integral::value, "T must be integral" ); + static_assert( !std::is_same::type, bool>::value, "T must not be bool" ); + + static_assert( std::is_unsigned::value, "R must be unsigned" ); + + typedef typename std::make_unsigned::type U; + + constexpr auto m = detail::get_result_multiplier(); + + return static_cast( static_cast( r * m ) ); } -template - T get_integral_result( digest const & r ) +// array-like R + +template + typename std::enable_if< !std::is_integral::value, T >::type + get_integral_result( R const & r ) { - static_assert( N >= 8, "Digest result type is too short" ); + static_assert( std::is_integral::value, "T must be integral" ); + static_assert( !std::is_same::type, bool>::value, "T must not be bool" ); + + static_assert( R().size() >= 8, "Array-like result type is too short" ); + return static_cast( detail::read64le( r.data() ) ); } diff --git a/test/Jamfile b/test/Jamfile index 166a3b3..037da97 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -30,9 +30,16 @@ run is_trivially_equality_comparable.cpp ; run is_endian_independent.cpp ; run has_constant_size.cpp ; -# helpers +# get_integral_result run get_integral_result.cpp ; +run get_integral_result_2.cpp ; +run get_integral_result_3.cpp ; +run get_integral_result_4.cpp ; +run get_integral_result_5.cpp ; + +# digest + run digest.cpp ; # detail @@ -41,7 +48,6 @@ run detail_read.cpp ; run detail_write.cpp ; run detail_write_2.cpp ; run detail_rot.cpp ; -run detail_reverse.cpp ; run detail_has_tag_invoke.cpp ; # hash_append diff --git a/test/append_map.cpp b/test/append_map.cpp index 59e6aca..c4b57cb 100644 --- a/test/append_map.cpp +++ b/test/append_map.cpp @@ -71,10 +71,10 @@ int main() test< fnv1a_32, little_endian_flavor, std::multimap >( 1082144933ul ); test< fnv1a_64, little_endian_flavor, std::multimap >( 12051529320333828229ull ); - test< fnv1a_32, little_endian_flavor, std::unordered_map >( 1094735330ul ); + test< fnv1a_32, little_endian_flavor, std::unordered_map >( 2445282413ul ); test< fnv1a_64, little_endian_flavor, std::unordered_map >( 2617313294186790738ull ); - test< fnv1a_32, little_endian_flavor, std::unordered_multimap >( 1094735330ul ); + test< fnv1a_32, little_endian_flavor, std::unordered_multimap >( 2445282413ul ); test< fnv1a_64, little_endian_flavor, std::unordered_multimap >( 2617313294186790738ull ); return boost::report_errors(); diff --git a/test/append_set.cpp b/test/append_set.cpp index d5296a2..9c1f3a4 100644 --- a/test/append_set.cpp +++ b/test/append_set.cpp @@ -69,10 +69,10 @@ int main() test< fnv1a_32, little_endian_flavor, std::multiset >( 3576652581ul ); test< fnv1a_64, little_endian_flavor, std::multiset >( 17046016161958689285ull ); - test< fnv1a_32, little_endian_flavor, std::unordered_set >( 3782055292ul ); + test< fnv1a_32, little_endian_flavor, std::unordered_set >( 776982489ul ); test< fnv1a_64, little_endian_flavor, std::unordered_set >( 3232503781718511241ull ); - test< fnv1a_32, little_endian_flavor, std::unordered_multiset >( 3782055292ul ); + test< fnv1a_32, little_endian_flavor, std::unordered_multiset >( 776982489ul ); test< fnv1a_64, little_endian_flavor, std::unordered_multiset >( 3232503781718511241ull ); return boost::report_errors(); diff --git a/test/detail_reverse.cpp b/test/detail_reverse.cpp deleted file mode 100644 index 93f252e..0000000 --- a/test/detail_reverse.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2024 Peter Dimov. -// Distributed under the Boost Software License, Version 1.0. -// https://www.boost.org/LICENSE_1_0.txt - -#include -#include - -template void test() -{ - unsigned char v[ N ] = {}; - for( std::size_t i = 0; i < N; ++i ) v[ i ] = static_cast( i + 1 ); - - unsigned char w[ N ] = {}; - boost::hash2::detail::reverse( w, v ); - - for( std::size_t i = 0; i < N; ++i ) BOOST_TEST_EQ( w[ i ], v[ N - 1 - i ] ); -} - -int main() -{ - test<1>(); - test<2>(); - test<3>(); - test<4>(); - test<5>(); - test<6>(); - test<7>(); - test<8>(); - test<9>(); - test<10>(); - test<11>(); - test<12>(); - test<13>(); - test<14>(); - test<15>(); - test<16>(); - test<17>(); - - return boost::report_errors(); -} diff --git a/test/get_integral_result.cpp b/test/get_integral_result.cpp index c844979..c910b55 100644 --- a/test/get_integral_result.cpp +++ b/test/get_integral_result.cpp @@ -1,94 +1,65 @@ -// Copyright 2017, 2018 Peter Dimov. +// Copyright 2017, 2018, 2024 Peter Dimov // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #include -#include -#include +#include +#include #include -#include + +template void test() +{ + using boost::hash2::get_integral_result; + + R r = R(); + + get_integral_result( r ); + get_integral_result( r ); + get_integral_result( r ); + get_integral_result( r ); + get_integral_result( r ); + get_integral_result( r ); + get_integral_result( r ); + get_integral_result( r ); + get_integral_result( r ); + get_integral_result( r ); + + get_integral_result( r ); + get_integral_result( r ); + get_integral_result( r ); +} int main() { using boost::hash2::get_integral_result; - { - std::uint32_t u32 = 0x12345678; + test(); + test(); + test(); + test(); + test(); - BOOST_TEST_EQ( get_integral_result( u32 ), 0x78 ); - BOOST_TEST_EQ( get_integral_result( u32 ), 0x78 ); - BOOST_TEST_EQ( get_integral_result( u32 ), 0x5678 ); - BOOST_TEST_EQ( get_integral_result( u32 ), 0x5678 ); - BOOST_TEST_EQ( get_integral_result( u32 ), 0x12345678 ); - BOOST_TEST_EQ( get_integral_result( u32 ), 0x12345678 ); - BOOST_TEST_EQ( get_integral_result( u32 ), 0x1234567812345678ull ); - BOOST_TEST_EQ( get_integral_result( u32 ), 0x1234567812345678ull ); - } + test< std::array >(); + test< std::array >(); + test< std::array >(); + test< std::array >(); + test< std::array >(); + test< std::array >(); + test< std::array >(); - { - std::uint32_t s32 = 0xFFFFFFFFu; + test< boost::array >(); + test< boost::array >(); + test< boost::array >(); + test< boost::array >(); + test< boost::array >(); + test< boost::array >(); + test< boost::array >(); - BOOST_TEST_EQ( get_integral_result( s32 ), 0xFF ); - BOOST_TEST_EQ( get_integral_result( s32 ), -1 ); - BOOST_TEST_EQ( get_integral_result( s32 ), 0xFFFF ); - BOOST_TEST_EQ( get_integral_result( s32 ), -1 ); - BOOST_TEST_EQ( get_integral_result( s32 ), 0xFFFFFFFFu ); - BOOST_TEST_EQ( get_integral_result( s32 ), -1 ); - BOOST_TEST_EQ( get_integral_result( s32 ), 0xFFFFFFFFFFFFFFFFull ); - BOOST_TEST_EQ( get_integral_result( s32 ), -1 ); - } - - { - std::uint64_t u64 = 0x0123456789ABCDEFull; - - BOOST_TEST_EQ( get_integral_result( u64 ), 0xEF ); - BOOST_TEST_EQ( get_integral_result( u64 ), -0x11 ); - BOOST_TEST_EQ( get_integral_result( u64 ), 0xCDEF ); - BOOST_TEST_EQ( get_integral_result( u64 ), -0x3211 ); - BOOST_TEST_EQ( get_integral_result( u64 ), 0x89ABCDEF ); - BOOST_TEST_EQ( get_integral_result( u64 ), 0x89ABCDEF ); - BOOST_TEST_EQ( get_integral_result( u64 ), 0x0123456789ABCDEFull ); - BOOST_TEST_EQ( get_integral_result( u64 ), 0x0123456789ABCDEFull ); - } - - { - std::uint64_t s64 = 0xFFFFFFFFFFFFFFFFull; - - BOOST_TEST_EQ( get_integral_result( s64 ), 0xFF ); - BOOST_TEST_EQ( get_integral_result( s64 ), -1 ); - BOOST_TEST_EQ( get_integral_result( s64 ), 0xFFFF ); - BOOST_TEST_EQ( get_integral_result( s64 ), -1 ); - BOOST_TEST_EQ( get_integral_result( s64 ), 0xFFFFFFFFu ); - BOOST_TEST_EQ( get_integral_result( s64 ), -1 ); - BOOST_TEST_EQ( get_integral_result( s64 ), 0xFFFFFFFFFFFFFFFFull ); - BOOST_TEST_EQ( get_integral_result( s64 ), -1 ); - } - - { - std::array a64 = {{ 0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01 }}; - - BOOST_TEST_EQ( get_integral_result( a64 ), 0xEF ); - BOOST_TEST_EQ( get_integral_result( a64 ), -0x11 ); - BOOST_TEST_EQ( get_integral_result( a64 ), 0xCDEF ); - BOOST_TEST_EQ( get_integral_result( a64 ), -0x3211 ); - BOOST_TEST_EQ( get_integral_result( a64 ), 0x89ABCDEF ); - BOOST_TEST_EQ( get_integral_result( a64 ), 0x89ABCDEF ); - BOOST_TEST_EQ( get_integral_result( a64 ), 0x0123456789ABCDEFull ); - BOOST_TEST_EQ( get_integral_result( a64 ), 0x0123456789ABCDEFull ); - } - - { - std::array b64 = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }}; - - BOOST_TEST_EQ( get_integral_result( b64 ), 0xFF ); - BOOST_TEST_EQ( get_integral_result( b64 ), -1 ); - BOOST_TEST_EQ( get_integral_result( b64 ), 0xFFFF ); - BOOST_TEST_EQ( get_integral_result( b64 ), -1 ); - BOOST_TEST_EQ( get_integral_result( b64 ), 0xFFFFFFFFu ); - BOOST_TEST_EQ( get_integral_result( b64 ), -1 ); - BOOST_TEST_EQ( get_integral_result( b64 ), 0xFFFFFFFFFFFFFFFFull ); - BOOST_TEST_EQ( get_integral_result( b64 ), -1 ); - } - - return boost::report_errors(); + test< boost::hash2::digest<8> >(); + test< boost::hash2::digest<16> >(); + test< boost::hash2::digest<20> >(); + test< boost::hash2::digest<28> >(); + test< boost::hash2::digest<32> >(); + test< boost::hash2::digest<48> >(); + test< boost::hash2::digest<64> >(); } diff --git a/test/get_integral_result_2.cpp b/test/get_integral_result_2.cpp new file mode 100644 index 0000000..0697d9f --- /dev/null +++ b/test/get_integral_result_2.cpp @@ -0,0 +1,78 @@ +// Copyright 2017, 2018, 2024 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include +#include + +template void test( R const& r ) +{ + using boost::hash2::get_integral_result; + + { + auto t1 = get_integral_result( r ); + auto t2 = get_integral_result( r ); + + BOOST_TEST_EQ( static_cast( t1 ), t2 ); + } + + { + auto t1 = get_integral_result( r ); + auto t2 = get_integral_result( r ); + + BOOST_TEST_EQ( static_cast( t1 ), t2 ); + } + + { + auto t1 = get_integral_result( r ); + auto t2 = get_integral_result( r ); + + BOOST_TEST_EQ( static_cast( t1 ), t2 ); + } + + { + auto t1 = get_integral_result( r ); + auto t2 = get_integral_result( r ); + + BOOST_TEST_EQ( static_cast( t1 ), t2 ); + } + + { + auto t1 = get_integral_result( r ); + auto t2 = get_integral_result( r ); + + BOOST_TEST_EQ( static_cast( t1 ), t2 ); + } +} + +int main() +{ + using boost::hash2::get_integral_result; + + test( 0x1E ); + test( 0xE1 ); + + test( 0x1E1E ); + test( 0xE1E1 ); + + test( 0x1E1E1E1Eu ); + test( 0xE1E1E1E1u ); + + test( 0x1E1E1E1E1E1E1E1Eull ); + test( 0xE1E1E1E1E1E1E1E1ull ); + + test< std::array >( {{ 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E }} ); + test< std::array >( {{ 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1 }} ); + + test< boost::array >( {{ 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E }} ); + test< boost::array >( {{ 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1 }} ); + + test< boost::hash2::digest<8> >( {{ 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E }} ); + test< boost::hash2::digest<8> >( {{ 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1 }} ); + + return boost::report_errors(); +} diff --git a/test/get_integral_result_3.cpp b/test/get_integral_result_3.cpp new file mode 100644 index 0000000..0e561eb --- /dev/null +++ b/test/get_integral_result_3.cpp @@ -0,0 +1,50 @@ +// Copyright 2017, 2018, 2024 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include +#include + +template void test() +{ + using boost::hash2::get_integral_result; + + { + R a64 = {{ 0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01 }}; + + BOOST_TEST_EQ( get_integral_result( a64 ), 0xEF ); + BOOST_TEST_EQ( get_integral_result( a64 ), -0x11 ); + BOOST_TEST_EQ( get_integral_result( a64 ), 0xCDEF ); + BOOST_TEST_EQ( get_integral_result( a64 ), -0x3211 ); + BOOST_TEST_EQ( get_integral_result( a64 ), 0x89ABCDEF ); + BOOST_TEST_EQ( get_integral_result( a64 ), 0x89ABCDEF ); + BOOST_TEST_EQ( get_integral_result( a64 ), 0x0123456789ABCDEFull ); + BOOST_TEST_EQ( get_integral_result( a64 ), 0x0123456789ABCDEFull ); + } + + { + R b64 = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }}; + + BOOST_TEST_EQ( get_integral_result( b64 ), 0xFF ); + BOOST_TEST_EQ( get_integral_result( b64 ), -1 ); + BOOST_TEST_EQ( get_integral_result( b64 ), 0xFFFF ); + BOOST_TEST_EQ( get_integral_result( b64 ), -1 ); + BOOST_TEST_EQ( get_integral_result( b64 ), 0xFFFFFFFFu ); + BOOST_TEST_EQ( get_integral_result( b64 ), -1 ); + BOOST_TEST_EQ( get_integral_result( b64 ), 0xFFFFFFFFFFFFFFFFull ); + BOOST_TEST_EQ( get_integral_result( b64 ), -1 ); + } +} + +int main() +{ + test< std::array >(); + test< boost::array >(); + test< boost::hash2::digest<8> >(); + + return boost::report_errors(); +} diff --git a/test/get_integral_result_4.cpp b/test/get_integral_result_4.cpp new file mode 100644 index 0000000..b7c4a46 --- /dev/null +++ b/test/get_integral_result_4.cpp @@ -0,0 +1,119 @@ +// Copyright 2017, 2018, 2024 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include + +template void test_identity() +{ + using boost::hash2::get_integral_result; + + using R = T; + + for( unsigned i = 0; i <= std::numeric_limits::max(); ++i ) + { + R r = static_cast( i ); + T t = get_integral_result( r ); + + BOOST_TEST_EQ( t, r ); + } +} + +template std::size_t test_permutation( int shift ) +{ + using boost::hash2::get_integral_result; + + std::set dist; + + for( unsigned i = 0; i <= std::numeric_limits::max(); ++i ) + { + R r = static_cast( i << shift ); + T t = get_integral_result( r ); + + dist.insert( t ); + } + + return dist.size(); +} + +template std::size_t test_roundtrip() +{ + using boost::hash2::get_integral_result; + + std::set dist; + + for( unsigned i = 0; i <= std::numeric_limits::max(); ++i ) + { + T t1 = static_cast( i ); + R r = get_integral_result( t1 ); + T t2 = get_integral_result( r ); + + dist.insert( t2 ); + } + + return dist.size(); +} + +int main() +{ + // 1 -> 1 + + test_identity(); + + // 1 -> 2 + + BOOST_TEST_EQ( (test_permutation( 0 )), 256u ); + BOOST_TEST_EQ( (test_permutation( 8 )), 256u ); + + BOOST_TEST_GE( (test_roundtrip()), 255u ); // ! + + // 1 -> 4 + + BOOST_TEST_EQ( (test_permutation( 0 )), 256u ); + BOOST_TEST_EQ( (test_permutation( 8 )), 256u ); + BOOST_TEST_GE( (test_permutation( 16 )), 255u ); // ! + BOOST_TEST_EQ( (test_permutation( 24 )), 256u ); + + BOOST_TEST_EQ( (test_roundtrip()), 256u ); + + // 1 -> 8 + + BOOST_TEST_EQ( (test_permutation( 0 )), 256u ); + BOOST_TEST_EQ( (test_permutation( 8 )), 256u ); + BOOST_TEST_EQ( (test_permutation( 16 )), 256u ); + BOOST_TEST_EQ( (test_permutation( 24 )), 256u ); + BOOST_TEST_EQ( (test_permutation( 32 )), 256u ); + BOOST_TEST_EQ( (test_permutation( 40 )), 256u ); + BOOST_TEST_EQ( (test_permutation( 48 )), 256u ); + BOOST_TEST_EQ( (test_permutation( 56 )), 256u ); + + BOOST_TEST_EQ( (test_roundtrip()), 256u ); + + // 2 -> 2 + + test_identity(); + + // 2 -> 4 + + BOOST_TEST_EQ( (test_permutation( 0 )), 65536u ); + BOOST_TEST_EQ( (test_permutation( 16 )), 65536u ); + + BOOST_TEST_GE( (test_roundtrip()), 65535u ); // ! + + // 2 -> 8 + + BOOST_TEST_EQ( (test_permutation( 0 )), 65536u ); + BOOST_TEST_EQ( (test_permutation( 16 )), 65536u ); + BOOST_TEST_EQ( (test_permutation( 32 )), 65536u ); + BOOST_TEST_EQ( (test_permutation( 48 )), 65536u ); + + BOOST_TEST_EQ( (test_roundtrip()), 65536u ); + + // + + return boost::report_errors(); +} diff --git a/test/get_integral_result_5.cpp b/test/get_integral_result_5.cpp new file mode 100644 index 0000000..20e2226 --- /dev/null +++ b/test/get_integral_result_5.cpp @@ -0,0 +1,74 @@ +// Copyright 2017, 2018, 2024 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include + +using T = std::uint32_t; + +void test_identity() +{ + using boost::hash2::get_integral_result; + + using R = T; + + for( unsigned i = 0; i < 65536; ++i ) + { + R r = static_cast( i * 0x9E3779B9u ); + T t = get_integral_result( r ); + + BOOST_TEST_EQ( t, r ); + } +} + +template void test_permutation( R offset = 0, R scale = 1 ) +{ + using boost::hash2::get_integral_result; + + std::set dist; + + for( unsigned i = 0; i < 65536; ++i ) + { + R r = static_cast( i * 0x9E3779B9u * scale + offset ); + T t = get_integral_result( r ); + + dist.insert( t ); + } + + BOOST_TEST_EQ( dist.size(), 65536u ); +} + +template void test_roundtrip() +{ + using boost::hash2::get_integral_result; + + std::set dist; + + for( unsigned i = 0; i < 65536; ++i ) + { + T t1 = static_cast( i * 0x9E3779B9u ); + R r = get_integral_result( t1 ); + T t2 = get_integral_result( r ); + + dist.insert( t2 ); + } + + BOOST_TEST_EQ( dist.size(), 65536u ); +} + +int main() +{ + test_identity(); + + test_permutation(); + test_permutation(); + + test_roundtrip(); + test_roundtrip(); + + return boost::report_errors(); +}