updated is_avalanching trait protocol

This commit is contained in:
joaquintides 2024-05-29 19:51:32 +02:00
parent 6745d67d62
commit f77bdb9b67
8 changed files with 74 additions and 18 deletions

View File

@ -1,5 +1,5 @@
// Copyright 2021 Peter Dimov. // Copyright 2021 Peter Dimov.
// Copyright 2023 Joaquin M Lopez Munoz. // Copyright 2023-2024 Joaquin M Lopez Munoz.
// Distributed under the Boost Software License, Version 1.0. // Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt // https://www.boost.org/LICENSE_1_0.txt
@ -25,6 +25,7 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <chrono> #include <chrono>
#include <type_traits>
using namespace std::chrono_literals; using namespace std::chrono_literals;
@ -341,7 +342,7 @@ template<> struct fnv1a_hash_impl<64>
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits > struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
{ {
using is_avalanching = void; using is_avalanching = std::true_type;
}; };
template<class K, class V> using std_unordered_map_fnv1a = template<class K, class V> using std_unordered_map_fnv1a =

View File

@ -18,6 +18,7 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <chrono> #include <chrono>
#include <type_traits>
using namespace std::chrono_literals; using namespace std::chrono_literals;
@ -262,7 +263,7 @@ template<> struct fnv1a_hash_impl<64>
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits > struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
{ {
using is_avalanching = void; using is_avalanching = std::true_type;
}; };
template<class K, class V> using boost_unordered_flat_map_fnv1a = template<class K, class V> using boost_unordered_flat_map_fnv1a =
@ -272,7 +273,7 @@ template<class K, class V> using boost_unordered_flat_map_fnv1a =
struct slightly_bad_hash struct slightly_bad_hash
{ {
using is_avalanching = void; using is_avalanching = std::true_type;
std::size_t operator()( std::string const& s ) const std::size_t operator()( std::string const& s ) const
{ {
@ -295,7 +296,7 @@ template<class K, class V> using boost_unordered_flat_map_slightly_bad_hash =
struct bad_hash struct bad_hash
{ {
using is_avalanching = void; using is_avalanching = std::true_type;
std::size_t operator()( std::string const& s ) const std::size_t operator()( std::string const& s ) const
{ {

View File

@ -1,5 +1,5 @@
// Copyright 2021 Peter Dimov. // Copyright 2021 Peter Dimov.
// Copyright 2023 Joaquin M Lopez Munoz. // Copyright 2023-2024 Joaquin M Lopez Munoz.
// Distributed under the Boost Software License, Version 1.0. // Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt // https://www.boost.org/LICENSE_1_0.txt
@ -26,6 +26,7 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <chrono> #include <chrono>
#include <type_traits>
using namespace std::chrono_literals; using namespace std::chrono_literals;
@ -342,7 +343,7 @@ template<> struct fnv1a_hash_impl<64>
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits > struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
{ {
using is_avalanching = void; using is_avalanching = std::true_type;
}; };
template<class K, class V> using std_unordered_map_fnv1a = template<class K, class V> using std_unordered_map_fnv1a =

View File

@ -10,6 +10,7 @@
* Added container `pmr` aliases when header `<memory_resource>` is available. The alias `boost::unordered::pmr::[container]` refers to `boost::unordered::[container]` with a `std::pmr::polymorphic_allocator` allocator type. * Added container `pmr` aliases when header `<memory_resource>` is available. The alias `boost::unordered::pmr::[container]` refers to `boost::unordered::[container]` with a `std::pmr::polymorphic_allocator` allocator type.
* Equipped open-addressing and concurrent containers to internally calculate and provide statistical metrics affected by the quality of the hash function. This functionality is enabled by the global macro `BOOST_UNORDERED_ENABLE_STATS`. * Equipped open-addressing and concurrent containers to internally calculate and provide statistical metrics affected by the quality of the hash function. This functionality is enabled by the global macro `BOOST_UNORDERED_ENABLE_STATS`.
* Avalanching hash functions must now be marked via an `is_avalanching` typedef with an embedded `value` constant set to `true` (typically, defining `is_avalanching` as `std::true_type`). `using is_avalanching = void` is deprecated but allowed for backwards compatibility.
== Release 1.85.0 == Release 1.85.0

View File

@ -33,7 +33,7 @@ follows:
---- ----
struct my_string_hash_function struct my_string_hash_function
{ {
using is_avalanching = void; // instruct Boost.Unordered to not use post-mixing using is_avalanching = std::true_type; // instruct Boost.Unordered to not use post-mixing
std::size_t operator()(const std::string& x) const std::size_t operator()(const std::string& x) const
{ {

View File

@ -32,9 +32,14 @@ large changes in the returned hash code &#8212;ideally, flipping one bit in the
the input value results in each bit of the hash code flipping with probability 50%. Approaching the input value results in each bit of the hash code flipping with probability 50%. Approaching
this property is critical for the proper behavior of open-addressing hash containers. this property is critical for the proper behavior of open-addressing hash containers.
`hash_is_avalanching<Hash>::value` is `true` if `Hash::is_avalanching` is a valid type, `hash_is_avalanching<Hash>::value` is:
and `false` otherwise.
Users can then declare a hash function `Hash` as avalanching either by embedding an `is_avalanching` typedef * `false` if `Hash::is_avalanching` is not present,
* `Hash::is_avalanching::value` if this is present and convertible at compile time to a `bool`,
* `true` if `Hash::is_avalanching` is `void` (this usage is deprecated).
The behavior is undefined if none of the three cases above is met.
Users can then declare a hash function `Hash` as avalanching either by embedding an appropriate `is_avalanching` typedef
into the definition of `Hash`, or directly by specializing `hash_is_avalanching<Hash>` to a class with into the definition of `Hash`, or directly by specializing `hash_is_avalanching<Hash>` to a class with
an embedded compile-time constant `value` set to `true`. an embedded compile-time constant `value` set to `true`.

View File

@ -1,6 +1,6 @@
/* Hash function characterization. /* Hash function characterization.
* *
* Copyright 2022 Joaquin M Lopez Munoz. * Copyright 2022-2024 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@ -19,12 +19,28 @@ namespace unordered{
namespace detail{ namespace detail{
template<typename Hash,typename=void> template<typename Hash,typename=void>
struct hash_is_avalanching_impl: std::false_type{}; struct hash_is_avalanching_impl:std::false_type{};
template<typename IsAvalanching>
struct avalanching_value
{
static constexpr bool value=IsAvalanching::value;
};
/* may be explicitly marked as BOOST_DEPRECATED in the future */
template<> struct avalanching_value<void>
{
static constexpr bool value=true;
};
template<typename Hash> template<typename Hash>
struct hash_is_avalanching_impl<Hash, struct hash_is_avalanching_impl<
boost::unordered::detail::void_t<typename Hash::is_avalanching> >: Hash,
std::true_type{}; boost::unordered::detail::void_t<typename Hash::is_avalanching>
>:std::integral_constant<
bool,
avalanching_value<typename Hash::is_avalanching>::value
>{};
} /* namespace detail */ } /* namespace detail */
@ -32,8 +48,12 @@ struct hash_is_avalanching_impl<Hash,
* when actual characterization differs from default. * when actual characterization differs from default.
*/ */
/* hash_is_avalanching<Hash>::value is true when the type Hash::is_avalanching /* hash_is_avalanching<Hash>::value is:
* is present, false otherwise. * - false if Hash::is_avalanching is not present.
* - Hash::is_avalanching::value if this is present and constexpr-convertible
* to a bool.
* - true if Hash::is_avalanching is void (deprecated).
* UB otherwise.
*/ */
template<typename Hash> template<typename Hash>
struct hash_is_avalanching: detail::hash_is_avalanching_impl<Hash>::type{}; struct hash_is_avalanching: detail::hash_is_avalanching_impl<Hash>::type{};

View File

@ -1,4 +1,5 @@
// Copyright 2022 Peter Dimov // Copyright 2022 Peter Dimov
// Copyright 2024 Joaquin M Lopez Munoz
// Distributed under the Boost Software License, Version 1.0. // Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt // https://www.boost.org/LICENSE_1_0.txt
@ -26,6 +27,7 @@ namespace unordered
#include <boost/unordered/hash_traits.hpp> #include <boost/unordered/hash_traits.hpp>
#include <boost/core/lightweight_test_trait.hpp> #include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
struct X1 struct X1
{ {
@ -36,6 +38,27 @@ struct X2
typedef void is_avalanching; typedef void is_avalanching;
}; };
struct X4
{
using is_avalanching = std::false_type;
};
struct X5
{
using is_avalanching = std::true_type;
};
struct X6
{
using is_avalanching = boost::false_type;
};
struct X7
{
using is_avalanching = boost::true_type;
};
int main() int main()
{ {
using boost::unordered::hash_is_avalanching; using boost::unordered::hash_is_avalanching;
@ -43,6 +66,10 @@ int main()
BOOST_TEST_TRAIT_FALSE((hash_is_avalanching<X1>)); BOOST_TEST_TRAIT_FALSE((hash_is_avalanching<X1>));
BOOST_TEST_TRAIT_TRUE((hash_is_avalanching<X2>)); BOOST_TEST_TRAIT_TRUE((hash_is_avalanching<X2>));
BOOST_TEST_TRAIT_TRUE((hash_is_avalanching<X3>)); BOOST_TEST_TRAIT_TRUE((hash_is_avalanching<X3>));
BOOST_TEST_TRAIT_FALSE((hash_is_avalanching<X4>));
BOOST_TEST_TRAIT_TRUE((hash_is_avalanching<X5>));
BOOST_TEST_TRAIT_FALSE((hash_is_avalanching<X6>));
BOOST_TEST_TRAIT_TRUE((hash_is_avalanching<X7>));
return boost::report_errors(); return boost::report_errors();
} }