Skip to content

Commit 0a00016

Browse files
authored
Feature/hash_is_avalanching (#40)
* added hash_is_avalanching * launched CI after enabling GHA * moved 1.89 entry from Change Log to Recent Changes * segregated some tests into hash_is_avalanching_test3.cpp and gotten rid of Unordered dependency * removed unneeded include * stopped using external std::hash for testing * typo * removed left over include * typo * moved hash_is_avalanching from boost::container_hash to boost * fixed specializations of boost::hash_is_avalanching
1 parent d8f1075 commit 0a00016

10 files changed

Lines changed: 172 additions & 23 deletions

File tree

doc/hash/recent.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ https://www.boost.org/LICENSE_1_0.txt
88
= Recent Changes
99
:idprefix: recent_
1010

11+
== Boost 1.89.0
12+
13+
* Added the `hash_is_avalanching` trait class.
14+
1115
== Boost 1.84.0
1216

1317
* {cpp}03 is no longer supported.

doc/hash/reference.adoc

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
////
22
Copyright 2005-2008 Daniel James
33
Copyright 2022 Christian Mazakas
4-
Copyright 2022 Peter Dimov
4+
Copyright 2022, 2025 Peter Dimov
55
Distributed under the Boost Software License, Version 1.0.
66
https://www.boost.org/LICENSE_1_0.txt
77
////
@@ -44,6 +44,8 @@ template<class It> std::size_t hash_range( It first, It last );
4444
template<class It> void hash_unordered_range( std::size_t& seed, It first, It last );
4545
template<class It> std::size_t hash_unordered_range( It first, It last );
4646
47+
template<class Hash> struct hash_is_avalanching;
48+
4749
} // namespace boost
4850
----
4951

@@ -572,6 +574,56 @@ where `x` is the currently contained value in `v`.
572574
Throws: ::
573575
`std::bad_variant_access` when `v.valueless_by_exception()` is `true`.
574576

577+
== <boost/container_hash/{zwsp}hash_is_avalanching.hpp>
578+
579+
Defines the trait `boost::hash_is_avalanching`.
580+
581+
[source]
582+
----
583+
namespace boost
584+
{
585+
586+
template<class Hash> struct hash_is_avalanching;
587+
588+
} // namespace boost
589+
----
590+
591+
=== hash_is_avalanching<Hash>
592+
593+
[source]
594+
----
595+
template<class Hash> struct hash_is_avalanching
596+
{
597+
static constexpr bool value = /* see below */;
598+
};
599+
----
600+
601+
`hash_is_avalanching<Hash>::value` is:
602+
603+
* `false` if `Hash::is_avalanching` is not present,
604+
* `Hash::is_avalanching::value` if this is present and convertible at compile time to a `bool`,
605+
* `true` if `Hash::is_avalanching` is `void` (this usage is deprecated),
606+
* ill-formed otherwise.
607+
608+
A hash function is said to have the _avalanching property_ if small changes
609+
in the input translate to large changes in the returned hash code
610+
&#8212;ideally, flipping one bit in the representation of the input value results
611+
in each bit of the hash code flipping with probability 50%. Libraries
612+
such as link:../../../unordered/index.html[Boost.Unordered] consult this trait
613+
to determine if the supplied hash function is of high quality.
614+
`boost::hash` for `std::basic_string<Ch>` and `std::basic_string_view<Ch>`
615+
has this trait set to `true` when `Ch` is an integral type (this includes
616+
`std::string` and `std::string_view`, among others).
617+
Users can set this trait for a particular `Hash` type by:
618+
619+
* Inserting the nested `is_avalanching` typedef in the class definition
620+
if they have access to its source code.
621+
* Writing a specialization of `boost::hash_is_avalanching`
622+
for `Hash`.
623+
624+
Note that usage of this trait is not restricted to hash functions produced
625+
with Boost.ContainerHash.
626+
575627
== <boost/container_hash/{zwsp}is_range.hpp>
576628

577629
Defines the trait `boost::container_hash::is_range`.

include/boost/container_hash/hash.hpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright 2005-2014 Daniel James.
2-
// Copyright 2021, 2022 Peter Dimov.
2+
// Copyright 2021, 2022, 2025 Peter Dimov.
33
// Distributed under the Boost Software License, Version 1.0.
44
// https://www.boost.org/LICENSE_1_0.txt
55

