Compare commits

...

166 Commits

Author SHA1 Message Date
Peter Dimov
48a306dcf2 Perform apt-get update before apt-add-repository 2023-10-13 02:28:26 +03:00
Peter Dimov
f6279a0615 Add diagnostic output to .drone.jsonnet 2023-10-13 01:43:44 +03:00
Peter Dimov
41746c0bdb Cosmetic fixes 2023-10-12 20:19:57 +03:00
Peter Dimov
07a0910640 Update revision history 2023-10-12 18:14:27 +03:00
Peter Dimov
4c32071739 Remove cxxstd=latest from clang-win/VS2017 on Appveyor 2023-10-12 17:35:57 +03:00
Peter Dimov
30c05c93b1 Remove GCC 4.4, 4.6 from Drone 2023-10-12 15:10:46 +03:00
Peter Dimov
197f75845c Update dependency list in cmake_subdir_test 2023-10-12 14:53:37 +03:00
Peter Dimov
bf8ad2c0ee Regenerate CMakeLists.txt 2023-10-12 14:51:55 +03:00
Peter Dimov
fef60938e5 Update meta/libraries.json 2023-10-12 14:51:15 +03:00
Peter Dimov
f04d866fa7 Remove msvc-9.0, 10.0, 11.0, 12.0 from Appveyor 2023-10-12 14:50:14 +03:00
Peter Dimov
17201433f8 Remove unnecessary file 2023-10-12 14:41:23 +03:00
Peter Dimov
9d09674f08 Work around libstdc++ not considering __int128 integral 2023-10-12 14:24:00 +03:00
Peter Dimov
f8ecd66820 Move integrals to detail/hash_integral.hpp 2023-10-12 14:06:56 +03:00
Peter Dimov
565bac8d31 Remove C++03 workarounds 2023-10-12 13:57:41 +03:00
Peter Dimov
b8496de2f2 Silence MSSTL has_denorm deprecation warnings 2023-10-12 12:43:37 +03:00
Peter Dimov
641a59342e Remove C++03 from CI 2023-10-12 12:28:18 +03:00
Peter Dimov
226eb066e9 Update .drone.jsonnet 2023-06-29 14:38:53 +03:00
Peter Dimov
d9cb23d96a Update ci.yml 2023-06-29 11:50:12 +03:00
Peter Dimov
bd8a5cb867 Merge pull request #34 from ecatmur/libcxx-16
Fix libc++16 failures
2023-06-29 11:22:13 +03:00
Ed Catmur
b43ce472fa Fix libc++16 failures
Similar to de8fe4fad7
2023-06-28 11:12:42 -05:00
Peter Dimov
e798972130 Update C++03 deprecation message 2023-06-03 02:27:41 +03:00
Peter Dimov
ebb49fa459 Update ci.yml 2023-05-21 15:28:59 +03:00
Peter Dimov
1e1c0ea38c Update ci.yml 2023-05-21 04:08:58 +03:00
Peter Dimov
e62a268566 Update documentation 2023-04-05 17:34:08 +03:00
Peter Dimov
ad89c02360 Use link=static for /boost//filesystem under UBSan 2023-03-05 04:59:42 +02:00
Peter Dimov
64948e5f57 Update .drone.jsonnet 2023-03-05 04:21:10 +02:00
Peter Dimov
1958e96561 Add C++03 deprecation notice 2023-03-05 02:38:16 +02:00
Peter Dimov
4a7287d371 Update ci.yml 2023-03-02 21:12:54 +02:00
Peter Dimov
5638134081 Update notes.adoc 2023-03-02 19:45:18 +02:00
Peter Dimov
7c49f0bfb1 Document switch to mulxp1_hash 2023-02-15 20:44:10 +02:00
Peter Dimov
9ae5790657 Update ci.yml 2023-02-04 01:22:15 +02:00
Peter Dimov
8ce81c361d Fix /RTCc violations because Unordered tests with it 2023-02-03 20:57:47 +02:00
Peter Dimov
4315faf470 Update ci.yml 2023-02-02 14:54:38 +02:00
Peter Dimov
eb049e0cae Update .drone.jsonnet 2023-02-02 14:19:37 +02:00
Peter Dimov
6373656710 Avoid -Wlong-long under C++03 2023-02-02 07:29:03 +02:00
Peter Dimov
ec1503bbc8 Hardcode q*q to avoid 'integral constant overflow' warnings 2023-02-02 06:15:01 +02:00
Peter Dimov
ee064dc7f8 Avoid -Wconversion warnings 2023-02-02 06:11:47 +02:00
Peter Dimov
b505e06b3c Update 64 bit reference values to reflect the change to mulxp1_hash 2023-02-02 06:06:36 +02:00
Peter Dimov
6075f3e1f5 Change 64 bit hash_range for char[] to mulxp1_hash 2023-02-02 06:00:00 +02:00
Peter Dimov
0bfeabfd63 Hardcode q*q to avoid 'integral constant overflow' warnings 2023-02-02 05:20:06 +02:00
Peter Dimov
758596533d Temporarily update 64 bit reference values to match mulxp1_hash32 2023-02-02 04:58:15 +02:00
Peter Dimov
640bd48f51 Avoid -Wconversion warning for p[x1] 2023-02-02 04:54:10 +02:00
Peter Dimov
b25fd745ca Update 32 bit reference values to reflect the change to mulxp1_hash32 2023-02-02 04:52:42 +02:00
Peter Dimov
6fe3469a8b Replace hash_range for char[] with mulxp1_hash32 2023-02-02 04:42:42 +02:00
Peter Dimov
c07630ac60 Add read32le to detail/hash_range.hpp 2023-02-02 04:09:54 +02:00
Peter Dimov
45270ae11e Update benchmark/unordered.cpp 2022-12-12 21:08:00 +02:00
Peter Dimov
5bef4901b9 Add a pointer overload for detail::hash_range under msvc 2022-12-09 21:12:30 +02:00
Peter Dimov
d724bcd0ef Update benchmark/.gitignore 2022-12-09 20:54:04 +02:00
Peter Dimov
ceb8303601 Add mulxp1_hash32 to benchmarks 2022-12-08 17:57:00 +02:00
Peter Dimov
cf87e304f6 Remove mul31, mulxp0, mulxp2 from the unordered_flat and word_count benchmarks 2022-12-01 18:53:34 +02:00
Peter Dimov
4d9f7b8931 Add ankerl::unordered_dense::hash to benchmarks 2022-12-01 02:22:07 +02:00
Peter Dimov
2f4efbced4 Document support for nullptr and tuple-like types 2022-11-29 02:00:06 +02:00
Peter Dimov
bf7a78594e Add a test with a tuple-like described struct 2022-11-28 18:46:13 +02:00
Peter Dimov
c0c70e5b3e Add support for tuple-like types. Refs #30. 2022-11-28 16:59:35 +02:00
Peter Dimov
891a64d45d Add is_tuple_like to hash_fwd.hpp 2022-11-28 15:55:25 +02:00
Peter Dimov
08d69c31b1 Merge branch 'develop' into feature/is_tuple_like 2022-11-28 15:50:36 +02:00
Peter Dimov
6526b24900 Add hash_integral_test2.cpp 2022-11-28 14:20:44 +02:00
Peter Dimov
1a8dca4f2c Disable is_tuple_like for msvc-12.0 and earlier 2022-11-28 05:15:06 +02:00
Peter Dimov
8761157a19 Merge branch 'develop' into feature/is_tuple_like 2022-11-28 03:13:35 +02:00
Peter Dimov
f2b2ef4ebe Avoid warning 4100 under early MSVC 2022-11-28 01:59:32 +02:00
Peter Dimov
30560ada18 Disable -Wmismatched-tags under Clang 2022-11-28 00:57:19 +02:00
Peter Dimov
c61a4f691e Add boost::container_hash::is_tuple_like. Refs #30. 2022-11-27 21:20:19 +02:00
Peter Dimov
fe28cdbd1f Add boost::hash_value for std::nullptr_t. Refs #29. 2022-11-27 20:13:52 +02:00
Peter Dimov
f98b943585 Add benchmark/.gitignore 2022-11-27 19:39:38 +02:00
Peter Dimov
4aeb7b2285 Update benchmark/unordered_flat.cpp 2022-11-27 06:47:54 +02:00
Peter Dimov
e310932a9c Add mulxp3_hash32 to benchmarks 2022-11-27 02:43:20 +02:00
Peter Dimov
558d0ead17 Suppress std::complex<int> warning under clang-cl 2022-11-25 21:13:57 +02:00
Peter Dimov
d6905ab159 Add benchmark/word_count.cpp 2022-11-25 20:52:56 +02:00
Peter Dimov
251894540d Split mul31_unrolled_hash into mul31_x4_hash and mul31_x8_hash in benchmarks 2022-11-25 20:52:30 +02:00
Peter Dimov
ffadafa0c1 Remove old_boost_hash from benchmarks 2022-11-25 20:27:20 +02:00
Peter Dimov
ce166d1030 Add mulxp_hash to benchmark/unordered.cpp 2022-11-25 20:24:59 +02:00
Peter Dimov
8ab83c1cd4 Add mulxp_hash to benchmark/unordered_flat.cpp 2022-11-25 20:24:38 +02:00
Peter Dimov
16546190f6 Add benchmark/unordered_flat.cpp 2022-11-19 03:19:34 +02:00
Peter Dimov
5e26a3b807 Add absl::Hash to benchmark/unordered.cpp 2022-11-18 17:37:09 +02:00
Peter Dimov
bd5b7a359c Update ci.yml 2022-11-03 14:19:56 +02:00
Peter Dimov
f5f5476dcc <boost/unordered/hash_traits.hpp> no longer requires C++11 2022-11-01 02:35:51 +02:00
Peter Dimov
228f7db5d3 Add examples/point2.cpp 2022-10-30 17:51:31 +02:00
Peter Dimov
f50b914456 Update documentation 2022-10-30 17:23:39 +02:00
Peter Dimov
c134ca39e9 Update test/CMakeLists.txt 2022-10-30 03:05:20 +02:00
Peter Dimov
f51f68fe93 Do not use the u8string and u8string_view typedefs, because char8_t availability does not guarantee their presence 2022-10-30 03:01:05 +02:00
Peter Dimov
0865c1d230 Disable hash_is_avalanching tests when BOOST_NO_CXX11_TEMPLATE_ALIASES is defined, because hash_traits.hpp uses void_t 2022-10-30 03:54:24 +03:00
Peter Dimov
0d2266decb Specialize boost::unordered::hash_is_avalanching for hash<string> and hash<string_view> 2022-10-30 02:47:10 +03:00
Peter Dimov
3c9ba89cf2 Update .drone.jsonnet 2022-10-28 21:21:44 +03:00
Peter Dimov
20ee3b60fd Update CMakeLists.txt 2022-10-28 21:18:10 +03:00
Peter Dimov
bdd3dcf944 Disable -Wunused-private-field in described_class_test.cpp 2022-10-28 20:04:13 +03:00
Peter Dimov
018fc4e1fa Add support for described classes to hash.hpp 2022-10-28 19:35:10 +03:00
Peter Dimov
7568176bfa is_described_class should be false for unions 2022-10-28 18:42:07 +03:00
Peter Dimov
08864cd1e9 Update cmake_subdir_test/CMakeLists.txt 2022-10-28 14:56:57 +03:00
Peter Dimov
5a616b9b54 Update CMakeLists.txt 2022-10-28 07:07:48 +03:00
Peter Dimov
16fb4cc749 Add is_described_class to hash_fwd.hpp; include it in hash.hpp 2022-10-28 03:32:18 +03:00
Peter Dimov
0171246a61 Add is_described_class<T> 2022-10-28 01:47:27 +03:00
Peter Dimov
29c85559e4 Update .drone.jsonnet 2022-10-27 02:44:38 +03:00
Peter Dimov
412bd51449 Avoid -Wunused-but-set-variable under Clang 15 2022-10-27 02:12:43 +03:00
Peter Dimov
87196a503e Update .drone.jsonnet 2022-10-27 01:16:34 +03:00
Peter Dimov
df1671d593 msvc-14.0 doesn't quite have expression SFINAE. Fixes #28. 2022-10-26 19:38:53 +03:00
Peter Dimov
1996cf36c1 Update ci.yml 2022-10-26 19:32:22 +03:00
Peter Dimov
a4b2048a29 Add is_contiguous_range_test3 (refs #28) 2022-10-26 19:13:27 +03:00
Peter Dimov
85f9f8a97a Update documentation 2022-09-20 21:20:31 +03:00
Peter Dimov
e92eae9eb2 Treat char8_t and std::byte as char types in hash_range 2022-09-20 21:17:41 +03:00
Peter Dimov
8a1335458a Update Acknowledgements section 2022-09-20 21:09:17 +03:00
Peter Dimov
f7e537d1a1 Update Notes section 2022-09-20 21:06:09 +03:00
Peter Dimov
607b73f1e0 Add README.md 2022-09-20 16:08:10 +03:00
Peter Dimov
789261c68c Update 32 bit float reference values (for GCC) 2022-09-20 15:23:13 +03:00
Peter Dimov
29ee19ee7f Update 32 bit float reference values (for MSVC) 2022-09-20 15:08:21 +03:00
Peter Dimov
8bb7d43646 Simplify hash_value for floating point 2022-09-20 15:01:45 +03:00
Peter Dimov
a426a1939f Honor __FLOAT_WORD_ORDER__ for 128 bit long double 2022-09-20 14:52:19 +03:00
Peter Dimov
034b81594d Update 128 bit long double hash_value 2022-09-20 14:49:37 +03:00
Peter Dimov
75ef5a14f5 Cosmetic documentation updates 2022-09-20 12:25:16 +03:00
Peter Dimov
b5bb4405a9 Update Links section 2022-09-20 01:41:38 +03:00
Peter Dimov
d43ae22ab4 Update Notes section 2022-09-20 01:20:26 +03:00
Peter Dimov
e061b3c4c0 Update Notes section 2022-09-19 21:23:52 +03:00
Peter Dimov
9035aa5485 Avoid a warning under g++ 4.8 2022-09-19 15:43:37 +03:00
Peter Dimov
3ae0aea360 Update hash_reference_values for long double 2022-09-19 15:32:51 +03:00
Peter Dimov
fc249670c0 Update test/hash_info.cpp 2022-09-19 14:35:58 +03:00
Peter Dimov
30ffbf9f16 Remove address-model=32 from S390x and ARM64 as it doesn't do anything 2022-09-19 14:32:07 +03:00
Peter Dimov
c36319c878 Run test//hash_info using --verbose-test 2022-09-19 14:14:54 +03:00
Peter Dimov
a2aaefc71a Add -I examples to depinst 2022-09-19 13:50:36 +03:00
Peter Dimov
e3cd2d7de8 Add Drone support 2022-09-19 13:30:02 +03:00
Peter Dimov
4571ec190a Add Recent Changes section 2022-09-19 13:00:41 +03:00
Peter Dimov
478730107d Rename Rationale section to Design and Implementation Notes 2022-09-19 12:29:38 +03:00
Peter Dimov
adcf81c732 Update Links section 2022-09-19 12:19:08 +03:00
Peter Dimov
75a37c2616 Update Reference section 2022-09-19 11:56:03 +03:00
Peter Dimov
c01270b0bd Update Links section 2022-09-18 22:05:30 +03:00
Peter Dimov
123875dc83 Update documentation 2022-09-18 20:58:00 +03:00
Peter Dimov
ed235989ef Add is_unordered_range_test2 2022-09-18 14:32:28 +03:00
Peter Dimov
bf0a77f062 Disable tests using fs::path for msvc-8.0 2022-09-18 14:28:24 +03:00
Peter Dimov
79fff9e1ea Add is_contiguous_range_test2 2022-09-18 14:26:30 +03:00
Peter Dimov
6757bd4f00 Match is_range workaround in is_range_test3 2022-09-18 14:11:49 +03:00
Peter Dimov
20c03417b0 Add is_range_test3 2022-09-18 14:04:05 +03:00
Peter Dimov
60be3b131e Update 64 bit reference values for the new multiplier 2022-09-17 03:31:35 +03:00
Peter Dimov
b148e34818 Fix 64 bit hash_mix multiplier 2022-09-17 02:34:14 +03:00
Peter Dimov
e391cf6841 Change hash_detail::hash_range to take and return by value to avoid It=char* aliasing 2022-09-17 01:09:47 +03:00
Peter Dimov
b4e0643ecd Update 32 bit reference values for container<char> 2022-09-16 21:43:53 +03:00
Peter Dimov
dc9a6e3e68 Update 64 bit reference values for container<char> 2022-09-16 21:33:48 +03:00
Peter Dimov
f47772f6f4 Implement faster hash_range when value_type is char 2022-09-16 21:25:20 +03:00
Peter Dimov
c1e5427e8d Update 32 bit float reference values (for GCC) 2022-09-16 20:36:29 +03:00
Peter Dimov
866cff96e5 Restore full grid size in hash_complex_test 2022-09-16 19:57:45 +03:00
Peter Dimov
9d4971b81d Update complex reference values 2022-09-16 19:56:00 +03:00
Peter Dimov
4b5a1cf0f2 Update complex hashing to use hash_mix 2022-09-16 19:48:36 +03:00
Peter Dimov
435ff87fd7 Update 64 bit reference values (for GCC) 2022-09-16 19:30:02 +03:00
Peter Dimov
58934422fb Update 32 bit reference values (for MSVC) 2022-09-16 19:26:07 +03:00
Peter Dimov
3fe7bbdd6c Update floating point hashing to use hash_mix 2022-09-16 19:23:07 +03:00
Peter Dimov
fba63d4379 Update integral reference values 2022-09-16 19:19:30 +03:00
Peter Dimov
8adcaffcc2 Update integral hashing to use hash_mix 2022-09-16 19:16:45 +03:00
Peter Dimov
eee5e3b7fd Update 32 bit reference values to reflect the new hash_combine 2022-09-16 19:10:18 +03:00
Peter Dimov
e98cae2c31 Update 64 bit reference values to reflect the new hash_combine 2022-09-16 19:05:05 +03:00
Peter Dimov
40ec854466 Add hash_mix, change hash_combine to use it 2022-09-16 18:57:21 +03:00
Peter Dimov
c5b63d2cbb Disable failing tests on msvc-10.0 and msvc-11.0 2022-09-16 11:00:23 +03:00
Peter Dimov
882192ea3a Update workaround for Dinkumware stdext::hash_value 2022-09-16 01:56:24 +03:00
Peter Dimov
03123685c4 Add hash_unordered_map_test 2022-09-15 18:12:52 +03:00
Peter Dimov
95fe6bd9a3 Add hash_unordered_set_test 2022-09-15 18:10:23 +03:00
Peter Dimov
6cb735fda6 Add hash_unordered_multimap_test 2022-09-15 18:05:00 +03:00
Peter Dimov
10b4ad598f Add hash_unordered_multiset_test 2022-09-15 18:02:22 +03:00
Peter Dimov
ce734b435e Implement boost::hash_unordered_range 2022-09-15 18:00:04 +03:00
Peter Dimov
e387d14d36 Add hash_multimap_test 2022-09-15 16:50:39 +03:00
Peter Dimov
1fb41a72ef Add hash_multiset_test 2022-09-15 16:48:18 +03:00
Peter Dimov
c399cf6a38 Add traits to hash_fwd.hpp 2022-09-13 20:10:35 +03:00
Peter Dimov
30c32bb3df Move traits headers from container_hash/detail/ to container_hash/ 2022-09-13 19:45:45 +03:00
Peter Dimov
d1b2640dff Move type classification traits from namespace hash_detail to namespace container_hash 2022-09-13 19:37:15 +03:00
Peter Dimov
f722383d1d Change macos-10.15 to macos-11 in ci.yml 2022-08-31 18:17:01 +03:00
Peter Dimov
21530840e1 Add hash_string_test4.cpp 2022-08-31 15:09:29 +03:00
Peter Dimov
d0c1e36fc1 Add hash_string_test3.cpp 2022-08-31 14:51:47 +03:00
Peter Dimov
e00f53a69c Remove msvc-14.2 from appveyor.yml 2022-07-16 14:10:28 +03:00
Peter Dimov
b0c9904414 Test _MSVC_STL_VERSION instead of BOOST_MSVC because clang-cl 2022-07-16 13:37:15 +03:00
Peter Dimov
2d557a746d Add hash_vector_test2.cpp 2022-07-16 11:16:06 +03:00
Peter Dimov
417180dd03 Update appveyor.yml 2022-07-14 20:16:19 +03:00
91 changed files with 6122 additions and 1425 deletions

View File

@@ -16,19 +16,16 @@ branches:
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0
ADDRMD: 32
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
TOOLSET: msvc-12.0,msvc-14.0
TOOLSET: msvc-14.0
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: msvc-14.1
CXXSTD: 14,17
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: msvc-14.2
CXXSTD: 14,17,latest
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: clang-win
ADDRMD: 64
CXXSTD: 14,17
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: clang-win
CXXSTD: 14,17,latest
@@ -36,19 +33,19 @@ environment:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\cygwin\bin;
TOOLSET: gcc
CXXSTD: 03,11,14,1z
CXXSTD: 11,14,1z
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\cygwin64\bin;
TOOLSET: gcc
CXXSTD: 03,11,14,1z
CXXSTD: 11,14,1z
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\mingw\bin;
TOOLSET: gcc
CXXSTD: 03,11,14,1z
CXXSTD: 11,14,1z
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin;
TOOLSET: gcc
CXXSTD: 03,11,14,1z
CXXSTD: 11,14,1z
install:
- set BOOST_BRANCH=develop

381
.drone.jsonnet Normal file
View File

@@ -0,0 +1,381 @@
# Copyright 2022 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
local library = "container_hash";
local triggers =
{
branch: [ "master", "develop", "feature/*" ]
};
local ubsan = { UBSAN: '1', UBSAN_OPTIONS: 'print_stacktrace=1' };
local asan = { ASAN: '1' };
local linux_pipeline(name, image, environment, packages = "", sources = [], arch = "amd64") =
{
name: name,
kind: "pipeline",
type: "docker",
trigger: triggers,
platform:
{
os: "linux",
arch: arch
},
steps:
[
{
name: "everything",
image: image,
environment: environment,
commands:
[
'set -e',
'uname -a',
'echo $DRONE_STAGE_MACHINE',
'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -',
] +
(if sources != [] then [ 'apt-get update' ] + [ ('apt-add-repository "' + source + '"') for source in sources ] else []) +
(if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) +
[
'export LIBRARY=' + library,
'./.drone/drone.sh',
]
}
]
};
local macos_pipeline(name, environment, xcode_version = "12.2", osx_version = "catalina", arch = "amd64") =
{
name: name,
kind: "pipeline",
type: "exec",
trigger: triggers,
platform: {
"os": "darwin",
"arch": arch
},
node: {
"os": osx_version
},
steps: [
{
name: "everything",
environment: environment + { "DEVELOPER_DIR": "/Applications/Xcode-" + xcode_version + ".app/Contents/Developer" },
commands:
[
'export LIBRARY=' + library,
'./.drone/drone.sh',
]
}
]
};
local windows_pipeline(name, image, environment, arch = "amd64") =
{
name: name,
kind: "pipeline",
type: "docker",
trigger: triggers,
platform:
{
os: "windows",
arch: arch
},
"steps":
[
{
name: "everything",
image: image,
environment: environment,
commands:
[
'cmd /C .drone\\\\drone.bat ' + library,
]
}
]
};
[
linux_pipeline(
"Linux 14.04 GCC 4.7 32/64",
"cppalliance/droneubuntu1404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-4.7', CXXSTD: '0x', ADDRMD: '32,64' },
"g++-4.7-multilib",
[ "ppa:ubuntu-toolchain-r/test" ],
),
linux_pipeline(
"Linux 14.04 GCC 4.8* 32/64",
"cppalliance/droneubuntu1404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 14.04 GCC 4.9 32/64",
"cppalliance/droneubuntu1404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-4.9', CXXSTD: '11', ADDRMD: '32,64' },
"g++-4.9-multilib",
[ "ppa:ubuntu-toolchain-r/test" ],
),
linux_pipeline(
"Linux 16.04 GCC 5* 32/64",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 18.04 GCC 6 32/64",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-6', CXXSTD: '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: '11,14,17', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 18.04 GCC 8 32/64",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '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: '11,14,17,2a', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 20.04 GCC 9* ARM64",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' },
arch="arm64",
),
linux_pipeline(
"Linux 20.04 GCC 9* S390x",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' },
arch="s390x",
),
linux_pipeline(
"Linux 20.04 GCC 10 32/64",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '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: '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: '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: '11,14,17,20,2b', ADDRMD: '64' } + asan,
"g++-12-multilib",
),
linux_pipeline(
"Linux 23.04 GCC 13 32/64",
"cppalliance/droneubuntu2304:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '11,14,17,20,2b', ADDRMD: '32,64' },
"g++-13-multilib",
),
linux_pipeline(
"Linux 16.04 Clang 3.5",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.5', CXXSTD: '11' },
"clang-3.5",
),
linux_pipeline(
"Linux 16.04 Clang 3.6",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.6', CXXSTD: '11,14' },
"clang-3.6",
),
linux_pipeline(
"Linux 16.04 Clang 3.7",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.7', CXXSTD: '11,14' },
"clang-3.7",
),
linux_pipeline(
"Linux 16.04 Clang 3.8",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.8', CXXSTD: '11,14' },
"clang-3.8",
),
linux_pipeline(
"Linux 18.04 Clang 3.9",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.9', CXXSTD: '11,14' },
"clang-3.9",
),
linux_pipeline(
"Linux 18.04 Clang 4.0",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-4.0', CXXSTD: '11,14' },
"clang-4.0",
),
linux_pipeline(
"Linux 18.04 Clang 5.0",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-5.0', CXXSTD: '11,14,1z' },
"clang-5.0",
),
linux_pipeline(
"Linux 18.04 Clang 6.0",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-6.0', CXXSTD: '11,14,17' },
"clang-6.0",
),
linux_pipeline(
"Linux 20.04 Clang 7",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-7', CXXSTD: '11,14,17' },
"clang-7",
),
linux_pipeline(
"Linux 20.04 Clang 8",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-8', CXXSTD: '11,14,17' },
"clang-8",
),
linux_pipeline(
"Linux 20.04 Clang 9",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-9', CXXSTD: '11,14,17,2a' },
"clang-9",
),
linux_pipeline(
"Linux 20.04 Clang 10",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-10', CXXSTD: '11,14,17,2a' },
"clang-10",
),
linux_pipeline(
"Linux 20.04 Clang 11",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-11', CXXSTD: '11,14,17,2a' },
"clang-11",
),
linux_pipeline(
"Linux 20.04 Clang 12",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-12', CXXSTD: '11,14,17,2a' },
"clang-12",
),
linux_pipeline(
"Linux 22.04 Clang 13",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '11,14,17,20,2b' },
"clang-13",
),
linux_pipeline(
"Linux 22.04 Clang 14",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '11,14,17,20,2b' },
"clang-14",
),
linux_pipeline(
"Linux 22.04 Clang 15 UBSAN",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '11,14,17,20,2b' } + ubsan,
"clang-15",
),
linux_pipeline(
"Linux 22.04 Clang 15 ASAN",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '11,14,17,20,2b' } + asan,
"clang-15",
),
linux_pipeline(
"Linux 23.04 Clang 16",
"cppalliance/droneubuntu2304:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-16', CXXSTD: '11,14,17,20,2b' },
"clang-16",
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,2a' } + ubsan,
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 ASAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,2a' } + asan,
),
macos_pipeline(
"MacOS 12.4 Xcode 13.4.1 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,20,2b' } + ubsan,
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
),
macos_pipeline(
"MacOS 12.4 Xcode 13.4.1 ASAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,20,2b' } + asan,
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
),
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' },
),
]

