mirror of
https://github.com/boostorg/container_hash.git
synced 2026-05-31 21:08:51 +02:00
Compare commits
29 Commits
| 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 | |||
| 789261c68c | |||
| 29ee19ee7f | |||
| 8bb7d43646 |
+182
-6
@@ -135,47 +135,205 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
|||||||
),
|
),
|
||||||
|
|
||||||
linux_pipeline(
|
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",
|
"cppalliance/droneubuntu2004:multiarch",
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
|
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
|
||||||
arch="arm64",
|
arch="arm64",
|
||||||
),
|
),
|
||||||
|
|
||||||
linux_pipeline(
|
linux_pipeline(
|
||||||
"Linux 20.04 GCC 9 S390x",
|
"Linux 20.04 GCC 9* S390x",
|
||||||
"cppalliance/droneubuntu2004:multiarch",
|
"cppalliance/droneubuntu2004:multiarch",
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
|
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
|
||||||
arch="s390x",
|
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_pipeline(
|
||||||
"Linux 22.04 GCC 12 32 ASAN",
|
"Linux 22.04 GCC 12 32 ASAN",
|
||||||
"cppalliance/droneubuntu2204:1",
|
"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",
|
"g++-12-multilib",
|
||||||
),
|
),
|
||||||
|
|
||||||
linux_pipeline(
|
linux_pipeline(
|
||||||
"Linux 22.04 GCC 12 64 ASAN",
|
"Linux 22.04 GCC 12 64 ASAN",
|
||||||
"cppalliance/droneubuntu2204:1",
|
"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",
|
"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_pipeline(
|
||||||
"Linux 22.04 Clang 14 UBSAN",
|
"Linux 22.04 Clang 14 UBSAN",
|
||||||
"cppalliance/droneubuntu2204:1",
|
"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",
|
"clang-14",
|
||||||
),
|
),
|
||||||
|
|
||||||
linux_pipeline(
|
linux_pipeline(
|
||||||
"Linux 22.04 Clang 14 ASAN",
|
"Linux 22.04 Clang 14 ASAN",
|
||||||
"cppalliance/droneubuntu2204:1",
|
"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",
|
"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_pipeline(
|
||||||
"MacOS 10.15 Xcode 12.2 UBSAN",
|
"MacOS 10.15 Xcode 12.2 UBSAN",
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + 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,
|
{ 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_pipeline(
|
||||||
"Windows VS2017 msvc-14.1",
|
"Windows VS2017 msvc-14.1",
|
||||||
"cppalliance/dronevs2017",
|
"cppalliance/dronevs2017",
|
||||||
{ TOOLSET: 'msvc-14.1', CXXSTD: '14,17,latest' },
|
{ 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' },
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ jobs:
|
|||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
if: matrix.install
|
if: matrix.install
|
||||||
@@ -195,7 +195,7 @@ jobs:
|
|||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup Boost
|
- name: Setup Boost
|
||||||
shell: cmd
|
shell: cmd
|
||||||
@@ -239,7 +239,7 @@ jobs:
|
|||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
if: matrix.install
|
if: matrix.install
|
||||||
@@ -286,7 +286,7 @@ jobs:
|
|||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
if: matrix.install
|
if: matrix.install
|
||||||
@@ -343,7 +343,7 @@ jobs:
|
|||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
if: matrix.install
|
if: matrix.install
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ target_include_directories(boost_container_hash INTERFACE include)
|
|||||||
target_link_libraries(boost_container_hash
|
target_link_libraries(boost_container_hash
|
||||||
INTERFACE
|
INTERFACE
|
||||||
Boost::config
|
Boost::config
|
||||||
|
Boost::describe
|
||||||
|
Boost::mp11
|
||||||
Boost::type_traits
|
Boost::type_traits
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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/tutorial.adoc[]
|
||||||
include::hash/user.adoc[]
|
include::hash/user.adoc[]
|
||||||
include::hash/combine.adoc[]
|
include::hash/combine.adoc[]
|
||||||
|
include::hash/describe.adoc[]
|
||||||
include::hash/reference.adoc[]
|
include::hash/reference.adoc[]
|
||||||
include::hash/notes.adoc[]
|
include::hash/notes.adoc[]
|
||||||
include::hash/links.adoc[]
|
include::hash/links.adoc[]
|
||||||
|
|||||||
@@ -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
|
* 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
|
value does not depend on the element order, such as `std::unordered_set` and
|
||||||
`std::unordered_map`);
|
`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::unique_ptr`, `std::shared_ptr`;
|
||||||
* `std::type_index`;
|
* `std::type_index`;
|
||||||
* `std::error_code`, `std::error_condition`;
|
* `std::error_code`, `std::error_condition`;
|
||||||
|
|||||||
+61
-17
@@ -10,6 +10,26 @@ https://www.boost.org/LICENSE_1_0.txt
|
|||||||
= Design and Implementation Notes
|
= Design and Implementation Notes
|
||||||
:idprefix: 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 hash_value Customization Point
|
||||||
|
|
||||||
The way one customizes the standard `std::hash` function object for user
|
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
|
https://github.com/aappleby/smhasher[SMHasher test suite] by Austin Appleby
|
||||||
(for a 64 bit `size_t`).
|
(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
|
The traditional implementation of `hash_range(seed, first, last)` has been
|
||||||
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
|
[source]
|
||||||
requires that the hashes of two different values are unlikely to collide.
|
----
|
||||||
Containers or algorithms designed to work with the standard hash function will
|
for( ; first != last; ++first )
|
||||||
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
|
boost::hash_combine<typename std::iterator_traits<It>::value_type>( seed, *first );
|
||||||
function would be wasteful.
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
(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()`
|
* User-defined containers (types that have `begin()` and `end()`
|
||||||
member functions that return iterators) are now supported out
|
member functions that return iterators) are now supported out
|
||||||
of the box.
|
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.
|
* `hash_combine` has been improved.
|
||||||
* The performance (and quality, as a result of the above change)
|
* The performance (and quality, as a result of the above change)
|
||||||
of string hashing has been improved. `boost::hash` for strings
|
of string hashing has been improved. `boost::hash` for strings
|
||||||
|
|||||||
+71
-1
@@ -29,6 +29,7 @@ namespace container_hash
|
|||||||
template<class T> struct is_range;
|
template<class T> struct is_range;
|
||||||
template<class T> struct is_contiguous_range;
|
template<class T> struct is_contiguous_range;
|
||||||
template<class T> struct is_unordered_range;
|
template<class T> struct is_unordered_range;
|
||||||
|
template<class T> struct is_described_class;
|
||||||
|
|
||||||
} // namespace container_hash
|
} // namespace container_hash
|
||||||
|
|
||||||
@@ -103,6 +104,10 @@ template<class T>
|
|||||||
template<class T>
|
template<class T>
|
||||||
std::size_t hash_value( T const& v );
|
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>
|
template<class T>
|
||||||
std::size_t hash_value( std::shared_ptr<T> const& v );
|
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`,
|
When `typename std::iterator_traits<It>::value_type` is not `char`, `signed char`,
|
||||||
`unsigned char`,
|
`unsigned char`, `std::byte`, or `char8_t`,
|
||||||
|
|
||||||
[source]
|
[source]
|
||||||
----
|
----
|
||||||
@@ -446,6 +451,34 @@ Remarks: ::
|
|||||||
This overload handles the standard unordered containers, such as
|
This overload handles the standard unordered containers, such as
|
||||||
`std::unordered_set` and `std::unordered_map`.
|
`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]
|
[source]
|
||||||
----
|
----
|
||||||
template<class T>
|
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
|
Users are allowed to specialize `is_unordered_range` for their types
|
||||||
if the default behavior does not deduce the correct value.
|
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.
|
||||||
|
|||||||
+10
-1
@@ -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]
|
[#thanks]
|
||||||
= Acknowledgements
|
= Acknowledgements
|
||||||
|
|
||||||
:idprefix: thanks_
|
: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.
|
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.
|
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 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.
|
||||||
|
|||||||
+1
-1
@@ -74,7 +74,7 @@ assert(books.find(knife) != books.end());
|
|||||||
assert(books.find(dandelion) == 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.hpp[examples/books.hpp] and
|
||||||
link:../../examples/books.cpp[examples/books.cpp].
|
link:../../examples/books.cpp[examples/books.cpp].
|
||||||
|
|
||||||
|
|||||||
@@ -7,3 +7,4 @@ run books.cpp ;
|
|||||||
run point.cpp ;
|
run point.cpp ;
|
||||||
run portable.cpp ;
|
run portable.cpp ;
|
||||||
run template.cpp : : : <toolset>msvc-8.0:<build>no ;
|
run template.cpp : : : <toolset>msvc-8.0:<build>no ;
|
||||||
|
run point2.cpp ;
|
||||||
|
|||||||
@@ -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<signed char>: public boost::true_type {};
|
||||||
template<> struct is_char_type<unsigned 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
|
#endif
|
||||||
|
|
||||||
template<class It>
|
template<class It>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <boost/container_hash/is_range.hpp>
|
#include <boost/container_hash/is_range.hpp>
|
||||||
#include <boost/container_hash/is_contiguous_range.hpp>
|
#include <boost/container_hash/is_contiguous_range.hpp>
|
||||||
#include <boost/container_hash/is_unordered_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.hpp>
|
||||||
#include <boost/container_hash/detail/hash_mix.hpp>
|
#include <boost/container_hash/detail/hash_mix.hpp>
|
||||||
#include <boost/container_hash/detail/hash_range.hpp>
|
#include <boost/container_hash/detail/hash_range.hpp>
|
||||||
@@ -25,7 +26,15 @@
|
|||||||
#include <boost/type_traits/make_unsigned.hpp>
|
#include <boost/type_traits/make_unsigned.hpp>
|
||||||
#include <boost/type_traits/enable_if.hpp>
|
#include <boost/type_traits/enable_if.hpp>
|
||||||
#include <boost/type_traits/conjunction.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>
|
#include <boost/cstdint.hpp>
|
||||||
|
|
||||||
|
#if defined(BOOST_DESCRIBE_CXX14)
|
||||||
|
# include <boost/mp11/algorithm.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <complex>
|
#include <complex>
|
||||||
@@ -54,6 +63,10 @@
|
|||||||
#include <variant>
|
#include <variant>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
|
||||||
|
# include <string_view>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -176,12 +189,11 @@ namespace boost
|
|||||||
{
|
{
|
||||||
template<class T,
|
template<class T,
|
||||||
std::size_t Bits = sizeof(T) * CHAR_BIT,
|
std::size_t Bits = sizeof(T) * CHAR_BIT,
|
||||||
int Digits = std::numeric_limits<T>::digits,
|
int Digits = std::numeric_limits<T>::digits>
|
||||||
std::size_t size_t_bits = sizeof(std::size_t) * CHAR_BIT>
|
|
||||||
struct hash_float_impl;
|
struct hash_float_impl;
|
||||||
|
|
||||||
// float
|
// float
|
||||||
template<class T, int Digits, std::size_t size_t_bits> struct hash_float_impl<T, 32, Digits, size_t_bits>
|
template<class T, int Digits> struct hash_float_impl<T, 32, Digits>
|
||||||
{
|
{
|
||||||
static std::size_t fn( T v )
|
static std::size_t fn( T v )
|
||||||
{
|
{
|
||||||
@@ -193,35 +205,19 @@ namespace boost
|
|||||||
};
|
};
|
||||||
|
|
||||||
// double
|
// double
|
||||||
template<class T, int Digits> struct hash_float_impl<T, 64, Digits, 64>
|
template<class T, int Digits> struct hash_float_impl<T, 64, Digits>
|
||||||
{
|
{
|
||||||
static std::size_t fn( T v )
|
static std::size_t fn( T v )
|
||||||
{
|
{
|
||||||
boost::uint64_t w;
|
boost::uint64_t w;
|
||||||
std::memcpy( &w, &v, sizeof( v ) );
|
std::memcpy( &w, &v, sizeof( v ) );
|
||||||
|
|
||||||
return w;
|
return hash_value( w );
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T, int Digits> struct hash_float_impl<T, 64, Digits, 32>
|
|
||||||
{
|
|
||||||
static std::size_t fn( T v )
|
|
||||||
{
|
|
||||||
boost::uint32_t w[ 2 ];
|
|
||||||
std::memcpy( &w, &v, sizeof( v ) );
|
|
||||||
|
|
||||||
std::size_t seed = 0;
|
|
||||||
|
|
||||||
seed = static_cast<std::size_t>( w[0] ) + hash_detail::hash_mix( seed );
|
|
||||||
seed = static_cast<std::size_t>( w[1] ) + hash_detail::hash_mix( seed );
|
|
||||||
|
|
||||||
return seed;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 80 bit long double in 12 bytes
|
// 80 bit long double in 12 bytes
|
||||||
template<class T> struct hash_float_impl<T, 96, 64, 64>
|
template<class T> struct hash_float_impl<T, 96, 64>
|
||||||
{
|
{
|
||||||
static std::size_t fn( T v )
|
static std::size_t fn( T v )
|
||||||
{
|
{
|
||||||
@@ -230,32 +226,15 @@ namespace boost
|
|||||||
|
|
||||||
std::size_t seed = 0;
|
std::size_t seed = 0;
|
||||||
|
|
||||||
seed = static_cast<std::size_t>( w[0] ) + hash_detail::hash_mix( seed );
|
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
|
||||||
seed = static_cast<std::size_t>( w[1] ) + hash_detail::hash_mix( seed );
|
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
|
||||||
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T> struct hash_float_impl<T, 96, 64, 32>
|
|
||||||
{
|
|
||||||
static std::size_t fn( T v )
|
|
||||||
{
|
|
||||||
boost::uint32_t w[ 3 ] = {};
|
|
||||||
std::memcpy( &w, &v, 80 / CHAR_BIT );
|
|
||||||
|
|
||||||
std::size_t seed = 0;
|
|
||||||
|
|
||||||
seed = static_cast<std::size_t>( w[0] ) + hash_detail::hash_mix( seed );
|
|
||||||
seed = static_cast<std::size_t>( w[1] ) + hash_detail::hash_mix( seed );
|
|
||||||
seed = static_cast<std::size_t>( w[2] ) + hash_detail::hash_mix( seed );
|
|
||||||
|
|
||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 80 bit long double in 16 bytes
|
// 80 bit long double in 16 bytes
|
||||||
template<class T> struct hash_float_impl<T, 128, 64, 64>
|
template<class T> struct hash_float_impl<T, 128, 64>
|
||||||
{
|
{
|
||||||
static std::size_t fn( T v )
|
static std::size_t fn( T v )
|
||||||
{
|
{
|
||||||
@@ -264,32 +243,15 @@ namespace boost
|
|||||||
|
|
||||||
std::size_t seed = 0;
|
std::size_t seed = 0;
|
||||||
|
|
||||||
seed = static_cast<std::size_t>( w[0] ) + hash_detail::hash_mix( seed );
|
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
|
||||||
seed = static_cast<std::size_t>( w[1] ) + hash_detail::hash_mix( seed );
|
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
|
||||||
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T> struct hash_float_impl<T, 128, 64, 32>
|
|
||||||
{
|
|
||||||
static std::size_t fn( T v )
|
|
||||||
{
|
|
||||||
boost::uint32_t w[ 3 ] = {};
|
|
||||||
std::memcpy( &w, &v, 80 / CHAR_BIT );
|
|
||||||
|
|
||||||
std::size_t seed = 0;
|
|
||||||
|
|
||||||
seed = static_cast<std::size_t>( w[0] ) + hash_detail::hash_mix( seed );
|
|
||||||
seed = static_cast<std::size_t>( w[1] ) + hash_detail::hash_mix( seed );
|
|
||||||
seed = static_cast<std::size_t>( w[2] ) + hash_detail::hash_mix( seed );
|
|
||||||
|
|
||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 128 bit long double
|
// 128 bit long double
|
||||||
template<class T, int Digits, std::size_t size_t_bits> struct hash_float_impl<T, 128, Digits, size_t_bits>
|
template<class T, int Digits> struct hash_float_impl<T, 128, Digits>
|
||||||
{
|
{
|
||||||
static std::size_t fn( T v )
|
static std::size_t fn( T v )
|
||||||
{
|
{
|
||||||
@@ -434,6 +396,49 @@ namespace boost
|
|||||||
return boost::hash_unordered_range( v.begin(), v.end() );
|
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
|
#endif
|
||||||
|
|
||||||
// std::unique_ptr, std::shared_ptr
|
// std::unique_ptr, std::shared_ptr
|
||||||
@@ -628,8 +633,30 @@ namespace boost
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
#undef BOOST_FUNCTIONAL_HASH_ROTL32
|
// 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
|
#endif // #ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Copyright 2005-2009 Daniel James.
|
// Copyright 2005-2009 Daniel James.
|
||||||
// Copyright 2021 Peter Dimov.
|
// Copyright 2021, 2022 Peter Dimov.
|
||||||
// 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
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ namespace container_hash
|
|||||||
template<class T> struct is_range;
|
template<class T> struct is_range;
|
||||||
template<class T> struct is_contiguous_range;
|
template<class T> struct is_contiguous_range;
|
||||||
template<class T> struct is_unordered_range;
|
template<class T> struct is_unordered_range;
|
||||||
|
template<class T> struct is_described_class;
|
||||||
|
|
||||||
} // namespace container_hash
|
} // namespace container_hash
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#include <boost/config/workaround.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/is_integral.hpp>
|
||||||
#include <boost/type_traits/declval.hpp>
|
#include <boost/type_traits/declval.hpp>
|
||||||
|
|||||||
@@ -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
|
||||||
+3
-2
@@ -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.
|
# 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
|
# 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)
|
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()
|
endif()
|
||||||
|
|||||||
@@ -101,3 +101,17 @@ run hash_unordered_map_test.cpp ;
|
|||||||
run is_range_test3.cpp ;
|
run is_range_test3.cpp ;
|
||||||
run is_contiguous_range_test2.cpp ;
|
run is_contiguous_range_test2.cpp ;
|
||||||
run is_unordered_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(../../../config boostorg/config)
|
||||||
add_subdirectory(../../../type_traits boostorg/type_traits)
|
add_subdirectory(../../../type_traits boostorg/type_traits)
|
||||||
add_subdirectory(../../../static_assert boostorg/static_assert)
|
add_subdirectory(../../../static_assert boostorg/static_assert)
|
||||||
|
add_subdirectory(../../../describe boostorg/describe)
|
||||||
|
add_subdirectory(../../../mp11 boostorg/mp11)
|
||||||
|
|
||||||
add_executable(quick ../quick.cpp)
|
add_executable(quick ../quick.cpp)
|
||||||
target_link_libraries(quick Boost::container_hash)
|
target_link_libraries(quick Boost::container_hash)
|
||||||
|
|||||||
@@ -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<float>();
|
||||||
test<double>();
|
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();
|
return boost::report_errors();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
#include <boost/core/lightweight_test.hpp>
|
#include <boost/core/lightweight_test.hpp>
|
||||||
#include "./compile_time.hpp"
|
#include "./compile_time.hpp"
|
||||||
|
|
||||||
void void_func1() { static int x = 1; ++x; }
|
void void_func1() { static int x = 1; ++x; (void)x; }
|
||||||
void void_func2() { static int x = 2; --x; }
|
void void_func2() { static int x = 2; --x; (void)x; }
|
||||||
int int_func1(int) { return 0; }
|
int int_func1(int) { return 0; }
|
||||||
int int_func2(int) { return 1; }
|
int int_func2(int) { return 1; }
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -171,16 +171,16 @@ int main()
|
|||||||
|
|
||||||
#if SIZE_MAX == 4294967295U
|
#if SIZE_MAX == 4294967295U
|
||||||
|
|
||||||
BOOST_TEST_EQ( hv(1.0), 1072693248U );
|
BOOST_TEST_EQ( hv(1.0), 2619008688U );
|
||||||
BOOST_TEST_EQ( hv(-1.0), 3220176896U );
|
BOOST_TEST_EQ( hv(-1.0), 146497060U );
|
||||||
BOOST_TEST_EQ( hv(3.14), 3972386992U );
|
BOOST_TEST_EQ( hv(3.14), 101651732U );
|
||||||
BOOST_TEST_EQ( hv(-3.14), 1824903344U );
|
BOOST_TEST_EQ( hv(-3.14), 210858151U );
|
||||||
BOOST_TEST_EQ( hv(1e-308), 2213556530U );
|
BOOST_TEST_EQ( hv(1e-308), 3911789313U );
|
||||||
BOOST_TEST_EQ( hv(-1e-308), 66072882U );
|
BOOST_TEST_EQ( hv(-1e-308), 1812507313U );
|
||||||
BOOST_TEST_EQ( hv(1e+308), 2623678890U );
|
BOOST_TEST_EQ( hv(1e+308), 987802568U );
|
||||||
BOOST_TEST_EQ( hv(-1e+308), 476195242U );
|
BOOST_TEST_EQ( hv(-1e+308), 1639042439U );
|
||||||
BOOST_TEST_EQ( hv(std::numeric_limits<double>::infinity()), 2146435072U );
|
BOOST_TEST_EQ( hv(std::numeric_limits<double>::infinity()), 3227645345U );
|
||||||
BOOST_TEST_EQ( hv(-std::numeric_limits<double>::infinity()), 4293918720U );
|
BOOST_TEST_EQ( hv(-std::numeric_limits<double>::infinity()), 2247339177U );
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@@ -207,21 +207,23 @@ int main()
|
|||||||
|
|
||||||
if( ldbits == 64 )
|
if( ldbits == 64 )
|
||||||
{
|
{
|
||||||
BOOST_TEST_EQ( hv(1.0L), 1072693248U );
|
BOOST_TEST_EQ( hv(1.0L), hv(1.0) );
|
||||||
BOOST_TEST_EQ( hv(-1.0L), 3220176896U );
|
BOOST_TEST_EQ( hv(-1.0L), hv(-1.0) );
|
||||||
BOOST_TEST_EQ( hv(3.14L), 3972386992U );
|
BOOST_TEST_EQ( hv(3.14L), hv(3.14) );
|
||||||
BOOST_TEST_EQ( hv(-3.14L), 1824903344U );
|
BOOST_TEST_EQ( hv(-3.14L), hv(-3.14) );
|
||||||
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 2146435072U );
|
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), hv(std::numeric_limits<double>::infinity()) );
|
||||||
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 4293918720U );
|
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), hv(-std::numeric_limits<double>::infinity()) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_TEST_EQ( hv(1.0L), 3770520689U );
|
// ldbits == 96
|
||||||
BOOST_TEST_EQ( hv(-1.0L), 3770553457U );
|
|
||||||
BOOST_TEST_EQ( hv(3.14L), 1150018772U );
|
BOOST_TEST_EQ( hv(1.0L), 3632050780U );
|
||||||
BOOST_TEST_EQ( hv(-3.14L), 1150051540U );
|
BOOST_TEST_EQ( hv(-1.0L), 3632083548U );
|
||||||
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 3770537073U );
|
BOOST_TEST_EQ( hv(3.14L), 1742026549U );
|
||||||
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 3770569841U );
|
BOOST_TEST_EQ( hv(-3.14L), 1742059317U );
|
||||||
|
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 3632067164U );
|
||||||
|
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 3632099932U );
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@@ -246,9 +248,7 @@ int main()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// ldbits == 128 && std::numeric_limits<long double>::digits == 113
|
// ldbits == 128 && std::numeric_limits<long double>::digits == 113
|
||||||
// under ARM64 and S390x, but the values differ presumably because of
|
|
||||||
// __FLOAT_WORD_ORDER__
|
|
||||||
|
|
||||||
BOOST_TEST_EQ( hv(1.0L), 4611404543450677248ULL );
|
BOOST_TEST_EQ( hv(1.0L), 4611404543450677248ULL );
|
||||||
BOOST_TEST_EQ( hv(-1.0L), 13834776580305453056ULL );
|
BOOST_TEST_EQ( hv(-1.0L), 13834776580305453056ULL );
|
||||||
@@ -344,10 +344,10 @@ int main()
|
|||||||
|
|
||||||
#if SIZE_MAX == 4294967295U
|
#if SIZE_MAX == 4294967295U
|
||||||
|
|
||||||
BOOST_TEST_EQ( hv(std::complex<double>(+1.0, 0.0)), 1072693248U );
|
BOOST_TEST_EQ( hv(std::complex<double>(+1.0, 0.0)), 2619008688U );
|
||||||
BOOST_TEST_EQ( hv(std::complex<double>(-1.0, 0.0)), 3220176896U );
|
BOOST_TEST_EQ( hv(std::complex<double>(-1.0, 0.0)), 146497060U );
|
||||||
BOOST_TEST_EQ( hv(std::complex<double>(0.0, +1.0)), 2619008688U );
|
BOOST_TEST_EQ( hv(std::complex<double>(0.0, +1.0)), 22395692U );
|
||||||
BOOST_TEST_EQ( hv(std::complex<double>(0.0, -1.0)), 146497060U );
|
BOOST_TEST_EQ( hv(std::complex<double>(0.0, -1.0)), 1449221192U );
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ int main()
|
|||||||
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<std::wstring const>));
|
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<std::wstring const>));
|
||||||
|
|
||||||
// std::vector doesn't have data() in C++03
|
// 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> >));
|
||||||
BOOST_TEST_TRAIT_TRUE((is_contiguous_range< std::vector<X> const >));
|
BOOST_TEST_TRAIT_TRUE((is_contiguous_range< std::vector<X> const >));
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ int main()
|
|||||||
{
|
{
|
||||||
using boost::container_hash::is_contiguous_range;
|
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>));
|
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<X1>));
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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