@@ -11,6 +11,7 @@
1111
#define BOOST_FUNCTIONAL_HASH_HASH_HPP
1212

1313
#include <boost/container_hash/hash_fwd.hpp>
14+
#include <boost/container_hash/hash_is_avalanching.hpp>
1415
#include <boost/container_hash/is_range.hpp>
1516
#include <boost/container_hash/is_contiguous_range.hpp>
1617
#include <boost/container_hash/is_unordered_range.hpp>
@@ -557,19 +558,15 @@ namespace boost
557558

558559
#endif
559560

560-
// boost::unordered::hash_is_avalanching
561+
// hash_is_avalanching
561562

562-
namespace unordered
563-
{
564-
template<class T> struct hash_is_avalanching;
565-
template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string<Ch> > >: std::is_integral<Ch> {};
563+
template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string<Ch> > >: std::is_integral<Ch> {};
566564

567565
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
568566

569-
template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string_view<Ch> > >: std::is_integral<Ch> {};
567+
template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string_view<Ch> > >: std::is_integral<Ch> {};
570568

571569
#endif
572-
} // namespace unordered
573570

574571
} // namespace boost
575572

include/boost/container_hash/hash_fwd.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright 2005-2009 Daniel James.
2-
// Copyright 2021, 2022 Peter Dimov.
2+
// Copyright 2021, 2022, 2025 Peter Dimov.
33
// Distributed under the Boost Software License, Version 1.0.
44
// https://www.boost.org/LICENSE_1_0.txt
55

@@ -32,6 +32,8 @@ template<class It> std::size_t hash_range( It, It );
3232
template<class It> void hash_unordered_range( std::size_t&, It, It );
3333
template<class It> std::size_t hash_unordered_range( It, It );
3434

35+
template<class Hash> struct hash_is_avalanching;
36+
3537
} // namespace boost
3638

3739
#endif // #ifndef BOOST_FUNCTIONAL_HASH_FWD_HPP
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2025 Joaquin M Lopez Munoz.
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// https://www.boost.org/LICENSE_1_0.txt
4+
5+
#ifndef BOOST_HASH_HASH_IS_AVALANCHING_HPP_INCLUDED
6+
#define BOOST_HASH_HASH_IS_AVALANCHING_HPP_INCLUDED
7+
8+
#include <type_traits>
9+
10+
namespace boost
11+
{
12+
namespace hash_detail
13+
{
14+
15+
template<class... Ts> struct make_void
16+
{
17+
using type = void;
18+
};
19+
20+
template<class... Ts> using void_t = typename make_void<Ts...>::type;
21+
22+
template<class IsAvalanching> struct avalanching_value
23+
{
24+
static constexpr bool value = IsAvalanching::value;
25+
};
26+
27+
// may be explicitly marked as BOOST_DEPRECATED in the future
28+
template<> struct avalanching_value<void>
29+
{
30+
static constexpr bool value = true;
31+
};
32+
33+
template<class Hash, class = void> struct hash_is_avalanching_impl: std::false_type
34+
{
35+
};
36+
37+
template<class Hash> struct hash_is_avalanching_impl<Hash, void_t<typename Hash::is_avalanching> >:
38+
std::integral_constant<bool, avalanching_value<typename Hash::is_avalanching>::value>
39+
{
40+
};
41+
42+
template<class Hash>
43+
struct hash_is_avalanching_impl<Hash, typename std::enable_if< ((void)Hash::is_avalanching, true) >::type>
44+
{
45+
// Hash::is_avalanching is not a type: we don't define value to produce
46+
// a compile error downstream
47+
};
48+
49+
} // namespace hash_detail
50+
51+
template<class Hash> struct hash_is_avalanching: hash_detail::hash_is_avalanching_impl<Hash>::type
52+
{
53+
};
54+
55+
} // namespace boost
56+
57+
#endif // #ifndef BOOST_HASH_HASH_IS_AVALANCHING_HPP_INCLUDED

test/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2018, 2019, 2021, 2022 Peter Dimov
1+
# Copyright 2018, 2019, 2021, 2022, 2025 Peter Dimov
22
# Distributed under the Boost Software License, Version 1.0.
33
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
44

