Compare commits

..

3 Commits

Author SHA1 Message Date
Peter Dimov
3ca95a65df Use boost::hash in hash_value, not std::hash (closes #27) 2021-03-13 05:08:03 +02:00
Peter Dimov
ae1f72671e Add test for types supported by boost::hash, but not by std::hash 2021-03-13 04:50:01 +02:00
Peter Dimov
a2dab8c7d3 Refactor detail::hash_value_L 2021-03-13 04:10:41 +02:00
4 changed files with 63 additions and 54 deletions

View File

@@ -26,6 +26,7 @@
#include <initializer_list>
#include <utility>
#include <functional> // std::hash
#include <cstdint>
//
@@ -38,6 +39,8 @@ BOOST_NORETURN void throw_exception( std::exception const & e ); // user defined
#endif
template<class T> struct hash;
namespace variant2
{
@@ -1581,7 +1584,7 @@ public:
template<class U,
class Ud = typename std::decay<U>::type,
class E1 = typename std::enable_if< !std::is_same<Ud, variant>::value && !std::is_base_of<variant, Ud>::value && !detail::is_in_place_index<Ud>::value && !detail::is_in_place_type<Ud>::value >::type,
class E1 = typename std::enable_if< !std::is_same<Ud, variant>::value && !detail::is_in_place_index<Ud>::value && !detail::is_in_place_type<Ud>::value >::type,
class V = detail::resolve_overload_type<U&&, T...>,
class E2 = typename std::enable_if<std::is_constructible<V, U&&>::value>::type
>
@@ -2195,31 +2198,59 @@ void swap( variant<T...> & v, variant<T...> & w )
namespace detail
{
template<class V> struct hash_value_L
inline std::size_t hash_value_impl_( mp11::mp_true, std::size_t index, std::size_t value )
{
boost::ulong_long_type hv = ( boost::ulong_long_type( 0xCBF29CE4 ) << 32 ) + 0x84222325;
boost::ulong_long_type const prime = ( boost::ulong_long_type( 0x00000100 ) << 32 ) + 0x000001B3;
hv ^= index;
hv *= prime;
hv ^= value;
hv *= prime;
return static_cast<std::size_t>( hv );
}
inline std::size_t hash_value_impl_( mp11::mp_false, std::size_t index, std::size_t value )
{
std::size_t hv = 0x811C9DC5;
std::size_t const prime = 0x01000193;
hv ^= index;
hv *= prime;
hv ^= value;
hv *= prime;
return hv;
}
inline std::size_t hash_value_impl( std::size_t index, std::size_t value )
{
return hash_value_impl_( mp11::mp_bool< (SIZE_MAX > UINT32_MAX) >(), index, value );
}
template<template<class> class H, class V> struct hash_value_L
{
V const & v;
template<class I> std::size_t operator()( I ) const
{
boost::ulong_long_type hv = ( boost::ulong_long_type( 0xCBF29CE4 ) << 32 ) + 0x84222325;
boost::ulong_long_type const prime = ( boost::ulong_long_type( 0x00000100 ) << 32 ) + 0x000001B3;
// index
hv ^= I::value;
hv *= prime;
// value
auto const & t = unsafe_get<I::value>( v );
hv ^= std::hash<remove_cv_ref_t<decltype(t)>>()( t );
hv *= prime;
std::size_t index = I::value;
std::size_t value = H<remove_cv_ref_t<decltype(t)>>()( t );
return static_cast<std::size_t>( hv );
return hash_value_impl( index, value );
}
};
template<class... T> std::size_t hash_value_std( variant<T...> const & v )
{
return mp11::mp_with_index<sizeof...(T)>( v.index(), detail::hash_value_L< std::hash, variant<T...> >{ v } );
}
} // namespace detail
inline std::size_t hash_value( monostate const & )
@@ -2229,7 +2260,7 @@ inline std::size_t hash_value( monostate const & )
template<class... T> std::size_t hash_value( variant<T...> const & v )
{
return mp11::mp_with_index<sizeof...(T)>( v.index(), detail::hash_value_L< variant<T...> >{ v } );
return mp11::mp_with_index<sizeof...(T)>( v.index(), detail::hash_value_L< boost::hash, variant<T...> >{ v } );
}
namespace detail
@@ -2250,7 +2281,7 @@ template<class V> struct std_hash_impl<V, true>
{
std::size_t operator()( V const & v ) const
{
return hash_value( v );
return detail::hash_value_std( v );
}
};

View File

@@ -119,5 +119,3 @@ run variant_visit_r.cpp : : :
<toolset>gcc,<target-os>windows:<variant>release
<toolset>gcc,<target-os>cygwin:<variant>release
;
compile variant_derived_construct.cpp ;

View File

@@ -1,33 +0,0 @@
// Copyright 2021 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/variant2/variant.hpp>
using namespace boost::variant2;
template<class... T> class X: variant<T...>
{
using base = variant<T...>;
using base::base;
};
struct Y
{
Y( Y const& rhs ) = default;
template<class T> Y( T const& t )
{
t.bar();
}
};
int main()
{
using W = X<int, double, Y>;
W a( 1 );
W b( a );
(void)b;
}

View File

@@ -12,6 +12,7 @@
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/container_hash/hash.hpp>
#include <boost/config/workaround.hpp>
#include <vector>
using namespace boost::variant2;
@@ -47,7 +48,17 @@ template<template<class...> class Hash, class T> void test2()
BOOST_TEST_NE( h2, h3 );
}
struct X {};
struct X
{
int m = 0;
};
std::size_t hash_value( X const& x )
{
return boost::hash<int>()( x.m );
}
struct Y {}; // no hash support
int main()
{
@@ -57,6 +68,8 @@ int main()
test<boost::hash, monostate, monostate, monostate>();
test<boost::hash, int, int, float>();
test<boost::hash, monostate, X, std::vector<X>>();
test2<std::hash, int>();
test2<std::hash, float>();
@@ -65,7 +78,7 @@ int main()
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910) && ( !defined(_LIBCPP_STD_VER) || _LIBCPP_STD_VER > 11 )
BOOST_TEST_TRAIT_FALSE(( detail::is_hash_enabled<X> ));
BOOST_TEST_TRAIT_FALSE(( detail::is_hash_enabled<Y> ));
#endif