mirror of
https://github.com/boostorg/container_hash.git
synced 2026-03-07 14:34:11 +01:00
Compare commits
5 Commits
feature/ha
...
feature/ha
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85f9f8a97a | ||
|
|
e92eae9eb2 | ||
|
|
8a1335458a | ||
|
|
f7e537d1a1 | ||
|
|
607b73f1e0 |
20
README.md
Normal file
20
README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Boost.ContainerHash
|
||||
|
||||
The Boost.ContainerHash library, part of [Boost C++ Libraries](https://boost.org),
|
||||
provides `boost::hash`, an enhanced implementation of the
|
||||
[hash function](https://en.wikipedia.org/wiki/Hash_function) object specified
|
||||
by C++11 as `std::hash`, and several support facilities (`hash_combine`,
|
||||
`hash_range`, `hash_unordered_range`).
|
||||
|
||||
`boost::hash` supports most standard types and some user-defined types out of
|
||||
the box, and is extensible; it's possible for a user-defined type `X` to make
|
||||
iself hashable via `boost::hash<X>` by defining an appropriate overload of the
|
||||
function `hash_value`.
|
||||
|
||||
See [the documentation of the library](https://www.boost.org/libs/container_hash)
|
||||
for more information.
|
||||
|
||||
## License
|
||||
|
||||
Distributed under the
|
||||
[Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).
|
||||
@@ -10,6 +10,26 @@ https://www.boost.org/LICENSE_1_0.txt
|
||||
= Design and Implementation Notes
|
||||
:idprefix: notes_
|
||||
|
||||
== Quality of the Hash Function
|
||||
|
||||
Many hash functions strive to have little correlation between the input and
|
||||
output values. They attempt to uniformally distribute the output values for
|
||||
very similar inputs. This hash function makes no such attempt. In fact, for
|
||||
integers, the result of the hash function is often just the input value. So
|
||||
similar but different input values will often result in similar but different
|
||||
output values. This means that it is not appropriate as a general hash
|
||||
function. For example, a hash table may discard bits from the hash function
|
||||
resulting in likely collisions, or might have poor collision resolution when
|
||||
hash values are clustered together. In such cases this hash function will
|
||||
perform poorly.
|
||||
|
||||
But the standard has no such requirement for the hash function, it just
|
||||
requires that the hashes of two different values are unlikely to collide.
|
||||
Containers or algorithms designed to work with the standard hash function will
|
||||
have to be implemented to work well when the hash function's output is
|
||||
correlated to its input. Since they are paying that cost a higher quality hash
|
||||
function would be wasteful.
|
||||
|
||||
== The hash_value Customization Point
|
||||
|
||||
The way one customizes the standard `std::hash` function object for user
|
||||
@@ -154,22 +174,46 @@ With this improved `hash_combine`, `boost::hash` for strings now passes the
|
||||
https://github.com/aappleby/smhasher[SMHasher test suite] by Austin Appleby
|
||||
(for a 64 bit `size_t`).
|
||||
|
||||
== Quality of the Hash Function
|
||||
== hash_range
|
||||
|
||||
Many hash functions strive to have little correlation between the input and
|
||||
output values. They attempt to uniformally distribute the output values for
|
||||
very similar inputs. This hash function makes no such attempt. In fact, for
|
||||
integers, the result of the hash function is often just the input value. So
|
||||
similar but different input values will often result in similar but different
|
||||
output values. This means that it is not appropriate as a general hash
|
||||
function. For example, a hash table may discard bits from the hash function
|
||||
resulting in likely collisions, or might have poor collision resolution when
|
||||
hash values are clustered together. In such cases this hash function will
|
||||
perform poorly.
|
||||
The traditional implementation of `hash_range(seed, first, last)` has been
|
||||
|
||||
But the standard has no such requirement for the hash function, it just
|
||||
requires that the hashes of two different values are unlikely to collide.
|
||||
Containers or algorithms designed to work with the standard hash function will
|
||||
have to be implemented to work well when the hash function's output is
|
||||
correlated to its input. Since they are paying that cost a higher quality hash
|
||||
function would be wasteful.
|
||||
[source]
|
||||
----
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
boost::hash_combine<typename std::iterator_traits<It>::value_type>( seed, *first );
|
||||
}
|
||||
----
|
||||
|
||||
(the explicit template parameter is needed to support iterators with proxy
|
||||
return types such as `std::vector<bool>::iterator`.)
|
||||
|
||||
This is logical, consistent and straightforward. In the common case where
|
||||
`typename std::iterator_traits<It>::value_type` is `char` -- which it is
|
||||
in the common case of `boost::hash<std::string>` -- this however leaves a
|
||||
lot of performance on the table, because processing each `char` individually
|
||||
is much less efficient than processing several in bulk.
|
||||
|
||||
In Boost 1.81, `hash_range` was changed to process elements of type `char`,
|
||||
`signed char`, `unsigned char`, `std::byte`, or `char8_t`, four of a time.
|
||||
A `uint32_t` is composed from `first[0]` to `first[3]`, and that `uint32_t`
|
||||
is fed to `hash_combine`.
|
||||
|
||||
In principle, when `size_t` is 64 bit, we could have used `uint64_t` instead.
|
||||
We do not, because this allows producing an arbitrary hash value by choosing
|
||||
the input bytes appropriately (because `hash_combine` is reversible.)
|
||||
|
||||
Allowing control only over 32 bits of the full 64 bit `size_t` value makes
|
||||
these "chosen plaintext attacks" harder.
|
||||
|
||||
This is not as harmful to performance as it first appears, because the
|
||||
input to `hash<string>` (e.g. the key in an unordered container) is often
|
||||
short (9 to 13 bytes in some typical scenarios.)
|
||||
|
||||
Note that `hash_range` has also traditionally guaranteed that the same element
|
||||
sequence yields the same hash value regardless of the iterator type. This
|
||||
property remains valid after the changes to `char` range hashing. `hash_range`,
|
||||
applied to the `char` sequence `{ 'a', 'b', 'c' }`, results in the same value
|
||||
whether the sequence comes from `char[3]`, `std::string`, `std::deque<char>`,
|
||||
or `std::list<char>`.
|
||||
|
||||
@@ -225,7 +225,7 @@ Effects: ::
|
||||
+
|
||||
--
|
||||
When `typename std::iterator_traits<It>::value_type` is not `char`, `signed char`,
|
||||
`unsigned char`,
|
||||
`unsigned char`, `std::byte`, or `char8_t`,
|
||||
|
||||
[source]
|
||||
----
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
////
|
||||
Copyright 2005-2008 Daniel James
|
||||
Copyright 2022 Christian Mazakas
|
||||
Copyright 2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#thanks]
|
||||
= Acknowledgements
|
||||
|
||||
:idprefix: thanks_
|
||||
|
||||
This library is based on the design by Peter Dimov. During the initial development Joaquín M López Muñoz made many useful suggestions and contributed fixes.
|
||||
@@ -12,3 +19,5 @@ The implementation of the hash function for pointers is based on suggestions mad
|
||||
Some useful improvements to the floating point hash algorithm were suggested by Daniel Krügler.
|
||||
|
||||
The original implementation came from Jeremy B. Maitin-Shepard's hash table library, although this is a complete rewrite.
|
||||
|
||||
The documentation was converted from Quickbook to AsciiDoc by Christian Mazakas.
|
||||
|
||||
@@ -27,6 +27,14 @@ template<> struct is_char_type<char>: public boost::true_type {};
|
||||
template<> struct is_char_type<signed char>: public boost::true_type {};
|
||||
template<> struct is_char_type<unsigned char>: public boost::true_type {};
|
||||
|
||||
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||
template<> struct is_char_type<char8_t>: public boost::true_type {};
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
|
||||
template<> struct is_char_type<std::byte>: public boost::true_type {};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
template<class It>
|
||||
|
||||
@@ -48,5 +48,13 @@ int main()
|
||||
test<float>();
|
||||
test<double>();
|
||||
|
||||
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||
test<char8_t>();
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
|
||||
test<std::byte>();
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user