@@ -7,6 +7,6 @@ include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
77
if(HAVE_BOOST_TEST)
88

99
boost_test_jamfile(FILE Jamfile.v2
10-
LINK_LIBRARIES Boost::container_hash Boost::core Boost::utility Boost::unordered)
10+
LINK_LIBRARIES Boost::container_hash Boost::core Boost::utility)
1111

1212
endif()

test/Jamfile.v2

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Copyright 2005-2012 Daniel James.
2-
# Copyright 2022 Peter Dimov
2+
# Copyright 2022, 2025 Peter Dimov
33
# Distributed under the Boost Software License, Version 1.0.
44
# https://www.boost.org/LICENSE_1_0.txt
55

@@ -119,10 +119,9 @@ run is_described_class_test3.cpp
119119
run described_class_test.cpp
120120
: : : <warnings>extra ;
121121

122-
run hash_is_avalanching_test.cpp
123-
/boost/unordered//boost_unordered ;
124-
run hash_is_avalanching_test2.cpp
125-
/boost/unordered//boost_unordered ;
122+
run hash_is_avalanching_test.cpp ;
123+
run hash_is_avalanching_test2.cpp ;
124+
run hash_is_avalanching_test3.cpp ;
126125

127126
run hash_integral_test2.cpp ;
128127

test/hash_is_avalanching_test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
// Copyright 2022 Peter Dimov.
1+
// Copyright 2022, 2025 Peter Dimov.
22
// Distributed under the Boost Software License, Version 1.0.
33
// https://www.boost.org/LICENSE_1_0.txt
44

55
#include <boost/container_hash/hash.hpp>
6+
#include <boost/container_hash/hash_is_avalanching.hpp>
67
#include <boost/core/lightweight_test_trait.hpp>
7-
#include <boost/unordered/hash_traits.hpp>
88
#include <boost/config.hpp>
99
#include <string>
1010

1111
enum my_char { min = 0, max = 255 };
1212

1313
int main()
1414
{
15-
using boost::unordered::hash_is_avalanching;
15+
using boost::hash_is_avalanching;
1616

1717
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< boost::hash<std::string> > ));
1818
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< boost::hash<std::wstring> > ));

test/hash_is_avalanching_test2.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
// Copyright 2022 Peter Dimov.
1+
// Copyright 2022, 2025 Peter Dimov.
22
// Distributed under the Boost Software License, Version 1.0.
33
// https://www.boost.org/LICENSE_1_0.txt
44

55
#include <boost/container_hash/hash.hpp>
6+
#include <boost/container_hash/hash_is_avalanching.hpp>
67
#include <boost/core/lightweight_test_trait.hpp>
78
#include <boost/config.hpp>
89
#include <boost/config/pragma_message.hpp>
@@ -14,14 +15,13 @@ int main() {}
1415

1516
#else
1617

17-
#include <boost/unordered/hash_traits.hpp>
1818
#include <string_view>
1919

2020
enum my_char { min = 0, max = 255 };
2121

2222
int main()
2323
{
24-
using boost::unordered::hash_is_avalanching;
24+
using boost::hash_is_avalanching;
2525

2626
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< boost::hash<std::string_view> > ));
2727
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< boost::hash<std::wstring_view> > ));

test/hash_is_avalanching_test3.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2025 Joaquin M Lopez Munoz.
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// https://www.boost.org/LICENSE_1_0.txt
4+
5+
#include <boost/container_hash/hash_is_avalanching.hpp>
6+
#include <boost/core/lightweight_test_trait.hpp>
7+
#include <type_traits>
8+
9+
struct X
10+
{
11+
using is_avalanching = void;
12+
};
13+
14+
struct Y
15+
{
16+
using is_avalanching = std::true_type;
17+
};
18+
19+
struct Z
20+
{
21+
using is_avalanching = std::false_type;
22+
};
23+
24+
struct W
25+
{
26+
};
27+
28+
int main()
29+
{
30+
using boost::hash_is_avalanching;
31+
32+
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< X > ));
33+
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< Y > ));
34+
BOOST_TEST_TRAIT_FALSE(( hash_is_avalanching< Z > ));
35+
BOOST_TEST_TRAIT_FALSE(( hash_is_avalanching< W > ));
36+
37+
return boost::report_errors();
38+
}

0 commit comments

Comments
 (0)