// Copyright 2022 Peter Dimov // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #ifndef BOOST_HASH_DETAIL_HASH_RANGE_HPP #define BOOST_HASH_DETAIL_HASH_RANGE_HPP #include #include #include #include #include #include #include #include namespace boost { namespace hash_detail { template struct is_char_type: public boost::false_type {}; #if CHAR_BIT == 8 template<> struct is_char_type: public boost::true_type {}; template<> struct is_char_type: public boost::true_type {}; template<> struct is_char_type: public boost::true_type {}; #if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L template<> struct is_char_type: public boost::true_type {}; #endif #if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L template<> struct is_char_type: public boost::true_type {}; #endif #endif template inline typename boost::enable_if_< !is_char_type::value_type>::value, std::size_t >::type hash_range( std::size_t seed, It first, It last ) { for( ; first != last; ++first ) { hash_combine::value_type>( seed, *first ); } return seed; } template inline typename boost::enable_if_< is_char_type::value_type>::value && is_same::iterator_category, std::random_access_iterator_tag>::value, std::size_t>::type hash_range( std::size_t seed, It first, It last ) { std::size_t n = static_cast( last - first ); for( ; n >= 4; first += 4, n -= 4 ) { // clang 5+, gcc 5+ figure out this pattern and use a single mov on x86 // gcc on s390x and power BE even knows how to use load-reverse boost::uint32_t w = static_cast( static_cast( first[0] ) ) | static_cast( static_cast( first[1] ) ) << 8 | static_cast( static_cast( first[2] ) ) << 16 | static_cast( static_cast( first[3] ) ) << 24; hash_combine( seed, w ); } { // add a trailing suffix byte of 0x01 because otherwise sequences of // trailing zeroes are indistinguishable from end of string boost::uint32_t w = 0x01u; switch( n ) { case 1: w = static_cast( static_cast( first[0] ) ) | 0x0100u; break; case 2: w = static_cast( static_cast( first[0] ) ) | static_cast( static_cast( first[1] ) ) << 8 | 0x010000u; break; case 3: w = static_cast( static_cast( first[0] ) ) | static_cast( static_cast( first[1] ) ) << 8 | static_cast( static_cast( first[2] ) ) << 16 | 0x01000000u; break; } hash_combine( seed, w ); } return seed; } template inline typename boost::enable_if_< is_char_type::value_type>::value && !is_same::iterator_category, std::random_access_iterator_tag>::value, std::size_t>::type hash_range( std::size_t seed, It first, It last ) { for( ;; ) { boost::uint32_t w = 0; if( first == last ) { hash_combine( seed, w | 0x01u ); return seed; } w |= static_cast( static_cast( *first ) ); ++first; if( first == last ) { hash_combine( seed, w | 0x0100u ); return seed; } w |= static_cast( static_cast( *first ) ) << 8; ++first; if( first == last ) { hash_combine( seed, w | 0x010000u ); return seed; } w |= static_cast( static_cast( *first ) ) << 16; ++first; if( first == last ) { hash_combine( seed, w | 0x01000000u ); return seed; } w |= static_cast( static_cast( *first ) ) << 24; ++first; hash_combine( seed, w ); } } } // namespace hash_detail } // namespace boost #endif // #ifndef BOOST_HASH_DETAIL_HASH_RANGE_HPP