24
.drone/drone.bat Normal file
View File

@@ -0,0 +1,24 @@
@REM Copyright 2022 Peter Dimov
@REM Distributed under the Boost Software License, Version 1.0.
@REM https://www.boost.org/LICENSE_1_0.txt
@ECHO ON
set LIBRARY=%1
set DRONE_BUILD_DIR=%CD%
set BOOST_BRANCH=develop
if "%DRONE_BRANCH%" == "master" set BOOST_BRANCH=master
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
git submodule update --init tools/boostdep
xcopy /s /e /q %DRONE_BUILD_DIR% libs\%LIBRARY%\
python tools/boostdep/depinst/depinst.py -I examples %LIBRARY%
cmd /c bootstrap
b2 -d0 headers
if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
b2 -j3 --verbose-test libs/%LIBRARY%/test//hash_info toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker
b2 -j3 libs/%LIBRARY%/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker

26
.drone/drone.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/bash
# Copyright 2022 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
set -ex
export PATH=~/.local/bin:/usr/local/bin:$PATH
DRONE_BUILD_DIR=$(pwd)
BOOST_BRANCH=develop
if [ "$DRONE_BRANCH" = "master" ]; then BOOST_BRANCH=master; fi
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
git submodule update --init tools/boostdep
cp -r $DRONE_BUILD_DIR/* libs/$LIBRARY
python tools/boostdep/depinst/depinst.py -I examples $LIBRARY
./bootstrap.sh
./b2 -d0 headers
echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam
./b2 -j3 --verbose-test libs/$LIBRARY/test//hash_info toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${ADDRMD:+address-model=$ADDRMD} ${UBSAN:+undefined-sanitizer=norecover debug-symbols=on} ${ASAN:+address-sanitizer=norecover debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}
./b2 -j3 libs/$LIBRARY/test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${ADDRMD:+address-model=$ADDRMD} ${UBSAN:+undefined-sanitizer=norecover debug-symbols=on} ${ASAN:+address-sanitizer=norecover debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}

View File

@@ -18,119 +18,161 @@ jobs:
matrix:
include:
- toolset: gcc-4.8
cxxstd: "03,11"
os: ubuntu-18.04
cxxstd: "11"
os: ubuntu-latest
container: ubuntu:18.04
install: g++-4.8-multilib
address-model: 32,64
- toolset: gcc-5
cxxstd: "03,11,14,1z"
os: ubuntu-18.04
cxxstd: "11,14,1z"
os: ubuntu-latest
container: ubuntu:18.04
install: g++-5-multilib
address-model: 32,64
- toolset: gcc-6
cxxstd: "03,11,14,1z"
os: ubuntu-18.04
cxxstd: "11,14,1z"
os: ubuntu-latest
container: ubuntu:18.04
install: g++-6-multilib
address-model: 32,64
- toolset: gcc-7
cxxstd: "03,11,14,17"
os: ubuntu-18.04
cxxstd: "11,14,17"
os: ubuntu-20.04
install: g++-7-multilib
address-model: 32,64
- toolset: gcc-8
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: g++-8-multilib
address-model: 32,64
- toolset: gcc-9
cxxstd: "03,11,14,17,2a"
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: g++-9-multilib
address-model: 32,64
- toolset: gcc-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
cxxstd: "11,14,17,2a"
os: ubuntu-22.04
install: g++-10-multilib
address-model: 32,64
- toolset: gcc-11
cxxstd: "03,11,14,17,20"
os: ubuntu-20.04
cxxstd: "11,14,17,20"
os: ubuntu-22.04
install: g++-11-multilib
address-model: 32,64
- toolset: gcc-12
cxxstd: "03,11,14,17,20"
cxxstd: "11,14,17,20,2b"
os: ubuntu-22.04
install: g++-12-multilib
address-model: 32,64
- toolset: gcc-13
cxxstd: "11,14,17,20,2b"
os: ubuntu-latest
container: ubuntu:23.04
install: g++-13-multilib
address-model: 32,64
- toolset: clang
compiler: clang++-3.9
cxxstd: "03,11,14"
os: ubuntu-18.04
cxxstd: "11,14"
os: ubuntu-latest
container: ubuntu:18.04
install: clang-3.9
- toolset: clang
compiler: clang++-4.0
cxxstd: "03,11,14"
os: ubuntu-18.04
cxxstd: "11,14"
os: ubuntu-latest
container: ubuntu:18.04
install: clang-4.0
- toolset: clang
compiler: clang++-5.0
cxxstd: "03,11,14,1z"
os: ubuntu-18.04
cxxstd: "11,14,1z"
os: ubuntu-latest
container: ubuntu:18.04
install: clang-5.0
- toolset: clang
compiler: clang++-6.0
cxxstd: "03,11,14,17"
os: ubuntu-18.04
cxxstd: "11,14,17"
os: ubuntu-20.04
install: clang-6.0
- toolset: clang
compiler: clang++-7
cxxstd: "03,11,14,17"
os: ubuntu-18.04
cxxstd: "11,14,17"
os: ubuntu-20.04
install: clang-7
- toolset: clang
compiler: clang++-8
cxxstd: "03,11,14,17"
cxxstd: "11,14,17"
os: ubuntu-20.04
install: clang-8
- toolset: clang
compiler: clang++-9
cxxstd: "03,11,14,17,2a"
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: clang-9
- toolset: clang
compiler: clang++-10
cxxstd: "03,11,14,17,2a"
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
- toolset: clang
compiler: clang++-11
cxxstd: "03,11,14,17,2a"
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
- toolset: clang
compiler: clang++-12
cxxstd: "03,11,14,17,20"
cxxstd: "11,14,17,20"
os: ubuntu-20.04
- toolset: clang
compiler: clang++-13
cxxstd: "03,11,14,17,20"
cxxstd: "11,14,17,20,2b"
os: ubuntu-22.04
install: clang-13
- toolset: clang
compiler: clang++-14
cxxstd: "03,11,14,17,20"
cxxstd: "11,14,17,20,2b"
os: ubuntu-22.04
install: clang-14
- toolset: clang
cxxstd: "03,11,14,17,2a"
os: macos-10.15
compiler: clang++-15
cxxstd: "11,14,17,20,2b"
os: ubuntu-22.04
install: clang-15
- toolset: clang
compiler: clang++-16
cxxstd: "11,14,17,20,2b"
os: ubuntu-latest
container: ubuntu:23.04
install: clang-16
- toolset: clang
cxxstd: "11,14,17,2a"
os: macos-11
- toolset: clang
cxxstd: "11,14,17,20,2b"
os: macos-12
- toolset: clang
cxxstd: "11,14,17,20,2b"
os: macos-13
runs-on: ${{matrix.os}}
container: ${{matrix.container}}
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup container environment
if: matrix.container
run: |
apt-get update
apt-get -y install sudo python3 git g++
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
run: |
sudo apt-get update
sudo apt-get -y install ${{matrix.install}}
- name: Setup Boost
run: |
@@ -150,7 +192,7 @@ jobs:
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py -I examples --git_args "--jobs 3" $LIBRARY
python3 tools/boostdep/depinst/depinst.py -I examples --git_args "--jobs 3" $LIBRARY
./bootstrap.sh
./b2 -d0 headers
@@ -188,14 +230,14 @@ jobs:
addrmd: 32,64
os: windows-2022
- toolset: gcc
cxxstd: "03,11,14,17,2a"
cxxstd: "11,14,17,2a"
addrmd: 64
os: windows-2019
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup Boost
shell: cmd
@@ -231,19 +273,20 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-10.15
- os: macos-11
- os: macos-12
- os: macos-13
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
run: sudo apt-get -y install ${{matrix.install}}
- name: Setup Boost
run: |
@@ -278,19 +321,20 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-10.15
- os: macos-11
- os: macos-12
- os: macos-13
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
run: sudo apt-get -y install ${{matrix.install}}
- name: Setup Boost
run: |
@@ -335,19 +379,20 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-10.15
- os: macos-11
- os: macos-12
- os: macos-13
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
run: sudo apt-get -y install ${{matrix.install}}
- name: Setup Boost
run: |
@@ -384,3 +429,183 @@ jobs:
run: |
cd ../boost-root/__build__
ctest --output-on-failure --no-tests=error
windows-cmake-subdir:
strategy:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
- name: Use library with add_subdirectory (Debug)
shell: cmd
run: |
cd ../boost-root/libs/%LIBRARY%/test/cmake_subdir_test
mkdir __build__ && cd __build__
cmake ..
cmake --build . --config Debug
ctest --output-on-failure --no-tests=error -C Debug
- name: Use library with add_subdirectory (Release)
shell: cmd
run: |
cd ../boost-root/libs/%LIBRARY%/test/cmake_subdir_test/__build__
cmake --build . --config Release
ctest --output-on-failure --no-tests=error -C Release
windows-cmake-install:
strategy:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
- name: Configure
shell: cmd
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=%LIBRARY% -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix ..
- name: Install (Debug)
shell: cmd
run: |
cd ../boost-root/__build__
cmake --build . --target install --config Debug
- name: Install (Release)
shell: cmd
run: |
cd ../boost-root/__build__
cmake --build . --target install --config Release
- name: Use the installed library (Debug)
shell: cmd
run: |
cd ../boost-root/libs/%LIBRARY%/test/cmake_install_test && mkdir __build__ && cd __build__
cmake -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix ..
cmake --build . --config Debug
ctest --output-on-failure --no-tests=error -C Debug
- name: Use the installed library (Release)
shell: cmd
run: |
cd ../boost-root/libs/%LIBRARY%/test/cmake_install_test/__build__
cmake --build . --config Release
ctest --output-on-failure --no-tests=error -C Release
windows-cmake-test:
strategy:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
- name: Configure
shell: cmd
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=%LIBRARY% -DBUILD_TESTING=ON ..
- name: Build tests (Debug)
shell: cmd
run: |
cd ../boost-root/__build__
cmake --build . --target tests --config Debug
- name: Run tests (Debug)
shell: cmd
run: |
cd ../boost-root/__build__
ctest --output-on-failure --no-tests=error -C Debug
- name: Build tests (Release)
shell: cmd
run: |
cd ../boost-root/__build__
cmake --build . --target tests --config Release
- name: Run tests (Release)
shell: cmd
run: |
cd ../boost-root/__build__
ctest --output-on-failure --no-tests=error -C Release

View File

@@ -3,7 +3,7 @@
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.5...3.20)
cmake_minimum_required(VERSION 3.8...3.20)
project(boost_container_hash VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
@@ -15,9 +15,12 @@ target_include_directories(boost_container_hash INTERFACE include)
target_link_libraries(boost_container_hash
INTERFACE
Boost::config
Boost::type_traits
Boost::describe
Boost::mp11
)
target_compile_features(boost_container_hash INTERFACE cxx_std_11)
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)

20
README.md Normal file
View 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).

4
benchmark/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
enwik8
enwik9
*.exe
*.obj

View File

@@ -3,12 +3,22 @@
// https://www.boost.org/LICENSE_1_0.txt
#define _CRT_SECURE_NO_WARNINGS
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
#include <boost/container_hash/hash.hpp>
#include <boost/unordered_set.hpp>
#include <boost/core/detail/splitmix64.hpp>
#include <boost/core/type_name.hpp>
#include <boost/config.hpp>
#ifdef HAVE_ABSEIL
# include "absl/hash/hash.h"
#endif
#ifdef HAVE_ANKERL_UNORDERED_DENSE
# include "ankerl/unordered_dense.h"
#endif
#ifdef HAVE_MULXP_HASH
# include "mulxp_hash.hpp"
#endif
#include <cstddef>
#include <cstdio>
#include <cstdint>
@@ -19,10 +29,8 @@
// mul31_hash
class mul31_hash
struct mul31_hash
{
public:
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
{
char const * p = st.data();
@@ -43,18 +51,20 @@ public:
}
};
// mul31_unrolled_hash
// mul31_x4_hash
template<int Bits> struct mul31_unrolled_hash_impl;
template<> struct mul31_unrolled_hash_impl<32>
struct mul31_x4_hash
{
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
{
char const * p = st.data();
std::size_t n = st.size();
#if SIZE_MAX > UINT32_MAX
std::size_t h = 0xCBF29CE484222325ull;
#else
std::size_t h = 0x811C9DC5u;
#endif
while( n >= 4 )
{
@@ -80,14 +90,20 @@ template<> struct mul31_unrolled_hash_impl<32>
}
};
template<> struct mul31_unrolled_hash_impl<64>
// mul31_x8_hash
struct mul31_x8_hash
{
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
{
char const * p = st.data();
std::size_t n = st.size();
std::size_t h = 0xCBF29CE484222325ull;
#if SIZE_MAX > UINT32_MAX
boost::uint64_t h = 0xCBF29CE484222325ull;
#else
boost::uint64_t h = 0x811C9DC5u;
#endif
while( n >= 8 )
{
@@ -113,12 +129,10 @@ template<> struct mul31_unrolled_hash_impl<64>
--n;
}
return h;
return static_cast<std::size_t>( h );
}
};
struct mul31_unrolled_hash: mul31_unrolled_hash_impl< std::numeric_limits<std::size_t>::digits > {};
// fnv1a_hash
template<int Bits> struct fnv1a_hash_impl;
@@ -163,28 +177,44 @@ template<> struct fnv1a_hash_impl<64>
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits > {};
// old_boost_hash
// mulxp_hash
class old_boost_hash
#ifdef HAVE_MULXP_HASH
struct mulxp1_hash_
{
public:
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
{
char const * p = st.data();
std::size_t n = st.size();
std::size_t h = 0;
for( std::size_t i = 0; i < n; ++i )
{
h ^= static_cast<unsigned char>( p[i] ) + 0x9e3779b9 + ( h << 6 ) + ( h >> 2 );
}
return h;
return mulxp1_hash( (unsigned char const*)st.data(), st.size(), 0 );
}
};
struct mulxp3_hash_
{
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
{
return mulxp3_hash( (unsigned char const*)st.data(), st.size(), 0 );
}
};
struct mulxp1_hash32_
{
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
{
return mulxp1_hash32( (unsigned char const*)st.data(), st.size(), 0 );
}
};
struct mulxp3_hash32_
{
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
{
return mulxp3_hash32( (unsigned char const*)st.data(), st.size(), 0 );
}
};
#endif
// test_hash_speed
template<class H, class V> void test_hash_speed( int N, V const& v )
@@ -210,11 +240,11 @@ template<class H, class V> void test_hash_speed( int N, V const& v )
#if defined( _MSC_VER )
std::printf( "%25s : q=%20Iu, %lld ms\n", hash.c_str(), q, ms1 );
std::printf( "%57s : q=%20Iu, %lld ms\n", hash.c_str(), q, ms1 );
#else
std::printf( "%25s : q=%20zu, %lld ms\n", hash.c_str(), q, ms1 );
std::printf( "%57s : q=%20zu, %lld ms\n", hash.c_str(), q, ms1 );
#endif
}
@@ -235,11 +265,11 @@ template<class H, class V> void test_hash_collision( int N, V const& v, std::siz
#if defined( _MSC_VER )
std::printf( "%25s : c=%Iu\n", hash.c_str(), n - s.size() );
std::printf( "%57s : c=%Iu\n", hash.c_str(), n - s.size() );
#else
std::printf( "%25s : c=%zu\n", hash.c_str(), n - s.size() );
std::printf( "%57s : c=%zu\n", hash.c_str(), n - s.size() );
#endif
}
@@ -292,11 +322,11 @@ template<class V, class S> void test4( int N, V const& v, char const * hash, S s
#if defined( _MSC_VER )
std::printf( "%25s : n=%Iu, m=%Iu, c=%Iu, q=%Iu, %lld + %lld ms\n", hash, n, m, c, q, ms1, ms2 );
std::printf( "%57s : n=%Iu, m=%Iu, c=%Iu, q=%Iu, %4lld + %4lld = %4lld ms\n", hash, n, m, c, q, ms1, ms2, ms1 + ms2 );
#else
std::printf( "%25s : n=%zu, m=%zu, c=%zu, q=%zu, %lld + %lld ms\n", hash, n, m, c, q, ms1, ms2 );
std::printf( "%57s : n=%zu, m=%zu, c=%zu, q=%zu, %4lld + %4lld = %4lld ms\n", hash, n, m, c, q, ms1, ms2, ms1 + ms2 );
#endif
}
@@ -340,11 +370,23 @@ int main()
std::puts( "Hash speed test:\n" );
test_hash_speed<mul31_hash>( N * 16, v );
test_hash_speed<mul31_unrolled_hash>( N * 16, v );
test_hash_speed<mul31_x4_hash>( N * 16, v );
test_hash_speed<mul31_x8_hash>( N * 16, v );
test_hash_speed<fnv1a_hash>( N * 16, v );
test_hash_speed<old_boost_hash>( N * 16, v );
test_hash_speed<boost::hash<std::string> >( N * 16, v );
test_hash_speed<std::hash<std::string> >( N * 16, v );
#ifdef HAVE_ABSEIL
test_hash_speed<absl::Hash<std::string> >( N * 16, v );
#endif
#ifdef HAVE_ANKERL_UNORDERED_DENSE
test_hash_speed<ankerl::unordered_dense::hash<std::string> >( N * 16, v );
#endif
#ifdef HAVE_MULXP_HASH
test_hash_speed<mulxp1_hash_>( N * 16, v );
test_hash_speed<mulxp3_hash_>( N * 16, v );
test_hash_speed<mulxp1_hash32_>( N * 16, v );
test_hash_speed<mulxp3_hash32_>( N * 16, v );
#endif
std::puts( "" );
@@ -365,25 +407,55 @@ int main()
}
test_hash_collision<mul31_hash>( N * 16, v, n );
test_hash_collision<mul31_unrolled_hash>( N * 16, v, n );
test_hash_collision<mul31_x4_hash>( N * 16, v, n );
test_hash_collision<mul31_x8_hash>( N * 16, v, n );
test_hash_collision<fnv1a_hash>( N * 16, v, n );
test_hash_collision<old_boost_hash>( N * 16, v, n );
test_hash_collision<boost::hash<std::string> >( N * 16, v, n );
test_hash_collision<std::hash<std::string> >( N * 16, v, n );
#ifdef HAVE_ABSEIL
test_hash_collision<absl::Hash<std::string> >( N * 16, v, n );
#endif
#ifdef HAVE_ANKERL_UNORDERED_DENSE
test_hash_collision<ankerl::unordered_dense::hash<std::string> >( N * 16, v, n );
#endif
#ifdef HAVE_MULXP_HASH
test_hash_collision<mulxp1_hash_>( N * 16, v, n );
test_hash_collision<mulxp3_hash_>( N * 16, v, n );
test_hash_collision<mulxp1_hash32_>( N * 16, v, n );
test_hash_collision<mulxp3_hash32_>( N * 16, v, n );
#endif
}
std::puts( "" );
typedef std::string K;
std::puts( "Container speed test:\n" );
std::puts( "Container speed test:\n---\n" );
test_container_speed<K, mul31_hash>( N, v );
test_container_speed<K, mul31_unrolled_hash>( N, v );
test_container_speed<K, mul31_x4_hash>( N, v );
test_container_speed<K, mul31_x8_hash>( N, v );
test_container_speed<K, fnv1a_hash>( N, v );
test_container_speed<K, old_boost_hash>( N, v );
test_container_speed<K, boost::hash<std::string> >( N, v );
test_container_speed<K, std::hash<std::string> >( N, v );
#ifdef HAVE_ABSEIL
test_container_speed<K, absl::Hash<std::string> >( N, v );
#endif
#ifdef HAVE_ANKERL_UNORDERED_DENSE
test_container_speed<K, ankerl::unordered_dense::hash<std::string> >( N, v );
#endif
#ifdef HAVE_MULXP_HASH
test_container_speed<K, mulxp1_hash_>( N, v );
test_container_speed<K, mulxp3_hash_>( N, v );
test_container_speed<K, mulxp1_hash32_>( N, v );
test_container_speed<K, mulxp3_hash32_>( N, v );
#endif
std::puts( "" );
}
#ifdef HAVE_ABSEIL
# include "absl/hash/internal/hash.cc"
# include "absl/hash/internal/low_level_hash.cc"
# include "absl/hash/internal/city.cc"
#endif

View File

@@ -0,0 +1,386 @@
// Copyright 2021 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/core/detail/splitmix64.hpp>
#include <boost/config.hpp>
#ifdef HAVE_ABSEIL
# include "absl/hash/hash.h"
#endif
#ifdef HAVE_ANKERL_UNORDERED_DENSE
# include "ankerl/unordered_dense.h"
#endif
#ifdef HAVE_MULXP_HASH
# include "mulxp_hash.hpp"
#endif
#include <vector>
#include <memory>
#include <cstdint>
#include <iostream>
#include <iomanip>
#include <chrono>
using namespace std::chrono_literals;
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::uint32_t s, std::size_t size )
{
auto t2 = std::chrono::steady_clock::now();
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
t1 = t2;
}
constexpr unsigned N = 2'000'000;
constexpr int K = 10;
static std::vector<std::string> indices1, indices2;
static std::string make_index( unsigned x )
{
char buffer[ 64 ];
std::snprintf( buffer, sizeof(buffer), "pfx_%u_sfx", x );
return buffer;
}
static std::string make_random_index( unsigned x )
{
char buffer[ 64 ];
std::snprintf( buffer, sizeof(buffer), "pfx_%0*d_%u_sfx", x % 8 + 1, 0, x );
return buffer;
}
static void init_indices()
{
indices1.reserve( N*2+1 );
indices1.push_back( make_index( 0 ) );
for( unsigned i = 1; i <= N*2; ++i )
{
indices1.push_back( make_index( i ) );
}
indices2.reserve( N*2+1 );
indices2.push_back( make_index( 0 ) );
{
boost::detail::splitmix64 rng;
for( unsigned i = 1; i <= N*2; ++i )
{
indices2.push_back( make_random_index( static_cast<std::uint32_t>( rng() ) ) );
}
}
}
template<class Map> BOOST_NOINLINE void test_insert( Map& map, std::chrono::steady_clock::time_point & t1 )
{
for( unsigned i = 1; i <= N; ++i )
{
map.insert( { indices1[ i ], i } );
}
print_time( t1, "Consecutive insert", 0, map.size() );
for( unsigned i = 1; i <= N; ++i )
{
map.insert( { indices2[ i ], i } );
}
print_time( t1, "Random insert", 0, map.size() );
std::cout << std::endl;
}
template<class Map> BOOST_NOINLINE void test_lookup( Map& map, std::chrono::steady_clock::time_point & t1 )
{
std::uint32_t s;
s = 0;
for( int j = 0; j < K; ++j )
{
for( unsigned i = 1; i <= N * 2; ++i )
{
auto it = map.find( indices1[ i ] );
if( it != map.end() ) s += it->second;
}
}
print_time( t1, "Consecutive lookup", s, map.size() );
s = 0;
for( int j = 0; j < K; ++j )
{
for( unsigned i = 1; i <= N * 2; ++i )
{
auto it = map.find( indices2[ i ] );
if( it != map.end() ) s += it->second;
}
}
print_time( t1, "Random lookup", s, map.size() );
std::cout << std::endl;
}
template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::steady_clock::time_point & t1 )
{
auto it = map.begin();
while( it != map.end() )
{
if( it->second & 1 )
{
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
{
map.erase( it++ );
}
else
{
it = map.erase( it );
}
}
else
{
++it;
}
}
print_time( t1, "Iterate and erase odd elements", 0, map.size() );
std::cout << std::endl;
}
template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::steady_clock::time_point & t1 )
{
for( unsigned i = 1; i <= N; ++i )
{
map.erase( indices1[ i ] );
}
print_time( t1, "Consecutive erase", 0, map.size() );
for( unsigned i = 1; i <= N; ++i )
{
map.erase( indices2[ i ] );
}
print_time( t1, "Random erase", 0, map.size() );
std::cout << std::endl;
}
//
struct record
{
std::string label_;
long long time_;
};
static std::vector<record> times;
template<class Hash> BOOST_NOINLINE void test( char const* label )
{
std::cout << label << ":\n\n";
boost::unordered_flat_map<std::string, std::uint32_t, Hash> map;
auto t0 = std::chrono::steady_clock::now();
auto t1 = t0;
test_insert( map, t1 );
record rec = { label, 0 };
test_lookup( map, t1 );
test_iteration( map, t1 );
test_lookup( map, t1 );
test_erase( map, t1 );
auto tN = std::chrono::steady_clock::now();
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
rec.time_ = ( tN - t0 ) / 1ms;
times.push_back( rec );
}
// fnv1a_hash
template<int Bits> struct fnv1a_hash_impl;
template<> struct fnv1a_hash_impl<32>
{
std::size_t operator()( std::string const& s ) const
{
std::size_t h = 0x811C9DC5u;
char const * first = s.data();
char const * last = first + s.size();
for( ; first != last; ++first )
{
h ^= static_cast<unsigned char>( *first );
h *= 0x01000193ul;
}
return h;
}
};
template<> struct fnv1a_hash_impl<64>
{
std::size_t operator()( std::string const& s ) const
{
std::size_t h = 0xCBF29CE484222325ull;
char const * first = s.data();
char const * last = first + s.size();
for( ; first != last; ++first )
{
h ^= static_cast<unsigned char>( *first );
h *= 0x00000100000001B3ull;
}
return h;
}
};
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
{
using is_avalanching = void;
};
// std_hash
struct std_hash: std::hash<std::string>
{
using is_avalanching = void;
};
// absl_hash
#ifdef HAVE_ABSEIL
struct absl_hash: absl::Hash<std::string>
{
using is_avalanching = void;
};
#endif
// mulxp_hash
#ifdef HAVE_MULXP_HASH
struct mulxp1_hash_
{
using is_avalanching = void;
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
{
return mulxp1_hash( (unsigned char const*)st.data(), st.size(), 0 );
}
};
struct mulxp3_hash_
{
using is_avalanching = void;
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
{
return mulxp3_hash( (unsigned char const*)st.data(), st.size(), 0 );
}
};
struct mulxp1_hash32_
{
using is_avalanching = void;
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
{
std::size_t r = mulxp1_hash32( (unsigned char const*)st.data(), st.size(), 0 );
#if SIZE_MAX > UINT32_MAX
r |= r << 32;
#endif
return r;
}
};
struct mulxp3_hash32_
{
using is_avalanching = void;
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
{
std::size_t r = mulxp3_hash32( (unsigned char const*)st.data(), st.size(), 0 );
#if SIZE_MAX > UINT32_MAX
r |= r << 32;
#endif
return r;
}
};
#endif
//
int main()
{
init_indices();
test< boost::hash<std::string> >( "boost::hash" );
test< std_hash >( "std::hash" );
test< fnv1a_hash >( "fnv1a_hash" );
#ifdef HAVE_ABSEIL
test< absl_hash >( "absl::Hash" );
#endif
#ifdef HAVE_ANKERL_UNORDERED_DENSE
test< ankerl::unordered_dense::hash<std::string> >( "ankerl::unordered_dense::hash" );
#endif
#ifdef HAVE_MULXP_HASH
test< mulxp1_hash_ >( "mulxp1_hash" );
test< mulxp3_hash_ >( "mulxp3_hash" );
test< mulxp1_hash32_ >( "mulxp1_hash32" );
test< mulxp3_hash32_ >( "mulxp3_hash32" );
#endif
std::cout << "---\n\n";
for( auto const& x: times )
{
std::cout << std::setw( 32 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms\n";
}
}
#ifdef HAVE_ABSEIL
# include "absl/hash/internal/hash.cc"
# include "absl/hash/internal/low_level_hash.cc"
# include "absl/hash/internal/city.cc"
#endif

319
benchmark/word_count.cpp Normal file
View File

@@ -0,0 +1,319 @@
// Copyright 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
#include <boost/unordered/unordered_flat_map.hpp>
#ifdef HAVE_ABSEIL
# include "absl/hash/hash.h"
#endif
#ifdef HAVE_ANKERL_UNORDERED_DENSE
# include "ankerl/unordered_dense.h"
#endif
#ifdef HAVE_MULXP_HASH
# include "mulxp_hash.hpp"
#endif
#include <boost/regex.hpp>
#include <vector>
#include <memory>
#include <cstdint>
#include <iostream>
#include <iomanip>
#include <chrono>
#include <fstream>
#include <string_view>
#include <string>
using namespace std::chrono_literals;
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::uint32_t s, std::size_t size )
{
auto t2 = std::chrono::steady_clock::now();
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
t1 = t2;
}
static std::vector<std::string> words;
static void init_words()
{
#if SIZE_MAX > UINT32_MAX
char const* fn = "enwik9"; // http://mattmahoney.net/dc/textdata
#else
char const* fn = "enwik8"; // ditto
#endif
auto t1 = std::chrono::steady_clock::now();
std::ifstream is( fn );
std::string in( std::istreambuf_iterator<char>( is ), std::istreambuf_iterator<char>{} );
boost::regex re( "[a-zA-Z]+");
boost::sregex_token_iterator it( in.begin(), in.end(), re, 0 ), end;
words.assign( it, end );
auto t2 = std::chrono::steady_clock::now();
std::cout << fn << ": " << words.size() << " words, " << ( t2 - t1 ) / 1ms << " ms\n\n";
}
template<class Map> BOOST_NOINLINE void test_word_count( Map& map, std::chrono::steady_clock::time_point & t1 )
{
std::size_t s = 0;
for( auto const& word: words )
{
++map[ word ];
++s;
}
print_time( t1, "Word count", s, map.size() );
std::cout << std::endl;
}
template<class Map> BOOST_NOINLINE void test_contains( Map& map, std::chrono::steady_clock::time_point & t1 )
{
std::size_t s = 0;
for( auto const& word: words )
{
std::string_view w2( word );
w2.remove_prefix( 1 );
s += map.contains( w2 );
}
print_time( t1, "Contains", s, map.size() );
std::cout << std::endl;
}
template<class Map> BOOST_NOINLINE void test_count( Map& map, std::chrono::steady_clock::time_point & t1 )
{
std::size_t s = 0;
for( auto const& word: words )
{
std::string_view w2( word );
w2.remove_prefix( 1 );
s += map.count( w2 );
}
print_time( t1, "Count", s, map.size() );
std::cout << std::endl;
}
//
struct record
{
std::string label_;
long long time_;
};
static std::vector<record> times;
template<class Hash> BOOST_NOINLINE void test( char const* label )
{
std::cout << label << ":\n\n";
boost::unordered_flat_map<std::string_view, std::size_t, Hash> map;
auto t0 = std::chrono::steady_clock::now();
auto t1 = t0;
test_word_count( map, t1 );
record rec = { label, 0 };
test_contains( map, t1 );
test_count( map, t1 );
auto tN = std::chrono::steady_clock::now();
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
rec.time_ = ( tN - t0 ) / 1ms;
times.push_back( rec );
}
// fnv1a_hash
template<int Bits> struct fnv1a_hash_impl;
template<> struct fnv1a_hash_impl<32>
{
std::size_t operator()( std::string_view const& s ) const
{
std::size_t h = 0x811C9DC5u;
char const * first = s.data();
char const * last = first + s.size();
for( ; first != last; ++first )
{
h ^= static_cast<unsigned char>( *first );
h *= 0x01000193ul;
}
return h;
}
};
template<> struct fnv1a_hash_impl<64>
{
std::size_t operator()( std::string_view const& s ) const
{
std::size_t h = 0xCBF29CE484222325ull;
char const * first = s.data();
char const * last = first + s.size();
for( ; first != last; ++first )
{
h ^= static_cast<unsigned char>( *first );
h *= 0x00000100000001B3ull;
}
return h;
}
};
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
{
using is_avalanching = void;
};
// std_hash
struct std_hash: std::hash<std::string_view>
{
using is_avalanching = void;
};
// absl_hash
#ifdef HAVE_ABSEIL
struct absl_hash: absl::Hash<std::string_view>
{
using is_avalanching = void;
};
#endif
#ifdef HAVE_MULXP_HASH
struct mulxp1_hash_
{
using is_avalanching = void;
std::size_t operator()( std::string_view const& st ) const BOOST_NOEXCEPT
{
return mulxp1_hash( (unsigned char const*)st.data(), st.size(), 0 );
}
};
struct mulxp3_hash_
{
using is_avalanching = void;
std::size_t operator()( std::string_view const& st ) const BOOST_NOEXCEPT
{
return mulxp3_hash( (unsigned char const*)st.data(), st.size(), 0 );
}
};
struct mulxp3_hash32_
{
using is_avalanching = void;
std::size_t operator()( std::string_view const& st ) const BOOST_NOEXCEPT
{
std::size_t r = mulxp3_hash32( (unsigned char const*)st.data(), st.size(), 0 );
#if SIZE_MAX > UINT32_MAX
r |= r << 32;
#endif
return r;
}
};
struct mulxp1_hash32_
{
using is_avalanching = void;
std::size_t operator()( std::string_view const& st ) const BOOST_NOEXCEPT
{
std::size_t r = mulxp1_hash32( (unsigned char const*)st.data(), st.size(), 0 );
#if SIZE_MAX > UINT32_MAX
r |= r << 32;
#endif
return r;
}
};
#endif
//
int main()
{
init_words();
test< boost::hash<std::string_view> >( "boost::hash" );
test< std_hash >( "std::hash" );
test< fnv1a_hash >( "fnv1a_hash" );
#ifdef HAVE_ABSEIL
test< absl_hash >( "absl::Hash" );
#endif
#ifdef HAVE_ANKERL_UNORDERED_DENSE
test< ankerl::unordered_dense::hash<std::string_view> >( "ankerl::unordered_dense::hash" );
#endif
#ifdef HAVE_MULXP_HASH
test< mulxp1_hash_ >( "mulxp1_hash" );
test< mulxp3_hash_ >( "mulxp3_hash" );
test< mulxp1_hash32_ >( "mulxp1_hash32" );
test< mulxp3_hash32_ >( "mulxp3_hash32" );
#endif
std::cout << "---\n\n";
for( auto const& x: times )
{
std::cout << std::setw( 32 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms\n";
}
}
#ifdef HAVE_ABSEIL
# include "absl/hash/internal/hash.cc"
# include "absl/hash/internal/low_level_hash.cc"
# include "absl/hash/internal/city.cc"
#endif

View File

@@ -1,6 +1,13 @@
////
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
////
= Boost.ContainerHash
:toc: left
:toclevels: 2
:toclevels: 3
:idprefix:
:docinfo: private-footer
:source-highlighter: rouge
@@ -11,14 +18,14 @@
:leveloffset: +1
include::hash/intro.adoc[]
include::hash/recent.adoc[]
include::hash/tutorial.adoc[]
include::hash/custom.adoc[]
include::hash/user.adoc[]
include::hash/combine.adoc[]
include::hash/portability.adoc[]
include::hash/disable.adoc[]
include::hash/changes.adoc[]
include::hash/rationale.adoc[]
include::hash/ref.adoc[]
include::hash/describe.adoc[]
include::hash/reference.adoc[]
include::hash/notes.adoc[]
include::hash/links.adoc[]
include::hash/thanks.adoc[]
include::hash/copyright.adoc[]
include::hash/changes.adoc[]
include::hash/copyright.adoc[]

View File

@@ -1,11 +1,17 @@
////
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
////
[#changes]
= Change Log
:cpp: C++
:int128: __int128
:idprefix: changes_
:int128: __int128
== Boost 1.67.0
* Moved library into its own module, `container_hash`.
* Moved headers for new module name, now at: `<boost/container_hash/hash.hpp>`, `<boost/container_hash/hash_fwd.hpp>`, `<boost/container_hash/extensions.hpp>`.
@@ -14,7 +20,7 @@
* Update include paths from other Boost libraries.
* Manually write out tuple overloads, rather than using the preprocessor to generate them. Should improve usability, due to better error messages, and easier debugging.
* Fix tutorial example (https://svn.boost.org/trac/boost/ticket/11017[#11017]).
* Quick fix for hashing `vector<bool>` when using lib{cpp}. Will try to introduce a more general fix in the next release.
* Quick fix for hashing `vector<bool>` when using libc++. Will try to introduce a more general fix in the next release.
== Boost 1.66.0
* Avoid float comparison warning when using Clang - this workaround was already in place for GCC, and was used when Clang pretends to be GCC, but the warning was appearing when running Clang in other contexts.
@@ -22,83 +28,103 @@
== Boost 1.65.0
* Support for `char16_t`, `char32_t`, `u16string`, `u32string`
[discrete]
== Boost 1.64.0
* Fix for recent versions of Visual {cpp} which have removed `std::unary_function` and `std::binary_function` (https://svn.boost.org/trac/boost/ticket/12353[#12353]).
[discrete]
== Boost 1.63.0
* Fixed some warnings.
* Only define hash for `std::wstring` when we know we have a `wchar_t`. Otherwise there's a compile error as there's no overload for hashing the characters in wide strings (https://svn.boost.org/trac/boost/ticket/8552[#8552]).
[discrete]
== Boost 1.58.0
* Fixed strict aliasing violation (https://github.com/boostorg/container_hash/issues/3[GitHub #3]).
[discrete]
== Boost 1.56.0
* Removed some Visual {cpp} 6 workarounds.
* Ongoing work on improving `hash_combine`. This changes the combine function which was previously defined in the reference documentation.
[discrete]
== Boost 1.55.0
* Simplify a SFINAE check so that it will hopefully work on Sun 5.9 (https://svn.boost.org/trac10/ticket/8822[#8822]).
* Suppress Visual {cpp} infinite loop warning (https://svn.boost.org/trac10/ticket/8568[#8568]).
[discrete]
== Boost 1.54.0
* https://svn.boost.org/trac/boost/ticket/7957[Ticket 7957]: Fixed a typo.
[discrete]
== Boost 1.53.0
* Add support for `boost::int128_type` and `boost::uint128_type` where available - currently only `{int128}` and `unsigned {int128}` on some versions of gcc.
* On platforms that are known to have the standard floating point functions, don't use automatic detection - which can break if there are ambiguous overloads.
* Fix undefined behaviour when using the binary `float` hash (Thomas Heller).
[discrete]
== Boost 1.52.0
* Restore `enum` support, which was accidentally removed in the last version.
* New floating point hasher - will hash the binary representation on more platforms, which should be faster.
[discrete]
== Boost 1.51.0
* Support the standard smart pointers.
* `hash_value` now implemented using SFINAE to avoid implicit casts to built in types when calling it.
* Updated to use the new config macros.
[discrete]
== Boost 1.50.0
* https://svn.boost.org/trac/boost/ticket/6771[Ticket 6771]: Avoid gcc's `-Wfloat-equal` warning.
* https://svn.boost.org/trac/boost/ticket/6806[Ticket 6806]: Support `std::array` and `std::tuple` when available.
* Add deprecation warning to the long deprecated `boost/container_hash/detail/container_fwd.hpp`.
[discrete]
== Boost 1.46.0
* Avoid warning due with gcc's `-Wconversion` flag.
[discrete]
== Boost 1.44.0
* Add option to prevent implicit conversions when calling `hash_value` by defining `BOOST_HASH_NO_IMPLICIT_CASTS`. When using `boost::hash` for a type that does not have `hash_value` declared but does have an implicit conversion to a type that does, it would use that implicit conversion to hash it. Which can sometimes go very wrong, e.g. using a conversion to `bool` and only hashing to 2 possible values. Since fixing this is a breaking change and was only approached quite late in the release cycle with little discussion it's opt-in for now. This, or something like it, will become the default in a future version.
[discrete]
== Boost 1.43.0
* https://svn.boost.org/trac/boost/ticket/3866[Ticket 3866]: Don't foward declare containers when using gcc's parallel library, allow user to stop forward declaration by defining the `BOOST_DETAIL_NO_CONTAINER_FWD` macro.
* https://svn.boost.org/trac/boost/ticket/4038[Ticket 4038]: Avoid hashing `0.5` and `0` to the same number.
* Stop using deprecated `BOOST_HAS_*` macros.
[discrete]
== Boost 1.42.0
* Reduce the number of warnings for Visual {cpp} warning level 4.
* Some code formatting changes to fit lines into 80 characters.
* Rename an internal namespace.
[discrete]
== Boost 1.40.0
* Automatically configure the `float` functions using template metaprogramming instead of trying to configure every possibility manually.
* Workaround for when STLport doesn't support long double.
[discrete]
== Boost 1.39.0
* Move the `hash_fwd.hpp` implementation into the hash subdirectory, leaving a forwarding header in the old location. You should still use the old location, the new location is mainly for implementation and possible modularization.
* https://svn.boost.org/trac/boost/ticket/2412[Ticket 2412]: Removed deprecated headers.
* https://svn.boost.org/trac/boost/ticket/2957[Ticket 2957]: Fix configuration for vxworks.
[discrete]
== Boost 1.38.0
* Changed the warnings in the deprecated headers from 1.34.0 to errors. These will be removed in a future version of Boost.
* Moved detail headers out of `boost/container_hash/detail`, since they are part of `functional/hash`, not `container_hash`. `boost/container_hash/detail/container_fwd.hpp` has been moved to `boost/detail/container_fwd.hpp` as it's used outside of this library, the others have been moved to `boost/functional/hash/detail`.
[discrete]
== Boost 1.37.0
* http://svn.boost.org/trac/boost/ticket/2264[Ticket 2264]: In Visual {cpp}, always use C99 float functions for long double and float as the {cpp} overloads aren't always availables.
[discrete]
== Boost 1.36.0
* Stop using OpenBSD's dodgy `std::numeric_limits`.
* Using the boost typedefs for `long long` and `unsigned long long`.
* Move the extensions into their own header.
[discrete]
== Boost 1.35.0
* Support for `long long`, `std::complex`.
* Improved algorithm for hashing floating point numbers:
@@ -114,9 +140,11 @@
** http://svn.boost.org/trac/boost/ticket/1509[Ticket 1509]: Suppress another Visual {cpp} warning.
** Some workarounds for the Sun compilers.
[discrete]
== Boost 1.34.1
* https://svn.boost.org/trac10/ticket/952[Ticket 952]: Suppress incorrect 64-bit warning on Visual {cpp}.
[discrete]
== Boost 1.34.0
* Use declarations for standard classes, so that the library doesn't need to include all of their headers
* Deprecated the `<boost/functional/hash/*.hpp>` headers. Now a single header, `<boost/functional/hash.hpp>` is used.
@@ -124,9 +152,10 @@
* Minor improvements to the hash functions for floating point numbers.
* Update the portable example to hopefully be more generally portable.
[discrete]
== Boost 1.33.1
* Fixed the points example, as pointed out by 沈慧峰.
[discrete]
== Boost 1.33.0
* Initial Release

View File

@@ -1,6 +1,13 @@
[#combine]
= Combining hash values
////
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
////
[#combine]
= Combining Hash Values
:idprefix: combine_
Say you have a point class, representing a two dimensional location:
@@ -11,7 +18,9 @@ class point
{
int x;
int y;
public:
point() : x(0), y(0) {}
point(int x, int y) : x(x), y(y) {}
@@ -22,7 +31,10 @@ public:
};
----
and you wish to use it as the key for an unordered_map. You need to customise the hash for this structure. To do this we need to combine the hash values for x and y. The function `boost::hash_combine` is supplied for this purpose:
and you wish to use it as the key for an `unordered_map`. You need to
customise the hash for this structure. To do this we need to combine the
hash values for `x` and `y`. The function `boost::hash_combine` is supplied
for this purpose:
[source]
----
@@ -33,6 +45,7 @@ class point
friend std::size_t hash_value(point const& p)
{
std::size_t seed = 0;
boost::hash_combine(seed, p.x);
boost::hash_combine(seed, p.y);
@@ -43,20 +56,22 @@ class point
};
----
Calls to `hash_combine` incrementally build the hash from the different members of `point`, it can be repeatedly called for any number of elements. It calls `hash_value` on the supplied element, and combines it with the seed.
Calls to `hash_combine` incrementally build the hash from the different
members of `point`, it can be repeatedly called for any number of elements.
It calls `hash_value` on the supplied element, and combines it with the seed.
Full code for this example is at link:../../examples/point.cpp[/libs/container_hash/examples/point.cpp].
Full code for this example is at link:../../examples/point.cpp[examples/point.cpp].
Note that when using `boost::hash_combine` the order of the calls matters.
[NOTE]
====
When using `boost::hash_combine` the order of the calls matters.
[source]
----
std::size_t seed = 0;
boost::hash_combine(seed, 1);
boost::hash_combine(seed, 2);
----
results in a different seed to:
and
[source]
----
@@ -65,9 +80,7 @@ boost::hash_combine(seed, 2);
boost::hash_combine(seed, 1);
----
If you are calculating a hash value for data where the order of the data doesn't matter in comparisons (e.g. a set) you will have to ensure that the data is always supplied in the same order.
====
result in a different values in `seed`.
To calculate the hash of an iterator range you can use `boost::hash_range`:
@@ -77,4 +90,34 @@ std::vector<std::string> some_strings;
std::size_t hash = boost::hash_range(some_strings.begin(), some_strings.end());
----
Note that when writing template classes, you might not want to include the main hash header as it's quite an expensive include that brings in a lot of other headers, so instead you can include the `<boost/container_hash/hash_fwd.hpp>` header which forward declares `boost::hash`, `boost::hash_range` and `boost::hash_combine`. You'll need to include the main header before instantiating `boost::hash`. When using a container that uses `boost::hash` it should do that for you, so your type will work fine with the boost hash containers. There's an example of this in link:../../examples/template.hpp[template.hpp] and link:../../examples/template.cpp[template.cpp].
Since `hash_range` works by repeatedly invoking `hash_combine` on the elements
of the range, the hash value will also be dependent on the element order.
If you are calculating a hash value for a range where the order of the data
doesn't matter, such as `unordered_set`, you can use
`boost::hash_unordered_range` instead.
[source]
----
std::unordered_set<std::string> set;
std::size_t hash = boost::hash_unordered_range(set.begin(), set.end());
----
When writing template classes, you might not want to include the main
`hash.hpp` header as it's quite an expensive include that brings in a lot of
other headers, so instead you can include the
`<boost/container_hash/hash_fwd.hpp>` header which forward declares
`boost::hash`, `boost::hash_combine`, `boost::hash_range`, and
`boost::hash_unordered_range`. You'll need to include the main header before
instantiating `boost::hash`. When using a container that uses `boost::hash` it
should do that for you, so your type will work fine with the Boost hash
containers. There's an example of this in
link:../../examples/template.hpp[examples/template.hpp] and
link:../../examples/template.cpp[examples/template.cpp].
To avoid including even `hash_fwd.hpp` - which still requires the contents
of Boost.ContainerHash to be physically present - you are allowed to copy the
declarations from `hash_fwd.hpp` (and only those) directly into your own
header. This is a special exception guaranteed by the library; in general,
you can't declare library functions, Boost or otherwise, without risk of
breakage in a subsequent release.

View File

@@ -1,10 +1,18 @@
////
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
////
[#copyright]
= Copyright and License
:idprefix:
:idprefix: copyright_
This documentation is
*Daniel James*
* Copyright 2005-2008 Daniel James
* Copyright 2022 Peter Dimov
Copyright (C) 2005-2008 Daniel James
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)
and is distributed under the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].

61
doc/hash/describe.adoc Normal file
View 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.

View File

@@ -1,12 +0,0 @@
[#disable]
= Disabling The Extensions
:idprefix: disable_
While ``boost::hash``'s extensions are generally useful, you might want to turn them of in order to check that your code will work with other implementations of TR1. To do this define the macro `BOOST_HASH_NO_EXTENSIONS`. When this macro is defined, only the specialisations detailed in TR1 will be declared. But, if you later undefine the macro and include `<boost/container_hash/hash.hpp>` then the non-specialised form will be defined - activating the extensions.
It is strongly recommended that you never undefine the macro - and only define it so that it applies to the complete translation unit, either by defining it at the beginning of the main source file or, preferably, by using a compiler switch or preference. And you really should never define it in header files.
If you are writing a library which has code in the header which requires the extensions, then the best action is to tell users not to define the macro. Their code won't _require_ the macro.
Translation units that are compiled with the macro defined will link with units that were compiled without it. This feature has been designed to avoid ODR violations.

View File

@@ -1,22 +1,66 @@
////
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
////
[#intro]
= Introduction
:idprefix: intro_
`boost::hash` is an implementation of the https://en.wikipedia.org/wiki/Hash_function[hash function] object specified by the http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf[Draft Technical Report on C++ Library Extensions] (TR1). It is the default hash function for link:../../../unordered/index.html[Boost.Unordered], link:../../../intrusive/index.html[Boost.Intrusive]'s unordered associative containers, and link:../../../multi_index/index.html[Boost.MultiIndex]'s hash indicies and link:../../../bimap/index.html[Boost.Bimap]'s `unordered_set_of`.
`boost::hash` is an enhanced implementation of the
https://en.wikipedia.org/wiki/Hash_function[hash function] object specified by
{cpp}11 as `std::hash`. It is the default hash function for
link:../../../unordered/index.html[Boost.Unordered],
link:../../../intrusive/index.html[Boost.Intrusive]'s unordered associative
containers, link:../../../multi_index/index.html[Boost.MultiIndex]'s hash
indices, and link:../../../bimap/index.html[Boost.Bimap]'s `unordered_set_of`.
As it is compliant with http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf[TR1], it will work with:
Out of the box, `boost::hash` supports
* integers
* floats
* pointers
* strings
* standard integral types (integers, character types, and `bool`);
* standard floating point types (`float`, `double`, `long double`);
* pointers (to objects and to functions, but not pointers to members)
and `nullptr`;
* enumeration types;
* C arrays;
* `std::complex`;
* tuple-like types, such as `std::pair`, `std::tuple`, and user-defined
types that specialize `std::tuple_size` and provide `get<I>`;
* sequence-like types, both standard and user-defined (sequence-like types
have `begin()` and `end()` member functions returning iterators);
* 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`;
* `std::optional`;
* `std::variant`, `std::monostate`.
It also implements the extension proposed by Peter Dimov in issue 6.18 of the http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf[Library Extension Technical Report Issues List] (page 63), this adds support for:
`boost::hash` 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`. Many, if not most, Boost types already contain the
necessary support.
* arrays
* `std::pair`
* the standard containers.
* extending `boost::hash` for custom types.
`boost::hash` meets the requirements for `std::hash` specified in the {cpp}11
standard, namely, that for two different input values their corresponding hash
values are either guaranteed to be distinct, or the probability of their being
the same (a hash collision) is small. Standard unordered containers, and the
hash-based Boost containers, are designed to work well with such hash functions.
NOTE: This hash function is designed to be used in containers based on the STL and is not suitable as a general purpose hash function. For more details see the <<rationale,rationale>>.
`boost::hash` does not meet the stronger requirements often placed on hash
functions in a more general context. In particular, the hash function is not
cryptographic, is not collision-resistant against a determined adversary, and
does not necessarily possess good "avalanche" properties; that is, small
(single bit) perturbations in the input do not necessarily result in large
(half bits changing) perturbations in the output.
In particular, `boost::hash` has traditionally been the identity function for
all integral types that fit into `std::size_t`, because this guarantees lack of
collisions and is as fast as possible.

View File

@@ -1,12 +1,114 @@
////
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
////
[#links]
= Links
:idprefix: links_
*A Proposal to Add Hash Tables to the Standard Library* http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1456.html The hash table proposal explains much of the design. The hash function object is discussed in Section D.
*A Proposal to Add Hash Tables to the Standard Library* +
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1456.html
*The C++ Standard Library Technical Report.* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf Contains the hash function specification in section 6.3.2.
The hash table proposal explains much of the design. The hash function object is discussed in Section D.
*Library Extension Technical Report Issues List.* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf The library implements the extension described in Issue 6.18, pages 63-67.
---
*Methods for Identifying Versioned and Plagiarised Documents* Timothy C. Hoad, Justin Zobel http://www.cs.rmit.edu.au/~jz/fulltext/jasist-tch.pdf Contains the hash function that `boost::hash_combine` is based on.
*The {cpp} Standard Library Technical Report* +
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf
Contains the hash function specification in section 6.3.2.
---
*Library Extension Technical Report Issues List* +
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf
The library implements the extension described in Issue 6.18, pages 63-67.
---
*Methods for Identifying Versioned and Plagiarised Documents* +
_Timothy C. Hoad, Justin Zobel_ +
https://people.eng.unimelb.edu.au/jzobel/fulltext/jasist03thz.pdf
Contains the hash function that the initial implementation of `boost::hash_combine` was based on.
---
*Performance in Practice of String Hashing Functions* +
_M.V. Ramakrishna, J. Zobel_ +
In Proc. Int. Conf. on Database Systems for Advanced Applications, pages 215-223, Melbourne, Australia, April 1997. +
https://www.comp.nus.edu.sg/~lingtw/dasfaa_proceedings/DASFAA97/P215.pdf
Referenced in the above paper as the source of the hash function.
---
*MurmurHash3 hash function source* +
_Austin Appleby_ +
https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash3.cpp#L65-L90
Austin Appleby's 32 and 64 bit finalization mixing functions that
introduced the "xmxmx" general form of a high quality bijective
transformation that approximates a random permutation.
---
*SMHasher hash function test suite* +
_Austin Appleby_ +
https://github.com/aappleby/smhasher
Contains a battery of tests for evaluating hash functions. The current
64 bit implementation of `boost::hash` for strings passes SMHasher.
Previous iterations did not.
---
*Better Bit Mixing - Improving on MurmurHash3's 64-bit Finalizer* +
_David Stafford_ +
https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
Describes the so-called "variant 13" mixing function, an improvement
over `fmix64` from MurmurHash3, made famous by its adoption by the
`splitmix64` http://xorshift.di.unimi.it/splitmix64.c[random number generator].
---
*Stronger, better, morer, Moremur; a better Murmur3-type mixer* +
_Pelle Evensen_ +
https://mostlymangling.blogspot.com/2019/12/stronger-better-morer-moremur-better.html
Describes Moremur, an improvement over MurmurHash3 `fmix64` and Stafford
"variant 13".
---
*Improved mx3 and the RRC test* +
_Jon Maiga_ +
http://jonkagstrom.com/mx3/mx3_rev2.html
Contains another improvement over MurmurHash3 `fmix64` and "variant 13". This
is what the current implementation of `boost::hash_combine` uses when
`std::size_t` is 64 bits.
---
*Prospecting for Hash Functions* +
_Chris Wellons_ +
https://nullprogram.com/blog/2018/07/31/
Describes https://github.com/skeeto/hash-prospector[Hash Prospector],
a utility for discovering and evaluating mixing functions.
---
*New best known functions* +
_"TheIronBorn"_ +
https://github.com/skeeto/hash-prospector/issues/19
Describes a good 32 bit mixing function, used by the current implementation
of `boost::hash_combine` when `std::size_t` is 32 bits.

228
doc/hash/notes.adoc Normal file
View File

@@ -0,0 +1,228 @@
////
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
////
[#notes]
= 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
types is via a specialization. `boost::hash` chooses a different mechanism --
an overload of a free function `hash_value` in the user namespace that is
found via argument-dependent lookup.
Both approaches have their pros and cons. Specializing the function object
is stricter in that it only applies to the exact type, and not to derived
or convertible types. Defining a function, on the other hand, is easier
and more convenient, as it can be done directly in the type definition as
an `inline` `friend`.
The fact that overloads can be invoked via conversions did cause issues in
an earlier iteration of the library that defined `hash_value` for all
integral types separately, including `bool`. Especially under {cpp}03,
which doesn't have `explicit` conversion operators, some types were
convertible to `bool` to allow their being tested in e.g. `if` statements,
which caused them to hash to 0 or 1, rarely what one expects or wants.
This, however, was fixed by declaring the built-in `hash_value` overloads
to be templates constrained on e.g. `std::is_integral` or its moral
equivalent. This causes types convertible to an integral to no longer
match, avoiding the problem.
== Hash Value Stability
In general, the library does not promise that the hash values will stay
the same from release to release (otherwise improvements would be
impossible). However, historically values have been quite stable. Before
release 1.81, the previous changes have been in 1.56 (a better
`hash_combine`) and 1.78 (macOS-specific change to `hash_combine`.)
Code should generally not depend on specific hash values, but for those
willing to take the risk of occasional breaks due to hash value changes,
the library now has a test that checks hash values for a number of types
against reference values (`test/hash_reference_values.cpp`),
whose https://github.com/boostorg/container_hash/commits/develop/test/hash_reference_values.cpp[version history]
can be used as a rough guide to when hash values have changed, and for what
types.
== hash_combine
The initial implementation of the library was based on Issue 6.18 of the
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf[Library Extension Technical Report Issues List]
(pages 63-67) which proposed the following implementation of `hash_combine`:
[source]
----
template<class T>
void hash_combine(size_t & seed, T const & v)
{
seed ^= hash_value(v) + (seed << 6) + (seed >> 2);
}
----
taken from the paper
"https://people.eng.unimelb.edu.au/jzobel/fulltext/jasist03thz.pdf[Methods for Identifying Versioned and Plagiarised Documents]"
by Timothy C. Hoad and Justin Zobel.
During the Boost formal review, Dave Harris pointed out that this suffers
from the so-called "zero trap"; if `seed` is initially 0, and all the
inputs are 0 (or hash to 0), `seed` remains 0 no matter how many input
values are combined.
This is an undesirable property, because it causes containers of zeroes
to have a zero hash value regardless of their sizes.
To fix this, the arbitrary constant `0x9e3779b9` (the golden ratio in a
32 bit fixed point representation) was added to the computation, yielding
[source]
----
template<class T>
void hash_combine(size_t & seed, T const & v)
{
seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
----
This is what shipped in Boost 1.33, the first release containing the library.
This function was a reasonable compromise between quality and speed for its
time, when the input consisted of ``char``s, but it's less suitable for
combining arbitrary `size_t` inputs.
In Boost 1.56, it was replaced by functions derived from Austin Appleby's
https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash2.cpp#L57-L62[MurmurHash2 hash function round].
In Boost 1.81, it was changed again -- to the equivalent of
`mix(seed + 0x9e3779b9 + hash_value(v))`, where `mix(x)` is a high quality
mixing function that is a bijection over the `size_t` values, of the form
[source]
----
x ^= x >> k1;
x *= m1;
x ^= x >> k2;
x *= m2;
x ^= x >> k3;
----
This type of mixing function was originally devised by Austin Appleby as
the "final mix" part of his MurmurHash3 hash function. He used
[source]
----
x ^= x >> 33;
x *= 0xff51afd7ed558ccd;
x ^= x >> 33;
x *= 0xc4ceb9fe1a85ec53;
x ^= x >> 33;
----
as the https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash2.cpp#L57-L62[64 bit function `fmix64`] and
[source]
----
x ^= x >> 16;
x *= 0x85ebca6b;
x ^= x >> 13;
x *= 0xc2b2ae35;
x ^= x >> 16;
----
as the https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash3.cpp#L68-L77[32 bit function `fmix32`].
Several improvements of the 64 bit function have been subsequently proposed,
by https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html[David Stafford],
https://mostlymangling.blogspot.com/2019/12/stronger-better-morer-moremur-better.html[Pelle Evensen],
and http://jonkagstrom.com/mx3/mx3_rev2.html[Jon Maiga]. We currently use Jon
Maiga's function
[source]
----
x ^= x >> 32;
x *= 0xe9846af9b1a615d;
x ^= x >> 32;
x *= 0xe9846af9b1a615d;
x ^= x >> 28;
----
Under 32 bit, we use a mixing function proposed by "TheIronBorn" in a
https://github.com/skeeto/hash-prospector/issues/19[Github issue] in
the https://github.com/skeeto/hash-prospector[repository] of
https://nullprogram.com/blog/2018/07/31/[Hash Prospector] by Chris Wellons:
[source]
----
x ^= x >> 16;
x *= 0x21f0aaad;
x ^= x >> 15;
x *= 0x735a2d97;
x ^= x >> 15;
----
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`).
== hash_range
The traditional implementation of `hash_range(seed, first, last)` has been
[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 Boost 1.82, `hash_range` for these types was changed to use
https://github.com/pdimov/mulxp_hash[`mulxp1_hash`]. This improves both
quality and speed of string hashing.
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>`.

View File

@@ -1,82 +0,0 @@
[#portability]
= Portability
:idprefix: portability_
`boost::hash` is written to be as portable as possible, but unfortunately, several older compilers don't support argument dependent lookup (ADL) - the mechanism used for customisation. On those compilers custom overloads for `hash_value` needs to be declared in the `boost` namespace.
On a strictly standards compliant compiler, an overload defined in the `boost` namespace won't be found when `boost::hash` is instantiated, so for these compilers the overload should only be declared in the same namespace as the class.
Let's say we have a simple custom type:
[source]
----
namespace foo
{
template <class T>
class custom_type
{
T value;
public:
custom_type(T x) : value(x) {}
friend std::size_t hash_value(custom_type x)
{
boost::hash<int> hasher;
return hasher(x.value);
}
};
}
----
On a compliant compiler, when `hash_value` is called for this type, it will look at the namespace inside the type and find `hash_value` but on a compiler which doesn't support ADL `hash_value` won't be found. To make things worse, some compilers which do support ADL won't find a friend class defined inside the class.
So first move the member function out of the class:
[source]
----
namespace foo
{
template <class T>
class custom_type
{
T value;
public:
custom_type(T x) : value(x) {}
std::size_t hash(custom_type x)
{
boost::hash<T> hasher;
return hasher(value);
}
};
template <class T>
inline std::size_t hash_value(custom_type<T> x)
{
return x.hash();
}
}
----
Unfortunately, I couldn't declare `hash_value` as a friend, as some compilers don't support template friends, so instead I declared a member function to calculate the hash, and called it from `hash_value`.
For compilers which don't support ADL, `hash_value` needs to be defined in the `boost` namespace:
[source]
----
#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
namespace boost
#else
namespace foo
#endif
{
template <class T>
std::size_t hash_value(foo::custom_type<T> x)
{
return x.hash();
}
}
----
Full code for this example is at link:../../examples/portable.cpp[/libs/container_hash/examples/portable.cpp].

View File

@@ -1,16 +0,0 @@
[#rationale]
= Rationale
:idprefix: rationale_
The rationale can be found in the original designfootnote:[issue 6.18 of the http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf[Library Extension Technical Report Issues List] (page 63)].
== 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 preform 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.
For other use cases, if you do need a higher quality hash function, then neither the standard hash function or `boost::hash` are appropriate. There are several options available. One is to use a second hash on the output of this hash function, such as http://web.archive.org/web/20121102023700/http://www.concentric.net/~Ttwang/tech/inthash.htm[Thomas Wang's hash function]. This this may not work as well as a hash algorithm tailored for the input.
For strings there are several fast, high quality hash functions available (for example http://code.google.com/p/smhasher/[MurmurHash3] and http://code.google.com/p/cityhash/[Google's CityHash]), although they tend to be more machine specific. These may also be appropriate for hashing a binary representation of your data - providing that all equal values have an equal representation, which is not always the case (e.g. for floating point values).

56
doc/hash/recent.adoc Normal file
View 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
////
[#recent]
= Recent Changes
:idprefix: recent_
== Boost 1.84.0
* {cpp}03 is no longer supported.
== Boost 1.82.0
* Added an overload of `hash_value` for `std::nullptr_t`.
* Added `is_tuple_like` and an overload of `hash_value` for
tuple-like types.
* Changed string hashing to use
https://github.com/pdimov/mulxp_hash[`mulxp1_hash`],
improving both quality and speed. This changes the hash values
for string-like types (ranges of `char`, `signed char`,
`unsigned char`, `std::byte`, `char8_t`).
== Boost 1.81.0
Major update.
* The specializations of `boost::hash` have been removed; it now
always calls `hash_value`.
* Support for `BOOST_HASH_NO_EXTENSIONS` has been removed. The
extensions are always enabled.
* All standard containers are now supported. This includes
`std::forward_list` and the unordered associative containers.
* 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. This changes the hash values
of composite (container and tuple) types and of scalar types
bigger than `size_t`.
* The performance (and quality, as a result of the above change)
of string hashing has been improved. `boost::hash` for strings
now passes SMHasher in 64 bit mode.
* The documentation has been substantially revised to reflect
the changes.
== Boost 1.78.0
* Fixed `hash_combine` so that its behavior no longer depends
on whether `size_t` is the exact same type as `boost::uint64_t`
(which wasn't the case on macOS). This changes the hash values
of composite (container and tuple) types on macOS.

View File

@@ -1,386 +0,0 @@
[#ref]
= Reference
:idprefix: ref_
For the full specification, see section 6.3 of the http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf[C++ Standard Library Technical Report] and issue 6.18 of the http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf[Library Extension Technical Report Issues List] (page 63).
== Header <boost/container_hash/hash.hpp>
Defines `boost::hash`, and helper functions.
[source]
----
namespace boost {
template<typename T> struct hash;
template<> struct hash<bool>;
template<> struct hash<char>;
template<> struct hash<signed char>;
template<> struct hash<unsigned char>;
template<> struct hash<wchar_t>;
template<> struct hash<char16_t>;
template<> struct hash<char32_t>;
template<> struct hash<short>;
template<> struct hash<unsigned short>;
template<> struct hash<int>;
template<> struct hash<unsigned int>;
template<> struct hash<long>;
template<> struct hash<unsigned long>;
template<> struct hash<long long>;
template<> struct hash<unsigned long long>;
template<> struct hash<float>;
template<> struct hash<double>;
template<> struct hash<long double>;
template<> struct hash<std::string>;
template<> struct hash<std::wstring>;
template<> struct hash<std::u16string>;
template<> struct hash<std::u32string>;
template<> struct hash<std::type_index>;
template<typename T> struct hash<T*>;
// Support functions (Boost extension).
template<typename T>
void hash_combine(size_t &, T const&);
template<typename It>
std::size_t hash_range(It, It);
template<typename It>
void hash_range(std::size_t&, It, It);
// Overloadable hash implementation (Boost extension).
std::size_t hash_value(bool);
std::size_t hash_value(char);
std::size_t hash_value(signed char);
std::size_t hash_value(unsigned char);
std::size_t hash_value(wchar_t);
std::size_t hash_value(char16_t);
std::size_t hash_value(char32_t);
std::size_t hash_value(short);
std::size_t hash_value(unsigned short);
std::size_t hash_value(int);
std::size_t hash_value(unsigned int);
std::size_t hash_value(long);
std::size_t hash_value(unsigned long);
std::size_t hash_value(long long);
std::size_t hash_value(unsigned long long);
std::size_t hash_value(float);
std::size_t hash_value(double);
std::size_t hash_value(long double);
template<typename T>
std::size_t hash_value(T* const&);
template<typename T, unsigned N>
std::size_t hash_value(T (&val)[N]);
template<typename T, unsigned N>
std::size_t hash_value(const T (&val)[N]);
template<typename Ch, typename A>
std::size_t hash_value(std::basic_string<Ch, std::char_traits<Ch>, A> const&);
template<typename A, typename B>
std::size_t hash_value(std::pair<A, B> const&);
template<typename T, typename A>
std::size_t hash_value(std::vector<T, A> const&);
template<typename T, typename A>
std::size_t hash_value(std::list<T, A> const&);
template<typename T, typename A>
std::size_t hash_value(std::deque<T, A> const&);
template<typename K, typename C, typename A>
std::size_t hash_value(std::set<K, C, A> const&);
template<typename K, typename C, typename A>
std::size_t hash_value(std::multiset<K, C, A> const&);
template<typename K, typename T, typename C, typename A>
std::size_t hash_value(std::map<K, T, C, A> const&);
template<typename K, typename T, typename C, typename A>
std::size_t hash_value(std::multimap<K, T, C, A> const&);
template<typename T> std::size_t hash_value(std::complex<T> const&);
std::size_t hash_value(std::type_index);
template<typename T, std::size_t N>
std::size_t hash_value(std::array<T, N> const&);
template<typename... T>
std::size_t hash_value(std::tuple<T...>);
}
----
== Struct template hash
=== hash
`boost::hash` — A http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf[TR1] compliant hash function object.
==== Synopsis
[source]
----
// #include <boost/container_hash/hash.hpp>
template<typename T>
struct hash : public std::unary_function<T, std::size_t> {
std::size_t operator()(T const&) const;
};
----
==== Description
[source]
----
std::size_t operator()(T const& val) const;
----
[horizontal]
Returns:: `hash_value(val)`
Notes:: The call to `hash_value` is unqualified, so that custom overloads can be found via argument dependent lookup.
+
This is not defined when the macro `BOOST_HASH_NO_EXTENSIONS` is defined. The specializations are still defined, so only the specializations required by TR1 are defined.
+
Forward declared in `<boost/container_hash/hash_fwd.hpp>`
+
This hash function is not intended for general use, and isn't guaranteed to be equal during separate runs of a program - so please don't use it for any persistent storage or communication.
Throws:: Only throws if `hash_value(T)` throws.
== Specializations
`boost::hash<T>`
=== Synopsis
[source]
----
// #include <boost/container_hash/hash.hpp>
struct hash<T> {
std::size_t operator()(T const&) const;
};
----
=== Description
[source]
----
std::size_t operator()(T const val) const;
----
[horizontal]
Returns:: Unspecified in TR1, except that equal arguments yield the same result.
+
`hash_value(val)` in Boost.
[horizontal]
Throws:: Doesn't throw
== Support functions (Boost extension).
=== hash_combine
[source]
----
template<typename T>
void hash_combine(size_t &, T const&);
----
Called repeatedly to incrementally create a hash value from several variables.
[horizontal]
Effects:: Updates seed with a new hash value generated by combining it with the result of `hash_value(v)`. Will always produce the same result for the same combination of seed and `hash_value(v)` during the single run of a program.
[horizontal]
Notes:: `hash_value` is called without qualification, so that overloads can be found via ADL. +
+
This is an extension to TR1 +
+
Forward declared in `<boost/container_hash/hash_fwd.hpp>` +
+
This hash function is not intended for general use, and isn't guaranteed to be equal during separate runs of a program - so please don't use it for any persistent storage or communication.
[horizontal]
Throws:: Only throws if `hash_value(T)` throws. Strong exception safety, as long as `hash_value(T)` also has strong exception safety.
=== hash_range
[source]
----
template<typename It>
std::size_t hash_range(It, It);
template<typename It>
void hash_range(std::size_t&, It, It);
----
Calculate the combined hash value of the elements of an iterator range.
[horizontal]
Effects:: For the two argument overload:
+
[source]
----
size_t seed = 0;
for(; first != last; ++first)
{
hash_combine(seed, *first);
}
return seed;
----
+
For the three arguments overload:
+
[source]
----
for(; first != last; ++first)
{
hash_combine(seed, *first);
}
----
[horizontal]
Notes:: `hash_range` is sensitive to the order of the elements so it wouldn't be appropriate to use this with an unordered container.
+
This is an extension to TR1
+
Forward declared in `<boost/container_hash/hash_fwd.hpp>`
+
This hash function is not intended for general use, and isn't guaranteed to be equal during separate runs of a program - so please don't use it for any persistent storage or communication.
[horizontal]
Throws:: Only throws if `hash_value(std::iterator_traits<It>::value_type)` throws. `hash_range(std::size_t&, It, It)` has basic exception safety as long as `hash_value(std::iterator_traits<It>::value_type)` has basic exception safety.
== Overloadable hash implementation (Boost extension).
=== hash_value
[source]
----
std::size_t hash_value(bool val);
std::size_t hash_value(char val);
std::size_t hash_value(signed char val);
std::size_t hash_value(unsigned char val);
std::size_t hash_value(wchar_t val);
std::size_t hash_value(char16_t val);
std::size_t hash_value(char32_t val);
std::size_t hash_value(short val);
std::size_t hash_value(unsigned short val);
std::size_t hash_value(int val);
std::size_t hash_value(unsigned int val);
std::size_t hash_value(long val);
std::size_t hash_value(unsigned long val);
std::size_t hash_value(long long val);
std::size_t hash_value(unsigned long long val);
std::size_t hash_value(float val);
std::size_t hash_value(double val);
std::size_t hash_value(long double val);
template<typename T> std::size_t hash_value(T* const& val);
template<typename T, unsigned N> std::size_t hash_value(T (&val)[N]);
template<typename T, unsigned N> std::size_t hash_value(const T (&val)[N]);
template<typename Ch, typename A>
std::size_t hash_value(std::basic_string<Ch, std::char_traits<Ch>, A> const& val);
template<typename A, typename B>
std::size_t hash_value(std::pair<A, B> const& val);
template<typename T, typename A>
std::size_t hash_value(std::vector<T, A> const& val);
template<typename T, typename A>
std::size_t hash_value(std::list<T, A> const& val);
template<typename T, typename A>
std::size_t hash_value(std::deque<T, A> const& val);
template<typename K, typename C, typename A>
std::size_t hash_value(std::set<K, C, A> const& val);
template<typename K, typename C, typename A>
std::size_t hash_value(std::multiset<K, C, A> const& val);
template<typename K, typename T, typename C, typename A>
std::size_t hash_value(std::map<K, T, C, A> const& val);
template<typename K, typename T, typename C, typename A>
std::size_t hash_value(std::multimap<K, T, C, A> const& val);
template<typename T> std::size_t hash_value(std::complex<T> const& val);
std::size_t hash_value(std::type_index val);
template<typename T, std::size_t N>
std::size_t hash_value(std::array<T, N> const& val);
template<typename... T>
std::size_t hash_value(std::tuple<T...> val);
----
Implementation of the hash function.
Generally shouldn't be called directly by users, instead they should use `boost::hash`, `boost::hash_range` or `boost::hash_combine` which call `hash_value` without namespace qualification so that overloads for custom types are found via ADL.
[horizontal]
Notes:: This is an extension to TR1
+
This hash function is not intended for general use, and isn't guaranteed to be equal during separate runs of a program - so please don't use it for any persistent storage or communication.
[horizontal]
Throws:: Only throws if a user supplied version of `hash_value` throws for an element of a container, or one of the types stored in a pair.
[vertical]
Returns::
+
[cols="1,1", frame=all, grid=rows]
|===
|Types |Returns
|`bool`, `char`, `signed char`, `unsigned char`, `wchar_t`, `char16_t`, `char32_t`, `short`, `unsigned short`, `int`, `unsigned int`, `long`, `unsigned long`
|val
|`long long`, `unsigned long long`
|val when `abs(val) \<= std::numeric_limits<std::size_t>::max()`.
|`float`, `double`, `long double`
|An unspecified value, except that equal arguments shall yield the same result.
|`T*`
|An unspecified value, except that equal arguments shall yield the same result.
|`T val[N]`, `const T val[N]`
|`hash_range(val, val+N)`
|`std:basic_string<Ch, std::char_traits<Ch>, A>`, `std::vector<T, A>`, `std::list<T, A>`, `std::deque<T, A>`, `std::set<K, C, A>`, `std::multiset<K, C, A>`, `std::map<K, T, C, A>`, `std::multimap<K, T, C, A>`, `std::array<T, N>`
|`hash_range(val.begin(), val.end())`
|`std::pair<A, B>`
a|
[source]
----
size_t seed = 0;
hash_combine(seed, val.first);
hash_combine(seed, val.second);
return seed;
----
|`std::tuple<T...>`
a|
[source]
----
size_t seed = 0;
hash_combine(seed, get<0>(val));
hash_combine(seed, get<1>(val));
// ....
return seed;
----
|`std::complex<T>`
|When T is a built in type and `val.imag() == 0`, the result is equal to `hash_value(val.real())`. Otherwise an unspecified value, except that equal arguments shall yield the same result.
|`std::type_index`
|`val.hash_code()`
|===

754
doc/hash/reference.adoc Normal file
View File

@@ -0,0 +1,754 @@
////
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
////
[#reference]
= Reference
:idprefix: ref_
== <boost/container_hash/{zwsp}hash_fwd.hpp>
This header contains forward declarations for the library primitives.
These declarations are guaranteed to be relatively stable, that is,
best effort will be expended on their not changing from release to
release, allowing their verbatim copy into user headers that do not
wish to physically depend on Boost.ContainerHash.
[source]
----
namespace boost
{
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;
template<class T> struct is_tuple_like;
} // namespace container_hash
template<class T> struct hash;
template<class T> void hash_combine( std::size_t& seed, T const& v );
template<class It> void hash_range( std::size_t& seed, It first, It last );
template<class It> std::size_t hash_range( It first, It last );
template<class It> void hash_unordered_range( std::size_t& seed, It first, It last );
template<class It> std::size_t hash_unordered_range( It first, It last );
} // namespace boost
----
== <boost/container_hash/{zwsp}hash.hpp>
Defines `boost::hash`, and helper functions.
[source]
----
namespace boost
{
template<class T> struct hash;
template<class T> void hash_combine( std::size_t& seed, T const& v );
template<class It> void hash_range( std::size_t& seed, It first, It last );
template<class It> std::size_t hash_range( It first, It last );
template<class It> void hash_unordered_range( std::size_t& seed, It first, It last );
template<class It> std::size_t hash_unordered_range( It first, It last );
// Enabled only when T is an integral type
template<class T>
std::size_t hash_value( T v );
// Enabled only when T is an enumeration type
template<class T>
std::size_t hash_value( T v );
// Enabled only when T is a floating point type
template<class T>
std::size_t hash_value( T v );
template<class T>
std::size_t hash_value( T* const& v );
template<class T, std::size_t N>
std::size_t hash_value( T const (&v)[N] );
template<class T>
std::size_t hash_value( std::complex<T> const& v );
template<class A, class B>
std::size_t hash_value( std::pair<A, B> const& v );
// Enabled only when container_hash::is_tuple_like<T>::value is true
template<class T>
std::size_t hash_value( T const& v );
// Enabled only when container_hash::is_range<T>::value is true
template<class T>
std::size_t hash_value( T const& v );
// Enabled only when container_hash::is_contiguous_range<T>::value is true
template<class T>
std::size_t hash_value( T const& v );
// Enabled only when container_hash::is_unordered_range<T>::value is true
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 );
template<class T, class D>
std::size_t hash_value( std::unique_ptr<T, D> const& v );
std::size_t hash_value( std::type_index const& v );
std::size_t hash_value( std::error_code const& v );
std::size_t hash_value( std::error_condition const& v );
template<class T>
std::size_t hash_value( std::optional<T> const& v );
std::size_t hash_value( std::monostate v );
template<class... T>
std::size_t hash_value( std::variant<T...> const& v );
} // namespace boost
----
=== hash<T>
[source]
----
template<class T> struct hash
{
std::size_t operator()( T const& v ) const;
};
----
==== operator()
[source]
----
std::size_t operator()( T const& v ) const;
----
Returns: :: `hash_value(v)`.
Throws: :: Only throws if `hash_value(v)` throws.
Remarks: :: The call to `hash_value` is unqualified, so that user-supplied
overloads will be found via argument dependent lookup.
=== hash_combine
[source]
----
template<class T> void hash_combine( std::size_t& seed, T const& v );
----
Called repeatedly to incrementally create a hash value from several variables.
Effects: :: Updates `seed` with a new hash value generated by
deterministically combining it with the result of `boost::hash<T>()(v)`.
Throws: :: Only throws if `boost::hash<T>()(v)` throws. On exception,
`seed` is not updated.
Remarks: ::
+
--
Equivalent to `seed = combine(seed, boost::hash<T>()(v))`,
where `combine(s, v)` is a mixing function that takes two arguments of
type `std::size_t` and returns `std::size_t`, with the following desirable
properties:
. For a constant `s`, when `v` takes all possible `size_t` values,
`combine(s, v)` should also take all possible `size_t` values, producing
a sequence that is close to random; that is, it should be a random
permutation.
+
This guarantees that for a given `seed`, `combine` does not introduce
hash collisions when none were produced by `boost::hash<T>(v)`; that is,
it does not lose information from the input. It also implies that
`combine(s, v)`, as a function of `v`, has good avalanche properties;
that is, small (e.g. single bit) perturbations in the input `v` lead to
large perturbations in the return value (half of the output bits changing,
on average).
. For two different seeds `s1` and `s2`, `combine(s1, v)` and
`combine(s2, v)`, treated as functions of `v`, should produce two
different random permutations.
. `combine(0, 0)` should not be 0. Since a common initial value of `seed`
is zero, `combine(0, 0) == 0` would imply that applying `hash_combine` on
any sequence of zeroes, regardless of length, will produce zero. This is
undesirable, as it would lead to e.g. `std::vector<int>()` and
`std::vector<int>(4)` to have the same hash value.
The current implementation uses the function `mix(s + 0x9e3779b9 + v)` as
`combine(s, v)`, where `mix(x)` is a high quality mixing function that is a
bijection over the `std::size_t` values, of the form
[source]
----
x ^= x >> k1;
x *= m1;
x ^= x >> k2;
x *= m2;
x ^= x >> k3;
----
where the constants `k1`, `k2`, `k3`, `m1`, `m2` are suitably chosen.
Note that `mix(0)` is 0. This is why we add the arbitrary constant
`0x9e3779b9` to meet the third requirement above.
--
=== hash_range
[source]
----
template<class It> void hash_range( std::size_t& seed, It first, It last );
----
Effects: ::
+
--
When `typename std::iterator_traits<It>::value_type` is not `char`, `signed char`,
`unsigned char`, `std::byte`, or `char8_t`,
[source]
----
for( ; first != last; ++first )
{
boost::hash_combine<typename std::iterator_traits<It>::value_type>( seed, *first );
}
----
Otherwise, bytes from `[first, last)` are coalesced and hashed in an
unspecified manner. This is done in order to improve performance when hashing
strings.
--
Remarks: ::
For chars, the current implementation uses
https://github.com/pdimov/mulxp_hash[`mulxp1_hash`] when `std::size_t` is
64 bit, and `mulxp1_hash32` when it's 32 bit.
[source]
----
template<class It> std::size_t hash_range( It first, It last );
----
Effects: ::
+
[source]
----
size_t seed = 0;
boost::hash_range( seed, first, last );
return seed;
----
=== hash_unordered_range
[source]
----
template<class It> void hash_unordered_range( std::size_t& seed, It first, It last );
----
Effects: :: Updates `seed` with the values of
`boost::hash<typename std::iterator_traits<It>::value_type>()(*i)`
for each `i` in `[first, last)`, such that the order of elements does
not affect the final result.
[source]
----
template<class It> std::size_t hash_unordered_range( It first, It last );
----
Effects: ::
+
[source]
----
size_t seed = 0;
boost::hash_unordered_range( seed, first, last );
return seed;
----
=== hash_value
[source]
----
// Enabled only when T is an integral type
template<class T>
std::size_t hash_value( T v );
----
Returns: ::
When the value of `v` fits into `std::size_t`, when `T` is an unsigned type,
or into `ssize_t`, when `T` is a signed type, `static_cast<std::size_t>(v)`.
+
Otherwise, an unspecified value obtained by mixing the value bits of `v`.
[source]
----
// Enabled only when T is an enumeration type
template<class T>
std::size_t hash_value( T v );
----
Returns: ::
`static_cast<std::size_t>(v)`.
Remarks: ::
`hash_value(std::to_underlying(v))` would be better, but {cpp}03
compatibility mandates the current implementation.
[source]
----
// Enabled only when T is a floating point type
template<class T>
std::size_t hash_value( T v );
----
Returns: ::
An unspecified value obtained by mixing the value bits of `v`.
Remarks: ::
When `sizeof(v) \<= sizeof(std::size_t)`, the bits of `v` are returned
as-is (except in the case of -0.0, which is treated as +0.0).
[source]
----
template<class T>
std::size_t hash_value( T* const& v );
----
Returns: ::
An unspecified value derived from `reinterpret_cast<std::uintptr_t>(v)`.
[source]
----
template<class T, std::size_t N>
std::size_t hash_value( T const (&v)[N] );
----
Returns: ::
`boost::hash_range( v, v + N )`.
[source]
----
template<class T>
std::size_t hash_value( std::complex<T> const& v );
----
Returns: ::
An unspecified value derived from `boost::hash<T>()(v.real())` and
`boost::hash<T>()(v.imag())` such that, if `v.imag() == 0`, the value
is equal to `boost::hash<T>()(v.real())`.
Remarks: ::
A more straightforward implementation would just have used `hash_combine`
on `v.real()` and `v.imag()`, but the historical guarantee that real-valued
complex numbers should match the hash value of their real part precludes it.
+
This guarantee may be dropped in a future release, as it's of questionable
utility.
[source]
----
template<class A, class B>
std::size_t hash_value( std::pair<A, B> const& v );
----
Effects: ::
+
[source]
----
std::size_t seed = 0;
boost::hash_combine( seed, v.first );
boost::hash_combine( seed, v.second );
return seed;
----
[source]
----
// Enabled only when container_hash::is_tuple_like<T>::value is true
template<class T>
std::size_t hash_value( T const& v );
----
Effects: ::
+
[source]
----
std::size_t seed = 0;
using std::get;
boost::hash_combine( seed, get<0>(v) );
boost::hash_combine( seed, get<1>(v) );
// ...
boost::hash_combine( seed, get<N-1>(v) );
return seed;
----
+
where `N` is `std::tuple_size<T>::value`.
Remarks: ::
This overload is only enabled when
`container_hash::is_range<T>::value` is `false`.
[source]
----
// Enabled only when container_hash::is_range<T>::value is true
template<class T>
std::size_t hash_value( T const& v );
----
Returns: ::
`boost::hash_range( v.begin(), v.end() )`.
Remarks: ::
This overload is only enabled when
`container_hash::is_contiguous_range<T>::value` and
`container_hash::is_unordered_range<T>::value` are both `false`.
+
It handles all standard containers that aren't contiguous or unordered, such
as `std::deque`, `std::list`, `std::set`, `std::map`.
[source]
----
// Enabled only when container_hash::is_contiguous_range<T>::value is true
template<class T>
std::size_t hash_value( T const& v );
----
Returns: ::
`boost::hash_range( v.data(), v.data() + v.size() )`.
Remarks: ::
This overload handles all standard contiguous containers, such as
`std::string`, `std::vector`, `std::array`, `std::string_view`.
[source]
----
// Enabled only when container_hash::is_unordered_range<T>::value is true
template<class T>
std::size_t hash_value( T const& v );
----
Returns: ::
`boost::hash_unordered_range( v.begin(), v.end() )`.
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>
std::size_t hash_value( std::shared_ptr<T> const& v );
template<class T, class D>
std::size_t hash_value( std::unique_ptr<T, D> const& v );
----
Returns: ::
`boost::hash<T*>( v.get() )`.
[source]
----
std::size_t hash_value( std::type_index const& v );
----
Returns: ::
`v.hash_code()`.
[source]
----
std::size_t hash_value( std::error_code const& v );
std::size_t hash_value( std::error_condition const& v );
----
Effects: ::
+
[source]
----
std::size_t seed = 0;
boost::hash_combine( seed, v.value() );
boost::hash_combine( seed, &v.category() );
return seed;
----
[source]
----
template<class T>
std::size_t hash_value( std::optional<T> const& v );
----
Returns: ::
For a disengaged `v`, an unspecified constant value; otherwise,
`boost::hash<T>()( *v )`.
[source]
----
std::size_t hash_value( std::monostate v );
----
Returns: ::
An unspecified constant value.
[source]
----
template<class... T>
std::size_t hash_value( std::variant<T...> const& v );
----
Effects: ::
+
[source]
----
std::size_t seed = 0;
boost::hash_combine( seed, v.index() );
boost::hash_combine( seed, x );
return seed;
----
+
where `x` is the currently contained value in `v`.
Throws: ::
`std::bad_variant_access` when `v.valueless_by_exception()` is `true`.
== <boost/container_hash/{zwsp}is_range.hpp>
Defines the trait `boost::container_hash::is_range`.
[source]
----
namespace boost
{
namespace container_hash
{
template<class T> struct is_range;
} // namespace container_hash
} // namespace boost
----
=== is_range<T>
[source]
----
template<class T> struct is_range
{
static constexpr bool value = /* see below */;
};
----
`is_range<T>::value` is `true` when, for a const value `x` of type
`T`, `x.begin()` and `x.end()` return iterators of the same type
`It` (such that `std::iterator_traits<It>` is a valid specialization.)
Users are allowed to specialize `is_range` for their types if the
default behavior does not deduce the correct value.
== <boost/container_hash/{zwsp}is_contiguous_range.hpp>
Defines the trait `boost::container_hash::is_contiguous_range`.
[source]
----
namespace boost
{
namespace container_hash
{
template<class T> struct is_contiguous_range;
} // namespace container_hash
} // namespace boost
----
=== is_contiguous_range<T>
[source]
----
template<class T> struct is_contiguous_range
{
static constexpr bool value = /* see below */;
};
----
`is_contiguous_range<T>::value` is `true` when `is_range<T>::value` is
`true` and when, for a const value `x` of type `T`, `x.data()` returns
a pointer to a type that matches the `value_type` of the iterator returned
by `x.begin()` and `x.end()`, and `x.size()` returns a value of an integral
type.
Users are allowed to specialize `is_contiguous_range` for their types
if the default behavior does not deduce the correct value.
== <boost/container_hash/{zwsp}is_unordered_range.hpp>
Defines the trait `boost::container_hash::is_unordered_range`.
[source]
----
namespace boost
{
namespace container_hash
{
template<class T> struct is_unordered_range;
} // namespace container_hash
} // namespace boost
----
=== is_unordered_range<T>
[source]
----
template<class T> struct is_unordered_range
{
static constexpr bool value = /* see below */;
};
----
`is_unordered_range<T>::value` is `true` when `is_range<T>::value` is
`true` and when `T::hasher` is a valid type.
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.
== <boost/container_hash/{zwsp}is_tuple_like.hpp>
Defines the trait `boost::container_hash::is_tuple_like`.
[source]
----
namespace boost
{
namespace container_hash
{
template<class T> struct is_tuple_like;
} // namespace container_hash
} // namespace boost
----
=== is_tuple_like<T>
[source]
----
template<class T> struct is_tuple_like
{
static constexpr bool value = /* see below */;
};
----
`is_tuple_like<T>::value` is `true` when `std::tuple_size<T>::value`
is valid.
Users are allowed to specialize `is_tuple_like` for their types
if the default behavior does not deduce the correct value.

