diff --git a/include/ebcl/inline/Utilities.hh b/include/ebcl/inline/Utilities.hh index 49688d2..6b5182e 100644 --- a/include/ebcl/inline/Utilities.hh +++ b/include/ebcl/inline/Utilities.hh @@ -376,6 +376,42 @@ inline uint32_t ComputeHash( std::pair< T1 , T2 > const& item ) return hv; } +// Recursive template that will hash each tuple element starting from +// the last one. +template< typename Tuple , size_t Index = std::tuple_size< Tuple >::value - 1 > +struct T_TupleHashHelper_ +{ + static void apply( uint32_t& hashValue , Tuple const& t ) + { + T_TupleHashHelper_< Tuple , Index - 1 >::apply( hashValue , t ); + CombineHash( hashValue , std::get< Index >( t ) ); + } +}; +// Specialize for the first element, as it must not recurse. +template< typename Tuple > +struct T_TupleHashHelper_< Tuple , 0 > +{ + static void apply( uint32_t& hashValue , Tuple const& t ) + { + CombineHash( hashValue , std::get< 0 >( t ) ); + } +}; + +template< typename... Types > +inline uint32_t ComputeHash( std::tuple< Types... > const& item ) +{ + uint32_t hv = 0; + T_TupleHashHelper_< std::tuple< Types... > >::apply( hv , item ); + return hv; +} + +// Specialize the function for empty tuples +template< > +inline uint32_t ComputeHash( std::tuple< > const& ) +{ + return 0; +} + /*= PRIVATE IMPLEMENTATION BASE ==============================================*/ diff --git a/tests/hash-functions.cc b/tests/hash-functions.cc index 4e11aa9..8e678a9 100644 --- a/tests/hash-functions.cc +++ b/tests/hash-functions.cc @@ -14,6 +14,11 @@ class ComputeHashTest : public CppUnit::TestFixture CPPUNIT_TEST( testInt64 ); CPPUNIT_TEST( testStructDefault ); CPPUNIT_TEST( testPair ); + + CPPUNIT_TEST( testTupleEmpty ); + CPPUNIT_TEST( testTupleOne ); + CPPUNIT_TEST( testTuplePair ); + CPPUNIT_TEST( testTupleMore ); CPPUNIT_TEST_SUITE_END( ); public: @@ -23,6 +28,11 @@ public: void testInt64( ); void testStructDefault( ); void testPair( ); + + void testTupleEmpty( ); + void testTupleOne( ); + void testTuplePair( ); + void testTupleMore( ); }; @@ -79,10 +89,38 @@ void ComputeHashTest::testStructDefault( ) void ComputeHashTest::testPair( ) { - auto p{ std::make_pair< uint8_t , uint32_t >( 12 , 128 ) }; - + const auto p{ std::make_pair< uint8_t , uint32_t >( 12 , 128 ) }; uint32_t hv = 0x9e3779b9 + 12; hv = 128 + 0x9e3779b9 + ( hv << 6 ) + ( hv >> 2 ); - CPPUNIT_ASSERT_EQUAL( hv , ComputeHash( p ) ); } + +/*----------------------------------------------------------------------------*/ + +void ComputeHashTest::testTupleEmpty( ) +{ + const std::tuple< > t{}; + CPPUNIT_ASSERT_EQUAL( 0u , ComputeHash( t ) ); +} + +void ComputeHashTest::testTupleOne( ) +{ + const std::tuple< uint8_t > t{ 12 }; + CPPUNIT_ASSERT_EQUAL( 0x9e3779b9 + 12u , ComputeHash( t ) ); +} + +void ComputeHashTest::testTuplePair( ) +{ + const auto p{ std::make_pair< uint8_t , uint32_t >( 12 , 128 ) }; + const auto t{ std::make_tuple< uint8_t , uint32_t >( 12 , 128 ) }; + CPPUNIT_ASSERT_EQUAL( ComputeHash( p ) , ComputeHash( t ) ); +} + +void ComputeHashTest::testTupleMore( ) +{ + const auto p{ std::make_pair< uint8_t , uint32_t >( 12 , 128 ) }; + const auto t{ std::make_tuple< uint8_t , uint32_t , uint8_t >( 12 , 128 , 92 ) }; + uint32_t hv = ComputeHash( p ); + CombineHash( hv , uint8_t( 92 ) ); + CPPUNIT_ASSERT_EQUAL( hv , ComputeHash( t ) ); +}