mirror of
https://github.com/boostorg/container_hash.git
synced 2026-03-07 14:34:11 +01:00
Compare commits
26 Commits
feature/ha
...
feature/po
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
228f7db5d3 | ||
|
|
f50b914456 | ||
|
|
c134ca39e9 | ||
|
|
f51f68fe93 | ||
|
|
0865c1d230 | ||
|
|
0d2266decb | ||
|
|
3c9ba89cf2 | ||
|
|
20ee3b60fd | ||
|
|
bdd3dcf944 | ||
|
|
018fc4e1fa | ||
|
|
7568176bfa | ||
|
|
08864cd1e9 | ||
|
|
5a616b9b54 | ||
|
|
16fb4cc749 | ||
|
|
0171246a61 | ||
|
|
29c85559e4 | ||
|
|
412bd51449 | ||
|
|
87196a503e | ||
|
|
df1671d593 | ||
|
|
1996cf36c1 | ||
|
|
a4b2048a29 | ||
|
|
85f9f8a97a | ||
|
|
e92eae9eb2 | ||
|
|
8a1335458a | ||
|
|
f7e537d1a1 | ||
|
|
607b73f1e0 |
188
.drone.jsonnet
188
.drone.jsonnet
@@ -135,47 +135,205 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9 ARM64",
|
||||
"Linux 16.04 GCC 5* 32/64",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 GCC 6 32/64",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-6', CXXSTD: '03,11,14', ADDRMD: '32,64' },
|
||||
"g++-6-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 GCC 7* 32/64",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 GCC 8 32/64",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '03,11,14,17', ADDRMD: '32,64' },
|
||||
"g++-8-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* 32/64",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* ARM64",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
|
||||
arch="arm64",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9 S390x",
|
||||
"Linux 20.04 GCC 9* S390x",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
|
||||
arch="s390x",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 10 32/64",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '03,11,14,17,20', ADDRMD: '32,64' },
|
||||
"g++-10-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 11* 32/64",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 12 32 ASAN",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14,17,20', ADDRMD: '32' } + asan,
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14,17,20,2b', ADDRMD: '32' } + asan,
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 12 64 ASAN",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14,17,20', ADDRMD: '64' } + asan,
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14,17,20,2b', ADDRMD: '64' } + asan,
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.5",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.5', CXXSTD: '03,11' },
|
||||
"clang-3.5",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.6",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.6', CXXSTD: '03,11,14' },
|
||||
"clang-3.6",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.7",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.7', CXXSTD: '03,11,14' },
|
||||
"clang-3.7",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.8",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.8', CXXSTD: '03,11,14' },
|
||||
"clang-3.8",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 3.9",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.9', CXXSTD: '03,11,14' },
|
||||
"clang-3.9",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 4.0",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-4.0', CXXSTD: '03,11,14' },
|
||||
"clang-4.0",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 5.0",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-5.0', CXXSTD: '03,11,14,1z' },
|
||||
"clang-5.0",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 6.0",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-6.0', CXXSTD: '03,11,14,17' },
|
||||
"clang-6.0",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 7",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-7', CXXSTD: '03,11,14,17' },
|
||||
"clang-7",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 8",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-8', CXXSTD: '03,11,14,17' },
|
||||
"clang-8",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 9",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-9', CXXSTD: '03,11,14,17,2a' },
|
||||
"clang-9",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 10",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-10', CXXSTD: '03,11,14,17,2a' },
|
||||
"clang-10",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 11",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-11', CXXSTD: '03,11,14,17,2a' },
|
||||
"clang-11",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 12",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-12', CXXSTD: '03,11,14,17,2a' },
|
||||
"clang-12",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 13",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '03,11,14,17,20' },
|
||||
"clang-13",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 14 UBSAN",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20' } + ubsan,
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20,2b' } + ubsan,
|
||||
"clang-14",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 14 ASAN",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20' } + asan,
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20,2b' } + asan,
|
||||
"clang-14",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 15",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '03,11,14,17,20,2b' },
|
||||
"clang-15",
|
||||
["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main"],
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
"MacOS 10.15 Xcode 12.2 UBSAN",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + ubsan,
|
||||
@@ -186,9 +344,27 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + asan,
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2015 msvc-14.0",
|
||||
"cppalliance/dronevs2015",
|
||||
{ TOOLSET: 'msvc-14.0', CXXSTD: '14,latest' },
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2017 msvc-14.1",
|
||||
"cppalliance/dronevs2017",
|
||||
{ TOOLSET: 'msvc-14.1', CXXSTD: '14,17,latest' },
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2019 msvc-14.2",
|
||||
"cppalliance/dronevs2019",
|
||||
{ TOOLSET: 'msvc-14.2', CXXSTD: '14,17,20,latest' },
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2022 msvc-14.3",
|
||||
"cppalliance/dronevs2022:1",
|
||||
{ TOOLSET: 'msvc-14.3', CXXSTD: '14,17,20,latest' },
|
||||
),
|
||||
]
|
||||
|
||||
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@@ -126,7 +126,7 @@ jobs:
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
@@ -195,7 +195,7 @@ jobs:
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
@@ -239,7 +239,7 @@ jobs:
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
@@ -286,7 +286,7 @@ jobs:
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
@@ -343,7 +343,7 @@ jobs:
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
|
||||
@@ -15,6 +15,8 @@ target_include_directories(boost_container_hash INTERFACE include)
|
||||
target_link_libraries(boost_container_hash
|
||||
INTERFACE
|
||||
Boost::config
|
||||
Boost::describe
|
||||
Boost::mp11
|
||||
Boost::type_traits
|
||||
)
|
||||
|
||||
|
||||
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).
|
||||
@@ -22,6 +22,7 @@ include::hash/recent.adoc[]
|
||||
include::hash/tutorial.adoc[]
|
||||
include::hash/user.adoc[]
|
||||
include::hash/combine.adoc[]
|
||||
include::hash/describe.adoc[]
|
||||
include::hash/reference.adoc[]
|
||||
include::hash/notes.adoc[]
|
||||
include::hash/links.adoc[]
|
||||
|
||||
61
doc/hash/describe.adoc
Normal file
61
doc/hash/describe.adoc
Normal file
@@ -0,0 +1,61 @@
|
||||
////
|
||||
Copyright 2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#describe]
|
||||
= Hashing User Types with Boost.Describe
|
||||
:idprefix: describe_
|
||||
|
||||
Let's look at our `point` class again:
|
||||
|
||||
[source]
|
||||
----
|
||||
class point
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
|
||||
public:
|
||||
|
||||
point() : x(0), y(0) {}
|
||||
point(int x, int y) : x(x), y(y) {}
|
||||
};
|
||||
----
|
||||
|
||||
If you're using {cpp}14 or above, a much easier way to add
|
||||
support for `boost::hash` to `point` is by using
|
||||
link:../../../describe/index.html[Boost.Describe] (and
|
||||
get an automatic definition of `operator==` for free):
|
||||
|
||||
[source]
|
||||
----
|
||||
|
||||
#include <boost/describe/class.hpp>
|
||||
#include <boost/describe/operators.hpp>
|
||||
|
||||
class point
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
|
||||
BOOST_DESCRIBE_CLASS(point, (), (), (), (x, y))
|
||||
|
||||
public:
|
||||
|
||||
point() : x(0), y(0) {}
|
||||
point(int x, int y) : x(x), y(y) {}
|
||||
};
|
||||
|
||||
using boost::describe::operators::operator==;
|
||||
using boost::describe::operators::operator!=;
|
||||
----
|
||||
|
||||
(Full code for this example is at
|
||||
link:../../examples/point2.cpp[examples/point2.cpp].)
|
||||
|
||||
Since the `point` class has been annotated with `BOOST_DESCRIBE_CLASS`,
|
||||
the library can enumerate its members (and base classes) and automatically
|
||||
synthesize the appropriate `hash_value` overload for it, without us needing
|
||||
to do so.
|
||||
@@ -32,6 +32,9 @@ Out of the box, `boost::hash` supports
|
||||
* unordered sequences, standard or user-defined (sequences for which the hash
|
||||
value does not depend on the element order, such as `std::unordered_set` and
|
||||
`std::unordered_map`);
|
||||
* described structs and classes -- ones that have been annotated with the
|
||||
`BOOST_DESCRIBE_STRUCT` or `BOOST_DESCRIBE_CLASS` macros from
|
||||
link:../../../describe/index.html[Boost.Describe];
|
||||
* `std::unique_ptr`, `std::shared_ptr`;
|
||||
* `std::type_index`;
|
||||
* `std::error_code`, `std::error_condition`;
|
||||
|
||||
@@ -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>`.
|
||||
|
||||
@@ -21,6 +21,9 @@ Major update.
|
||||
* User-defined containers (types that have `begin()` and `end()`
|
||||
member functions that return iterators) are now supported out
|
||||
of the box.
|
||||
* Described structs and classes (those annotated with
|
||||
`BOOST_DESCRIBE_STRUCT` or `BOOST_DESCRIBE_CLASS`) are now
|
||||
supported out of the box.
|
||||
* `hash_combine` has been improved.
|
||||
* The performance (and quality, as a result of the above change)
|
||||
of string hashing has been improved. `boost::hash` for strings
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace container_hash
|
||||
template<class T> struct is_range;
|
||||
template<class T> struct is_contiguous_range;
|
||||
template<class T> struct is_unordered_range;
|
||||
template<class T> struct is_described_class;
|
||||
|
||||
} // namespace container_hash
|
||||
|
||||
@@ -103,6 +104,10 @@ template<class T>
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
|
||||
// Enabled only when container_hash::is_described_class<T>::value is true
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
|
||||
template<class T>
|
||||
std::size_t hash_value( std::shared_ptr<T> const& v );
|
||||
|
||||
@@ -225,7 +230,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]
|
||||
----
|
||||
@@ -446,6 +451,34 @@ Remarks: ::
|
||||
This overload handles the standard unordered containers, such as
|
||||
`std::unordered_set` and `std::unordered_map`.
|
||||
|
||||
[source]
|
||||
----
|
||||
// Enabled only when container_hash::is_described_class<T>::value is true
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
----
|
||||
|
||||
Effects: ::
|
||||
+
|
||||
[source]
|
||||
----
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_combine( seed, b1 );
|
||||
boost::hash_combine( seed, b2 );
|
||||
// ...
|
||||
boost::hash_combine( seed, bM );
|
||||
|
||||
boost::hash_combine( seed, m1 );
|
||||
boost::hash_combine( seed, m2 );
|
||||
// ...
|
||||
boost::hash_combine( seed, mN );
|
||||
|
||||
return seed;
|
||||
----
|
||||
+
|
||||
where `bi` are the bases of `v` and `mi` are its members.
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T>
|
||||
@@ -633,3 +666,40 @@ template<class T> struct is_unordered_range
|
||||
|
||||
Users are allowed to specialize `is_unordered_range` for their types
|
||||
if the default behavior does not deduce the correct value.
|
||||
|
||||
== <boost/container_hash/{zwsp}is_described_class.hpp>
|
||||
|
||||
Defines the trait `boost::container_hash::is_described_class`.
|
||||
|
||||
[source]
|
||||
----
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_described_class;
|
||||
|
||||
} // namespace container_hash
|
||||
|
||||
} // namespace boost
|
||||
----
|
||||
|
||||
=== is_described_class<T>
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T> struct is_described_class
|
||||
{
|
||||
static constexpr bool value = /* see below */;
|
||||
};
|
||||
----
|
||||
|
||||
`is_described_class<T>::value` is `true` when
|
||||
`boost::describe::has_describe_bases<T>::value` is `true`,
|
||||
`boost::describe::has_describe_members<T>::value` is `true`, and
|
||||
`T` is not a union.
|
||||
|
||||
Users are allowed to specialize `is_described_class` for their types
|
||||
if the default behavior does not deduce the correct value.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -74,7 +74,7 @@ assert(books.find(knife) != books.end());
|
||||
assert(books.find(dandelion) == books.end());
|
||||
----
|
||||
|
||||
The full example can be found in:
|
||||
The full example can be found in
|
||||
link:../../examples/books.hpp[examples/books.hpp] and
|
||||
link:../../examples/books.cpp[examples/books.cpp].
|
||||
|
||||
|
||||
@@ -7,3 +7,4 @@ run books.cpp ;
|
||||
run point.cpp ;
|
||||
run portable.cpp ;
|
||||
run template.cpp : : : <toolset>msvc-8.0:<build>no ;
|
||||
run point2.cpp ;
|
||||
|
||||
65
examples/point2.cpp
Normal file
65
examples/point2.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
|
||||
// Copyright 2005 Daniel James.
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
// Force use of assert.
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/describe/class.hpp>
|
||||
#include <boost/describe/operators.hpp>
|
||||
#include <cassert>
|
||||
|
||||
// This example illustrates how to use Boost.Describe to obtain
|
||||
// automatic boost::hash support. For full details see the hash
|
||||
// tutorial.
|
||||
|
||||
#if defined(BOOST_DESCRIBE_CXX14)
|
||||
|
||||
class point
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
|
||||
BOOST_DESCRIBE_CLASS(point, (), (), (), (x, y))
|
||||
|
||||
public:
|
||||
|
||||
point() : x(0), y(0) {}
|
||||
point(int x, int y) : x(x), y(y) {}
|
||||
};
|
||||
|
||||
using boost::describe::operators::operator==;
|
||||
using boost::describe::operators::operator!=;
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::hash<point> point_hasher;
|
||||
|
||||
point p1(0, 0);
|
||||
point p2(1, 2);
|
||||
point p3(4, 1);
|
||||
point p4 = p1;
|
||||
|
||||
assert(point_hasher(p1) == point_hasher(p4));
|
||||
|
||||
// These tests could legally fail, but if they did it'd be a pretty bad
|
||||
// hash function.
|
||||
assert(point_hasher(p1) != point_hasher(p2));
|
||||
assert(point_hasher(p1) != point_hasher(p3));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::puts( "This example requires C++14." );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -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>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <boost/container_hash/is_range.hpp>
|
||||
#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_mix.hpp>
|
||||
#include <boost/container_hash/detail/hash_range.hpp>
|
||||
@@ -25,7 +26,15 @@
|
||||
#include <boost/type_traits/make_unsigned.hpp>
|
||||
#include <boost/type_traits/enable_if.hpp>
|
||||
#include <boost/type_traits/conjunction.hpp>
|
||||
#include <boost/type_traits/is_union.hpp>
|
||||
#include <boost/describe/bases.hpp>
|
||||
#include <boost/describe/members.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#if defined(BOOST_DESCRIBE_CXX14)
|
||||
# include <boost/mp11/algorithm.hpp>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
#include <complex>
|
||||
@@ -54,6 +63,10 @@
|
||||
#include <variant>
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
|
||||
# include <string_view>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
@@ -383,6 +396,49 @@ namespace boost
|
||||
return boost::hash_unordered_range( v.begin(), v.end() );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// described classes
|
||||
|
||||
#if defined(BOOST_DESCRIBE_CXX14)
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER == 1900
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4100) // unreferenced formal parameter
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
typename boost::enable_if_<container_hash::is_described_class<T>::value, std::size_t>::type
|
||||
hash_value( T const& v )
|
||||
{
|
||||
static_assert( !boost::is_union<T>::value, "described unions are not supported" );
|
||||
|
||||
std::size_t r = 0;
|
||||
|
||||
using Bd = describe::describe_bases<T, describe::mod_any_access>;
|
||||
|
||||
mp11::mp_for_each<Bd>([&](auto D){
|
||||
|
||||
using B = typename decltype(D)::type;
|
||||
boost::hash_combine( r, (B const&)v );
|
||||
|
||||
});
|
||||
|
||||
using Md = describe::describe_members<T, describe::mod_any_access>;
|
||||
|
||||
mp11::mp_for_each<Md>([&](auto D){
|
||||
|
||||
boost::hash_combine( r, v.*D.pointer );
|
||||
|
||||
});
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER == 1900
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// std::unique_ptr, std::shared_ptr
|
||||
@@ -577,6 +633,30 @@ namespace boost
|
||||
};
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// boost::unordered::hash_is_avalanching
|
||||
|
||||
namespace unordered
|
||||
{
|
||||
template<class T> struct hash_is_avalanching;
|
||||
template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string<Ch> > >: boost::is_integral<Ch> {};
|
||||
|
||||
// boost::is_integral<char8_t> is false, but should be true (https://github.com/boostorg/type_traits/issues/175)
|
||||
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||
template<> struct hash_is_avalanching< boost::hash< std::basic_string<char8_t> > >: boost::true_type {};
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
|
||||
|
||||
template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string_view<Ch> > >: boost::is_integral<Ch> {};
|
||||
|
||||
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||
template<> struct hash_is_avalanching< boost::hash< std::basic_string_view<char8_t> > >: boost::true_type {};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
} // namespace unordered
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Copyright 2021 Peter Dimov.
|
||||
// Copyright 2021, 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace container_hash
|
||||
template<class T> struct is_range;
|
||||
template<class T> struct is_contiguous_range;
|
||||
template<class T> struct is_unordered_range;
|
||||
template<class T> struct is_described_class;
|
||||
|
||||
} // namespace container_hash
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700)
|
||||
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700) && !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
|
||||
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/type_traits/declval.hpp>
|
||||
|
||||
38
include/boost/container_hash/is_described_class.hpp
Normal file
38
include/boost/container_hash/is_described_class.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_HASH_IS_DESCRIBED_CLASS_HPP_INCLUDED
|
||||
#define BOOST_HASH_IS_DESCRIBED_CLASS_HPP_INCLUDED
|
||||
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/type_traits/is_union.hpp>
|
||||
#include <boost/describe/bases.hpp>
|
||||
#include <boost/describe/members.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
#if defined(BOOST_DESCRIBE_CXX11)
|
||||
|
||||
template<class T> struct is_described_class: boost::integral_constant<bool,
|
||||
describe::has_describe_bases<T>::value &&
|
||||
describe::has_describe_members<T>::value &&
|
||||
!boost::is_union<T>::value>
|
||||
{
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template<class T> struct is_described_class: boost::false_type
|
||||
{
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace container_hash
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_IS_DESCRIBED_CLASS_HPP_INCLUDED
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright 2018, 2019, 2021 Peter Dimov
|
||||
# Copyright 2018, 2019, 2021, 2022 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
@@ -6,6 +6,7 @@ include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
|
||||
|
||||
if(HAVE_BOOST_TEST)
|
||||
|
||||
boost_test_jamfile(FILE Jamfile.v2 LINK_LIBRARIES Boost::container_hash Boost::core Boost::utility)
|
||||
boost_test_jamfile(FILE Jamfile.v2
|
||||
LINK_LIBRARIES Boost::container_hash Boost::core Boost::utility Boost::unordered)
|
||||
|
||||
endif()
|
||||
|
||||
@@ -101,3 +101,17 @@ run hash_unordered_map_test.cpp ;
|
||||
run is_range_test3.cpp ;
|
||||
run is_contiguous_range_test2.cpp ;
|
||||
run is_unordered_range_test2.cpp ;
|
||||
run is_contiguous_range_test3.cpp ;
|
||||
|
||||
run is_described_class_test.cpp
|
||||
: : : <warnings>extra ;
|
||||
run is_described_class_test2.cpp
|
||||
: : : <warnings>extra ;
|
||||
run is_described_class_test3.cpp
|
||||
: : : <warnings>extra ;
|
||||
|
||||
run described_class_test.cpp
|
||||
: : : <warnings>extra ;
|
||||
|
||||
run hash_is_avalanching_test.cpp ;
|
||||
run hash_is_avalanching_test2.cpp ;
|
||||
|
||||
@@ -11,6 +11,8 @@ add_subdirectory(../.. boostorg/container_hash)
|
||||
add_subdirectory(../../../config boostorg/config)
|
||||
add_subdirectory(../../../type_traits boostorg/type_traits)
|
||||
add_subdirectory(../../../static_assert boostorg/static_assert)
|
||||
add_subdirectory(../../../describe boostorg/describe)
|
||||
add_subdirectory(../../../mp11 boostorg/mp11)
|
||||
|
||||
add_executable(quick ../quick.cpp)
|
||||
target_link_libraries(quick Boost::container_hash)
|
||||
|
||||
159
test/described_class_test.cpp
Normal file
159
test/described_class_test.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
// 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 "-Wunused-private-field"
|
||||
#endif
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/describe/class.hpp>
|
||||
#include <boost/describe/operators.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
|
||||
#if !defined(BOOST_DESCRIBE_CXX14)
|
||||
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
BOOST_PRAGMA_MESSAGE( "Skipping test because BOOST_DESCRIBE_CXX14 is not defined" )
|
||||
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
|
||||
struct X1
|
||||
{
|
||||
int m;
|
||||
explicit X1( int m_ ): m( m_ ) {}
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT( X1, (), (m) )
|
||||
|
||||
struct X2
|
||||
{
|
||||
int m;
|
||||
explicit X2( int m_ ): m( m_ ) {}
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT( X2, (), (m) )
|
||||
|
||||
struct X3
|
||||
{
|
||||
int m;
|
||||
explicit X3( int m_ ): m( m_ ) {}
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT( X3, (), (m) )
|
||||
|
||||
class Y: public X1, protected X2, private X3
|
||||
{
|
||||
public:
|
||||
|
||||
int m1;
|
||||
|
||||
protected:
|
||||
|
||||
int m2;
|
||||
|
||||
private:
|
||||
|
||||
int m3;
|
||||
|
||||
public:
|
||||
|
||||
Y( int x1, int x2, int x3, int m1_, int m2_, int m3_ ):
|
||||
X1( x1 ), X2( x2 ), X3( x3 ), m1( m1_ ), m2( m2_ ), m3( m3_ ) {}
|
||||
|
||||
BOOST_DESCRIBE_CLASS( Y, (X1, X2, X3), (m1), (m2), (m3) )
|
||||
};
|
||||
|
||||
using boost::describe::operators::operator==;
|
||||
using boost::describe::operators::operator!=;
|
||||
using boost::describe::operators::operator<<;
|
||||
|
||||
int main()
|
||||
{
|
||||
Y y1( 0, 0, 0, 0, 0, 0 );
|
||||
|
||||
BOOST_TEST_EQ( y1, y1 );
|
||||
BOOST_TEST_EQ( boost::hash<Y>()(y1), boost::hash<Y>()(y1) );
|
||||
|
||||
Y y2( 1, 0, 0, 0, 0, 0 );
|
||||
|
||||
BOOST_TEST_NE( y1, y2 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y2) );
|
||||
|
||||
Y y3( 0, 1, 0, 0, 0, 0 );
|
||||
|
||||
BOOST_TEST_NE( y1, y3 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y3) );
|
||||
|
||||
BOOST_TEST_NE( y2, y3 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y3) );
|
||||
|
||||
Y y4( 0, 0, 1, 0, 0, 0 );
|
||||
|
||||
BOOST_TEST_NE( y1, y4 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y4) );
|
||||
|
||||
BOOST_TEST_NE( y2, y4 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y4) );
|
||||
|
||||
BOOST_TEST_NE( y3, y4 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y3), boost::hash<Y>()(y4) );
|
||||
|
||||
Y y5( 0, 0, 0, 1, 0, 0 );
|
||||
|
||||
BOOST_TEST_NE( y1, y5 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y5) );
|
||||
|
||||
BOOST_TEST_NE( y2, y5 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y5) );
|
||||
|
||||
BOOST_TEST_NE( y3, y5 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y3), boost::hash<Y>()(y5) );
|
||||
|
||||
BOOST_TEST_NE( y4, y5 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y4), boost::hash<Y>()(y5) );
|
||||
|
||||
Y y6( 0, 0, 0, 0, 1, 0 );
|
||||
|
||||
BOOST_TEST_NE( y1, y6 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y6) );
|
||||
|
||||
BOOST_TEST_NE( y2, y6 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y6) );
|
||||
|
||||
BOOST_TEST_NE( y3, y6 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y3), boost::hash<Y>()(y6) );
|
||||
|
||||
BOOST_TEST_NE( y4, y6 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y4), boost::hash<Y>()(y6) );
|
||||
|
||||
BOOST_TEST_NE( y5, y6 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y5), boost::hash<Y>()(y6) );
|
||||
|
||||
Y y7( 0, 0, 0, 0, 0, 1 );
|
||||
|
||||
BOOST_TEST_NE( y1, y7 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y7) );
|
||||
|
||||
BOOST_TEST_NE( y2, y7 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y7) );
|
||||
|
||||
BOOST_TEST_NE( y3, y7 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y3), boost::hash<Y>()(y7) );
|
||||
|
||||
BOOST_TEST_NE( y4, y7 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y4), boost::hash<Y>()(y7) );
|
||||
|
||||
BOOST_TEST_NE( y5, y7 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y5), boost::hash<Y>()(y7) );
|
||||
|
||||
BOOST_TEST_NE( y6, y7 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y6), boost::hash<Y>()(y7) );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "./compile_time.hpp"
|
||||
|
||||
void void_func1() { static int x = 1; ++x; }
|
||||
void void_func2() { static int x = 2; --x; }
|
||||
void void_func1() { static int x = 1; ++x; (void)x; }
|
||||
void void_func2() { static int x = 2; --x; (void)x; }
|
||||
int int_func1(int) { return 0; }
|
||||
int int_func2(int) { return 1; }
|
||||
|
||||
|
||||
57
test/hash_is_avalanching_test.cpp
Normal file
57
test/hash_is_avalanching_test.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
#if defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
|
||||
|
||||
BOOST_PRAGMA_MESSAGE( "Test skipped, BOOST_NO_CXX11_HDR_TYPE_TRAITS is defined" )
|
||||
int main() {}
|
||||
|
||||
#elif defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
|
||||
|
||||
BOOST_PRAGMA_MESSAGE( "Test skipped, BOOST_NO_CXX11_TEMPLATE_ALIASES is defined" )
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
|
||||
#include <boost/unordered/hash_traits.hpp>
|
||||
#include <string>
|
||||
|
||||
enum my_char { min = 0, max = 255 };
|
||||
|
||||
int main()
|
||||
{
|
||||
using boost::unordered::hash_is_avalanching;
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< boost::hash<std::string> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< boost::hash<std::wstring> > ));
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_CHAR16_T)
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< boost::hash<std::u16string> > ));
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_CHAR32_T)
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< boost::hash<std::u32string> > ));
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< boost::hash< std::basic_string<char8_t> > > ));
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( hash_is_avalanching< boost::hash<std::basic_string<my_char> > > ));
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
62
test/hash_is_avalanching_test2.cpp
Normal file
62
test/hash_is_avalanching_test2.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
#if defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
|
||||
|
||||
BOOST_PRAGMA_MESSAGE( "Test skipped, BOOST_NO_CXX11_HDR_TYPE_TRAITS is defined" )
|
||||
int main() {}
|
||||
|
||||
#elif defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
|
||||
|
||||
BOOST_PRAGMA_MESSAGE( "Test skipped, BOOST_NO_CXX11_TEMPLATE_ALIASES is defined" )
|
||||
int main() {}
|
||||
|
||||
#elif defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
|
||||
|
||||
BOOST_PRAGMA_MESSAGE( "Test skipped, BOOST_NO_CXX17_HDR_STRING_VIEW is defined" )
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
|
||||
#include <boost/unordered/hash_traits.hpp>
|
||||
#include <string_view>
|
||||
|
||||
enum my_char { min = 0, max = 255 };
|
||||
|
||||
int main()
|
||||
{
|
||||
using boost::unordered::hash_is_avalanching;
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< boost::hash<std::string_view> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< boost::hash<std::wstring_view> > ));
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_CHAR16_T)
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< boost::hash<std::u16string_view> > ));
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_CHAR32_T)
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< boost::hash<std::u32string_view> > ));
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< boost::hash< std::basic_string_view<char8_t> > > ));
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( hash_is_avalanching< boost::hash<std::basic_string_view<my_char> > > ));
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -51,7 +51,7 @@ int main()
|
||||
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<std::wstring const>));
|
||||
|
||||
// std::vector doesn't have data() in C++03
|
||||
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700)
|
||||
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700) && !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
|
||||
BOOST_TEST_TRAIT_TRUE((is_contiguous_range< std::vector<X> >));
|
||||
BOOST_TEST_TRAIT_TRUE((is_contiguous_range< std::vector<X> const >));
|
||||
#endif
|
||||
|
||||
@@ -50,7 +50,7 @@ int main()
|
||||
{
|
||||
using boost::container_hash::is_contiguous_range;
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700)
|
||||
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700) && !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<X1>));
|
||||
|
||||
|
||||
25
test/is_contiguous_range_test3.cpp
Normal file
25
test/is_contiguous_range_test3.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/container_hash/is_contiguous_range.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
struct X1
|
||||
{
|
||||
char const* begin() const;
|
||||
char const* end() const;
|
||||
std::size_t size() const;
|
||||
|
||||
char data[16];
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
using boost::container_hash::is_contiguous_range;
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<X1>));
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
56
test/is_described_class_test.cpp
Normal file
56
test/is_described_class_test.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/container_hash/is_described_class.hpp>
|
||||
#include <boost/describe/class.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <string>
|
||||
|
||||
struct X1
|
||||
{
|
||||
};
|
||||
|
||||
struct X2
|
||||
{
|
||||
int m;
|
||||
};
|
||||
|
||||
struct Y1
|
||||
{
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT( Y1, (), () )
|
||||
|
||||
struct Y2: Y1
|
||||
{
|
||||
int m;
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT( Y2, (Y1), (m) )
|
||||
|
||||
int main()
|
||||
{
|
||||
using boost::container_hash::is_described_class;
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE((is_described_class<void>));
|
||||
BOOST_TEST_TRAIT_FALSE((is_described_class<int>));
|
||||
BOOST_TEST_TRAIT_FALSE((is_described_class<X1>));
|
||||
BOOST_TEST_TRAIT_FALSE((is_described_class<X2>));
|
||||
BOOST_TEST_TRAIT_FALSE((is_described_class<int[2]>));
|
||||
BOOST_TEST_TRAIT_FALSE((is_described_class<std::string>));
|
||||
|
||||
#if defined(BOOST_DESCRIBE_CXX14)
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE((is_described_class<Y1>));
|
||||
BOOST_TEST_TRAIT_TRUE((is_described_class<Y2>));
|
||||
|
||||
#else
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE((is_described_class<Y1>));
|
||||
BOOST_TEST_TRAIT_FALSE((is_described_class<Y2>));
|
||||
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
35
test/is_described_class_test2.cpp
Normal file
35
test/is_described_class_test2.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/describe/class.hpp>
|
||||
|
||||
struct X
|
||||
{
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT( X, (), () )
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_described_class;
|
||||
template<> struct is_described_class<X>: boost::false_type {};
|
||||
|
||||
} // namespace container_hash
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/container_hash/is_described_class.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
using boost::container_hash::is_described_class;
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE((is_described_class<X>));
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
31
test/is_described_class_test3.cpp
Normal file
31
test/is_described_class_test3.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/container_hash/is_described_class.hpp>
|
||||
#include <boost/describe/class.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
|
||||
union Y1
|
||||
{
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT( Y1, (), () )
|
||||
|
||||
union Y2
|
||||
{
|
||||
int m1;
|
||||
float m2;
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT( Y2, (), (m1, m2) )
|
||||
|
||||
int main()
|
||||
{
|
||||
using boost::container_hash::is_described_class;
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE((is_described_class<Y1>));
|
||||
BOOST_TEST_TRAIT_FALSE((is_described_class<Y2>));
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
Reference in New Issue
Block a user