View File

@@ -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.

View File

@@ -1,11 +1,23 @@
////
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
////
[#tutorial]
= Tutorial
:idprefix: tutorial_
When using a hash index with link:../../../multi_index/index.html[Boost.MultiIndex], you don't need to do anything to use `boost::hash` as it uses it by default. To find out how to use a user-defined type, read the <<custom,section on extending boost::hash for a custom data type>>.
When using a Boost container such as
link:../../../unordered/index.html[Boost.Unordered], you don't need to do
anything to use `boost::hash` as it's the default. To find out how to use
a user-defined type, read the <<user,section on extending boost::hash
for user types>>.
If your standard library supplies its own implementation of the unordered associative containers and you wish to use `boost::hash`, just use an extra template parameter:
If you wish to use `boost::hash` with the standard unordered associative
containers, pass it as a template parameter:
[source]
----
@@ -27,12 +39,24 @@ To use `boost::hash` directly, create an instance and call it as a function:
int main()
{
boost::hash<std::string> string_hash;
std::size_t h = string_hash("Hash me");
}
----
For an example of generic use, here is a function to generate a vector containing the hashes of the elements of a container:
or alternatively:
[source]
----
#include <boost/container_hash/hash.hpp>
int main()
{
std::size_t h = boost::hash<std::string>()("Hash me");
}
----
For an example of generic use, here is a function to generate a vector
containing the hashes of the elements of a container:
[source]
----

View File

@@ -1,11 +1,22 @@
[#custom]
= Extending boost::hash for a custom data type
////
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
////
:idprefix: custom_
[#user]
= Extending boost::hash for User Types
:idprefix: user_
`boost::hash` is implemented by calling the function `hash_value`. The namespace isn't specified so that it can detect overloads via argument dependant lookup. So if there is a free function `hash_value` in the same namespace as a custom type, it will get called.
`boost::hash` is implemented by calling the function `hash_value`. The
namespace isn't specified so that it can detect overloads via argument
dependant lookup. So if there is a free function `hash_value` in the same
namespace as a user type, it will get called.
If you have a structure `library::book`, where each book is uniquely defined by its member `id`:
If you have a structure `library::book`, where each book is uniquely defined
by its member `id`:
[source]
----
@@ -63,6 +74,13 @@ assert(books.find(knife) != books.end());
assert(books.find(dandelion) == books.end());
----
The full example can be found in: link:../../examples/books.hpp[/libs/container_hash/examples/books.hpp] and link:../../examples/books.cpp[/libs/container_hash/examples/books.cpp].
The full example can be found in
link:../../examples/books.hpp[examples/books.hpp] and
link:../../examples/books.cpp[examples/books.cpp].
TIP: When writing a hash function, first look at how the equality function works. Objects that are equal must generate the same hash value. When objects are not equal they should generate different hash values. In this object equality was based just on the id so the hash function only hashes the id. If it was based on the object's name and author then the hash function should take them into account (how to do this is discussed in the next section).
TIP: When writing a hash function, first look at how the equality function
works. Objects that are equal must generate the same hash value. When objects
are not equal they should generate different hash values. In this object
equality was based just on `id` so the hash function only hashes `id`. If it
was based on the object's name and author then the hash function should take
them into account (how to do this is discussed in the next section).

View File

@@ -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 ;

View File

@@ -3,12 +3,20 @@
// 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)
// Force use of assert.
#if defined(NDEBUG)
#undef NDEBUG
#endif
#include "./books.hpp"
#include <boost/container_hash/hash.hpp>
#include <boost/config.hpp>
#include <cassert>
// If std::unordered_set was available:
//#include <unordered_set>
// If std::unordered_set is available:
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET)
#include <unordered_set>
#endif
// This example illustrates how to use boost::hash with a custom hash function.
// For full details, see the tutorial.
@@ -22,18 +30,19 @@ int main()
std::size_t knife_hash_value = book_hasher(knife);
(void)knife_hash_value; // suppress unused variable warning
// If std::unordered_set was available:
//
//std::unordered_set<library::book, boost::hash<library::book> > books;
//books.insert(knife);
//books.insert(library::book(2443, "Lindgren, Torgny", "Hash"));
//books.insert(library::book(1953, "Snyder, Bernadette M.",
// "Heavenly Hash: A Tasty Mix of a Mother's Meditations"));
// If std::unordered_set is available:
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET)
//assert(books.find(knife) != books.end());
//assert(books.find(dandelion) == books.end());
std::unordered_set<library::book, boost::hash<library::book> > books;
books.insert(knife);
books.insert(library::book(2443, "Lindgren, Torgny", "Hash"));
books.insert(library::book(1953, "Snyder, Bernadette M.",
"Heavenly Hash: A Tasty Mix of a Mother's Meditations"));
return 0;
assert(books.find(knife) != books.end());
assert(books.find(dandelion) == books.end());
#endif
}
namespace library

