mirror of
https://github.com/boostorg/container_hash.git
synced 2025-08-03 14:34:39 +02:00
Add support for tuple-like types. Refs #30.
This commit is contained in:
@@ -1,133 +0,0 @@
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Copyright 2021 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP
|
||||
#define BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP
|
||||
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
#include <boost/type_traits/enable_if.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
// no support
|
||||
|
||||
#else
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
template <std::size_t I, typename T>
|
||||
inline typename boost::enable_if_<(I == std::tuple_size<T>::value),
|
||||
void>::type
|
||||
hash_combine_tuple(std::size_t&, T const&)
|
||||
{
|
||||
}
|
||||
|
||||
template <std::size_t I, typename T>
|
||||
inline typename boost::enable_if_<(I < std::tuple_size<T>::value),
|
||||
void>::type
|
||||
hash_combine_tuple(std::size_t& seed, T const& v)
|
||||
{
|
||||
boost::hash_combine(seed, std::get<I>(v));
|
||||
boost::hash_detail::hash_combine_tuple<I + 1>(seed, v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::size_t hash_tuple(T const& v)
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
boost::hash_detail::hash_combine_tuple<0>(seed, v);
|
||||
return seed;
|
||||
}
|
||||
|
||||
} // namespace hash_detail
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
|
||||
template <typename... T>
|
||||
inline std::size_t hash_value(std::tuple<T...> const& v)
|
||||
{
|
||||
return boost::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline std::size_t hash_value(std::tuple<> const& v)
|
||||
{
|
||||
return boost::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0>
|
||||
inline std::size_t hash_value(std::tuple<A0> const& v)
|
||||
{
|
||||
return boost::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1>
|
||||
inline std::size_t hash_value(std::tuple<A0, A1> const& v)
|
||||
{
|
||||
return boost::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2>
|
||||
inline std::size_t hash_value(std::tuple<A0, A1, A2> const& v)
|
||||
{
|
||||
return boost::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3>
|
||||
inline std::size_t hash_value(std::tuple<A0, A1, A2, A3> const& v)
|
||||
{
|
||||
return boost::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4>
|
||||
inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4> const& v)
|
||||
{
|
||||
return boost::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
|
||||
inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5> const& v)
|
||||
{
|
||||
return boost::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
|
||||
inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6> const& v)
|
||||
{
|
||||
return boost::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
|
||||
inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6, A7> const& v)
|
||||
{
|
||||
return boost::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
|
||||
inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6, A7, A8> const& v)
|
||||
{
|
||||
return boost::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
|
||||
inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6, A7, A8, A9> const& v)
|
||||
{
|
||||
return boost::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
#endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #if defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
#endif // #ifndef BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP
|
156
include/boost/container_hash/detail/hash_tuple_like.hpp
Normal file
156
include/boost/container_hash/detail/hash_tuple_like.hpp
Normal file
@@ -0,0 +1,156 @@
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Copyright 2021 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP
|
||||
#define BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP
|
||||
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
#include <boost/container_hash/is_tuple_like.hpp>
|
||||
#include <boost/container_hash/is_range.hpp>
|
||||
#include <boost/type_traits/enable_if.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
|
||||
#if defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
// no support for tuple-likes
|
||||
|
||||
#else
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
template <std::size_t I, typename T>
|
||||
inline
|
||||
typename boost::enable_if_<(I == std::tuple_size<T>::value), void>::type
|
||||
hash_combine_tuple_like( std::size_t&, T const& )
|
||||
{
|
||||
}
|
||||
|
||||
template <std::size_t I, typename T>
|
||||
inline
|
||||
typename boost::enable_if_<(I < std::tuple_size<T>::value), void>::type
|
||||
hash_combine_tuple_like( std::size_t& seed, T const& v )
|
||||
{
|
||||
using std::get;
|
||||
boost::hash_combine( seed, get<I>( v ) );
|
||||
|
||||
boost::hash_detail::hash_combine_tuple_like<I + 1>( seed, v );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::size_t hash_tuple_like( T const& v )
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_detail::hash_combine_tuple_like<0>( seed, v );
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
} // namespace hash_detail
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1800)
|
||||
|
||||
template <class T>
|
||||
inline
|
||||
typename boost::enable_if_<
|
||||
container_hash::is_tuple_like<T>::value && !container_hash::is_range<T>::value,
|
||||
std::size_t>::type
|
||||
hash_value( T const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename... T>
|
||||
inline std::size_t hash_value( std::tuple<T...> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
inline std::size_t hash_value( std::tuple<> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
template<typename A0>
|
||||
inline std::size_t hash_value( std::tuple<A0> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
template<typename A0, typename A1>
|
||||
inline std::size_t hash_value( std::tuple<A0, A1> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2>
|
||||
inline std::size_t hash_value( std::tuple<A0, A1, A2> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3>
|
||||
inline std::size_t hash_value( std::tuple<A0, A1, A2, A3> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4>
|
||||
inline std::size_t hash_value( std::tuple<A0, A1, A2, A3, A4> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
|
||||
inline std::size_t hash_value( std::tuple<A0, A1, A2, A3, A4, A5> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
|
||||
inline std::size_t hash_value( std::tuple<A0, A1, A2, A3, A4, A5, A6> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
|
||||
inline std::size_t hash_value( std::tuple<A0, A1, A2, A3, A4, A5, A6, A7> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
|
||||
inline std::size_t hash_value( std::tuple<A0, A1, A2, A3, A4, A5, A6, A7, A8> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
|
||||
inline std::size_t hash_value( std::tuple<A0, A1, A2, A3, A4, A5, A6, A7, A8, A9> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
#endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #if defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
#endif // #ifndef BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP
|
@@ -15,7 +15,7 @@
|
||||
#include <boost/container_hash/is_contiguous_range.hpp>
|
||||
#include <boost/container_hash/is_unordered_range.hpp>
|
||||
#include <boost/container_hash/is_described_class.hpp>
|
||||
#include <boost/container_hash/detail/hash_tuple.hpp>
|
||||
#include <boost/container_hash/detail/hash_tuple_like.hpp>
|
||||
#include <boost/container_hash/detail/hash_mix.hpp>
|
||||
#include <boost/container_hash/detail/hash_range.hpp>
|
||||
#include <boost/type_traits/is_enum.hpp>
|
||||
|
@@ -121,3 +121,4 @@ run hash_integral_test2.cpp ;
|
||||
run hash_nullptr_test.cpp ;
|
||||
|
||||
run is_tuple_like_test.cpp ;
|
||||
run hash_tuple_like_test.cpp ;
|
||||
|
204
test/hash_tuple_like_test.cpp
Normal file
204
test/hash_tuple_like_test.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||
#endif
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/type_traits/enable_if.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <utility>
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
# include <tuple>
|
||||
|
||||
namespace user
|
||||
{
|
||||
|
||||
struct Y1
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
template<std::size_t I> int& get( Y1& v );
|
||||
template<std::size_t I> int const& get( Y1 const& v );
|
||||
|
||||
template<> int& get<0>( Y1& v )
|
||||
{
|
||||
return v.a;
|
||||
}
|
||||
|
||||
template<> int const& get<0>( Y1 const& v )
|
||||
{
|
||||
return v.a;
|
||||
}
|
||||
|
||||
template<> int& get<1>( Y1& v )
|
||||
{
|
||||
return v.b;
|
||||
}
|
||||
|
||||
template<> int const& get<1>( Y1 const& v )
|
||||
{
|
||||
return v.b;
|
||||
}
|
||||
|
||||
struct Y2
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
|
||||
template<class T> friend
|
||||
typename boost::enable_if_<boost::is_same<T, Y2>::value, std::size_t>::type
|
||||
hash_value( T const& v )
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_combine( seed, v.a );
|
||||
boost::hash_combine( seed, v.b );
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace user
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<> struct tuple_size<user::Y1>: std::integral_constant<std::size_t, 2>
|
||||
{
|
||||
};
|
||||
|
||||
template<> struct tuple_size<user::Y2>: std::integral_constant<std::size_t, 2>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<> struct is_tuple_like<user::Y2>: boost::false_type {};
|
||||
|
||||
} // namespace container_hash
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
template<class T> std::size_t hv( T const& t )
|
||||
{
|
||||
return boost::hash<T>()( t );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
std::pair<int, int> tp( 1, 2 );
|
||||
int const a[] = { 1, 2 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
{
|
||||
std::tuple<> tp;
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), 0u );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int> tp( 1 );
|
||||
int const a[] = { 1 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int> tp( 1, 2 );
|
||||
int const a[] = { 1, 2 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int, int> tp( 1, 2, 3 );
|
||||
int const a[] = { 1, 2, 3 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int, int, int> tp( 1, 2, 3, 4 );
|
||||
int const a[] = { 1, 2, 3, 4 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int, int, int, int> tp( 1, 2, 3, 4, 5 );
|
||||
int const a[] = { 1, 2, 3, 4, 5 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6 );
|
||||
int const a[] = { 1, 2, 3, 4, 5, 6 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6, 7 );
|
||||
int const a[] = { 1, 2, 3, 4, 5, 6, 7 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int, int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6, 7, 8 );
|
||||
int const a[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int, int, int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6, 7, 8, 9 );
|
||||
int const a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1800)
|
||||
|
||||
{
|
||||
user::Y1 tp = { 1, 2 };
|
||||
int const a[] = { 1, 2 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
{
|
||||
user::Y2 tp = { 1, 2 };
|
||||
int const a[] = { 1, 2 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
Reference in New Issue
Block a user