View File

@@ -19,7 +19,9 @@ class point
{
int x;
int y;
public:
point() : x(0), y(0) {}
point(int x, int y) : x(x), y(y) {}
@@ -31,6 +33,7 @@ public:
friend std::size_t hash_value(point const& p)
{
std::size_t seed = 0;
boost::hash_combine(seed, p.x);
boost::hash_combine(seed, p.y);

65
examples/point2.cpp Normal file
View 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

View File

@@ -3,9 +3,14 @@
// 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)
// Force use of assert.
#if defined(NDEBUG)
#undef NDEBUG
#endif
#include "template.hpp"
#include <cassert>
#include <boost/unordered_set.hpp>
#include <cassert>
int main()
{

View File

@@ -13,7 +13,9 @@ class my_pair
{
A value1;
B value2;
public:
my_pair(A const& v1, B const& v2)
: value1(v1), value2(v2)
{}
@@ -27,10 +29,10 @@ public:
friend std::size_t hash_value(my_pair const& p)
{
std::size_t seed = 0;
boost::hash_combine(seed, p.value1);
boost::hash_combine(seed, p.value2);
return seed;
}
};

View File

@@ -0,0 +1,146 @@
// Copyright 2021-2023 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_DETAIL_HASH_INTEGRAL_HPP
#define BOOST_HASH_DETAIL_HASH_INTEGRAL_HPP
#include <boost/container_hash/detail/hash_mix.hpp>
#include <type_traits>
#include <cstddef>
#include <climits>
namespace boost
{
namespace hash_detail
{
// libstdc++ doesn't provide support for __int128 in the standard traits
template<class T> struct is_integral: public std::is_integral<T>
{
};
template<class T> struct is_unsigned: public std::is_unsigned<T>
{
};
template<class T> struct make_unsigned: public std::make_unsigned<T>
{
};
#if defined(__SIZEOF_INT128__)
template<> struct is_integral<__int128_t>: public std::true_type
{
};
template<> struct is_integral<__uint128_t>: public std::true_type
{
};
template<> struct is_unsigned<__int128_t>: public std::false_type
{
};
template<> struct is_unsigned<__uint128_t>: public std::true_type
{
};
template<> struct make_unsigned<__int128_t>
{
typedef __uint128_t type;
};
template<> struct make_unsigned<__uint128_t>
{
typedef __uint128_t type;
};
#endif
template<class T,
bool bigger_than_size_t = (sizeof(T) > sizeof(std::size_t)),
bool is_unsigned = is_unsigned<T>::value,
std::size_t size_t_bits = sizeof(std::size_t) * CHAR_BIT,
std::size_t type_bits = sizeof(T) * CHAR_BIT>
struct hash_integral_impl;
template<class T, bool is_unsigned, std::size_t size_t_bits, std::size_t type_bits> struct hash_integral_impl<T, false, is_unsigned, size_t_bits, type_bits>
{
static std::size_t fn( T v )
{
return static_cast<std::size_t>( v );
}
};
template<class T, std::size_t size_t_bits, std::size_t type_bits> struct hash_integral_impl<T, true, false, size_t_bits, type_bits>
{
static std::size_t fn( T v )
{
typedef typename make_unsigned<T>::type U;
if( v >= 0 )
{
return hash_integral_impl<U>::fn( static_cast<U>( v ) );
}
else
{
return ~hash_integral_impl<U>::fn( static_cast<U>( ~static_cast<U>( v ) ) );
}
}
};
template<class T> struct hash_integral_impl<T, true, true, 32, 64>
{
static std::size_t fn( T v )
{
std::size_t seed = 0;
seed = static_cast<std::size_t>( v >> 32 ) + hash_detail::hash_mix( seed );
seed = static_cast<std::size_t>( v & 0xFFFFFFFF ) + hash_detail::hash_mix( seed );
return seed;
}
};
template<class T> struct hash_integral_impl<T, true, true, 32, 128>
{
static std::size_t fn( T v )
{
std::size_t seed = 0;
seed = static_cast<std::size_t>( v >> 96 ) + hash_detail::hash_mix( seed );
seed = static_cast<std::size_t>( v >> 64 ) + hash_detail::hash_mix( seed );
seed = static_cast<std::size_t>( v >> 32 ) + hash_detail::hash_mix( seed );
seed = static_cast<std::size_t>( v ) + hash_detail::hash_mix( seed );
return seed;
}
};
template<class T> struct hash_integral_impl<T, true, true, 64, 128>
{
static std::size_t fn( T v )
{
std::size_t seed = 0;
seed = static_cast<std::size_t>( v >> 64 ) + hash_detail::hash_mix( seed );
seed = static_cast<std::size_t>( v ) + hash_detail::hash_mix( seed );
return seed;
}
};
} // namespace hash_detail
template <typename T>
typename std::enable_if<hash_detail::is_integral<T>::value, std::size_t>::type
hash_value( T v )
{
return hash_detail::hash_integral_impl<T>::fn( v );
}
} // namespace boost
#endif // #ifndef BOOST_HASH_DETAIL_HASH_INTEGRAL_HPP

View File

@@ -0,0 +1,113 @@
// Copyright 2022 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_DETAIL_HASH_MIX_HPP
#define BOOST_HASH_DETAIL_HASH_MIX_HPP
#include <cstdint>
#include <cstddef>
#include <climits>
namespace boost
{
namespace hash_detail
{
template<std::size_t Bits> struct hash_mix_impl;
// hash_mix for 64 bit size_t
//
// The general "xmxmx" form of state of the art 64 bit mixers originates
// from Murmur3 by Austin Appleby, which uses the following function as
// its "final mix":
//
// k ^= k >> 33;
// k *= 0xff51afd7ed558ccd;
// k ^= k >> 33;
// k *= 0xc4ceb9fe1a85ec53;
// k ^= k >> 33;
//
// (https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp)
//
// It has subsequently been improved multiple times by different authors
// by changing the constants. The most well known improvement is the
// so-called "variant 13" function by David Stafford:
//
// k ^= k >> 30;
// k *= 0xbf58476d1ce4e5b9;
// k ^= k >> 27;
// k *= 0x94d049bb133111eb;
// k ^= k >> 31;
//
// (https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html)
//
// This mixing function is used in the splitmix64 RNG:
// http://xorshift.di.unimi.it/splitmix64.c
//
// We use Jon Maiga's implementation from
// http://jonkagstrom.com/mx3/mx3_rev2.html
//
// x ^= x >> 32;
// x *= 0xe9846af9b1a615d;
// x ^= x >> 32;
// x *= 0xe9846af9b1a615d;
// x ^= x >> 28;
//
// An equally good alternative is Pelle Evensen's Moremur:
//
// x ^= x >> 27;
// x *= 0x3C79AC492BA7B653;
// x ^= x >> 33;
// x *= 0x1C69B3F74AC4AE35;
// x ^= x >> 27;
//
// (https://mostlymangling.blogspot.com/2019/12/stronger-better-morer-moremur-better.html)
template<> struct hash_mix_impl<64>
{
inline static std::uint64_t fn( std::uint64_t x )
{
std::uint64_t const m = 0xe9846af9b1a615d;
x ^= x >> 32;
x *= m;
x ^= x >> 32;
x *= m;
x ^= x >> 28;
return x;
}
};
// hash_mix for 32 bit size_t
//
// We use the "best xmxmx" implementation from
// https://github.com/skeeto/hash-prospector/issues/19
template<> struct hash_mix_impl<32>
{
inline static std::uint32_t fn( std::uint32_t x )
{
std::uint32_t const m1 = 0x21f0aaad;
std::uint32_t const m2 = 0x735a2d97;
x ^= x >> 16;
x *= m1;
x ^= x >> 15;
x *= m2;
x ^= x >> 15;
return x;
}
};
inline std::size_t hash_mix( std::size_t v )
{
return hash_mix_impl<sizeof(std::size_t) * CHAR_BIT>::fn( v );
}
} // namespace hash_detail
} // namespace boost
#endif // #ifndef BOOST_HASH_DETAIL_HASH_MIX_HPP

View File

@@ -0,0 +1,408 @@
// Copyright 2022 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_DETAIL_HASH_RANGE_HPP
#define BOOST_HASH_DETAIL_HASH_RANGE_HPP
#include <boost/container_hash/hash_fwd.hpp>
#include <boost/container_hash/detail/mulx.hpp>
#include <type_traits>
#include <cstdint>
#include <iterator>
#include <limits>
#include <cstddef>
#include <climits>
#include <cstring>
namespace boost
{
namespace hash_detail
{
template<class T> struct is_char_type: public std::false_type {};
#if CHAR_BIT == 8
template<> struct is_char_type<char>: public std::true_type {};
template<> struct is_char_type<signed char>: public std::true_type {};
template<> struct is_char_type<unsigned char>: public std::true_type {};
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
template<> struct is_char_type<char8_t>: public std::true_type {};
#endif
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
template<> struct is_char_type<std::byte>: public std::true_type {};
#endif
#endif
// generic version
template<class It>
inline typename std::enable_if<
!is_char_type<typename std::iterator_traits<It>::value_type>::value,
std::size_t >::type
hash_range( std::size_t seed, It first, It last )
{
for( ; first != last; ++first )
{
hash_combine<typename std::iterator_traits<It>::value_type>( seed, *first );
}
return seed;
}
// specialized char[] version, 32 bit
template<class It> inline std::uint32_t read32le( It p )
{
// clang 5+, gcc 5+ figure out this pattern and use a single mov on x86
// gcc on s390x and power BE even knows how to use load-reverse
std::uint32_t w =
static_cast<std::uint32_t>( static_cast<unsigned char>( p[0] ) ) |
static_cast<std::uint32_t>( static_cast<unsigned char>( p[1] ) ) << 8 |
static_cast<std::uint32_t>( static_cast<unsigned char>( p[2] ) ) << 16 |
static_cast<std::uint32_t>( static_cast<unsigned char>( p[3] ) ) << 24;
return w;
}
#if defined(_MSC_VER) && !defined(__clang__)
template<class T> inline std::uint32_t read32le( T* p )
{
std::uint32_t w;
std::memcpy( &w, p, 4 );
return w;
}
#endif
inline std::uint64_t mul32( std::uint32_t x, std::uint32_t y )
{
return static_cast<std::uint64_t>( x ) * y;
}
template<class It>
inline typename std::enable_if<
is_char_type<typename std::iterator_traits<It>::value_type>::value &&
std::is_same<typename std::iterator_traits<It>::iterator_category, std::random_access_iterator_tag>::value &&
std::numeric_limits<std::size_t>::digits <= 32,
std::size_t>::type
hash_range( std::size_t seed, It first, It last )
{
It p = first;
std::size_t n = static_cast<std::size_t>( last - first );
std::uint32_t const q = 0x9e3779b9U;
std::uint32_t const k = 0xe35e67b1U; // q * q
std::uint64_t h = mul32( static_cast<std::uint32_t>( seed ) + q, k );
std::uint32_t w = static_cast<std::uint32_t>( h & 0xFFFFFFFF );
h ^= n;
while( n >= 4 )
{
std::uint32_t v1 = read32le( p );
w += q;
h ^= mul32( v1 + w, k );
p += 4;
n -= 4;
}
{
std::uint32_t v1 = 0;
if( n >= 1 )
{
std::size_t const x1 = ( n - 1 ) & 2; // 1: 0, 2: 0, 3: 2
std::size_t const x2 = n >> 1; // 1: 0, 2: 1, 3: 1
v1 =
static_cast<std::uint32_t>( static_cast<unsigned char>( p[ static_cast<std::ptrdiff_t>( x1 ) ] ) ) << x1 * 8 |
static_cast<std::uint32_t>( static_cast<unsigned char>( p[ static_cast<std::ptrdiff_t>( x2 ) ] ) ) << x2 * 8 |
static_cast<std::uint32_t>( static_cast<unsigned char>( p[ 0 ] ) );
}
w += q;
h ^= mul32( v1 + w, k );
}
w += q;
h ^= mul32( static_cast<std::uint32_t>( h & 0xFFFFFFFF ) + w, static_cast<std::uint32_t>( h >> 32 ) + w + k );
return static_cast<std::uint32_t>( h & 0xFFFFFFFF ) ^ static_cast<std::uint32_t>( h >> 32 );
}
template<class It>
inline typename std::enable_if<
is_char_type<typename std::iterator_traits<It>::value_type>::value &&
!std::is_same<typename std::iterator_traits<It>::iterator_category, std::random_access_iterator_tag>::value &&
std::numeric_limits<std::size_t>::digits <= 32,
std::size_t>::type
hash_range( std::size_t seed, It first, It last )
{
std::size_t n = 0;
std::uint32_t const q = 0x9e3779b9U;
std::uint32_t const k = 0xe35e67b1U; // q * q
std::uint64_t h = mul32( static_cast<std::uint32_t>( seed ) + q, k );
std::uint32_t w = static_cast<std::uint32_t>( h & 0xFFFFFFFF );
std::uint32_t v1 = 0;
for( ;; )
{
v1 = 0;
if( first == last )
{
break;
}
v1 |= static_cast<std::uint32_t>( static_cast<unsigned char>( *first ) );
++first;
++n;
if( first == last )
{
break;
}
v1 |= static_cast<std::uint32_t>( static_cast<unsigned char>( *first ) ) << 8;
++first;
++n;
if( first == last )
{
break;
}
v1 |= static_cast<std::uint32_t>( static_cast<unsigned char>( *first ) ) << 16;
++first;
++n;
if( first == last )
{
break;
}
v1 |= static_cast<std::uint32_t>( static_cast<unsigned char>( *first ) ) << 24;
++first;
++n;
w += q;
h ^= mul32( v1 + w, k );
}
h ^= n;
w += q;
h ^= mul32( v1 + w, k );
w += q;
h ^= mul32( static_cast<std::uint32_t>( h & 0xFFFFFFFF ) + w, static_cast<std::uint32_t>( h >> 32 ) + w + k );
return static_cast<std::uint32_t>( h & 0xFFFFFFFF ) ^ static_cast<std::uint32_t>( h >> 32 );
}
// specialized char[] version, 64 bit
template<class It> inline std::uint64_t read64le( It p )
{
std::uint64_t w =
static_cast<std::uint64_t>( static_cast<unsigned char>( p[0] ) ) |
static_cast<std::uint64_t>( static_cast<unsigned char>( p[1] ) ) << 8 |
static_cast<std::uint64_t>( static_cast<unsigned char>( p[2] ) ) << 16 |
static_cast<std::uint64_t>( static_cast<unsigned char>( p[3] ) ) << 24 |
static_cast<std::uint64_t>( static_cast<unsigned char>( p[4] ) ) << 32 |
static_cast<std::uint64_t>( static_cast<unsigned char>( p[5] ) ) << 40 |
static_cast<std::uint64_t>( static_cast<unsigned char>( p[6] ) ) << 48 |
static_cast<std::uint64_t>( static_cast<unsigned char>( p[7] ) ) << 56;
return w;
}
#if defined(_MSC_VER) && !defined(__clang__)
template<class T> inline std::uint64_t read64le( T* p )
{
std::uint64_t w;
std::memcpy( &w, p, 8 );
return w;
}
#endif
template<class It>
inline typename std::enable_if<
is_char_type<typename std::iterator_traits<It>::value_type>::value &&
std::is_same<typename std::iterator_traits<It>::iterator_category, std::random_access_iterator_tag>::value &&
(std::numeric_limits<std::size_t>::digits > 32),
std::size_t>::type
hash_range( std::size_t seed, It first, It last )
{
It p = first;
std::size_t n = static_cast<std::size_t>( last - first );
std::uint64_t const q = 0x9e3779b97f4a7c15;
std::uint64_t const k = 0xdf442d22ce4859b9; // q * q
std::uint64_t w = mulx( seed + q, k );
std::uint64_t h = w ^ n;
while( n >= 8 )
{
std::uint64_t v1 = read64le( p );
w += q;
h ^= mulx( v1 + w, k );
p += 8;
n -= 8;
}
{
std::uint64_t v1 = 0;
if( n >= 4 )
{
v1 = static_cast<std::uint64_t>( read32le( p + static_cast<std::ptrdiff_t>( n - 4 ) ) ) << ( n - 4 ) * 8 | read32le( p );
}
else if( n >= 1 )
{
std::size_t const x1 = ( n - 1 ) & 2; // 1: 0, 2: 0, 3: 2
std::size_t const x2 = n >> 1; // 1: 0, 2: 1, 3: 1
v1 =
static_cast<std::uint64_t>( static_cast<unsigned char>( p[ static_cast<std::ptrdiff_t>( x1 ) ] ) ) << x1 * 8 |
static_cast<std::uint64_t>( static_cast<unsigned char>( p[ static_cast<std::ptrdiff_t>( x2 ) ] ) ) << x2 * 8 |
static_cast<std::uint64_t>( static_cast<unsigned char>( p[ 0 ] ) );
}
w += q;
h ^= mulx( v1 + w, k );
}
return mulx( h + w, k );
}
template<class It>
inline typename std::enable_if<
is_char_type<typename std::iterator_traits<It>::value_type>::value &&
!std::is_same<typename std::iterator_traits<It>::iterator_category, std::random_access_iterator_tag>::value &&
(std::numeric_limits<std::size_t>::digits > 32),
std::size_t>::type
hash_range( std::size_t seed, It first, It last )
{
std::size_t n = 0;
std::uint64_t const q = 0x9e3779b97f4a7c15;
std::uint64_t const k = 0xdf442d22ce4859b9; // q * q
std::uint64_t w = mulx( seed + q, k );
std::uint64_t h = w;
std::uint64_t v1 = 0;
for( ;; )
{
v1 = 0;
if( first == last )
{
break;
}
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) );
++first;
++n;
if( first == last )
{
break;
}
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) ) << 8;
++first;
++n;
if( first == last )
{
break;
}
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) ) << 16;
++first;
++n;
if( first == last )
{
break;
}
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) ) << 24;
++first;
++n;
if( first == last )
{
break;
}
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) ) << 32;
++first;
++n;
if( first == last )
{
break;
}
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) ) << 40;
++first;
++n;
if( first == last )
{
break;
}
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) ) << 48;
++first;
++n;
if( first == last )
{
break;
}
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) ) << 56;
++first;
++n;
w += q;
h ^= mulx( v1 + w, k );
}
h ^= n;
w += q;
h ^= mulx( v1 + w, k );
return mulx( h + w, k );
}
} // namespace hash_detail
} // namespace boost
#endif // #ifndef BOOST_HASH_DETAIL_HASH_RANGE_HPP

View File

@@ -1,133 +0,0 @@
// Copyright 2005-2009 Daniel James.
// Copyright 2021 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP
#define BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP
#include <boost/container_hash/hash_fwd.hpp>
#include <boost/type_traits/enable_if.hpp>
#include <boost/config.hpp>
#if defined(BOOST_NO_CXX11_HDR_TUPLE)
// no support
#else
#include <tuple>
namespace boost
{
namespace hash_detail
{
template <std::size_t I, typename T>
inline typename boost::enable_if_<(I == std::tuple_size<T>::value),
void>::type
hash_combine_tuple(std::size_t&, T const&)
{
}
template <std::size_t I, typename T>
inline typename boost::enable_if_<(I < std::tuple_size<T>::value),
void>::type
hash_combine_tuple(std::size_t& seed, T const& v)
{
boost::hash_combine(seed, std::get<I>(v));
boost::hash_detail::hash_combine_tuple<I + 1>(seed, v);
}
template <typename T>
inline std::size_t hash_tuple(T const& v)
{
std::size_t seed = 0;
boost::hash_detail::hash_combine_tuple<0>(seed, v);
return seed;
}
} // namespace hash_detail
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <typename... T>
inline std::size_t hash_value(std::tuple<T...> const& v)
{
return boost::hash_detail::hash_tuple(v);
}
#else
inline std::size_t hash_value(std::tuple<> const& v)
{
return boost::hash_detail::hash_tuple(v);
}
template<typename A0>
inline std::size_t hash_value(std::tuple<A0> const& v)
{
return boost::hash_detail::hash_tuple(v);
}
template<typename A0, typename A1>
inline std::size_t hash_value(std::tuple<A0, A1> const& v)
{
return boost::hash_detail::hash_tuple(v);
}
template<typename A0, typename A1, typename A2>
inline std::size_t hash_value(std::tuple<A0, A1, A2> const& v)
{
return boost::hash_detail::hash_tuple(v);
}
template<typename A0, typename A1, typename A2, typename A3>
inline std::size_t hash_value(std::tuple<A0, A1, A2, A3> const& v)
{
return boost::hash_detail::hash_tuple(v);
}
template<typename A0, typename A1, typename A2, typename A3, typename A4>
inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4> const& v)
{
return boost::hash_detail::hash_tuple(v);
}
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5> const& v)
{
return boost::hash_detail::hash_tuple(v);
}
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6> const& v)
{
return boost::hash_detail::hash_tuple(v);
}
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6, A7> const& v)
{
return boost::hash_detail::hash_tuple(v);
}
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6, A7, A8> const& v)
{
return boost::hash_detail::hash_tuple(v);
}
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6, A7, A8, A9> const& v)
{
return boost::hash_detail::hash_tuple(v);
}
#endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
} // namespace boost
#endif // #if defined(BOOST_NO_CXX11_HDR_TUPLE)
#endif // #ifndef BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP

View File

@@ -0,0 +1,62 @@
// Copyright 2005-2009 Daniel James.
// Copyright 2021 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP
#define BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP
#include <boost/container_hash/hash_fwd.hpp>
#include <boost/container_hash/is_tuple_like.hpp>
#include <boost/container_hash/is_range.hpp>
#include <type_traits>
#include <utility>
namespace boost
{
namespace hash_detail
{
template <std::size_t I, typename T>
inline
typename std::enable_if<(I == std::tuple_size<T>::value), void>::type
hash_combine_tuple_like( std::size_t&, T const& )
{
}
template <std::size_t I, typename T>
inline
typename std::enable_if<(I < std::tuple_size<T>::value), void>::type
hash_combine_tuple_like( std::size_t& seed, T const& v )
{
using std::get;
boost::hash_combine( seed, get<I>( v ) );
boost::hash_detail::hash_combine_tuple_like<I + 1>( seed, v );
}
template <typename T>
inline std::size_t hash_tuple_like( T const& v )
{
std::size_t seed = 0;
boost::hash_detail::hash_combine_tuple_like<0>( seed, v );
return seed;
}
} // namespace hash_detail
template <class T>
inline
typename std::enable_if<
container_hash::is_tuple_like<T>::value && !container_hash::is_range<T>::value,
std::size_t>::type
hash_value( T const& v )
{
return boost::hash_detail::hash_tuple_like( v );
}
} // namespace boost
#endif // #ifndef BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP

View File

@@ -1,81 +0,0 @@
// Copyright 2017, 2018 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_DETAIL_IS_CONTIGUOUS_RANGE_HPP_INCLUDED
#define BOOST_HASH_DETAIL_IS_CONTIGUOUS_RANGE_HPP_INCLUDED
#include <boost/type_traits/integral_constant.hpp>
#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)
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/declval.hpp>
#include <boost/type_traits/is_same.hpp>
#include <iterator>
namespace boost
{
namespace hash_detail
{
template<class It, class T, class S>
integral_constant< bool, is_same<typename std::iterator_traits<It>::value_type, T>::value && is_integral<S>::value >
is_contiguous_range_check( It first, It last, T const*, T const*, S );
template<class T> decltype( is_contiguous_range_check( declval<T const&>().begin(), declval<T const&>().end(), declval<T const&>().data(), declval<T const&>().data() + declval<T const&>().size(), declval<T const&>().size() ) ) is_contiguous_range_( int );
template<class T> false_type is_contiguous_range_( ... );
template<class T> struct is_contiguous_range: decltype( hash_detail::is_contiguous_range_<T>( 0 ) )
{
};
} // namespace hash_detail
} // namespace boost
#else // !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR)
#include <cstddef>
#include <vector>
#include <string>
#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
#include <array>
#endif
namespace boost
{
namespace hash_detail
{
template<class T> struct is_contiguous_range: false_type
{
};
template<class E, class T, class A> struct is_contiguous_range< std::basic_string<E, T, A> >: true_type
{
};
template<class E, class T, class A> struct is_contiguous_range< std::basic_string<E, T, A> const >: true_type
{
};
#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
template<class T, std::size_t N> struct is_contiguous_range< std::array<T, N> >: true_type
{
};
template<class T, std::size_t N> struct is_contiguous_range< std::array<T, N> const >: true_type
{
};
#endif
} // namespace hash_detail
} // namespace boost
#endif // !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR)
#endif // #ifndef BOOST_HASH_DETAIL_IS_CONTIGUOUS_RANGE_HPP_INCLUDED

View File

@@ -1,57 +0,0 @@
// Copyright 2017 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_DETAIL_IS_RANGE_HPP_INCLUDED
#define BOOST_HASH_DETAIL_IS_RANGE_HPP_INCLUDED
#include <boost/type_traits/integral_constant.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/declval.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <iterator>
namespace boost
{
namespace hash_detail
{
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700)
template<class T, class It>
integral_constant< bool, !is_same<typename remove_cv<T>::type, typename std::iterator_traits<It>::value_type>::value >
is_range_check( It first, It last );
template<class T> decltype( is_range_check<T>( declval<T const&>().begin(), declval<T const&>().end() ) ) is_range_( int );
template<class T> false_type is_range_( ... );
template<class T> struct is_range: decltype( is_range_<T>( 0 ) )
{
};
#else
template<class T, class E = true_type> struct is_range_: false_type
{
};
template<class T> struct is_range_< T, integral_constant< bool,
is_same<typename T::value_type, typename std::iterator_traits<typename T::const_iterator>::value_type>::value &&
is_integral<typename T::size_type>::value
> >: true_type
{
};
template<class T> struct is_range: is_range_<T>
{
};
#endif // !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR)
} // namespace hash_detail
} // namespace boost
#endif // #ifndef BOOST_HASH_DETAIL_IS_RANGE_HPP_INCLUDED

View File

@@ -1,34 +0,0 @@
// Copyright 2017 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_DETAIL_IS_UNORDERED_RANGE_HPP_INCLUDED
#define BOOST_HASH_DETAIL_IS_UNORDERED_RANGE_HPP_INCLUDED
#include <boost/container_hash/detail/is_range.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/type_traits/is_same.hpp>
namespace boost
{
namespace hash_detail
{
template<class T, class E = true_type> struct has_hasher_: false_type
{
};
template<class T> struct has_hasher_< T, integral_constant< bool,
is_same<typename T::hasher, typename T::hasher>::value
> >: true_type
{
};
template<class T> struct is_unordered_range: integral_constant< bool, is_range<T>::value && has_hasher_<T>::value >
{
};
} // namespace hash_detail
} // namespace boost
#endif // #ifndef BOOST_HASH_DETAIL_IS_UNORDERED_RANGE_HPP_INCLUDED

View File

@@ -0,0 +1,79 @@
// Copyright 2022, 2023 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_DETAIL_MULX_HPP
#define BOOST_HASH_DETAIL_MULX_HPP
#include <cstdint>
#if defined(_MSC_VER)
# include <intrin.h>
#endif
namespace boost
{
namespace hash_detail
{
#if defined(_MSC_VER) && defined(_M_X64) && !defined(__clang__)
__forceinline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
{
std::uint64_t r2;
std::uint64_t r = _umul128( x, y, &r2 );
return r ^ r2;
}
#elif defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__)
__forceinline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
{
std::uint64_t r = x * y;
std::uint64_t r2 = __umulh( x, y );
return r ^ r2;
}
#elif defined(__SIZEOF_INT128__)
inline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
{
__uint128_t r = static_cast<__uint128_t>( x ) * y;
return static_cast<std::uint64_t>( r ) ^ static_cast<std::uint64_t>( r >> 64 );
}
#else
inline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
{
std::uint64_t x1 = static_cast<std::uint32_t>( x );
std::uint64_t x2 = x >> 32;
std::uint64_t y1 = static_cast<std::uint32_t>( y );
std::uint64_t y2 = y >> 32;
std::uint64_t r3 = x2 * y2;
std::uint64_t r2a = x1 * y2;
r3 += r2a >> 32;
std::uint64_t r2b = x2 * y1;
r3 += r2b >> 32;
std::uint64_t r1 = x1 * y1;
std::uint64_t r2 = (r1 >> 32) + static_cast<std::uint32_t>( r2a ) + static_cast<std::uint32_t>( r2b );
r1 = (r2 << 32) + static_cast<std::uint32_t>( r1 );
r3 += r2 >> 32;
return r1 ^ r3;
}
#endif
} // namespace hash_detail
} // namespace boost
#endif // #ifndef BOOST_HASH_DETAIL_MULX_HPP

View File

@@ -1,35 +1,33 @@
// Copyright 2005-2014 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
// Based on Peter Dimov's proposal
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
// issue 6.18.
//
// This also contains public domain code from MurmurHash. From the
// MurmurHash header:
// MurmurHash3 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code.
#ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP
#define BOOST_FUNCTIONAL_HASH_HASH_HPP
#include <boost/container_hash/hash_fwd.hpp>
#include <boost/container_hash/detail/is_range.hpp>
#include <boost/container_hash/detail/is_contiguous_range.hpp>
#include <boost/container_hash/detail/is_unordered_range.hpp>
#include <boost/container_hash/detail/hash_tuple.hpp>
#include <boost/type_traits/is_enum.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/is_floating_point.hpp>
#include <boost/type_traits/is_signed.hpp>
#include <boost/type_traits/is_unsigned.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/type_traits/enable_if.hpp>
#include <boost/type_traits/conjunction.hpp>
#include <boost/cstdint.hpp>
#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_integral.hpp>
#include <boost/container_hash/detail/hash_tuple_like.hpp>
#include <boost/container_hash/detail/hash_mix.hpp>
#include <boost/container_hash/detail/hash_range.hpp>
#include <boost/describe/bases.hpp>
#include <boost/describe/members.hpp>
#include <type_traits>
#include <cstdint>
#if defined(BOOST_DESCRIBE_CXX14)
# include <boost/mp11/algorithm.hpp>
#endif
#include <string>
#include <iterator>
#include <complex>
@@ -58,10 +56,8 @@
#include <variant>
#endif
#if defined(_MSC_VER)
# define BOOST_FUNCTIONAL_HASH_ROTL32(x, r) _rotl(x,r)
#else
# define BOOST_FUNCTIONAL_HASH_ROTL32(x, r) (x << r) | (x >> (32 - r))
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
# include <string_view>
#endif
namespace boost
@@ -72,95 +68,12 @@ namespace boost
//
// integral types
namespace hash_detail
{
template<class T,
bool bigger_than_size_t = (sizeof(T) > sizeof(std::size_t)),
bool is_unsigned = boost::is_unsigned<T>::value,
std::size_t size_t_bits = sizeof(std::size_t) * CHAR_BIT,
std::size_t type_bits = sizeof(T) * CHAR_BIT>
struct hash_integral_impl;
template<class T, bool is_unsigned, std::size_t size_t_bits, std::size_t type_bits> struct hash_integral_impl<T, false, is_unsigned, size_t_bits, type_bits>
{
static std::size_t fn( T v )
{
return static_cast<std::size_t>( v );
}
};
template<class T, std::size_t size_t_bits, std::size_t type_bits> struct hash_integral_impl<T, true, false, size_t_bits, type_bits>
{
static std::size_t fn( T v )
{
typedef typename boost::make_unsigned<T>::type U;
if( v >= 0 )
{
return hash_integral_impl<U>::fn( static_cast<U>( v ) );
}
else
{
return ~hash_integral_impl<U>::fn( static_cast<U>( ~static_cast<U>( v ) ) );
}
}
};
template<class T> struct hash_integral_impl<T, true, true, 32, 64>
{
static std::size_t fn( T v )
{
std::size_t seed = 0;
seed ^= static_cast<std::size_t>( v >> 32 ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( v ) + ( seed << 6 ) + ( seed >> 2 );
return seed;
}
};
template<class T> struct hash_integral_impl<T, true, true, 32, 128>
{
static std::size_t fn( T v )
{
std::size_t seed = 0;
seed ^= static_cast<std::size_t>( v >> 96 ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( v >> 64 ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( v >> 32 ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( v ) + ( seed << 6 ) + ( seed >> 2 );
return seed;
}
};
template<class T> struct hash_integral_impl<T, true, true, 64, 128>
{
static std::size_t fn( T v )
{
std::size_t seed = 0;
seed ^= static_cast<std::size_t>( v >> 64 ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( v ) + ( seed << 6 ) + ( seed >> 2 );
return seed;
}
};
} // namespace hash_detail
template <typename T>
typename boost::enable_if_<boost::is_integral<T>::value, std::size_t>::type
hash_value( T v )
{
return hash_detail::hash_integral_impl<T>::fn( v );
}
// in detail/hash_integral.hpp
// enumeration types
template <typename T>
typename boost::enable_if_<boost::is_enum<T>::value, std::size_t>::type
typename std::enable_if<std::is_enum<T>::value, std::size_t>::type
hash_value( T v )
{
// This should in principle return the equivalent of
@@ -186,16 +99,15 @@ namespace boost
{
template<class T,
std::size_t Bits = sizeof(T) * CHAR_BIT,
int Digits = std::numeric_limits<T>::digits,
std::size_t size_t_bits = sizeof(std::size_t) * CHAR_BIT>
int Digits = std::numeric_limits<T>::digits>
struct hash_float_impl;
// 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 )
{
boost::uint32_t w;
std::uint32_t w;
std::memcpy( &w, &v, sizeof( v ) );
return w;
@@ -203,132 +115,72 @@ namespace boost
};
// 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 )
{
boost::uint64_t w;
std::uint64_t w;
std::memcpy( &w, &v, sizeof( v ) );
return 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] ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( w[1] ) + ( seed << 6 ) + ( seed >> 2 );
return seed;
return hash_value( w );
}
};
// 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 )
{
boost::uint64_t w[ 2 ] = {};
std::uint64_t w[ 2 ] = {};
std::memcpy( &w, &v, 80 / CHAR_BIT );
std::size_t seed = 0;
seed ^= static_cast<std::size_t>( w[0] ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( w[1] ) + ( seed << 6 ) + ( seed >> 2 );
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] ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( w[1] ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( w[2] ) + ( seed << 6 ) + ( seed >> 2 );
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
return seed;
}
};
// 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 )
{
boost::uint64_t w[ 2 ] = {};
std::uint64_t w[ 2 ] = {};
std::memcpy( &w, &v, 80 / CHAR_BIT );
std::size_t seed = 0;
seed ^= static_cast<std::size_t>( w[0] ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( w[1] ) + ( seed << 6 ) + ( seed >> 2 );
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] ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( w[1] ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( w[2] ) + ( seed << 6 ) + ( seed >> 2 );
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
return seed;
}
};
// 128 bit long double
template<class T, int Digits> struct hash_float_impl<T, 128, Digits, 64>
template<class T, int Digits> struct hash_float_impl<T, 128, Digits>
{
static std::size_t fn( T v )
{
boost::uint64_t w[ 2 ];
std::uint64_t w[ 2 ];
std::memcpy( &w, &v, sizeof( v ) );
std::size_t seed = 0;
seed ^= static_cast<std::size_t>( w[0] ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( w[1] ) + ( seed << 6 ) + ( seed >> 2 );
#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__
return seed;
}
};
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
template<class T, int Digits> struct hash_float_impl<T, 128, Digits, 32>
{
static std::size_t fn( T v )
{
boost::uint32_t w[ 4 ];
std::memcpy( &w, &v, sizeof( v ) );
#else
std::size_t seed = 0;
seed ^= static_cast<std::size_t>( w[0] ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( w[1] ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( w[2] ) + ( seed << 6 ) + ( seed >> 2 );
seed ^= static_cast<std::size_t>( w[3] ) + ( seed << 6 ) + ( seed >> 2 );
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
#endif
return seed;
}
};
@@ -336,7 +188,7 @@ namespace boost
} // namespace hash_detail
template <typename T>
typename boost::enable_if_<boost::is_floating_point<T>::value, std::size_t>::type
typename std::enable_if<std::is_floating_point<T>::value, std::size_t>::type
hash_value( T v )
{
return boost::hash_detail::hash_float_impl<T>::fn( v + 0 );
@@ -347,7 +199,7 @@ namespace boost
// `x + (x >> 3)` adjustment by Alberto Barbati and Dave Harris.
template <class T> std::size_t hash_value( T* const& v )
{
boost::uintptr_t x = reinterpret_cast<boost::uintptr_t>( v );
std::uintptr_t x = reinterpret_cast<std::uintptr_t>( v );
return boost::hash_value( x + (x >> 3) );
}
@@ -373,8 +225,7 @@ namespace boost
std::size_t re = boost::hash<T>()( v.real() );
std::size_t im = boost::hash<T>()( v.imag() );
im ^= re + ( im << 6 ) + ( im >> 2 );
return im;
return re + hash_detail::hash_mix( im );
}
// pair
@@ -393,7 +244,7 @@ namespace boost
// ranges (list, set, deque...)
template <typename T>
typename boost::enable_if_<hash_detail::is_range<T>::value && !hash_detail::is_contiguous_range<T>::value && !hash_detail::is_unordered_range<T>::value, std::size_t>::type
typename std::enable_if<container_hash::is_range<T>::value && !container_hash::is_contiguous_range<T>::value && !container_hash::is_unordered_range<T>::value, std::size_t>::type
hash_value( T const& v )
{
return boost::hash_range( v.begin(), v.end() );
@@ -402,7 +253,7 @@ namespace boost
// contiguous ranges (string, vector, array)
template <typename T>
typename boost::enable_if_<hash_detail::is_contiguous_range<T>::value, std::size_t>::type
typename std::enable_if<container_hash::is_contiguous_range<T>::value, std::size_t>::type
hash_value( T const& v )
{
return boost::hash_range( v.data(), v.data() + v.size() );
@@ -411,18 +262,20 @@ namespace boost
// unordered ranges (unordered_set, unordered_map)
template <typename T>
typename boost::enable_if_<hash_detail::is_unordered_range<T>::value, std::size_t>::type
typename std::enable_if<container_hash::is_unordered_range<T>::value, std::size_t>::type
hash_value( T const& v )
{
return boost::hash_unordered_range( v.begin(), v.end() );
}
#if defined(BOOST_MSVC) && BOOST_MSVC >= 1910 && BOOST_MSVC < 1920 && BOOST_CXX_VERSION >= 201700L
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ( \
( defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142 ) || \
( !defined(_MSVC_STL_VERSION) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520 ) )
// resolve ambiguity with unconstrained stdext::hash_value in <xhash> :-/
template<template<class...> class L, class... T>
typename boost::enable_if_<hash_detail::is_range<L<T...>>::value && !hash_detail::is_contiguous_range<L<T...>>::value && !hash_detail::is_unordered_range<L<T...>>::value, std::size_t>::type
typename std::enable_if<container_hash::is_range<L<T...>>::value && !container_hash::is_contiguous_range<L<T...>>::value && !container_hash::is_unordered_range<L<T...>>::value, std::size_t>::type
hash_value( L<T...> const& v )
{
return boost::hash_range( v.begin(), v.end() );
@@ -431,14 +284,14 @@ namespace boost
// contiguous ranges (string, vector, array)
template<template<class...> class L, class... T>
typename boost::enable_if_<hash_detail::is_contiguous_range<L<T...>>::value, std::size_t>::type
typename std::enable_if<container_hash::is_contiguous_range<L<T...>>::value, std::size_t>::type
hash_value( L<T...> const& v )
{
return boost::hash_range( v.data(), v.data() + v.size() );
}
template<template<class, std::size_t> class L, class T, std::size_t N>
typename boost::enable_if_<hash_detail::is_contiguous_range<L<T, N>>::value, std::size_t>::type
typename std::enable_if<container_hash::is_contiguous_range<L<T, N>>::value, std::size_t>::type
hash_value( L<T, N> const& v )
{
return boost::hash_range( v.data(), v.data() + v.size() );
@@ -447,12 +300,55 @@ namespace boost
// unordered ranges (unordered_set, unordered_map)
template<template<class...> class L, class... T>
typename boost::enable_if_<hash_detail::is_unordered_range<L<T...>>::value, std::size_t>::type
typename std::enable_if<container_hash::is_unordered_range<L<T...>>::value, std::size_t>::type
hash_value( L<T...> const& v )
{
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 std::enable_if<container_hash::is_described_class<T>::value, std::size_t>::type
hash_value( T const& v )
{
static_assert( !std::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
@@ -508,6 +404,19 @@ namespace boost
return seed;
}
#endif
// std::nullptr_t
#if !defined(BOOST_NO_CXX11_NULLPTR)
template <typename T>
typename std::enable_if<std::is_same<T, std::nullptr_t>::value, std::size_t>::type
hash_value( T const& /*v*/ )
{
return boost::hash_value( static_cast<void*>( nullptr ) );
}
#endif
// std::optional
@@ -519,7 +428,7 @@ namespace boost
{
if( !v )
{
// Arbitray value for empty optional.
// Arbitrary value for empty optional.
return 0x12345678;
}
else
@@ -556,103 +465,62 @@ namespace boost
// boost::hash_combine
//
namespace hash_detail
{
template<std::size_t Bits> struct hash_combine_impl
{
template <typename SizeT>
inline static SizeT fn(SizeT seed, SizeT value)
{
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
return seed;
}
};
template<> struct hash_combine_impl<32>
{
inline static boost::uint32_t fn(boost::uint32_t h1, boost::uint32_t k1)
{
const boost::uint32_t c1 = 0xcc9e2d51;
const boost::uint32_t c2 = 0x1b873593;
k1 *= c1;
k1 = BOOST_FUNCTIONAL_HASH_ROTL32(k1,15);
k1 *= c2;
h1 ^= k1;
h1 = BOOST_FUNCTIONAL_HASH_ROTL32(h1,13);
h1 = h1*5+0xe6546b64;
return h1;
}
};
template<> struct hash_combine_impl<64>
{
inline static boost::uint64_t fn(boost::uint64_t h, boost::uint64_t k)
{
const boost::uint64_t m = (boost::uint64_t(0xc6a4a793) << 32) + 0x5bd1e995;
const int r = 47;
k *= m;
k ^= k >> r;
k *= m;
h ^= k;
h *= m;
// Completely arbitrary number, to prevent 0's
// from hashing to 0.
h += 0xe6546b64;
return h;
}
};
}
#if defined(BOOST_MSVC)
#pragma warning(push)
#if BOOST_MSVC <= 1400
#pragma warning(disable:4267) // 'argument' : conversion from 'size_t' to
// 'unsigned int', possible loss of data
// A misguided attempt to detect 64-bit
// incompatability.
#endif
#endif
template <class T>
inline void hash_combine(std::size_t& seed, T const& v)
inline void hash_combine( std::size_t& seed, T const& v )
{
boost::hash<T> hasher;
seed = boost::hash_detail::hash_combine_impl<sizeof(std::size_t) * CHAR_BIT>::fn(seed, hasher(v));
seed = boost::hash_detail::hash_mix( seed + 0x9e3779b9 + boost::hash<T>()( v ) );
}
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
//
// boost::hash_range
//
template <class It>
inline std::size_t hash_range(It first, It last)
inline void hash_range( std::size_t& seed, It first, It last )
{
seed = hash_detail::hash_range( seed, first, last );
}
template <class It>
inline std::size_t hash_range( It first, It last )
{
std::size_t seed = 0;
hash_range(seed, first, last);
hash_range( seed, first, last );
return seed;
}
//
// boost::hash_unordered_range
//
template <class It>
inline void hash_range(std::size_t& seed, It first, It last)
inline void hash_unordered_range( std::size_t& seed, It first, It last )
{
for(; first != last; ++first)
std::size_t r = 0;
std::size_t const s2( seed );
for( ; first != last; ++first )
{
hash_combine<typename std::iterator_traits<It>::value_type>(seed, *first);
std::size_t s3( s2 );
hash_combine<typename std::iterator_traits<It>::value_type>( s3, *first );
r += s3;
}
seed += r;
}
template <class It>
inline std::size_t hash_unordered_range( It first, It last )
{
std::size_t seed = 0;
hash_unordered_range( seed, first, last );
return seed;
}
//
@@ -670,9 +538,11 @@ namespace boost
}
};
#if defined(BOOST_MSVC) && BOOST_MSVC >= 1910 && BOOST_MSVC < 1920 && BOOST_CXX_VERSION >= 201700L
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ( \
( defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142 ) || \
( !defined(_MSVC_STL_VERSION) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520 ) )
// msvc-14.1 has stdext::hash_value for basic_string in <xhash> :-/
// Dinkumware has stdext::hash_value for basic_string in <xhash> :-/
template<class E, class T, class A> struct hash< std::basic_string<E, T, A> >
{
@@ -686,8 +556,21 @@ namespace boost
};
#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> > >: std::is_integral<Ch> {};
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string_view<Ch> > >: std::is_integral<Ch> {};
#endif
} // namespace unordered
} // namespace boost
#endif // #ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP

View File

@@ -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
@@ -10,15 +10,28 @@
namespace boost
{
template <class T> struct hash;
template <class T> void hash_combine(std::size_t& seed, T const& v);
namespace container_hash
{
template <class It> std::size_t hash_range(It, It);
template <class It> void hash_range(std::size_t&, It, It);
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;
template<class T> struct is_tuple_like;
template <class It> std::size_t hash_unordered_range(It, It);
template <class It> void hash_unordered_range(std::size_t&, It, It);
}
} // namespace container_hash
template<class T> struct hash;
template<class T> void hash_combine( std::size_t& seed, T const& v );
template<class It> void hash_range( std::size_t&, It, It );
template<class It> std::size_t hash_range( It, It );
template<class It> void hash_unordered_range( std::size_t&, It, It );
template<class It> std::size_t hash_unordered_range( It, It );
} // namespace boost
#endif // #ifndef BOOST_FUNCTIONAL_HASH_FWD_HPP

View File

@@ -0,0 +1,98 @@
// Copyright 2017, 2018 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_IS_CONTIGUOUS_RANGE_HPP_INCLUDED
#define BOOST_HASH_IS_CONTIGUOUS_RANGE_HPP_INCLUDED
#include <boost/container_hash/is_range.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <type_traits>
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
#include <iterator>
namespace boost
{
namespace hash_detail
{
template<class It, class T, class S>
std::integral_constant< bool, std::is_same<typename std::iterator_traits<It>::value_type, T>::value && std::is_integral<S>::value >
is_contiguous_range_check( It first, It last, T const*, T const*, S );
template<class T> decltype( is_contiguous_range_check( std::declval<T const&>().begin(), std::declval<T const&>().end(), std::declval<T const&>().data(), std::declval<T const&>().data() + std::declval<T const&>().size(), std::declval<T const&>().size() ) ) is_contiguous_range_( int );
template<class T> std::false_type is_contiguous_range_( ... );
template<class T> struct is_contiguous_range: decltype( hash_detail::is_contiguous_range_<T>( 0 ) )
{
};
} // namespace hash_detail
namespace container_hash
{
template<class T> struct is_contiguous_range: std::integral_constant< bool, is_range<T>::value && hash_detail::is_contiguous_range<T>::value >
{
};
} // namespace container_hash
} // namespace boost
#else // !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
#include <cstddef>
#include <vector>
#include <string>
#include <array>
namespace boost
{
namespace container_hash
{
template<class T> struct is_contiguous_range: std::false_type
{
};
template<class E, class T, class A> struct is_contiguous_range< std::basic_string<E, T, A> >: std::true_type
{
};
template<class E, class T, class A> struct is_contiguous_range< std::basic_string<E, T, A> const >: std::true_type
{
};
template<class T, class A> struct is_contiguous_range< std::vector<T, A> >: std::true_type
{
};
template<class T, class A> struct is_contiguous_range< std::vector<T, A> const >: std::true_type
{
};
template<class A> struct is_contiguous_range< std::vector<bool, A> >: std::false_type
{
};
template<class A> struct is_contiguous_range< std::vector<bool, A> const >: std::false_type
{
};
template<class T, std::size_t N> struct is_contiguous_range< std::array<T, N> >: std::true_type
{
};
template<class T, std::size_t N> struct is_contiguous_range< std::array<T, N> const >: std::true_type
{
};
} // namespace container_hash
} // namespace boost
#endif // !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
#endif // #ifndef BOOST_HASH_IS_CONTIGUOUS_RANGE_HPP_INCLUDED

View File

@@ -0,0 +1,37 @@
// 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/describe/bases.hpp>
#include <boost/describe/members.hpp>
#include <type_traits>
namespace boost
{
namespace container_hash
{
#if defined(BOOST_DESCRIBE_CXX11)
template<class T> struct is_described_class: std::integral_constant<bool,
describe::has_describe_bases<T>::value &&
describe::has_describe_members<T>::value &&
!std::is_union<T>::value>
{
};
#else
template<class T> struct is_described_class: std::false_type
{
};
#endif
} // namespace container_hash
} // namespace boost
#endif // #ifndef BOOST_HASH_IS_DESCRIBED_CLASS_HPP_INCLUDED

View File

@@ -0,0 +1,37 @@
// Copyright 2017 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_IS_RANGE_HPP_INCLUDED
#define BOOST_HASH_IS_RANGE_HPP_INCLUDED
#include <iterator>
#include <type_traits>
namespace boost
{
namespace hash_detail
{
template<class T, class It>
std::integral_constant< bool, !std::is_same<typename std::remove_cv<T>::type, typename std::iterator_traits<It>::value_type>::value >
is_range_check( It first, It last );
template<class T> decltype( is_range_check<T>( std::declval<T const&>().begin(), std::declval<T const&>().end() ) ) is_range_( int );
template<class T> std::false_type is_range_( ... );
} // namespace hash_detail
namespace container_hash
{
template<class T> struct is_range: decltype( hash_detail::is_range_<T>( 0 ) )
{
};
} // namespace container_hash
} // namespace boost
#endif // #ifndef BOOST_HASH_IS_RANGE_HPP_INCLUDED

View File

@@ -0,0 +1,36 @@
#ifndef BOOST_HASH_IS_TUPLE_LIKE_HPP_INCLUDED
#define BOOST_HASH_IS_TUPLE_LIKE_HPP_INCLUDED
// Copyright 2017, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <type_traits>
#include <utility>
namespace boost
{
namespace hash_detail
{
template<class T, class E = std::true_type> struct is_tuple_like_: std::false_type
{
};
template<class T> struct is_tuple_like_<T, std::integral_constant<bool, std::tuple_size<T>::value == std::tuple_size<T>::value> >: std::true_type
{
};
} // namespace hash_detail
namespace container_hash
{
template<class T> struct is_tuple_like: hash_detail::is_tuple_like_<T>
{
};
} // namespace container_hash
} // namespace boost
#endif // #ifndef BOOST_HASH_IS_TUPLE_LIKE_HPP_INCLUDED

View File

@@ -0,0 +1,38 @@
// Copyright 2017 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_IS_UNORDERED_RANGE_HPP_INCLUDED
#define BOOST_HASH_IS_UNORDERED_RANGE_HPP_INCLUDED
#include <boost/container_hash/is_range.hpp>
#include <type_traits>
namespace boost
{
namespace hash_detail
{
template<class T, class E = std::true_type> struct has_hasher_: std::false_type
{
};
template<class T> struct has_hasher_< T, std::integral_constant< bool,
std::is_same<typename T::hasher, typename T::hasher>::value
> >: std::true_type
{
};
} // namespace hash_detail
namespace container_hash
{
template<class T> struct is_unordered_range: std::integral_constant< bool, is_range<T>::value && hash_detail::has_hasher_<T>::value >
{
};
} // namespace container_hash
} // namespace boost
#endif // #ifndef BOOST_HASH_IS_UNORDERED_RANGE_HPP_INCLUDED

View File

@@ -7,7 +7,7 @@
"Daniel James"
],
"maintainers": [
"Daniel James <dnljms -at- gmail.com>"
"Peter Dimov <pdimov -at- gmail.com>"
],
"description": "An STL-compatible hash function object that can be extended to hash user defined types.",
"std": [
@@ -16,6 +16,6 @@
"category": [
"Function-objects"
],
"cxxstd": "03"
"cxxstd": "11"
}
]

View File

@@ -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()

View File

@@ -62,9 +62,9 @@ build-project ../examples ;
run hash_reference_values.cpp ;
run detail_is_range_test.cpp ;
run detail_is_contiguous_range_test.cpp ;
run detail_is_unordered_range_test.cpp ;
run is_range_test.cpp ;
run is_contiguous_range_test.cpp ;
run is_unordered_range_test.cpp ;
run hash_forward_list_test.cpp ;
@@ -77,7 +77,51 @@ run hash_string_test2.cpp ;
# for gcc-4.8
local fs-path-req = "-<toolset>gcc:<cxxflags>-Wshadow" "-<toolset>gcc:<cxxflags>-Wconversion" ;
run hash_fs_path_test.cpp /boost//filesystem/<warnings>off : : : $(fs-path-req) <toolset>msvc-14.0,<cxxstd>latest:<build>no ;
run detail_is_range_test2.cpp : : : $(fs-path-req) ;
run hash_fs_path_test.cpp /boost//filesystem/<warnings>off : : : $(fs-path-req) <toolset>msvc-14.0,<cxxstd>latest:<build>no <toolset>msvc-8.0:<build>no <undefined-sanitizer>norecover:<link>static ;
run is_range_test2.cpp : : : $(fs-path-req) <toolset>msvc-8.0:<build>no ;
run hash_container_test.cpp ;
run hash_vector_test2.cpp ;
run hash_string_test3.cpp ;
run hash_string_test4.cpp ;
run hash_multiset_test.cpp ;
run hash_multimap_test.cpp ;
run hash_unordered_range_test.cpp ;
run hash_unordered_multiset_test.cpp ;
run hash_unordered_multimap_test.cpp ;
run hash_unordered_set_test.cpp ;
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 ;
run hash_integral_test2.cpp ;
run hash_nullptr_test.cpp ;
run is_tuple_like_test.cpp ;
run hash_tuple_like_test.cpp ;
run hash_tuple_like_test2.cpp
: : : <warnings>extra ;

View File

@@ -9,8 +9,8 @@ project(cmake_subdir_test LANGUAGES CXX)
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)

View 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

View File

@@ -3,6 +3,8 @@
// 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)
#define _SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING
#include "./config.hpp"
#if !defined(BOOST_HASH_TEST_EXTENSIONS)
@@ -122,9 +124,9 @@ int main()
complex_integral_tests((unsigned long*) 0);
complex_grid_test<int>( 16 );
complex_grid_test<float>( 7 );
complex_grid_test<float>( 16 );
complex_grid_test<double>( 16 );
complex_grid_test<long double>( 15 );
complex_grid_test<long double>( 16 );
return boost::report_errors();
}

View File

@@ -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();
}

View File

@@ -3,6 +3,8 @@
// 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)
#define _SILENCE_CXX23_DENORM_DEPRECATION_WARNING
#include "hash_float_test.hpp"
int main()

View File

@@ -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; }

View File

@@ -50,10 +50,11 @@ void write_compiler_info() {
msvc) - 1;
unsigned difference = msvc.version - v->version;
std::cout << v->description << std::endl;
std::cout << v->description;
if (difference) {
std::cout << "+" << difference << std::endl;
std::cout << " +" << difference;
}
std::cout << std::endl;
}
#else
@@ -109,6 +110,7 @@ int main() {
std::cout << std::endl;
PRINT(sizeof(std::size_t)*CHAR_BIT);
PRINT(std::numeric_limits<std::size_t>::digits);
std::cout << std::endl;
PRINT(sizeof(float)*CHAR_BIT);

View File

@@ -7,7 +7,7 @@
#include <boost/core/lightweight_test.hpp>
#include <boost/core/type_name.hpp>
#include <boost/type_traits/is_signed.hpp>
#include <set>
#include <boost/config.hpp>
#if defined(BOOST_MSVC)
#pragma warning(disable: 4127) // conditional expression is constant

View File

@@ -0,0 +1,52 @@
// Copyright 2005-2009 Daniel James.
// Copyright 2021 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.hpp>
#include <boost/core/type_name.hpp>
#include <boost/type_traits/is_signed.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/static_assert.hpp>
#include <boost/config.hpp>
// This test checks that values representable in a signed
// and the corresponding unsigned type hash to the same value
template<class T>
void signed_unsigned_test()
{
BOOST_STATIC_ASSERT( boost::is_signed<T>::value );
typedef typename boost::make_unsigned<T>::type U;
T x = std::numeric_limits<T>::max();
do
{
BOOST_TEST_EQ( boost::hash<T>()( x ), boost::hash<U>()( static_cast<U>( x ) ) );
x /= 3;
}
while( x > 0 );
}
#define TEST(type) std::cerr << "Testing: " #type " (" << boost::core::type_name<type>() << ")\n"; signed_unsigned_test<type>();
int main()
{
TEST(signed char)
TEST(short)
TEST(int)
TEST(long)
#if !defined(BOOST_NO_LONG_LONG)
TEST(boost::long_long_type)
#endif
#if defined(BOOST_HAS_INT128)
TEST(boost::int128_type)
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,45 @@
// 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/unordered/hash_traits.hpp>
#include <boost/config.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
#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 160000
// std::char_traits<Ch> is deprecated for non-char types
#else
BOOST_TEST_TRAIT_FALSE(( hash_is_avalanching< boost::hash<std::basic_string<my_char> > > ));
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,52 @@
// 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_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

View File

@@ -3,6 +3,8 @@
// 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)
#define _SILENCE_CXX23_DENORM_DEPRECATION_WARNING
#include "hash_float_test.hpp"
int main()

View File

@@ -0,0 +1,46 @@
// Copyright 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <map>
template<class T> void test()
{
typedef std::multimap<T, T> map;
typedef boost::hash<map> hash;
int const N = 32;
std::size_t h[ N ];
map v;
for( int i = 0; i < N; ++i )
{
h[ i ] = hash()( v );
BOOST_TEST_EQ( h[ i ], hash()( v ) );
for( int j = 0; j < i; ++j )
{
BOOST_TEST_NE( h[ j ], h[ i ] );
}
v.insert( std::pair<T const, T>() );
}
}
int main()
{
test<int>();
test<float>();
test<double>();
return boost::report_errors();
}

View File

@@ -0,0 +1,46 @@
// Copyright 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <set>
template<class T> void test()
{
typedef std::multiset<T> set;
typedef boost::hash<set> hash;
int const N = 32;
std::size_t h[ N ];
set v;
for( int i = 0; i < N; ++i )
{
h[ i ] = hash()( v );
BOOST_TEST_EQ( h[ i ], hash()( v ) );
for( int j = 0; j < i; ++j )
{
BOOST_TEST_NE( h[ j ], h[ i ] );
}
v.insert( T() );
}
}
int main()
{
test<int>();
test<float>();
test<double>();
return boost::report_errors();
}

View File

@@ -0,0 +1,41 @@
// 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.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#include <cstddef>
#if defined(BOOST_NO_CXX11_NULLPTR)
BOOST_PRAGMA_MESSAGE( "Test skipped, BOOST_NO_CXX11_NULLPTR is defined" )
int main() {}
#else
template<class T> std::size_t hv( T const& x )
{
return boost::hash<T>()( x );
}
int main()
{
{
BOOST_TEST_EQ( hv((void*)0), hv(nullptr) );
}
{
int x = 0;
BOOST_TEST_EQ( hv((int*)0), hv(nullptr) );
BOOST_TEST_NE( hv(&x), hv(nullptr) );
(void)x;
}
return boost::report_errors();
}
#endif

View File

@@ -21,6 +21,10 @@ int main() {}
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#if defined(_MSC_VER)
# pragma warning(disable: 4127) // conditional expression is constant
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <string>
@@ -109,7 +113,7 @@ int main()
BOOST_TEST_EQ( hv(1ULL), 1 );
BOOST_TEST_EQ( hv(65535ULL), 65535 );
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv((unsigned long long)-1), 3221225537U );
BOOST_TEST_EQ( hv((unsigned long long)-1), 2578835074U );
#else
BOOST_TEST_EQ( hv((unsigned long long)-1), (std::size_t)-1 );
#endif
@@ -141,7 +145,7 @@ int main()
#else
BOOST_TEST_EQ( hv((uint128)-1), 13835058055282163777ULL );
BOOST_TEST_EQ( hv((uint128)-1), 10400452472442790415ULL );
#endif
@@ -167,16 +171,16 @@ int main()
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(1.0), 1072693248U );
BOOST_TEST_EQ( hv(-1.0), 3220176896U );
BOOST_TEST_EQ( hv(3.14), 2660156064U );
BOOST_TEST_EQ( hv(-3.14), 512672416U );
BOOST_TEST_EQ( hv(1e-308), 1553872728U );
BOOST_TEST_EQ( hv(-1e-308), 3701356376U );
BOOST_TEST_EQ( hv(1e+308), 2577739707U );
BOOST_TEST_EQ( hv(-1e+308), 430256059U );
BOOST_TEST_EQ( hv(std::numeric_limits<double>::infinity()), 2146435072U );
BOOST_TEST_EQ( hv(-std::numeric_limits<double>::infinity()), 4293918720U );
BOOST_TEST_EQ( hv(1.0), 2619008688U );
BOOST_TEST_EQ( hv(-1.0), 146497060U );
BOOST_TEST_EQ( hv(3.14), 101651732U );
BOOST_TEST_EQ( hv(-3.14), 210858151U );
BOOST_TEST_EQ( hv(1e-308), 3911789313U );
BOOST_TEST_EQ( hv(-1e-308), 1812507313U );
BOOST_TEST_EQ( hv(1e+308), 987802568U );
BOOST_TEST_EQ( hv(-1e+308), 1639042439U );
BOOST_TEST_EQ( hv(std::numeric_limits<double>::infinity()), 3227645345U );
BOOST_TEST_EQ( hv(-std::numeric_limits<double>::infinity()), 2247339177U );
#else
@@ -197,49 +201,62 @@ int main()
BOOST_TEST_EQ( hv(0.0L), 0 );
BOOST_TEST_EQ( hv(-0.0L), 0 );
#if defined(_WIN32) && !defined(__GNUC__) // Under MS ABI, long double == double
std::size_t const ldbits = sizeof( long double ) * CHAR_BIT;
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(1.0L), 1072693248U );
BOOST_TEST_EQ( hv(-1.0L), 3220176896U );
BOOST_TEST_EQ( hv(3.14L), 2660156064U );
BOOST_TEST_EQ( hv(-3.14L), 512672416U );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 2146435072U );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 4293918720U );
if( ldbits == 64 )
{
BOOST_TEST_EQ( hv(1.0L), hv(1.0) );
BOOST_TEST_EQ( hv(-1.0L), hv(-1.0) );
BOOST_TEST_EQ( hv(3.14L), hv(3.14) );
BOOST_TEST_EQ( hv(-3.14L), hv(-3.14) );
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()), hv(-std::numeric_limits<double>::infinity()) );
}
else
{
// ldbits == 96
BOOST_TEST_EQ( hv(1.0L), 3632050780U );
BOOST_TEST_EQ( hv(-1.0L), 3632083548U );
BOOST_TEST_EQ( hv(3.14L), 1742026549U );
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
BOOST_TEST_EQ( hv(1.0L), 4607182418800017408ULL );
BOOST_TEST_EQ( hv(-1.0L), 13830554455654793216ULL );
BOOST_TEST_EQ( hv(3.14L), 4614253070214989087ULL );
BOOST_TEST_EQ( hv(-3.14L), 13837625107069764895ULL );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 9218868437227405312ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 18442240474082181120ULL );
if( ldbits == 64 )
{
BOOST_TEST_EQ( hv(1.0L), 4607182418800017408ULL );
BOOST_TEST_EQ( hv(-1.0L), 13830554455654793216ULL );
BOOST_TEST_EQ( hv(3.14L), 4614253070214989087ULL );
BOOST_TEST_EQ( hv(-3.14L), 13837625107069764895ULL );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 9218868437227405312ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 18442240474082181120ULL );
}
else if( ldbits == 128 && std::numeric_limits<long double>::digits == 64 )
{
BOOST_TEST_EQ( hv(1.0L), 18308860000934227808ULL );
BOOST_TEST_EQ( hv(-1.0L), 18308860000934260576ULL );
BOOST_TEST_EQ( hv(3.14L), 13482288377848558187ULL );
BOOST_TEST_EQ( hv(-3.14L), 13482288377848590955ULL );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 18308860000934244192ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 18308860000934276960ULL );
}
else
{
// ldbits == 128 && std::numeric_limits<long double>::digits == 113
#endif
#else
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(1.0L), 2684370943U );
BOOST_TEST_EQ( hv(-1.0L), 2684403711U );
BOOST_TEST_EQ( hv(3.14L), 83002659U );
BOOST_TEST_EQ( hv(-3.14L), 82969891U );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 0xA0007FFFu );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 0xA000FFFFu );
#else
BOOST_TEST_EQ( hv(1.0L), 11529215046068486143ULL );
BOOST_TEST_EQ( hv(-1.0L), 11529215046068518911ULL );
BOOST_TEST_EQ( hv(3.14L), 12059468778148142067ULL );
BOOST_TEST_EQ( hv(-3.14L), 12059468778147191795ULL );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 11529215046068502527ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 11529215046068535295ULL );
#endif
BOOST_TEST_EQ( hv(1.0L), 4611404543450677248ULL );
BOOST_TEST_EQ( hv(-1.0L), 13834776580305453056ULL );
BOOST_TEST_EQ( hv(3.14L), 5967435363179612952ULL );
BOOST_TEST_EQ( hv(-3.14L), 15190807400034388760ULL );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 9223090561878065152ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 18446462598732840960ULL );
}
#endif
@@ -251,15 +268,15 @@ int main()
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(a1), 3864292196U );
BOOST_TEST_EQ( hv(a2), 2842917718U );
BOOST_TEST_EQ( hv(a3), 325752138U );
BOOST_TEST_EQ( hv(a1), 1684164658U );
BOOST_TEST_EQ( hv(a2), 3385628684U );
BOOST_TEST_EQ( hv(a3), 354805152U );
#else
BOOST_TEST_EQ( hv(a1), 3864292196ULL );
BOOST_TEST_EQ( hv(a2), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(a3), 17867750819888810972ULL );
BOOST_TEST_EQ( hv(a1), 11915877628236072130ULL );
BOOST_TEST_EQ( hv(a2), 17303869719317669699ULL );
BOOST_TEST_EQ( hv(a3), 14973878137098559850ULL );
#endif
}
@@ -267,19 +284,19 @@ int main()
// string
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::string()), 0 );
BOOST_TEST_EQ( hv(std::string("abc")), 1849538372U );
BOOST_TEST_EQ( hv(std::string("\0", 1)), 3864292196U );
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 2842917718U );
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 325752138U );
BOOST_TEST_EQ( hv(std::string()), 1868390524U );
BOOST_TEST_EQ( hv(std::string("abc")), 3674866719U );
BOOST_TEST_EQ( hv(std::string("\0", 1)), 1965885047U );
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 54340706U );
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 688730713U );
#else
BOOST_TEST_EQ( hv(std::string()), 0 );
BOOST_TEST_EQ( hv(std::string("abc")), 6420922261882292859ULL );
BOOST_TEST_EQ( hv(std::string("\0", 1)), 3864292196ULL );
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 17867750819888810972ULL );
BOOST_TEST_EQ( hv(std::string()), 2060355526954642342ULL );
BOOST_TEST_EQ( hv(std::string("abc")), 2539195663733406973ULL );
BOOST_TEST_EQ( hv(std::string("\0", 1)), 18432168439372857722ULL );
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 6494115972580589074ULL );
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 4419026507380069870ULL );
#endif
@@ -290,17 +307,18 @@ int main()
// complex<int>
BOOST_TEST_EQ( hv(std::complex<int>(0, 0)), 0U );
BOOST_TEST_EQ( hv(std::complex<int>(+1, 0)), 1U );
BOOST_TEST_EQ( hv(std::complex<int>(0, +1)), 65U );
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::complex<int>(0, +1)), 2261973619U );
BOOST_TEST_EQ( hv(std::complex<int>(-1, 0)), 4294967295U );
BOOST_TEST_EQ( hv(std::complex<int>(0, -1)), 3221225536U );
BOOST_TEST_EQ( hv(std::complex<int>(0, -1)), 2578835075U );
#else
BOOST_TEST_EQ( hv(std::complex<int>(0, +1)), 4326460912318144697U );
BOOST_TEST_EQ( hv(std::complex<int>(-1, 0)), 18446744073709551615ULL );
BOOST_TEST_EQ( hv(std::complex<int>(0, -1)), 13835058055282163776ULL );
BOOST_TEST_EQ( hv(std::complex<int>(0, -1)), 10400452472442790416ULL );
#endif
@@ -311,13 +329,13 @@ int main()
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, +1.0f)), 3495952384U );
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, -1.0f)), 2959081472U );
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, +1.0f)), 1867597054U );
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, -1.0f)), 1969397420U );
#else
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, +1.0f)), 67920461824ULL );
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, -1.0f)), 209117511680ULL );
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, +1.0f)), 15274800114361806457ULL );
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, -1.0f)), 4238815378092176215ULL );
#endif
@@ -326,49 +344,49 @@ int main()
#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)), 3220176896U );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, +1.0)), 873201664U );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, -1.0)), 2483814400U );
BOOST_TEST_EQ( hv(std::complex<double>(+1.0, 0.0)), 2619008688U );
BOOST_TEST_EQ( hv(std::complex<double>(-1.0, 0.0)), 146497060U );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, +1.0)), 22395692U );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, -1.0)), 1449221192U );
#else
BOOST_TEST_EQ( hv(std::complex<double>(+1.0, 0.0)), 4607182418800017408ULL );
BOOST_TEST_EQ( hv(std::complex<double>(-1.0, 0.0)), 13830554455654793216ULL );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, +1.0)), 3750372589692780544ULL );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, -1.0)), 10667901617333862400ULL );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, +1.0)), 837908647691372762ULL );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, -1.0)), 3605795203555706515ULL );
#endif
// pair
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::make_pair(0, 0)), 2842917718U );
BOOST_TEST_EQ( hv(std::make_pair(1, 2)), 2507434894U );
BOOST_TEST_EQ( hv(std::make_pair(-1, -2)), 1874100199 );
BOOST_TEST_EQ( hv(std::make_pair(0, 0)), 3385628684U );
BOOST_TEST_EQ( hv(std::make_pair(1, 2)), 1013020961U );
BOOST_TEST_EQ( hv(std::make_pair(-1, -2)), 1207763712U );
#else
BOOST_TEST_EQ( hv(std::make_pair(0, 0)), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(std::make_pair(1, 2)), 3370697991563800380ULL );
BOOST_TEST_EQ( hv(std::make_pair(-1, -2)), 4139767141999124554ULL );
BOOST_TEST_EQ( hv(std::make_pair(0, 0)), 17303869719317669699ULL );
BOOST_TEST_EQ( hv(std::make_pair(1, 2)), 3509426265802930590ULL );
BOOST_TEST_EQ( hv(std::make_pair(-1, -2)), 9712138927275741808ULL );
#endif
// vector<char>
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::vector<char>(0)), 0 );
BOOST_TEST_EQ( hv(std::vector<char>(1)), 3864292196U );
BOOST_TEST_EQ( hv(std::vector<char>(2)), 2842917718U );
BOOST_TEST_EQ( hv(std::vector<char>(3)), 325752138U );
BOOST_TEST_EQ( hv(std::vector<char>(0)), 1868390524U );
BOOST_TEST_EQ( hv(std::vector<char>(1)), 1965885047U );
BOOST_TEST_EQ( hv(std::vector<char>(2)), 54340706U );
BOOST_TEST_EQ( hv(std::vector<char>(3)), 688730713U );
#else
BOOST_TEST_EQ( hv(std::vector<char>(0)), 0 );
BOOST_TEST_EQ( hv(std::vector<char>(1)), 3864292196ULL );
BOOST_TEST_EQ( hv(std::vector<char>(2)), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(std::vector<char>(3)), 17867750819888810972ULL );
BOOST_TEST_EQ( hv(std::vector<char>(0)), 2060355526954642342ULL );
BOOST_TEST_EQ( hv(std::vector<char>(1)), 18432168439372857722ULL );
BOOST_TEST_EQ( hv(std::vector<char>(2)), 6494115972580589074ULL );
BOOST_TEST_EQ( hv(std::vector<char>(3)), 4419026507380069870ULL );
#endif
@@ -376,16 +394,16 @@ int main()
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::vector<int>(0)), 0 );
BOOST_TEST_EQ( hv(std::vector<int>(1)), 3864292196U );
BOOST_TEST_EQ( hv(std::vector<int>(2)), 2842917718U );
BOOST_TEST_EQ( hv(std::vector<int>(3)), 325752138U );
BOOST_TEST_EQ( hv(std::vector<int>(1)), 1684164658U );
BOOST_TEST_EQ( hv(std::vector<int>(2)), 3385628684U );
BOOST_TEST_EQ( hv(std::vector<int>(3)), 354805152U );
#else
BOOST_TEST_EQ( hv(std::vector<int>(0)), 0 );
BOOST_TEST_EQ( hv(std::vector<int>(1)), 3864292196ULL );
BOOST_TEST_EQ( hv(std::vector<int>(2)), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(std::vector<int>(3)), 17867750819888810972ULL );
BOOST_TEST_EQ( hv(std::vector<int>(1)), 11915877628236072130ULL );
BOOST_TEST_EQ( hv(std::vector<int>(2)), 17303869719317669699ULL );
BOOST_TEST_EQ( hv(std::vector<int>(3)), 14973878137098559850ULL );
#endif
@@ -393,33 +411,33 @@ int main()
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(0)), 0 );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(1)), 3864292196U );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(2)), 2842917718U );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(3)), 325752138U );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(1)), 1684164658U );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(2)), 3385628684U );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(3)), 354805152U );
#else
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(0)), 0 );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(1)), 3864292196ULL );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(2)), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(3)), 17867750819888810972ULL );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(1)), 11915877628236072130ULL );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(2)), 17303869719317669699ULL );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(3)), 14973878137098559850ULL );
#endif
// list<char>
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::list<char>(0)), 0 );
BOOST_TEST_EQ( hv(std::list<char>(1)), 3864292196U );
BOOST_TEST_EQ( hv(std::list<char>(2)), 2842917718U );
BOOST_TEST_EQ( hv(std::list<char>(3)), 325752138U );
BOOST_TEST_EQ( hv(std::list<char>(0)), 1868390524U );
BOOST_TEST_EQ( hv(std::list<char>(1)), 1965885047U );
BOOST_TEST_EQ( hv(std::list<char>(2)), 54340706U );
BOOST_TEST_EQ( hv(std::list<char>(3)), 688730713U );
#else
BOOST_TEST_EQ( hv(std::list<char>(0)), 0 );
BOOST_TEST_EQ( hv(std::list<char>(1)), 3864292196ULL );
BOOST_TEST_EQ( hv(std::list<char>(2)), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(std::list<char>(3)), 17867750819888810972ULL );
BOOST_TEST_EQ( hv(std::list<char>(0)), 2060355526954642342ULL );
BOOST_TEST_EQ( hv(std::list<char>(1)), 18432168439372857722ULL );
BOOST_TEST_EQ( hv(std::list<char>(2)), 6494115972580589074ULL );
BOOST_TEST_EQ( hv(std::list<char>(3)), 4419026507380069870ULL );
#endif
@@ -427,16 +445,16 @@ int main()
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::list<int>(0)), 0 );
BOOST_TEST_EQ( hv(std::list<int>(1)), 3864292196U );
BOOST_TEST_EQ( hv(std::list<int>(2)), 2842917718U );
BOOST_TEST_EQ( hv(std::list<int>(3)), 325752138U );
BOOST_TEST_EQ( hv(std::list<int>(1)), 1684164658U );
BOOST_TEST_EQ( hv(std::list<int>(2)), 3385628684U );
BOOST_TEST_EQ( hv(std::list<int>(3)), 354805152U );
#else
BOOST_TEST_EQ( hv(std::list<int>(0)), 0 );
BOOST_TEST_EQ( hv(std::list<int>(1)), 3864292196ULL );
BOOST_TEST_EQ( hv(std::list<int>(2)), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(std::list<int>(3)), 17867750819888810972ULL );
BOOST_TEST_EQ( hv(std::list<int>(1)), 11915877628236072130ULL );
BOOST_TEST_EQ( hv(std::list<int>(2)), 17303869719317669699ULL );
BOOST_TEST_EQ( hv(std::list<int>(3)), 14973878137098559850ULL );
#endif

View File

@@ -0,0 +1,42 @@
// Copyright 2021, 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.hpp>
#include <string>
void test( unsigned char ch )
{
typedef boost::hash<std::string> hash;
int const N = 32;
std::size_t h[ N ];
std::string v;
for( int i = 0; i < N; ++i )
{
h[ i ] = hash()( v );
BOOST_TEST_EQ( h[ i ], hash()( v ) );
for( int j = 0; j < i; ++j )
{
BOOST_TEST_NE( h[ j ], h[ i ] );
}
v.push_back( static_cast<char>( ch ) );
}
}
int main()
{
for( unsigned ch = 0; ch < 256; ++ch )
{
test( static_cast<unsigned char>( ch ) );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,41 @@
// Copyright 2021, 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.hpp>
#include <string>
#include <cstddef>
void test( std::size_t n, unsigned char ch )
{
typedef boost::hash<std::string> hash;
std::string const v( n, static_cast<char>( ch ) );
for( std::size_t i = 0; i < n * 8; ++i )
{
std::string w( v );
unsigned char ch2 = static_cast<unsigned char>( w[ i / 8 ] );
ch2 = static_cast<unsigned char>( ch2 ^ ( 1 << ( i % 8 ) ) );
w[ i / 8 ] = static_cast<char>( ch2 );
BOOST_TEST_NE( hash()( v ), hash()( w ) );
}
}
int main()
{
for( unsigned ch = 0; ch < 256; ++ch )
{
for( std::size_t n = 1; n < 32; ++n )
{
test( n, static_cast<unsigned char>( ch ) );
}
}
return boost::report_errors();
}

View File

@@ -0,0 +1,204 @@
// 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 "-Wmismatched-tags"
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/type_traits/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/config.hpp>
#include <utility>
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
#include <tuple>
namespace user
{
struct Y1
{
int a;
int b;
};
template<std::size_t I> int& get( Y1& v );
template<std::size_t I> int const& get( Y1 const& v );
template<> int& get<0>( Y1& v )
{
return v.a;
}
template<> int const& get<0>( Y1 const& v )
{
return v.a;
}
template<> int& get<1>( Y1& v )
{
return v.b;
}
template<> int const& get<1>( Y1 const& v )
{
return v.b;
}
struct Y2
{
int a;
int b;
template<class T> friend
typename boost::enable_if_<boost::is_same<T, Y2>::value, std::size_t>::type
hash_value( T const& v )
{
std::size_t seed = 0;
boost::hash_combine( seed, v.a );
boost::hash_combine( seed, v.b );
return seed;
}
};
} // namespace user
namespace std
{
template<> struct tuple_size<user::Y1>: std::integral_constant<std::size_t, 2>
{
};
template<> struct tuple_size<user::Y2>: std::integral_constant<std::size_t, 2>
{
};
} // namespace std
namespace boost
{
namespace container_hash
{
template<> struct is_tuple_like<user::Y2>: boost::false_type {};
} // namespace container_hash
} // namespace boost
#endif
template<class T> std::size_t hv( T const& t )
{
return boost::hash<T>()( t );
}
int main()
{
{
std::pair<int, int> tp( 1, 2 );
int const a[] = { 1, 2 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
{
std::tuple<> tp;
BOOST_TEST_EQ( hv(tp), 0u );
}
{
std::tuple<int> tp( 1 );
int const a[] = { 1 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int> tp( 1, 2 );
int const a[] = { 1, 2 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int, int> tp( 1, 2, 3 );
int const a[] = { 1, 2, 3 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int, int, int> tp( 1, 2, 3, 4 );
int const a[] = { 1, 2, 3, 4 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int, int, int, int> tp( 1, 2, 3, 4, 5 );
int const a[] = { 1, 2, 3, 4, 5 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6 );
int const a[] = { 1, 2, 3, 4, 5, 6 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6, 7 );
int const a[] = { 1, 2, 3, 4, 5, 6, 7 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int, int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6, 7, 8 );
int const a[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int, int, int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6, 7, 8, 9 );
int const a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1800)
{
user::Y1 tp = { 1, 2 };
int const a[] = { 1, 2 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
#endif
{
user::Y2 tp = { 1, 2 };
int const a[] = { 1, 2 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,78 @@
// 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 "-Wmismatched-tags"
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/describe/class.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#include <utility>
#if defined(BOOST_NO_CXX11_HDR_TUPLE)
BOOST_PRAGMA_MESSAGE( "Skipping test because BOOST_NO_CXX11_HDR_TUPLE is defined" )
int main() {}
#elif !defined(BOOST_DESCRIBE_CXX14)
BOOST_PRAGMA_MESSAGE( "Skipping test because BOOST_DESCRIBE_CXX14 is not defined" )
int main() {}
#else
namespace user
{
struct Y3
{
int a;
int b;
};
BOOST_DESCRIBE_STRUCT(Y3, (), (a, b))
} // namespace user
namespace std
{
template<> struct tuple_size<user::Y3>: std::integral_constant<std::size_t, 2>
{
};
} // namespace std
namespace boost
{
namespace container_hash
{
template<> struct is_tuple_like<user::Y3>: boost::false_type {};
} // namespace container_hash
} // namespace boost
template<class T> std::size_t hv( T const& t )
{
return boost::hash<T>()( t );
}
int main()
{
{
user::Y3 tp = { 1, 2 };
int const a[] = { 1, 2 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
return boost::report_errors();
}
#endif

View File

@@ -0,0 +1,63 @@
// Copyright 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/detail/splitmix64.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP)
BOOST_PRAGMA_MESSAGE( "Test skipped, BOOST_NO_CXX11_HDR_UNORDERED_MAP is defined" )
int main() {}
#elif defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520
BOOST_PRAGMA_MESSAGE( "Test skipped, _CPPLIB_VER >= 520 and BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined" )
int main() {}
#else
#include <unordered_map>
template<class T> std::size_t hv( T const& x )
{
return boost::hash<T>()( x );
}
template<class T> void test()
{
typedef std::unordered_map<T, T> set;
int const N = 256;
set v;
boost::detail::splitmix64 rng;
for( int i = 0; i < N; ++i )
{
BOOST_TEST_EQ( hv( v ), boost::hash_unordered_range( v.begin(), v.end() ) );
T x = static_cast<T>( rng() );
v.insert( std::pair<T const, T>( x, x ) );
}
}
int main()
{
test<unsigned>();
test<boost::uint64_t>();
test<float>();
test<double>();
return boost::report_errors();
}
#endif

View File

@@ -0,0 +1,63 @@
// Copyright 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP)
BOOST_PRAGMA_MESSAGE( "Test skipped, BOOST_NO_CXX11_HDR_UNORDERED_MAP is defined" )
int main() {}
#elif defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520
BOOST_PRAGMA_MESSAGE( "Test skipped, _CPPLIB_VER >= 520 and BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined" )
int main() {}
#else
#include <unordered_map>
template<class T> void test()
{
typedef std::unordered_multimap<T, T> map;
typedef boost::hash<map> hash;
int const N = 32;
std::size_t h[ N ];
map v;
for( int i = 0; i < N; ++i )
{
h[ i ] = hash()( v );
BOOST_TEST_EQ( h[ i ], hash()( v ) );
for( int j = 0; j < i; ++j )
{
BOOST_TEST_NE( h[ j ], h[ i ] );
}
v.insert( std::pair<T const, T>() );
}
}
int main()
{
test<int>();
test<float>();
test<double>();
return boost::report_errors();
}
#endif

View File

@@ -0,0 +1,63 @@
// Copyright 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX11_HDR_UNORDERED_SET)
BOOST_PRAGMA_MESSAGE( "Test skipped, BOOST_NO_CXX11_HDR_UNORDERED_SET is defined" )
int main() {}
#elif defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520
BOOST_PRAGMA_MESSAGE( "Test skipped, _CPPLIB_VER >= 520 and BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined" )
int main() {}
#else
#include <unordered_set>
template<class T> void test()
{
typedef std::unordered_multiset<T> set;
typedef boost::hash<set> hash;
int const N = 32;
std::size_t h[ N ];
set v;
for( int i = 0; i < N; ++i )
{
h[ i ] = hash()( v );
BOOST_TEST_EQ( h[ i ], hash()( v ) );
for( int j = 0; j < i; ++j )
{
BOOST_TEST_NE( h[ j ], h[ i ] );
}
v.insert( T() );
}
}
int main()
{
test<int>();
test<float>();
test<double>();
return boost::report_errors();
}
#endif

View File

@@ -0,0 +1,33 @@
// Copyright 2021, 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.hpp>
#include <algorithm>
#include <vector>
int main()
{
int const N = 16;
std::vector<int> v;
for( int i = 0; i < N; ++i )
{
v.push_back( i );
}
std::size_t h0 = boost::hash_unordered_range( v.begin(), v.end() );
int const M = 256;
for( int i = 0; i < M; ++i )
{
std::next_permutation( v.begin(), v.end() );
std::size_t h1 = boost::hash_unordered_range( v.begin(), v.end() );
BOOST_TEST_EQ( h0, h1 );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,61 @@
// Copyright 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/detail/splitmix64.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX11_HDR_UNORDERED_SET)
BOOST_PRAGMA_MESSAGE( "Test skipped, BOOST_NO_CXX11_HDR_UNORDERED_SET is defined" )
int main() {}
#elif defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520
BOOST_PRAGMA_MESSAGE( "Test skipped, _CPPLIB_VER >= 520 and BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined" )
int main() {}
#else
#include <unordered_set>
template<class T> std::size_t hv( T const& x )
{
return boost::hash<T>()( x );
}
template<class T> void test()
{
typedef std::unordered_set<T> set;
int const N = 256;
set v;
boost::detail::splitmix64 rng;
for( int i = 0; i < N; ++i )
{
BOOST_TEST_EQ( hv( v ), boost::hash_unordered_range( v.begin(), v.end() ) );
v.insert( static_cast<T>( rng() ) );
}
}
int main()
{
test<unsigned>();
test<boost::uint64_t>();
test<float>();
test<double>();
return boost::report_errors();
}
#endif

View File

@@ -0,0 +1,48 @@
// Copyright 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <vector>
#include <functional> // to catch msvc-14.1 conflicts
template<class T> void test()
{
typedef std::vector<T> list;
typedef boost::hash<list> hash;
int const N = 32;
std::size_t h[ N ];
list v;
for( int i = 0; i < N; ++i )
{
h[ i ] = hash()( v );
BOOST_TEST_EQ( h[ i ], hash()( v ) );
for( int j = 0; j < i; ++j )
{
BOOST_TEST_NE( h[ j ], h[ i ] );
}
v.push_back( T() );
}
}
int main()
{
test<int>();
test<float>();
test<double>();
test< std::vector<int> >();
return boost::report_errors();
}

View File

@@ -2,7 +2,7 @@
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/container_hash/detail/is_contiguous_range.hpp>
#include <boost/container_hash/is_contiguous_range.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config.hpp>
#include <string>
@@ -30,7 +30,7 @@ struct X
int main()
{
using boost::hash_detail::is_contiguous_range;
using boost::container_hash::is_contiguous_range;
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<void>));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<void const>));
@@ -50,11 +50,11 @@ int main()
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<std::wstring>));
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)
BOOST_TEST_TRAIT_TRUE((is_contiguous_range< std::vector<X> >));
BOOST_TEST_TRAIT_TRUE((is_contiguous_range< std::vector<X> const >));
#endif
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::vector<bool> >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::vector<bool> const >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::deque<X> >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::deque<X> const >));

View File

@@ -0,0 +1,63 @@
// 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 <cstddef>
struct X1
{
char const* begin() const;
char const* end() const;
char const* data() const;
std::size_t size() const;
};
struct X2
{
char const* begin() const;
char const* end() const;
char const* data() const;
std::size_t size() const;
};
struct X3
{
char const* begin() const;
char const* end() const;
char const* data() const;
std::size_t size() const;
};
namespace boost
{
namespace container_hash
{
template<class T> struct is_contiguous_range;
template<> struct is_contiguous_range<X2>: boost::false_type {};
template<class T> struct is_range;
template<> struct is_range<X3>: boost::false_type {};
} // namespace container_hash
} // namespace boost
#include <boost/container_hash/is_contiguous_range.hpp>
#include <boost/core/lightweight_test_trait.hpp>
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) && !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<X1>));
#endif
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<X2>));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<X3>));
return boost::report_errors();
}

View 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();
}

View 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();
}

View 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();
}

View 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();
}

View File

@@ -2,7 +2,7 @@
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/container_hash/detail/is_range.hpp>
#include <boost/container_hash/is_range.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config.hpp>
#include <string>
@@ -30,7 +30,7 @@ struct X
int main()
{
using boost::hash_detail::is_range;
using boost::container_hash::is_range;
BOOST_TEST_TRAIT_FALSE((is_range<void>));
BOOST_TEST_TRAIT_FALSE((is_range<void const>));

View File

@@ -10,7 +10,7 @@
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#include <boost/container_hash/detail/is_range.hpp>
#include <boost/container_hash/is_range.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config.hpp>
#include <boost/filesystem/path.hpp>
@@ -21,7 +21,7 @@
int main()
{
using boost::hash_detail::is_range;
using boost::container_hash::is_range;
BOOST_TEST_TRAIT_FALSE((is_range< boost::filesystem::path >));
BOOST_TEST_TRAIT_FALSE((is_range< boost::filesystem::path const >));

46
test/is_range_test3.cpp Normal file
View File

@@ -0,0 +1,46 @@
// 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>
struct X1
{
char const* begin() const;
char const* end() const;
};
struct X2
{
char const* begin() const;
char const* end() const;
};
namespace boost
{
namespace container_hash
{
template<class T> struct is_range;
template<> struct is_range<X2>: boost::false_type {};
} // namespace container_hash
} // namespace boost
#include <boost/container_hash/is_range.hpp>
#include <boost/core/lightweight_test_trait.hpp>
int main()
{
using boost::container_hash::is_range;
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700)
BOOST_TEST_TRAIT_TRUE((is_range<X1>));
#endif
BOOST_TEST_TRAIT_FALSE((is_range<X2>));
return boost::report_errors();
}

View File

@@ -0,0 +1,91 @@
// Copyright 2017, 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 "-Wmismatched-tags"
#endif
#include <boost/container_hash/is_tuple_like.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <utility>
struct X
{
};
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
#include <tuple>
namespace user
{
struct Y
{
int a;
int b;
};
template<std::size_t I> int& get( Y& v );
template<std::size_t I> int const& get( Y const& v );
template<> int& get<0>( Y& v )
{
return v.a;
}
template<> int const& get<0>( Y const& v )
{
return v.a;
}
template<> int& get<1>( Y& v )
{
return v.b;
}
template<> int const& get<1>( Y const& v )
{
return v.b;
}
} // namespace user
namespace std
{
template<> struct tuple_size<user::Y>: std::integral_constant<std::size_t, 2>
{
};
} // namespace std
#endif // #if !defined(BOOST_NO_CXX11_HDR_TUPLE)
int main()
{
using boost::container_hash::is_tuple_like;
BOOST_TEST_TRAIT_FALSE((is_tuple_like<void>));
BOOST_TEST_TRAIT_FALSE((is_tuple_like<int>));
BOOST_TEST_TRAIT_FALSE((is_tuple_like<X>));
BOOST_TEST_TRAIT_FALSE((is_tuple_like<int[2]>));
#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && !BOOST_WORKAROUND(BOOST_MSVC, <= 1800)
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::pair<int, X> >));
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<> >));
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<X> >));
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<X, X> >));
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<X, X, X> >));
BOOST_TEST_TRAIT_TRUE((is_tuple_like<user::Y>));
#endif
return boost::report_errors();
}

View File

@@ -2,7 +2,7 @@
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/container_hash/detail/is_unordered_range.hpp>
#include <boost/container_hash/is_unordered_range.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config.hpp>
#include <string>
@@ -30,7 +30,7 @@ struct X
int main()
{
using boost::hash_detail::is_unordered_range;
using boost::container_hash::is_unordered_range;
BOOST_TEST_TRAIT_FALSE((is_unordered_range<void>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range<void const>));

View File

@@ -0,0 +1,60 @@
// 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 <cstddef>
struct X1
{
char const* begin() const;
char const* end() const;
typedef void hasher;
};
struct X2
{
char const* begin() const;
char const* end() const;
typedef void hasher;
};
struct X3
{
char const* begin() const;
char const* end() const;
typedef void hasher;
};
namespace boost
{
namespace container_hash
{
template<class T> struct is_unordered_range;
template<> struct is_unordered_range<X2>: boost::false_type {};
template<class T> struct is_range;
template<> struct is_range<X3>: boost::false_type {};
} // namespace container_hash
} // namespace boost
#include <boost/container_hash/is_unordered_range.hpp>
#include <boost/core/lightweight_test_trait.hpp>
int main()
{
using boost::container_hash::is_unordered_range;
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700)
BOOST_TEST_TRAIT_TRUE((is_unordered_range<X1>));
#endif
BOOST_TEST_TRAIT_FALSE((is_unordered_range<X2>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range<X3>));
return boost::report_errors();
}