mirror of
https://github.com/boostorg/container_hash.git
synced 2026-05-28 11:32:46 +02:00
Compare commits
163 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2698b43803 | |||
| c745320880 | |||
| e32dbe5013 | |||
| 1e51179fc7 | |||
| 3e27ff182c | |||
| 68fabb1a8e | |||
| 8d5ae8536f | |||
| e3cbbebc8a | |||
| 12f8284c1a | |||
| 07fdcf16cb | |||
| bd3084a1c9 | |||
| 3a0f818eb8 | |||
| b2cb43dca0 | |||
| 828a53d8a4 | |||
| 060d4aea6b | |||
| 186c38e255 | |||
| c8dab7f85a | |||
| 5d8b8ac2b9 | |||
| 1e1cf6c46e | |||
| 88aacb6d46 | |||
| 0a000167b7 | |||
| d8f1075080 | |||
| b8179488b2 | |||
| edd436231a | |||
| d56fc37fe5 | |||
| fa6601f974 | |||
| 89e5b98f6b | |||
| 1193ed067c | |||
| f85cb77bd3 | |||
| 7d68e5f1d2 | |||
| 3c9ce69f92 | |||
| aa2e8b3674 | |||
| c3cb5896fc | |||
| 58cd5e35b1 | |||
| 386d007088 | |||
| b8090f9b87 | |||
| a5c2949670 | |||
| b16f42ef10 | |||
| de85b0c248 | |||
| 583e14413c | |||
| ef914e1b34 | |||
| ee5285bfa6 | |||
| 0a9803dffe | |||
| 881448f75e | |||
| c5b1f4894c | |||
| 6d214eb776 | |||
| b0d3107b99 | |||
| e2446b187e | |||
| 1dd2f73866 | |||
| 1278f1c2b5 | |||
| 067f636d6c | |||
| 338c053889 | |||
| 94d4f7cb88 | |||
| 6957a20ab1 | |||
| 28cc18a4bc | |||
| 7288df8bee | |||
| 5c2d5e5b36 | |||
| db8743e1c3 | |||
| 48a306dcf2 | |||
| f6279a0615 | |||
| 41746c0bdb | |||
| 07a0910640 | |||
| 4c32071739 | |||
| 30c05c93b1 | |||
| 197f75845c | |||
| bf8ad2c0ee | |||
| fef60938e5 | |||
| f04d866fa7 | |||
| 17201433f8 | |||
| 9d09674f08 | |||
| f8ecd66820 | |||
| 565bac8d31 | |||
| b8496de2f2 | |||
| 641a59342e | |||
| 226eb066e9 | |||
| d9cb23d96a | |||
| bd8a5cb867 | |||
| b43ce472fa | |||
| e798972130 | |||
| ebb49fa459 | |||
| 1e1c0ea38c | |||
| e62a268566 | |||
| ad89c02360 | |||
| 64948e5f57 | |||
| 1958e96561 | |||
| 4a7287d371 | |||
| 5638134081 | |||
| 7c49f0bfb1 | |||
| 9ae5790657 | |||
| 8ce81c361d | |||
| 4315faf470 | |||
| eb049e0cae | |||
| 6373656710 | |||
| ec1503bbc8 | |||
| ee064dc7f8 | |||
| b505e06b3c | |||
| 6075f3e1f5 | |||
| 0bfeabfd63 | |||
| 758596533d | |||
| 640bd48f51 | |||
| b25fd745ca | |||
| 6fe3469a8b | |||
| c07630ac60 | |||
| 45270ae11e | |||
| 5bef4901b9 | |||
| d724bcd0ef | |||
| ceb8303601 | |||
| cf87e304f6 | |||
| 4d9f7b8931 | |||
| 2f4efbced4 | |||
| bf7a78594e | |||
| c0c70e5b3e | |||
| 891a64d45d | |||
| 08d69c31b1 | |||
| 6526b24900 | |||
| 1a8dca4f2c | |||
| 8761157a19 | |||
| f2b2ef4ebe | |||
| 30560ada18 | |||
| c61a4f691e | |||
| fe28cdbd1f | |||
| f98b943585 | |||
| 4aeb7b2285 | |||
| e310932a9c | |||
| 558d0ead17 | |||
| d6905ab159 | |||
| 251894540d | |||
| ffadafa0c1 | |||
| ce166d1030 | |||
| 8ab83c1cd4 | |||
| 16546190f6 | |||
| 5e26a3b807 | |||
| bd5b7a359c | |||
| f5f5476dcc | |||
| 228f7db5d3 | |||
| f50b914456 | |||
| c134ca39e9 | |||
| f51f68fe93 | |||
| 0865c1d230 | |||
| 0d2266decb | |||
| 3c9ba89cf2 | |||
| 20ee3b60fd | |||
| bdd3dcf944 | |||
| 018fc4e1fa | |||
| 7568176bfa | |||
| 08864cd1e9 | |||
| 5a616b9b54 | |||
| 16fb4cc749 | |||
| 0171246a61 | |||
| 29c85559e4 | |||
| 412bd51449 | |||
| 87196a503e | |||
| df1671d593 | |||
| 1996cf36c1 | |||
| a4b2048a29 | |||
| 85f9f8a97a | |||
| e92eae9eb2 | |||
| 8a1335458a | |||
| f7e537d1a1 | |||
| 607b73f1e0 | |||
| 789261c68c | |||
| 29ee19ee7f | |||
| 8bb7d43646 |
+11
-14
@@ -16,10 +16,7 @@ branches:
|
|||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||||
TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0
|
TOOLSET: msvc-14.0
|
||||||
ADDRMD: 32
|
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
|
||||||
TOOLSET: msvc-12.0,msvc-14.0
|
|
||||||
ADDRMD: 32,64
|
ADDRMD: 32,64
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
TOOLSET: msvc-14.1
|
TOOLSET: msvc-14.1
|
||||||
@@ -28,7 +25,7 @@ environment:
|
|||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
TOOLSET: clang-win
|
TOOLSET: clang-win
|
||||||
ADDRMD: 64
|
ADDRMD: 64
|
||||||
CXXSTD: 14,17,latest
|
CXXSTD: 14,17
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||||
TOOLSET: clang-win
|
TOOLSET: clang-win
|
||||||
CXXSTD: 14,17,latest
|
CXXSTD: 14,17,latest
|
||||||
@@ -36,19 +33,19 @@ environment:
|
|||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||||
ADDPATH: C:\cygwin\bin;
|
ADDPATH: C:\cygwin\bin;
|
||||||
TOOLSET: gcc
|
TOOLSET: gcc
|
||||||
CXXSTD: 03,11,14,1z
|
CXXSTD: 11,14,1z
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||||
ADDPATH: C:\cygwin64\bin;
|
ADDPATH: C:\cygwin64\bin;
|
||||||
TOOLSET: gcc
|
TOOLSET: gcc
|
||||||
CXXSTD: 03,11,14,1z
|
CXXSTD: 11,14,17
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||||
ADDPATH: C:\mingw\bin;
|
ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin;
|
||||||
TOOLSET: gcc
|
TOOLSET: gcc
|
||||||
CXXSTD: 03,11,14,1z
|
CXXSTD: 11,14,17
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||||
ADDPATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin;
|
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
|
||||||
TOOLSET: gcc
|
TOOLSET: gcc
|
||||||
CXXSTD: 03,11,14,1z
|
CXXSTD: 11,14,17
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- set BOOST_BRANCH=develop
|
- set BOOST_BRANCH=develop
|
||||||
|
|||||||
+309
-42
@@ -32,9 +32,10 @@ local linux_pipeline(name, image, environment, packages = "", sources = [], arch
|
|||||||
commands:
|
commands:
|
||||||
[
|
[
|
||||||
'set -e',
|
'set -e',
|
||||||
'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -',
|
'uname -a',
|
||||||
|
'echo $DRONE_STAGE_MACHINE',
|
||||||
] +
|
] +
|
||||||
(if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) +
|
(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 []) +
|
(if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) +
|
||||||
[
|
[
|
||||||
'export LIBRARY=' + library,
|
'export LIBRARY=' + library,
|
||||||
@@ -96,94 +97,342 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
|||||||
};
|
};
|
||||||
|
|
||||||
[
|
[
|
||||||
linux_pipeline(
|
|
||||||
"Linux 14.04 GCC 4.4",
|
|
||||||
"cppalliance/droneubuntu1404:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.4', CXXSTD: '98,0x' },
|
|
||||||
"g++-4.4",
|
|
||||||
[ "ppa:ubuntu-toolchain-r/test" ],
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 14.04 GCC 4.6 32/64",
|
|
||||||
"cppalliance/droneubuntu1404:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.6', CXXSTD: '98,0x', ADDRMD: '32,64' },
|
|
||||||
"g++-4.6-multilib",
|
|
||||||
[ "ppa:ubuntu-toolchain-r/test" ],
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
linux_pipeline(
|
||||||
"Linux 14.04 GCC 4.7 32/64",
|
"Linux 14.04 GCC 4.7 32/64",
|
||||||
"cppalliance/droneubuntu1404:1",
|
"cppalliance/droneubuntu1404:1",
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.7', CXXSTD: '98,0x', ADDRMD: '32,64' },
|
{ TOOLSET: 'gcc', COMPILER: 'g++-4.7', CXXSTD: '0x', ADDRMD: '32,64' },
|
||||||
"g++-4.7-multilib",
|
"g++-4.7-multilib",
|
||||||
[ "ppa:ubuntu-toolchain-r/test" ],
|
|
||||||
),
|
),
|
||||||
|
|
||||||
linux_pipeline(
|
linux_pipeline(
|
||||||
"Linux 14.04 GCC 4.8* 32/64",
|
"Linux 14.04 GCC 4.8* 32/64",
|
||||||
"cppalliance/droneubuntu1404:1",
|
"cppalliance/droneubuntu1404:1",
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11', ADDRMD: '32,64' },
|
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11', ADDRMD: '32,64' },
|
||||||
),
|
),
|
||||||
|
|
||||||
linux_pipeline(
|
linux_pipeline(
|
||||||
"Linux 14.04 GCC 4.9 32/64",
|
"Linux 16.04 GCC 4.9 32/64",
|
||||||
"cppalliance/droneubuntu1404:1",
|
"cppalliance/droneubuntu1604:1",
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.9', CXXSTD: '03,11', ADDRMD: '32,64' },
|
{ TOOLSET: 'gcc', COMPILER: 'g++-4.9', CXXSTD: '11', ADDRMD: '32,64' },
|
||||||
"g++-4.9-multilib",
|
"g++-4.9-multilib",
|
||||||
[ "ppa:ubuntu-toolchain-r/test" ],
|
|
||||||
),
|
),
|
||||||
|
|
||||||
linux_pipeline(
|
linux_pipeline(
|
||||||
"Linux 20.04 GCC 9 ARM64",
|
"Linux 16.04 GCC 5* 32/64",
|
||||||
|
"cppalliance/droneubuntu1604:1",
|
||||||
|
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '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",
|
"cppalliance/droneubuntu2004:multiarch",
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
|
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' },
|
||||||
arch="arm64",
|
arch="arm64",
|
||||||
),
|
),
|
||||||
|
|
||||||
linux_pipeline(
|
linux_pipeline(
|
||||||
"Linux 20.04 GCC 9 S390x",
|
"Linux 20.04 GCC 9* S390x",
|
||||||
"cppalliance/droneubuntu2004:multiarch",
|
"cppalliance/droneubuntu2004:multiarch",
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
|
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' },
|
||||||
arch="s390x",
|
arch="s390x",
|
||||||
),
|
),
|
||||||
|
|
||||||
linux_pipeline(
|
linux_pipeline(
|
||||||
"Linux 22.04 GCC 12 32 ASAN",
|
"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",
|
"cppalliance/droneubuntu2204:1",
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14,17,20', ADDRMD: '32' } + asan,
|
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a', ADDRMD: '32,64' },
|
||||||
|
),
|
||||||
|
|
||||||
|
linux_pipeline(
|
||||||
|
"Linux 22.04 GCC 12 32/64",
|
||||||
|
"cppalliance/droneubuntu2204:1",
|
||||||
|
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '11,14,17,20,2b', ADDRMD: '32,64' },
|
||||||
"g++-12-multilib",
|
"g++-12-multilib",
|
||||||
),
|
),
|
||||||
|
|
||||||
linux_pipeline(
|
linux_pipeline(
|
||||||
"Linux 22.04 GCC 12 64 ASAN",
|
"Linux 24.04 GCC 13 32/64 UBSAN",
|
||||||
"cppalliance/droneubuntu2204:1",
|
"cppalliance/droneubuntu2404:1",
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14,17,20', ADDRMD: '64' } + asan,
|
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '11,14,17,20,2b', ADDRMD: '32,64' } + ubsan,
|
||||||
"g++-12-multilib",
|
"g++-13-multilib",
|
||||||
),
|
),
|
||||||
|
|
||||||
linux_pipeline(
|
linux_pipeline(
|
||||||
"Linux 22.04 Clang 14 UBSAN",
|
"Linux 24.04 GCC 13 32 ASAN",
|
||||||
|
"cppalliance/droneubuntu2404:1",
|
||||||
|
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '11,14,17,20,2b', ADDRMD: '32' } + asan,
|
||||||
|
"g++-13-multilib",
|
||||||
|
),
|
||||||
|
|
||||||
|
linux_pipeline(
|
||||||
|
"Linux 24.04 GCC 14 UBSAN",
|
||||||
|
"cppalliance/droneubuntu2404:1",
|
||||||
|
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b' } + ubsan,
|
||||||
|
"g++-14-multilib",
|
||||||
|
),
|
||||||
|
|
||||||
|
linux_pipeline(
|
||||||
|
"Linux 24.04 GCC 14 ASAN",
|
||||||
|
"cppalliance/droneubuntu2404:1",
|
||||||
|
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b' } + asan,
|
||||||
|
"g++-14-multilib",
|
||||||
|
),
|
||||||
|
|
||||||
|
linux_pipeline(
|
||||||
|
"Linux 26.04 GCC 15 UBSAN",
|
||||||
|
"cppalliance/droneubuntu2604:1",
|
||||||
|
{ TOOLSET: 'gcc', COMPILER: 'g++-15', CXXSTD: '11,14,17,20,23,2c' } + ubsan,
|
||||||
|
"g++-15-multilib",
|
||||||
|
),
|
||||||
|
|
||||||
|
linux_pipeline(
|
||||||
|
"Linux 26.04 GCC 15 ASAN",
|
||||||
|
"cppalliance/droneubuntu2604:1",
|
||||||
|
{ TOOLSET: 'gcc', COMPILER: 'g++-15', CXXSTD: '11,14,17,20,23,2c' } + asan,
|
||||||
|
"g++-15-multilib",
|
||||||
|
),
|
||||||
|
|
||||||
|
linux_pipeline(
|
||||||
|
"Linux 26.04 GCC 16",
|
||||||
|
"cppalliance/droneubuntu2604:1",
|
||||||
|
{ TOOLSET: 'gcc', COMPILER: 'g++-16', CXXSTD: '11,14,17,20,23,2c' },
|
||||||
|
"g++-16-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",
|
"cppalliance/droneubuntu2204:1",
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20' } + ubsan,
|
{ 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",
|
"clang-14",
|
||||||
),
|
),
|
||||||
|
|
||||||
linux_pipeline(
|
linux_pipeline(
|
||||||
"Linux 22.04 Clang 14 ASAN",
|
"Linux 22.04 Clang 15",
|
||||||
"cppalliance/droneubuntu2204:1",
|
"cppalliance/droneubuntu2204:1",
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20' } + asan,
|
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '11,14,17,20,2b' },
|
||||||
"clang-14",
|
"clang-15",
|
||||||
|
),
|
||||||
|
|
||||||
|
linux_pipeline(
|
||||||
|
"Linux 24.04 Clang 16",
|
||||||
|
"cppalliance/droneubuntu2404:1",
|
||||||
|
{ TOOLSET: 'clang', COMPILER: 'clang++-16', CXXSTD: '11,14,17,20,2b' },
|
||||||
|
"clang-16",
|
||||||
|
),
|
||||||
|
|
||||||
|
linux_pipeline(
|
||||||
|
"Linux 24.04 Clang 17",
|
||||||
|
"cppalliance/droneubuntu2404:1",
|
||||||
|
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' },
|
||||||
|
"clang-17",
|
||||||
|
),
|
||||||
|
|
||||||
|
linux_pipeline(
|
||||||
|
"Linux 24.04 Clang 18",
|
||||||
|
"cppalliance/droneubuntu2404:1",
|
||||||
|
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' },
|
||||||
|
"clang-18",
|
||||||
|
),
|
||||||
|
|
||||||
|
linux_pipeline(
|
||||||
|
"Linux 24.04 Clang 19",
|
||||||
|
"cppalliance/droneubuntu2404:1",
|
||||||
|
{ TOOLSET: 'clang', COMPILER: 'clang++-19', CXXSTD: '11,14,17,20,2b' },
|
||||||
|
"clang-19",
|
||||||
|
),
|
||||||
|
|
||||||
|
linux_pipeline(
|
||||||
|
"Linux 24.04 Clang 20 UBSAN",
|
||||||
|
"cppalliance/droneubuntu2404:1",
|
||||||
|
{ TOOLSET: 'clang', COMPILER: 'clang++-20', CXXSTD: '11,14,17,20,23,2c' } + ubsan,
|
||||||
|
"clang-20",
|
||||||
|
),
|
||||||
|
|
||||||
|
linux_pipeline(
|
||||||
|
"Linux 24.04 Clang 20 ASAN",
|
||||||
|
"cppalliance/droneubuntu2404:1",
|
||||||
|
{ TOOLSET: 'clang', COMPILER: 'clang++-20', CXXSTD: '11,14,17,20,23,2c' } + asan,
|
||||||
|
"clang-20",
|
||||||
|
),
|
||||||
|
|
||||||
|
linux_pipeline(
|
||||||
|
"Linux 26.04 Clang 21",
|
||||||
|
"cppalliance/droneubuntu2604:1",
|
||||||
|
{ TOOLSET: 'clang', COMPILER: 'clang++-21', CXXSTD: '11,14,17,20,23,2c' },
|
||||||
|
"clang-21",
|
||||||
|
),
|
||||||
|
|
||||||
|
linux_pipeline(
|
||||||
|
"Linux 26.04 Clang 22",
|
||||||
|
"cppalliance/droneubuntu2604:1",
|
||||||
|
{ TOOLSET: 'clang', COMPILER: 'clang++-22', CXXSTD: '11,14,17,20,23,2c' },
|
||||||
|
"clang-22",
|
||||||
),
|
),
|
||||||
|
|
||||||
macos_pipeline(
|
macos_pipeline(
|
||||||
"MacOS 10.15 Xcode 12.2 UBSAN",
|
"MacOS 10.15 Xcode 12.2 UBSAN",
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + ubsan,
|
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,2a' } + ubsan,
|
||||||
),
|
),
|
||||||
|
|
||||||
macos_pipeline(
|
macos_pipeline(
|
||||||
"MacOS 10.15 Xcode 12.2 ASAN",
|
"MacOS 10.15 Xcode 12.2 ASAN",
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + 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', B2_DONT_EMBED_MANIFEST: '1' },
|
||||||
),
|
),
|
||||||
|
|
||||||
windows_pipeline(
|
windows_pipeline(
|
||||||
@@ -191,4 +440,22 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
|||||||
"cppalliance/dronevs2017",
|
"cppalliance/dronevs2017",
|
||||||
{ TOOLSET: 'msvc-14.1', CXXSTD: '14,17,latest' },
|
{ TOOLSET: 'msvc-14.1', CXXSTD: '14,17,latest' },
|
||||||
),
|
),
|
||||||
|
|
||||||
|
windows_pipeline(
|
||||||
|
"Windows VS2019 msvc-14.2",
|
||||||
|
"cppalliance/dronevs2019",
|
||||||
|
{ TOOLSET: 'msvc-14.2', CXXSTD: '14,17,20,latest' },
|
||||||
|
),
|
||||||
|
|
||||||
|
windows_pipeline(
|
||||||
|
"Windows VS2022 msvc-14.3",
|
||||||
|
"cppalliance/dronevs2022:1",
|
||||||
|
{ TOOLSET: 'msvc-14.3', CXXSTD: '14,17,20,latest' },
|
||||||
|
),
|
||||||
|
|
||||||
|
windows_pipeline(
|
||||||
|
"Windows VS2026 msvc-14.5",
|
||||||
|
"cppalliance/dronevs2026:1",
|
||||||
|
{ TOOLSET: 'msvc-14.5', CXXSTD: '14,17,20,latest' },
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
# https://www.boost.org/LICENSE_1_0.txt
|
# https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
set -ex
|
set -ex
|
||||||
|
export PATH=~/.local/bin:/usr/local/bin:$PATH
|
||||||
|
|
||||||
DRONE_BUILD_DIR=$(pwd)
|
DRONE_BUILD_DIR=$(pwd)
|
||||||
|
|
||||||
|
|||||||
+343
-97
@@ -17,120 +17,199 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- toolset: gcc-4.8
|
|
||||||
cxxstd: "03,11"
|
|
||||||
os: ubuntu-18.04
|
|
||||||
install: g++-4.8-multilib
|
|
||||||
address-model: 32,64
|
|
||||||
- toolset: gcc-5
|
|
||||||
cxxstd: "03,11,14,1z"
|
|
||||||
os: ubuntu-18.04
|
|
||||||
install: g++-5-multilib
|
|
||||||
address-model: 32,64
|
|
||||||
- toolset: gcc-6
|
|
||||||
cxxstd: "03,11,14,1z"
|
|
||||||
os: ubuntu-18.04
|
|
||||||
install: g++-6-multilib
|
|
||||||
address-model: 32,64
|
|
||||||
- toolset: gcc-7
|
- toolset: gcc-7
|
||||||
cxxstd: "03,11,14,17"
|
cxxstd: "11,14,17"
|
||||||
os: ubuntu-18.04
|
container: ubuntu:20.04
|
||||||
|
os: ubuntu-latest
|
||||||
install: g++-7-multilib
|
install: g++-7-multilib
|
||||||
address-model: 32,64
|
address-model: 32,64
|
||||||
- toolset: gcc-8
|
- toolset: gcc-8
|
||||||
cxxstd: "03,11,14,17,2a"
|
cxxstd: "11,14,17,2a"
|
||||||
os: ubuntu-18.04
|
container: ubuntu:20.04
|
||||||
|
os: ubuntu-latest
|
||||||
install: g++-8-multilib
|
install: g++-8-multilib
|
||||||
address-model: 32,64
|
address-model: 32,64
|
||||||
- toolset: gcc-9
|
- toolset: gcc-9
|
||||||
cxxstd: "03,11,14,17,2a"
|
cxxstd: "11,14,17,2a"
|
||||||
os: ubuntu-20.04
|
container: ubuntu:20.04
|
||||||
|
os: ubuntu-latest
|
||||||
install: g++-9-multilib
|
install: g++-9-multilib
|
||||||
address-model: 32,64
|
address-model: 32,64
|
||||||
- toolset: gcc-10
|
- toolset: gcc-10
|
||||||
cxxstd: "03,11,14,17,2a"
|
cxxstd: "11,14,17,2a"
|
||||||
os: ubuntu-20.04
|
container: ubuntu:22.04
|
||||||
|
os: ubuntu-latest
|
||||||
install: g++-10-multilib
|
install: g++-10-multilib
|
||||||
address-model: 32,64
|
address-model: 32,64
|
||||||
- toolset: gcc-11
|
- toolset: gcc-11
|
||||||
cxxstd: "03,11,14,17,20"
|
cxxstd: "11,14,17,20"
|
||||||
os: ubuntu-20.04
|
container: ubuntu:22.04
|
||||||
|
os: ubuntu-latest
|
||||||
install: g++-11-multilib
|
install: g++-11-multilib
|
||||||
address-model: 32,64
|
address-model: 32,64
|
||||||
- toolset: gcc-12
|
- toolset: gcc-12
|
||||||
cxxstd: "03,11,14,17,20"
|
cxxstd: "11,14,17,20,2b"
|
||||||
os: ubuntu-22.04
|
container: ubuntu:22.04
|
||||||
|
os: ubuntu-latest
|
||||||
install: g++-12-multilib
|
install: g++-12-multilib
|
||||||
address-model: 32,64
|
address-model: 32,64
|
||||||
- toolset: clang
|
- toolset: gcc-13
|
||||||
compiler: clang++-3.9
|
cxxstd: "11,14,17,20,2b"
|
||||||
cxxstd: "03,11,14"
|
container: ubuntu:24.04
|
||||||
os: ubuntu-18.04
|
os: ubuntu-latest
|
||||||
install: clang-3.9
|
install: g++-13-multilib
|
||||||
- toolset: clang
|
address-model: 32,64
|
||||||
compiler: clang++-4.0
|
- toolset: gcc-14
|
||||||
cxxstd: "03,11,14"
|
cxxstd: "11,14,17,20,2b"
|
||||||
os: ubuntu-18.04
|
container: ubuntu:24.04
|
||||||
install: clang-4.0
|
os: ubuntu-latest
|
||||||
- toolset: clang
|
install: g++-14-multilib
|
||||||
compiler: clang++-5.0
|
address-model: 32,64
|
||||||
cxxstd: "03,11,14,1z"
|
- toolset: gcc-15
|
||||||
os: ubuntu-18.04
|
cxxstd: "11,14,17,20,23,2c"
|
||||||
install: clang-5.0
|
container: ubuntu:26.04
|
||||||
|
os: ubuntu-latest
|
||||||
|
install: g++-15-multilib
|
||||||
|
address-model: 32,64
|
||||||
|
- toolset: gcc-16
|
||||||
|
cxxstd: "11,14,17,20,23,2c"
|
||||||
|
container: ubuntu:26.04
|
||||||
|
os: ubuntu-latest
|
||||||
|
install: g++-16-multilib
|
||||||
|
address-model: 32,64
|
||||||
- toolset: clang
|
- toolset: clang
|
||||||
compiler: clang++-6.0
|
compiler: clang++-6.0
|
||||||
cxxstd: "03,11,14,17"
|
cxxstd: "11,14,17"
|
||||||
os: ubuntu-18.04
|
container: ubuntu:20.04
|
||||||
|
os: ubuntu-latest
|
||||||
install: clang-6.0
|
install: clang-6.0
|
||||||
- toolset: clang
|
- toolset: clang
|
||||||
compiler: clang++-7
|
compiler: clang++-7
|
||||||
cxxstd: "03,11,14,17"
|
cxxstd: "11,14,17"
|
||||||
os: ubuntu-18.04
|
container: ubuntu:20.04
|
||||||
|
os: ubuntu-latest
|
||||||
install: clang-7
|
install: clang-7
|
||||||
- toolset: clang
|
- toolset: clang
|
||||||
compiler: clang++-8
|
compiler: clang++-8
|
||||||
cxxstd: "03,11,14,17"
|
cxxstd: "11,14,17"
|
||||||
os: ubuntu-20.04
|
container: ubuntu:20.04
|
||||||
|
os: ubuntu-latest
|
||||||
install: clang-8
|
install: clang-8
|
||||||
- toolset: clang
|
- toolset: clang
|
||||||
compiler: clang++-9
|
compiler: clang++-9
|
||||||
cxxstd: "03,11,14,17,2a"
|
cxxstd: "11,14,17,2a"
|
||||||
os: ubuntu-20.04
|
container: ubuntu:20.04
|
||||||
|
os: ubuntu-latest
|
||||||
install: clang-9
|
install: clang-9
|
||||||
- toolset: clang
|
- toolset: clang
|
||||||
compiler: clang++-10
|
compiler: clang++-10
|
||||||
cxxstd: "03,11,14,17,2a"
|
cxxstd: "11,14,17,2a"
|
||||||
os: ubuntu-20.04
|
container: ubuntu:20.04
|
||||||
|
os: ubuntu-latest
|
||||||
|
install: clang-10
|
||||||
- toolset: clang
|
- toolset: clang
|
||||||
compiler: clang++-11
|
compiler: clang++-11
|
||||||
cxxstd: "03,11,14,17,2a"
|
cxxstd: "11,14,17,2a"
|
||||||
os: ubuntu-20.04
|
container: ubuntu:20.04
|
||||||
|
os: ubuntu-latest
|
||||||
|
install: clang-11
|
||||||
- toolset: clang
|
- toolset: clang
|
||||||
compiler: clang++-12
|
compiler: clang++-12
|
||||||
cxxstd: "03,11,14,17,20"
|
cxxstd: "11,14,17,20"
|
||||||
os: ubuntu-20.04
|
container: ubuntu:20.04
|
||||||
|
os: ubuntu-latest
|
||||||
|
install: clang-12
|
||||||
- toolset: clang
|
- toolset: clang
|
||||||
compiler: clang++-13
|
compiler: clang++-13
|
||||||
cxxstd: "03,11,14,17,20"
|
cxxstd: "11,14,17,20,2b"
|
||||||
os: ubuntu-22.04
|
container: ubuntu:22.04
|
||||||
|
os: ubuntu-latest
|
||||||
install: clang-13
|
install: clang-13
|
||||||
- toolset: clang
|
- toolset: clang
|
||||||
compiler: clang++-14
|
compiler: clang++-14
|
||||||
cxxstd: "03,11,14,17,20"
|
cxxstd: "11,14,17,20,2b"
|
||||||
os: ubuntu-22.04
|
container: ubuntu:22.04
|
||||||
|
os: ubuntu-latest
|
||||||
install: clang-14
|
install: clang-14
|
||||||
- toolset: clang
|
- toolset: clang
|
||||||
cxxstd: "03,11,14,17,2a"
|
compiler: clang++-15
|
||||||
os: macos-11
|
cxxstd: "11,14,17,20,2b"
|
||||||
|
container: ubuntu:22.04
|
||||||
|
os: ubuntu-latest
|
||||||
|
install: clang-15
|
||||||
|
- toolset: clang
|
||||||
|
compiler: clang++-16
|
||||||
|
cxxstd: "11,14,17,20,2b"
|
||||||
|
container: ubuntu:24.04
|
||||||
|
os: ubuntu-latest
|
||||||
|
install: clang-16
|
||||||
|
- toolset: clang
|
||||||
|
compiler: clang++-17
|
||||||
|
cxxstd: "11,14,17,20,2b"
|
||||||
|
container: ubuntu:24.04
|
||||||
|
os: ubuntu-latest
|
||||||
|
install: clang-17
|
||||||
|
- toolset: clang
|
||||||
|
compiler: clang++-18
|
||||||
|
cxxstd: "11,14,17,20,2b"
|
||||||
|
container: ubuntu:24.04
|
||||||
|
os: ubuntu-latest
|
||||||
|
install: clang-18
|
||||||
|
- toolset: clang
|
||||||
|
compiler: clang++-19
|
||||||
|
cxxstd: "11,14,17,20,2b"
|
||||||
|
container: ubuntu:24.04
|
||||||
|
os: ubuntu-latest
|
||||||
|
install: clang-19
|
||||||
|
- toolset: clang
|
||||||
|
compiler: clang++-20
|
||||||
|
cxxstd: "11,14,17,20,23,2c"
|
||||||
|
container: ubuntu:24.04
|
||||||
|
os: ubuntu-latest
|
||||||
|
install: clang-20
|
||||||
|
- toolset: clang
|
||||||
|
compiler: clang++-21
|
||||||
|
cxxstd: "11,14,17,20,23,2c"
|
||||||
|
container: ubuntu:26.04
|
||||||
|
os: ubuntu-latest
|
||||||
|
install: clang-21
|
||||||
|
- toolset: clang
|
||||||
|
compiler: clang++-22
|
||||||
|
cxxstd: "11,14,17,20,23,2c"
|
||||||
|
container: ubuntu:26.04
|
||||||
|
os: ubuntu-latest
|
||||||
|
install: clang-22
|
||||||
|
- toolset: clang
|
||||||
|
cxxstd: "11,14,17,20,2b"
|
||||||
|
os: macos-14
|
||||||
|
- toolset: clang
|
||||||
|
cxxstd: "11,14,17,20,2b"
|
||||||
|
os: macos-15
|
||||||
|
- toolset: clang
|
||||||
|
cxxstd: "11,14,17,20,23,2c"
|
||||||
|
os: macos-26
|
||||||
|
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
container: ${{matrix.container}}
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- name: Setup container environment
|
||||||
|
if: matrix.container
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
apt-get -y install sudo python3 git g++ curl xz-utils
|
||||||
|
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
if: matrix.install
|
if: matrix.install
|
||||||
run: sudo apt install ${{matrix.install}}
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -y install ${{matrix.install}}
|
||||||
|
|
||||||
- name: Setup Boost
|
- name: Setup Boost
|
||||||
run: |
|
run: |
|
||||||
@@ -150,7 +229,7 @@ jobs:
|
|||||||
cd boost-root
|
cd boost-root
|
||||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||||
git submodule update --init tools/boostdep
|
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
|
./bootstrap.sh
|
||||||
./b2 -d0 headers
|
./b2 -d0 headers
|
||||||
|
|
||||||
@@ -171,31 +250,27 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- toolset: msvc-14.0
|
|
||||||
cxxstd: 14,latest
|
|
||||||
addrmd: 32,64
|
|
||||||
os: windows-2019
|
|
||||||
- toolset: msvc-14.2
|
|
||||||
cxxstd: "14,17,20,latest"
|
|
||||||
addrmd: 32,64
|
|
||||||
os: windows-2019
|
|
||||||
- toolset: msvc-14.3
|
- toolset: msvc-14.3
|
||||||
cxxstd: "14,17,20,latest"
|
cxxstd: "14,17,20,latest"
|
||||||
addrmd: 32,64
|
addrmd: 32,64
|
||||||
os: windows-2022
|
os: windows-2022
|
||||||
- toolset: clang-win
|
- toolset: msvc-14.5
|
||||||
cxxstd: "14,17,latest"
|
cxxstd: "14,17,20,latest"
|
||||||
addrmd: 32,64
|
addrmd: 32,64
|
||||||
os: windows-2022
|
os: windows-2025-vs2026
|
||||||
|
- toolset: clang-win
|
||||||
|
cxxstd: "14,17,20,latest"
|
||||||
|
addrmd: 32,64
|
||||||
|
os: windows-2025
|
||||||
- toolset: gcc
|
- toolset: gcc
|
||||||
cxxstd: "03,11,14,17,2a"
|
cxxstd: "11,14,17,2a"
|
||||||
addrmd: 64
|
addrmd: 64
|
||||||
os: windows-2019
|
os: windows-2025
|
||||||
|
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup Boost
|
- name: Setup Boost
|
||||||
shell: cmd
|
shell: cmd
|
||||||
@@ -231,19 +306,17 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-18.04
|
- os: ubuntu-latest
|
||||||
- os: ubuntu-20.04
|
- os: macos-latest
|
||||||
- os: ubuntu-22.04
|
|
||||||
- os: macos-11
|
|
||||||
|
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
if: matrix.install
|
if: matrix.install
|
||||||
run: sudo apt install ${{matrix.install}}
|
run: sudo apt-get -y install ${{matrix.install}}
|
||||||
|
|
||||||
- name: Setup Boost
|
- name: Setup Boost
|
||||||
run: |
|
run: |
|
||||||
@@ -278,19 +351,17 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-18.04
|
- os: ubuntu-latest
|
||||||
- os: ubuntu-20.04
|
- os: macos-latest
|
||||||
- os: ubuntu-22.04
|
|
||||||
- os: macos-11
|
|
||||||
|
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
if: matrix.install
|
if: matrix.install
|
||||||
run: sudo apt install ${{matrix.install}}
|
run: sudo apt-get -y install ${{matrix.install}}
|
||||||
|
|
||||||
- name: Setup Boost
|
- name: Setup Boost
|
||||||
run: |
|
run: |
|
||||||
@@ -335,19 +406,17 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-18.04
|
- os: ubuntu-latest
|
||||||
- os: ubuntu-20.04
|
- os: macos-latest
|
||||||
- os: ubuntu-22.04
|
|
||||||
- os: macos-11
|
|
||||||
|
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
if: matrix.install
|
if: matrix.install
|
||||||
run: sudo apt install ${{matrix.install}}
|
run: sudo apt-get -y install ${{matrix.install}}
|
||||||
|
|
||||||
- name: Setup Boost
|
- name: Setup Boost
|
||||||
run: |
|
run: |
|
||||||
@@ -384,3 +453,180 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd ../boost-root/__build__
|
cd ../boost-root/__build__
|
||||||
ctest --output-on-failure --no-tests=error
|
ctest --output-on-failure --no-tests=error
|
||||||
|
|
||||||
|
windows-cmake-subdir:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: windows-latest
|
||||||
|
|
||||||
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- 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-latest
|
||||||
|
|
||||||
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- 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-latest
|
||||||
|
|
||||||
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- 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
|
||||||
|
|||||||
+5
-2
@@ -3,7 +3,7 @@
|
|||||||
# Distributed under the Boost Software License, Version 1.0.
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
# https://www.boost.org/LICENSE_1_0.txt
|
# https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
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)
|
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
|
target_link_libraries(boost_container_hash
|
||||||
INTERFACE
|
INTERFACE
|
||||||
Boost::config
|
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")
|
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||||
|
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
|||||||
@@ -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
|
||||||
|
itself 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).
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
enwik8
|
||||||
|
enwik9
|
||||||
|
*.exe
|
||||||
|
*.obj
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
# Copyright Daniel James 2005. Use, modification, and distribution are
|
||||||
|
# subject to 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)
|
||||||
|
|
||||||
|
import testing ;
|
||||||
|
|
||||||
|
project :
|
||||||
|
requirements
|
||||||
|
<library>/boost/container_hash//boost_container_hash
|
||||||
|
<library>/boost/core//boost_core
|
||||||
|
<library>/boost/unordered//boost_unordered
|
||||||
|
;
|
||||||
|
|
||||||
|
link char_seq.cpp ;
|
||||||
|
link unordered.cpp ;
|
||||||
|
link unordered_flat.cpp : <cxxstd>11:<build>no <cxxstd>14:<build>no ;
|
||||||
|
link word_count.cpp : <cxxstd>11:<build>no <cxxstd>14:<build>no ;
|
||||||
@@ -79,11 +79,11 @@ int main()
|
|||||||
|
|
||||||
if( k & 1 )
|
if( k & 1 )
|
||||||
{
|
{
|
||||||
sprintf( buffer, "prefix_%llu_suffix", k );
|
std::snprintf( buffer, sizeof( buffer ), "prefix_%llu_suffix", k );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf( buffer, "{%u}", static_cast<unsigned>( k ) );
|
std::snprintf( buffer, sizeof( buffer ), "{%u}", static_cast<unsigned>( k ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
v.push_back( buffer );
|
v.push_back( buffer );
|
||||||
|
|||||||
+114
-42
@@ -3,12 +3,22 @@
|
|||||||
// https://www.boost.org/LICENSE_1_0.txt
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
#define _CRT_SECURE_NO_WARNINGS
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||||
|
|
||||||
#include <boost/container_hash/hash.hpp>
|
#include <boost/container_hash/hash.hpp>
|
||||||
#include <boost/unordered_set.hpp>
|
#include <boost/unordered_set.hpp>
|
||||||
#include <boost/core/detail/splitmix64.hpp>
|
#include <boost/core/detail/splitmix64.hpp>
|
||||||
#include <boost/core/type_name.hpp>
|
#include <boost/core/type_name.hpp>
|
||||||
#include <boost/config.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 <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -19,10 +29,8 @@
|
|||||||
|
|
||||||
// mul31_hash
|
// mul31_hash
|
||||||
|
|
||||||
class mul31_hash
|
struct mul31_hash
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
|
|
||||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||||
{
|
{
|
||||||
char const * p = st.data();
|
char const * p = st.data();
|
||||||
@@ -43,18 +51,20 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// mul31_unrolled_hash
|
// mul31_x4_hash
|
||||||
|
|
||||||
template<int Bits> struct mul31_unrolled_hash_impl;
|
struct mul31_x4_hash
|
||||||
|
|
||||||
template<> struct mul31_unrolled_hash_impl<32>
|
|
||||||
{
|
{
|
||||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||||
{
|
{
|
||||||
char const * p = st.data();
|
char const * p = st.data();
|
||||||
std::size_t n = st.size();
|
std::size_t n = st.size();
|
||||||
|
|
||||||
|
#if SIZE_MAX > UINT32_MAX
|
||||||
|
std::size_t h = 0xCBF29CE484222325ull;
|
||||||
|
#else
|
||||||
std::size_t h = 0x811C9DC5u;
|
std::size_t h = 0x811C9DC5u;
|
||||||
|
#endif
|
||||||
|
|
||||||
while( n >= 4 )
|
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
|
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||||
{
|
{
|
||||||
char const * p = st.data();
|
char const * p = st.data();
|
||||||
std::size_t n = st.size();
|
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 )
|
while( n >= 8 )
|
||||||
{
|
{
|
||||||
@@ -113,12 +129,10 @@ template<> struct mul31_unrolled_hash_impl<64>
|
|||||||
--n;
|
--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
|
// fnv1a_hash
|
||||||
|
|
||||||
template<int Bits> struct fnv1a_hash_impl;
|
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 > {};
|
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
|
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||||
{
|
{
|
||||||
char const * p = st.data();
|
return mulxp1_hash( (unsigned char const*)st.data(), st.size(), 0 );
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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
|
// test_hash_speed
|
||||||
|
|
||||||
template<class H, class V> void test_hash_speed( int N, V const& v )
|
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 )
|
#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
|
#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
|
#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 )
|
#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
|
#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
|
#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 )
|
#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
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
@@ -326,11 +356,11 @@ int main()
|
|||||||
|
|
||||||
if( k & 1 )
|
if( k & 1 )
|
||||||
{
|
{
|
||||||
sprintf( buffer, "prefix_%llu_suffix", k );
|
std::snprintf( buffer, sizeof( buffer ), "prefix_%llu_suffix", k );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf( buffer, "{%u}", static_cast<unsigned>( k ) );
|
std::snprintf( buffer, sizeof( buffer ), "{%u}", static_cast<unsigned>( k ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
v.push_back( buffer );
|
v.push_back( buffer );
|
||||||
@@ -340,11 +370,23 @@ int main()
|
|||||||
std::puts( "Hash speed test:\n" );
|
std::puts( "Hash speed test:\n" );
|
||||||
|
|
||||||
test_hash_speed<mul31_hash>( N * 16, v );
|
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<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<boost::hash<std::string> >( N * 16, v );
|
||||||
test_hash_speed<std::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( "" );
|
std::puts( "" );
|
||||||
|
|
||||||
@@ -365,25 +407,55 @@ int main()
|
|||||||
}
|
}
|
||||||
|
|
||||||
test_hash_collision<mul31_hash>( N * 16, v, n );
|
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<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<boost::hash<std::string> >( N * 16, v, n );
|
||||||
test_hash_collision<std::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( "" );
|
std::puts( "" );
|
||||||
|
|
||||||
typedef std::string K;
|
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_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, 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, boost::hash<std::string> >( N, v );
|
||||||
test_container_speed<K, std::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( "" );
|
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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Copyright 2023-2024 René Ferdinand Rivera Morell
|
||||||
|
# Copyright 2024 Peter Dimov
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
|
require-b2 5.2 ;
|
||||||
|
|
||||||
|
constant boost_dependencies :
|
||||||
|
/boost/config//boost_config
|
||||||
|
/boost/describe//boost_describe
|
||||||
|
/boost/mp11//boost_mp11
|
||||||
|
;
|
||||||
|
|
||||||
|
project /boost/container_hash ;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
[ alias boost_container_hash : : : : <include>include <library>$(boost_dependencies) ]
|
||||||
|
[ alias all : boost_container_hash examples test ]
|
||||||
|
;
|
||||||
|
|
||||||
|
call-if : boost-library container_hash
|
||||||
|
;
|
||||||
@@ -22,6 +22,7 @@ include::hash/recent.adoc[]
|
|||||||
include::hash/tutorial.adoc[]
|
include::hash/tutorial.adoc[]
|
||||||
include::hash/user.adoc[]
|
include::hash/user.adoc[]
|
||||||
include::hash/combine.adoc[]
|
include::hash/combine.adoc[]
|
||||||
|
include::hash/describe.adoc[]
|
||||||
include::hash/reference.adoc[]
|
include::hash/reference.adoc[]
|
||||||
include::hash/notes.adoc[]
|
include::hash/notes.adoc[]
|
||||||
include::hash/links.adoc[]
|
include::hash/links.adoc[]
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
////
|
||||||
|
Copyright 2022 Peter Dimov
|
||||||
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
|
https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
////
|
||||||
|
|
||||||
|
[#describe]
|
||||||
|
= Hashing User Types with Boost.Describe
|
||||||
|
:idprefix: describe_
|
||||||
|
|
||||||
|
Let's look at our `point` class again:
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
class point
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
point() : x(0), y(0) {}
|
||||||
|
point(int x, int y) : x(x), y(y) {}
|
||||||
|
};
|
||||||
|
----
|
||||||
|
|
||||||
|
If you're using {cpp}14 or above, a much easier way to add
|
||||||
|
support for `boost::hash` to `point` is by using
|
||||||
|
link:../../../describe/index.html[Boost.Describe] (and
|
||||||
|
get an automatic definition of `operator==` for free):
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
|
||||||
|
#include <boost/describe/class.hpp>
|
||||||
|
#include <boost/describe/operators.hpp>
|
||||||
|
|
||||||
|
class point
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
BOOST_DESCRIBE_CLASS(point, (), (), (), (x, y))
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
point() : x(0), y(0) {}
|
||||||
|
point(int x, int y) : x(x), y(y) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
using boost::describe::operators::operator==;
|
||||||
|
using boost::describe::operators::operator!=;
|
||||||
|
----
|
||||||
|
|
||||||
|
(Full code for this example is at
|
||||||
|
link:../../examples/point2.cpp[examples/point2.cpp].)
|
||||||
|
|
||||||
|
Since the `point` class has been annotated with `BOOST_DESCRIBE_CLASS`,
|
||||||
|
the library can enumerate its members (and base classes) and automatically
|
||||||
|
synthesize the appropriate `hash_value` overload for it, without us needing
|
||||||
|
to do so.
|
||||||
+8
-3
@@ -22,16 +22,21 @@ Out of the box, `boost::hash` supports
|
|||||||
|
|
||||||
* standard integral types (integers, character types, and `bool`);
|
* standard integral types (integers, character types, and `bool`);
|
||||||
* standard floating point types (`float`, `double`, `long double`);
|
* standard floating point types (`float`, `double`, `long double`);
|
||||||
* pointers (to objects and to functions, but not pointers to members);
|
* pointers (to objects and to functions, but not pointers to members)
|
||||||
|
and `nullptr`;
|
||||||
* enumeration types;
|
* enumeration types;
|
||||||
* C arrays;
|
* C arrays;
|
||||||
* `std::complex`;
|
* `std::complex`;
|
||||||
* `std::pair`, `std::tuple`;
|
* 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
|
* sequence-like types, both standard and user-defined (sequence-like types
|
||||||
have `begin()` and `end()` member functions returning iterators);
|
have `begin()` and `end()` member functions returning iterators);
|
||||||
* unordered sequences, standard or user-defined (sequences for which the hash
|
* unordered sequences, standard or user-defined (sequences for which the hash
|
||||||
value does not depend on the element order, such as `std::unordered_set` and
|
value does not depend on the element order, such as `std::unordered_set` and
|
||||||
`std::unordered_map`);
|
`std::unordered_map`);
|
||||||
|
* described structs and classes -- ones that have been annotated with the
|
||||||
|
`BOOST_DESCRIBE_STRUCT` or `BOOST_DESCRIBE_CLASS` macros from
|
||||||
|
link:../../../describe/index.html[Boost.Describe];
|
||||||
* `std::unique_ptr`, `std::shared_ptr`;
|
* `std::unique_ptr`, `std::shared_ptr`;
|
||||||
* `std::type_index`;
|
* `std::type_index`;
|
||||||
* `std::error_code`, `std::error_condition`;
|
* `std::error_code`, `std::error_condition`;
|
||||||
@@ -39,7 +44,7 @@ Out of the box, `boost::hash` supports
|
|||||||
* `std::variant`, `std::monostate`.
|
* `std::variant`, `std::monostate`.
|
||||||
|
|
||||||
`boost::hash` is extensible; it's possible for a user-defined type `X` to make
|
`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
|
itself hashable via `boost::hash<X>` by defining an appropriate overload of the
|
||||||
function `hash_value`. Many, if not most, Boost types already contain the
|
function `hash_value`. Many, if not most, Boost types already contain the
|
||||||
necessary support.
|
necessary support.
|
||||||
|
|
||||||
|
|||||||
+70
-17
@@ -10,6 +10,26 @@ https://www.boost.org/LICENSE_1_0.txt
|
|||||||
= Design and Implementation Notes
|
= Design and Implementation Notes
|
||||||
:idprefix: notes_
|
:idprefix: notes_
|
||||||
|
|
||||||
|
== Quality of the Hash Function
|
||||||
|
|
||||||
|
Many hash functions strive to have little correlation between the input and
|
||||||
|
output values. They attempt to uniformally distribute the output values for
|
||||||
|
very similar inputs. This hash function makes no such attempt. In fact, for
|
||||||
|
integers, the result of the hash function is often just the input value. So
|
||||||
|
similar but different input values will often result in similar but different
|
||||||
|
output values. This means that it is not appropriate as a general hash
|
||||||
|
function. For example, a hash table may discard bits from the hash function
|
||||||
|
resulting in likely collisions, or might have poor collision resolution when
|
||||||
|
hash values are clustered together. In such cases this hash function will
|
||||||
|
perform poorly.
|
||||||
|
|
||||||
|
But the standard has no such requirement for the hash function, it just
|
||||||
|
requires that the hashes of two different values are unlikely to collide.
|
||||||
|
Containers or algorithms designed to work with the standard hash function will
|
||||||
|
have to be implemented to work well when the hash function's output is
|
||||||
|
correlated to its input. Since they are paying that cost a higher quality hash
|
||||||
|
function would be wasteful.
|
||||||
|
|
||||||
== The hash_value Customization Point
|
== The hash_value Customization Point
|
||||||
|
|
||||||
The way one customizes the standard `std::hash` function object for user
|
The way one customizes the standard `std::hash` function object for user
|
||||||
@@ -35,6 +55,22 @@ to be templates constrained on e.g. `std::is_integral` or its moral
|
|||||||
equivalent. This causes types convertible to an integral to no longer
|
equivalent. This causes types convertible to an integral to no longer
|
||||||
match, avoiding the problem.
|
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
|
== hash_combine
|
||||||
|
|
||||||
The initial implementation of the library was based on Issue 6.18 of the
|
The initial implementation of the library was based on Issue 6.18 of the
|
||||||
@@ -154,22 +190,39 @@ With this improved `hash_combine`, `boost::hash` for strings now passes the
|
|||||||
https://github.com/aappleby/smhasher[SMHasher test suite] by Austin Appleby
|
https://github.com/aappleby/smhasher[SMHasher test suite] by Austin Appleby
|
||||||
(for a 64 bit `size_t`).
|
(for a 64 bit `size_t`).
|
||||||
|
|
||||||
== Quality of the Hash Function
|
== hash_range
|
||||||
|
|
||||||
Many hash functions strive to have little correlation between the input and
|
The traditional implementation of `hash_range(seed, first, last)` has been
|
||||||
output values. They attempt to uniformally distribute the output values for
|
|
||||||
very similar inputs. This hash function makes no such attempt. In fact, for
|
|
||||||
integers, the result of the hash function is often just the input value. So
|
|
||||||
similar but different input values will often result in similar but different
|
|
||||||
output values. This means that it is not appropriate as a general hash
|
|
||||||
function. For example, a hash table may discard bits from the hash function
|
|
||||||
resulting in likely collisions, or might have poor collision resolution when
|
|
||||||
hash values are clustered together. In such cases this hash function will
|
|
||||||
perform poorly.
|
|
||||||
|
|
||||||
But the standard has no such requirement for the hash function, it just
|
[source]
|
||||||
requires that the hashes of two different values are unlikely to collide.
|
----
|
||||||
Containers or algorithms designed to work with the standard hash function will
|
for( ; first != last; ++first )
|
||||||
have to be implemented to work well when the hash function's output is
|
{
|
||||||
correlated to its input. Since they are paying that cost a higher quality hash
|
boost::hash_combine<typename std::iterator_traits<It>::value_type>( seed, *first );
|
||||||
function would be wasteful.
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
(the explicit template parameter is needed to support iterators with proxy
|
||||||
|
return types such as `std::vector<bool>::iterator`.)
|
||||||
|
|
||||||
|
This is logical, consistent and straightforward. In the common case where
|
||||||
|
`typename std::iterator_traits<It>::value_type` is `char` -- which it is
|
||||||
|
in the common case of `boost::hash<std::string>` -- this however leaves a
|
||||||
|
lot of performance on the table, because processing each `char` individually
|
||||||
|
is much less efficient than processing several in bulk.
|
||||||
|
|
||||||
|
In Boost 1.81, `hash_range` was changed to process elements of type `char`,
|
||||||
|
`signed char`, `unsigned char`, `std::byte`, or `char8_t`, four of a time.
|
||||||
|
A `uint32_t` is composed from `first[0]` to `first[3]`, and that `uint32_t`
|
||||||
|
is fed to `hash_combine`.
|
||||||
|
|
||||||
|
In 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>`.
|
||||||
|
|||||||
+36
-1
@@ -8,6 +8,29 @@ https://www.boost.org/LICENSE_1_0.txt
|
|||||||
= Recent Changes
|
= Recent Changes
|
||||||
:idprefix: recent_
|
:idprefix: recent_
|
||||||
|
|
||||||
|
== Boost 1.92.0
|
||||||
|
|
||||||
|
* Hashing a valueless `std::variant` instance no longer throws.
|
||||||
|
|
||||||
|
== Boost 1.89.0
|
||||||
|
|
||||||
|
* Added the `hash_is_avalanching` trait class.
|
||||||
|
|
||||||
|
== 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
|
== Boost 1.81.0
|
||||||
|
|
||||||
Major update.
|
Major update.
|
||||||
@@ -21,9 +44,21 @@ Major update.
|
|||||||
* User-defined containers (types that have `begin()` and `end()`
|
* User-defined containers (types that have `begin()` and `end()`
|
||||||
member functions that return iterators) are now supported out
|
member functions that return iterators) are now supported out
|
||||||
of the box.
|
of the box.
|
||||||
* `hash_combine` has been improved.
|
* 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)
|
* The performance (and quality, as a result of the above change)
|
||||||
of string hashing has been improved. `boost::hash` for strings
|
of string hashing has been improved. `boost::hash` for strings
|
||||||
now passes SMHasher in 64 bit mode.
|
now passes SMHasher in 64 bit mode.
|
||||||
* The documentation has been substantially revised to reflect
|
* The documentation has been substantially revised to reflect
|
||||||
the changes.
|
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.
|
||||||
|
|||||||
+184
-13
@@ -1,7 +1,7 @@
|
|||||||
////
|
////
|
||||||
Copyright 2005-2008 Daniel James
|
Copyright 2005-2008 Daniel James
|
||||||
Copyright 2022 Christian Mazakas
|
Copyright 2022 Christian Mazakas
|
||||||
Copyright 2022 Peter Dimov
|
Copyright 2022, 2025 Peter Dimov
|
||||||
Distributed under the Boost Software License, Version 1.0.
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
https://www.boost.org/LICENSE_1_0.txt
|
https://www.boost.org/LICENSE_1_0.txt
|
||||||
////
|
////
|
||||||
@@ -29,6 +29,8 @@ namespace container_hash
|
|||||||
template<class T> struct is_range;
|
template<class T> struct is_range;
|
||||||
template<class T> struct is_contiguous_range;
|
template<class T> struct is_contiguous_range;
|
||||||
template<class T> struct is_unordered_range;
|
template<class T> struct is_unordered_range;
|
||||||
|
template<class T> struct is_described_class;
|
||||||
|
template<class T> struct is_tuple_like;
|
||||||
|
|
||||||
} // namespace container_hash
|
} // namespace container_hash
|
||||||
|
|
||||||
@@ -42,6 +44,8 @@ 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> 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 );
|
template<class It> std::size_t hash_unordered_range( It first, It last );
|
||||||
|
|
||||||
|
template<class Hash> struct hash_is_avalanching;
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -88,8 +92,9 @@ template<class T>
|
|||||||
template<class A, class B>
|
template<class A, class B>
|
||||||
std::size_t hash_value( std::pair<A, B> const& v );
|
std::size_t hash_value( std::pair<A, B> const& v );
|
||||||
|
|
||||||
template<class... T>
|
// Enabled only when container_hash::is_tuple_like<T>::value is true
|
||||||
std::size_t hash_value( std::tuple<T...> const& v );
|
template<class T>
|
||||||
|
std::size_t hash_value( T const& v );
|
||||||
|
|
||||||
// Enabled only when container_hash::is_range<T>::value is true
|
// Enabled only when container_hash::is_range<T>::value is true
|
||||||
template<class T>
|
template<class T>
|
||||||
@@ -103,6 +108,10 @@ template<class T>
|
|||||||
template<class T>
|
template<class T>
|
||||||
std::size_t hash_value( T const& v );
|
std::size_t hash_value( T const& v );
|
||||||
|
|
||||||
|
// Enabled only when container_hash::is_described_class<T>::value is true
|
||||||
|
template<class T>
|
||||||
|
std::size_t hash_value( T const& v );
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
std::size_t hash_value( std::shared_ptr<T> const& v );
|
std::size_t hash_value( std::shared_ptr<T> const& v );
|
||||||
|
|
||||||
@@ -225,7 +234,7 @@ Effects: ::
|
|||||||
+
|
+
|
||||||
--
|
--
|
||||||
When `typename std::iterator_traits<It>::value_type` is not `char`, `signed char`,
|
When `typename std::iterator_traits<It>::value_type` is not `char`, `signed char`,
|
||||||
`unsigned char`,
|
`unsigned char`, `std::byte`, or `char8_t`,
|
||||||
|
|
||||||
[source]
|
[source]
|
||||||
----
|
----
|
||||||
@@ -235,11 +244,16 @@ for( ; first != last; ++first )
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
Otherwise, bytes from `[first, last)` are coalesced in an unspecified manner
|
Otherwise, bytes from `[first, last)` are coalesced and hashed in an
|
||||||
and then passed to `hash_combine`, more than one at a time. This is done in
|
unspecified manner. This is done in order to improve performance when hashing
|
||||||
order to improve performance when hashing strings.
|
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]
|
[source]
|
||||||
----
|
----
|
||||||
template<class It> std::size_t hash_range( It first, It last );
|
template<class It> std::size_t hash_range( It first, It last );
|
||||||
@@ -380,8 +394,9 @@ return seed;
|
|||||||
|
|
||||||
[source]
|
[source]
|
||||||
----
|
----
|
||||||
template<class... T>
|
// Enabled only when container_hash::is_tuple_like<T>::value is true
|
||||||
std::size_t hash_value( std::tuple<T...> const& v );
|
template<class T>
|
||||||
|
std::size_t hash_value( T const& v );
|
||||||
----
|
----
|
||||||
|
|
||||||
Effects: ::
|
Effects: ::
|
||||||
@@ -390,15 +405,21 @@ Effects: ::
|
|||||||
----
|
----
|
||||||
std::size_t seed = 0;
|
std::size_t seed = 0;
|
||||||
|
|
||||||
boost::hash_combine( seed, std::get<0>(v) );
|
using std::get;
|
||||||
boost::hash_combine( seed, std::get<1>(v) );
|
|
||||||
|
boost::hash_combine( seed, get<0>(v) );
|
||||||
|
boost::hash_combine( seed, get<1>(v) );
|
||||||
// ...
|
// ...
|
||||||
boost::hash_combine( seed, std::get<N-1>(v) );
|
boost::hash_combine( seed, get<N-1>(v) );
|
||||||
|
|
||||||
return seed;
|
return seed;
|
||||||
----
|
----
|
||||||
+
|
+
|
||||||
where `N` is `sizeof...(T)`.
|
where `N` is `std::tuple_size<T>::value`.
|
||||||
|
|
||||||
|
Remarks: ::
|
||||||
|
This overload is only enabled when
|
||||||
|
`container_hash::is_range<T>::value` is `false`.
|
||||||
|
|
||||||
[source]
|
[source]
|
||||||
----
|
----
|
||||||
@@ -446,6 +467,34 @@ Remarks: ::
|
|||||||
This overload handles the standard unordered containers, such as
|
This overload handles the standard unordered containers, such as
|
||||||
`std::unordered_set` and `std::unordered_map`.
|
`std::unordered_set` and `std::unordered_map`.
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
// Enabled only when container_hash::is_described_class<T>::value is true
|
||||||
|
template<class T>
|
||||||
|
std::size_t hash_value( T const& v );
|
||||||
|
----
|
||||||
|
|
||||||
|
Effects: ::
|
||||||
|
+
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
std::size_t seed = 0;
|
||||||
|
|
||||||
|
boost::hash_combine( seed, b1 );
|
||||||
|
boost::hash_combine( seed, b2 );
|
||||||
|
// ...
|
||||||
|
boost::hash_combine( seed, bM );
|
||||||
|
|
||||||
|
boost::hash_combine( seed, m1 );
|
||||||
|
boost::hash_combine( seed, m2 );
|
||||||
|
// ...
|
||||||
|
boost::hash_combine( seed, mN );
|
||||||
|
|
||||||
|
return seed;
|
||||||
|
----
|
||||||
|
+
|
||||||
|
where `bi` are the bases of `v` and `mi` are its members.
|
||||||
|
|
||||||
[source]
|
[source]
|
||||||
----
|
----
|
||||||
template<class T>
|
template<class T>
|
||||||
@@ -525,6 +574,56 @@ where `x` is the currently contained value in `v`.
|
|||||||
Throws: ::
|
Throws: ::
|
||||||
`std::bad_variant_access` when `v.valueless_by_exception()` is `true`.
|
`std::bad_variant_access` when `v.valueless_by_exception()` is `true`.
|
||||||
|
|
||||||
|
== <boost/container_hash/{zwsp}hash_is_avalanching.hpp>
|
||||||
|
|
||||||
|
Defines the trait `boost::hash_is_avalanching`.
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
|
||||||
|
template<class Hash> struct hash_is_avalanching;
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
----
|
||||||
|
|
||||||
|
=== hash_is_avalanching<Hash>
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template<class Hash> struct hash_is_avalanching
|
||||||
|
{
|
||||||
|
static constexpr bool value = /* see below */;
|
||||||
|
};
|
||||||
|
----
|
||||||
|
|
||||||
|
`hash_is_avalanching<Hash>::value` is:
|
||||||
|
|
||||||
|
* `false` if `Hash::is_avalanching` is not present,
|
||||||
|
* `Hash::is_avalanching::value` if this is present and convertible at compile time to a `bool`,
|
||||||
|
* `true` if `Hash::is_avalanching` is `void` (this usage is deprecated),
|
||||||
|
* ill-formed otherwise.
|
||||||
|
|
||||||
|
A hash function is said to have the _avalanching property_ if small changes
|
||||||
|
in the input translate to large changes in the returned hash code
|
||||||
|
—ideally, flipping one bit in the representation of the input value results
|
||||||
|
in each bit of the hash code flipping with probability 50%. Libraries
|
||||||
|
such as link:../../../unordered/index.html[Boost.Unordered] consult this trait
|
||||||
|
to determine if the supplied hash function is of high quality.
|
||||||
|
`boost::hash` for `std::basic_string<Ch>` and `std::basic_string_view<Ch>`
|
||||||
|
has this trait set to `true` when `Ch` is an integral type (this includes
|
||||||
|
`std::string` and `std::string_view`, among others).
|
||||||
|
Users can set this trait for a particular `Hash` type by:
|
||||||
|
|
||||||
|
* Inserting the nested `is_avalanching` typedef in the class definition
|
||||||
|
if they have access to its source code.
|
||||||
|
* Writing a specialization of `boost::hash_is_avalanching`
|
||||||
|
for `Hash`.
|
||||||
|
|
||||||
|
Note that usage of this trait is not restricted to hash functions produced
|
||||||
|
with Boost.ContainerHash.
|
||||||
|
|
||||||
== <boost/container_hash/{zwsp}is_range.hpp>
|
== <boost/container_hash/{zwsp}is_range.hpp>
|
||||||
|
|
||||||
Defines the trait `boost::container_hash::is_range`.
|
Defines the trait `boost::container_hash::is_range`.
|
||||||
@@ -633,3 +732,75 @@ template<class T> struct is_unordered_range
|
|||||||
|
|
||||||
Users are allowed to specialize `is_unordered_range` for their types
|
Users are allowed to specialize `is_unordered_range` for their types
|
||||||
if the default behavior does not deduce the correct value.
|
if the default behavior does not deduce the correct value.
|
||||||
|
|
||||||
|
== <boost/container_hash/{zwsp}is_described_class.hpp>
|
||||||
|
|
||||||
|
Defines the trait `boost::container_hash::is_described_class`.
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace container_hash
|
||||||
|
{
|
||||||
|
|
||||||
|
template<class T> struct is_described_class;
|
||||||
|
|
||||||
|
} // namespace container_hash
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
----
|
||||||
|
|
||||||
|
=== is_described_class<T>
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template<class T> struct is_described_class
|
||||||
|
{
|
||||||
|
static constexpr bool value = /* see below */;
|
||||||
|
};
|
||||||
|
----
|
||||||
|
|
||||||
|
`is_described_class<T>::value` is `true` when
|
||||||
|
`boost::describe::has_describe_bases<T>::value` is `true`,
|
||||||
|
`boost::describe::has_describe_members<T>::value` is `true`, and
|
||||||
|
`T` is not a union.
|
||||||
|
|
||||||
|
Users are allowed to specialize `is_described_class` for their types
|
||||||
|
if the default behavior does not deduce the correct value.
|
||||||
|
|
||||||
|
== <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.
|
||||||
|
|||||||
+10
-1
@@ -1,6 +1,13 @@
|
|||||||
|
////
|
||||||
|
Copyright 2005-2008 Daniel James
|
||||||
|
Copyright 2022 Christian Mazakas
|
||||||
|
Copyright 2022 Peter Dimov
|
||||||
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
|
https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
////
|
||||||
|
|
||||||
[#thanks]
|
[#thanks]
|
||||||
= Acknowledgements
|
= Acknowledgements
|
||||||
|
|
||||||
:idprefix: thanks_
|
:idprefix: thanks_
|
||||||
|
|
||||||
This library is based on the design by Peter Dimov. During the initial development Joaquín M López Muñoz made many useful suggestions and contributed fixes.
|
This library is based on the design by Peter Dimov. During the initial development Joaquín M López Muñoz made many useful suggestions and contributed fixes.
|
||||||
@@ -12,3 +19,5 @@ The implementation of the hash function for pointers is based on suggestions mad
|
|||||||
Some useful improvements to the floating point hash algorithm were suggested by Daniel Krügler.
|
Some useful improvements to the floating point hash algorithm were suggested by Daniel Krügler.
|
||||||
|
|
||||||
The original implementation came from Jeremy B. Maitin-Shepard's hash table library, although this is a complete rewrite.
|
The original implementation came from Jeremy B. Maitin-Shepard's hash table library, although this is a complete rewrite.
|
||||||
|
|
||||||
|
The documentation was converted from Quickbook to AsciiDoc by Christian Mazakas.
|
||||||
|
|||||||
+1
-1
@@ -74,7 +74,7 @@ assert(books.find(knife) != books.end());
|
|||||||
assert(books.find(dandelion) == books.end());
|
assert(books.find(dandelion) == books.end());
|
||||||
----
|
----
|
||||||
|
|
||||||
The full example can be found in:
|
The full example can be found in
|
||||||
link:../../examples/books.hpp[examples/books.hpp] and
|
link:../../examples/books.hpp[examples/books.hpp] and
|
||||||
link:../../examples/books.cpp[examples/books.cpp].
|
link:../../examples/books.cpp[examples/books.cpp].
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -3,7 +3,12 @@
|
|||||||
# subject to the Boost Software License, Version 1.0. (See accompanying
|
# subject to 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)
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
import testing ;
|
||||||
|
|
||||||
|
project : requirements <library>/boost/container_hash//boost_container_hash ;
|
||||||
|
|
||||||
run books.cpp ;
|
run books.cpp ;
|
||||||
run point.cpp ;
|
run point.cpp ;
|
||||||
run portable.cpp ;
|
run portable.cpp ;
|
||||||
run template.cpp : : : <toolset>msvc-8.0:<build>no ;
|
run template.cpp /boost/unordered//boost_unordered : : : <toolset>msvc-8.0:<build>no ;
|
||||||
|
run point2.cpp ;
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
|
||||||
|
// Copyright 2005 Daniel James.
|
||||||
|
// Copyright 2022 Peter Dimov.
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
|
// Force use of assert.
|
||||||
|
#if defined(NDEBUG)
|
||||||
|
#undef NDEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/container_hash/hash.hpp>
|
||||||
|
#include <boost/describe/class.hpp>
|
||||||
|
#include <boost/describe/operators.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
// This example illustrates how to use Boost.Describe to obtain
|
||||||
|
// automatic boost::hash support. For full details see the hash
|
||||||
|
// tutorial.
|
||||||
|
|
||||||
|
#if defined(BOOST_DESCRIBE_CXX14)
|
||||||
|
|
||||||
|
class point
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
BOOST_DESCRIBE_CLASS(point, (), (), (), (x, y))
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
point() : x(0), y(0) {}
|
||||||
|
point(int x, int y) : x(x), y(y) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
using boost::describe::operators::operator==;
|
||||||
|
using boost::describe::operators::operator!=;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
boost::hash<point> point_hasher;
|
||||||
|
|
||||||
|
point p1(0, 0);
|
||||||
|
point p2(1, 2);
|
||||||
|
point p3(4, 1);
|
||||||
|
point p4 = p1;
|
||||||
|
|
||||||
|
assert(point_hasher(p1) == point_hasher(p4));
|
||||||
|
|
||||||
|
// These tests could legally fail, but if they did it'd be a pretty bad
|
||||||
|
// hash function.
|
||||||
|
assert(point_hasher(p1) != point_hasher(p2));
|
||||||
|
assert(point_hasher(p1) != point_hasher(p3));
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::puts( "This example requires C++14." );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -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
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
#ifndef BOOST_HASH_DETAIL_HASH_MIX_HPP
|
#ifndef BOOST_HASH_DETAIL_HASH_MIX_HPP
|
||||||
#define BOOST_HASH_DETAIL_HASH_MIX_HPP
|
#define BOOST_HASH_DETAIL_HASH_MIX_HPP
|
||||||
|
|
||||||
#include <boost/cstdint.hpp>
|
#include <cstdint>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
|
||||||
@@ -66,9 +66,9 @@ template<std::size_t Bits> struct hash_mix_impl;
|
|||||||
|
|
||||||
template<> struct hash_mix_impl<64>
|
template<> struct hash_mix_impl<64>
|
||||||
{
|
{
|
||||||
inline static boost::uint64_t fn( boost::uint64_t x )
|
inline static std::uint64_t fn( std::uint64_t x )
|
||||||
{
|
{
|
||||||
boost::uint64_t const m = (boost::uint64_t(0xe9846af) << 32) + 0x9b1a615d;
|
std::uint64_t const m = 0xe9846af9b1a615d;
|
||||||
|
|
||||||
x ^= x >> 32;
|
x ^= x >> 32;
|
||||||
x *= m;
|
x *= m;
|
||||||
@@ -87,10 +87,10 @@ template<> struct hash_mix_impl<64>
|
|||||||
|
|
||||||
template<> struct hash_mix_impl<32>
|
template<> struct hash_mix_impl<32>
|
||||||
{
|
{
|
||||||
inline static boost::uint32_t fn( boost::uint32_t x )
|
inline static std::uint32_t fn( std::uint32_t x )
|
||||||
{
|
{
|
||||||
boost::uint32_t const m1 = 0x21f0aaad;
|
std::uint32_t const m1 = 0x21f0aaad;
|
||||||
boost::uint32_t const m2 = 0x735a2d97;
|
std::uint32_t const m2 = 0x735a2d97;
|
||||||
|
|
||||||
x ^= x >> 16;
|
x ^= x >> 16;
|
||||||
x *= m1;
|
x *= m1;
|
||||||
|
|||||||
@@ -6,31 +6,42 @@
|
|||||||
#define BOOST_HASH_DETAIL_HASH_RANGE_HPP
|
#define BOOST_HASH_DETAIL_HASH_RANGE_HPP
|
||||||
|
|
||||||
#include <boost/container_hash/hash_fwd.hpp>
|
#include <boost/container_hash/hash_fwd.hpp>
|
||||||
#include <boost/type_traits/integral_constant.hpp>
|
#include <boost/container_hash/detail/mulx.hpp>
|
||||||
#include <boost/type_traits/enable_if.hpp>
|
#include <type_traits>
|
||||||
#include <boost/type_traits/is_same.hpp>
|
#include <cstdint>
|
||||||
#include <boost/cstdint.hpp>
|
#include <iterator>
|
||||||
|
#include <limits>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <iterator>
|
#include <cstring>
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
namespace hash_detail
|
namespace hash_detail
|
||||||
{
|
{
|
||||||
|
|
||||||
template<class T> struct is_char_type: public boost::false_type {};
|
template<class T> struct is_char_type: public std::false_type {};
|
||||||
|
|
||||||
#if CHAR_BIT == 8
|
#if CHAR_BIT == 8
|
||||||
|
|
||||||
template<> struct is_char_type<char>: public boost::true_type {};
|
template<> struct is_char_type<char>: public std::true_type {};
|
||||||
template<> struct is_char_type<signed char>: public boost::true_type {};
|
template<> struct is_char_type<signed char>: public std::true_type {};
|
||||||
template<> struct is_char_type<unsigned char>: public boost::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
|
#endif
|
||||||
|
|
||||||
|
// generic version
|
||||||
|
|
||||||
template<class It>
|
template<class It>
|
||||||
inline typename boost::enable_if_<
|
inline typename std::enable_if<
|
||||||
!is_char_type<typename std::iterator_traits<It>::value_type>::value,
|
!is_char_type<typename std::iterator_traits<It>::value_type>::value,
|
||||||
std::size_t >::type
|
std::size_t >::type
|
||||||
hash_range( std::size_t seed, It first, It last )
|
hash_range( std::size_t seed, It first, It last )
|
||||||
@@ -43,120 +54,352 @@ std::size_t >::type
|
|||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class It>
|
// specialized char[] version, 32 bit
|
||||||
inline typename boost::enable_if_<
|
|
||||||
is_char_type<typename std::iterator_traits<It>::value_type>::value &&
|
template<class It> inline std::uint32_t read32le( It p )
|
||||||
is_same<typename std::iterator_traits<It>::iterator_category, std::random_access_iterator_tag>::value,
|
|
||||||
std::size_t>::type
|
|
||||||
hash_range( std::size_t seed, It first, It last )
|
|
||||||
{
|
{
|
||||||
std::size_t n = static_cast<std::size_t>( last - first );
|
// 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
|
||||||
|
|
||||||
for( ; n >= 4; first += 4, n -= 4 )
|
std::uint32_t w =
|
||||||
{
|
static_cast<std::uint32_t>( static_cast<unsigned char>( p[0] ) ) |
|
||||||
// clang 5+, gcc 5+ figure out this pattern and use a single mov on x86
|
static_cast<std::uint32_t>( static_cast<unsigned char>( p[1] ) ) << 8 |
|
||||||
// gcc on s390x and power BE even knows how to use load-reverse
|
static_cast<std::uint32_t>( static_cast<unsigned char>( p[2] ) ) << 16 |
|
||||||
|
static_cast<std::uint32_t>( static_cast<unsigned char>( p[3] ) ) << 24;
|
||||||
|
|
||||||
boost::uint32_t w =
|
return w;
|
||||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[0] ) ) |
|
}
|
||||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[1] ) ) << 8 |
|
|
||||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[2] ) ) << 16 |
|
|
||||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[3] ) ) << 24;
|
|
||||||
|
|
||||||
hash_combine( seed, w );
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
}
|
|
||||||
|
|
||||||
{
|
template<class T> inline std::uint32_t read32le( T* p )
|
||||||
// add a trailing suffix byte of 0x01 because otherwise sequences of
|
{
|
||||||
// trailing zeroes are indistinguishable from end of string
|
std::uint32_t w;
|
||||||
|
|
||||||
boost::uint32_t w = 0x01u;
|
std::memcpy( &w, p, 4 );
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
switch( n )
|
#endif
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
|
|
||||||
w =
|
inline std::uint64_t mul32( std::uint32_t x, std::uint32_t y )
|
||||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[0] ) ) |
|
{
|
||||||
0x0100u;
|
return static_cast<std::uint64_t>( x ) * y;
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
|
|
||||||
w =
|
|
||||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[0] ) ) |
|
|
||||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[1] ) ) << 8 |
|
|
||||||
0x010000u;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
|
|
||||||
w =
|
|
||||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[0] ) ) |
|
|
||||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[1] ) ) << 8 |
|
|
||||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[2] ) ) << 16 |
|
|
||||||
0x01000000u;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
hash_combine( seed, w );
|
|
||||||
}
|
|
||||||
|
|
||||||
return seed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class It>
|
template<class It>
|
||||||
inline typename boost::enable_if_<
|
inline typename std::enable_if<
|
||||||
is_char_type<typename std::iterator_traits<It>::value_type>::value &&
|
is_char_type<typename std::iterator_traits<It>::value_type>::value &&
|
||||||
!is_same<typename std::iterator_traits<It>::iterator_category, std::random_access_iterator_tag>::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
|
std::size_t>::type
|
||||||
hash_range( std::size_t seed, It first, It last )
|
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( ;; )
|
for( ;; )
|
||||||
{
|
{
|
||||||
boost::uint32_t w = 0;
|
v1 = 0;
|
||||||
|
|
||||||
if( first == last )
|
if( first == last )
|
||||||
{
|
{
|
||||||
hash_combine( seed, w | 0x01u );
|
break;
|
||||||
return seed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
w |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) );
|
v1 |= static_cast<std::uint32_t>( static_cast<unsigned char>( *first ) );
|
||||||
++first;
|
++first;
|
||||||
|
++n;
|
||||||
|
|
||||||
if( first == last )
|
if( first == last )
|
||||||
{
|
{
|
||||||
hash_combine( seed, w | 0x0100u );
|
break;
|
||||||
return seed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
w |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) ) << 8;
|
v1 |= static_cast<std::uint32_t>( static_cast<unsigned char>( *first ) ) << 8;
|
||||||
++first;
|
++first;
|
||||||
|
++n;
|
||||||
|
|
||||||
if( first == last )
|
if( first == last )
|
||||||
{
|
{
|
||||||
hash_combine( seed, w | 0x010000u );
|
break;
|
||||||
return seed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
w |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) ) << 16;
|
v1 |= static_cast<std::uint32_t>( static_cast<unsigned char>( *first ) ) << 16;
|
||||||
++first;
|
++first;
|
||||||
|
++n;
|
||||||
|
|
||||||
if( first == last )
|
if( first == last )
|
||||||
{
|
{
|
||||||
hash_combine( seed, w | 0x01000000u );
|
break;
|
||||||
return seed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
w |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) ) << 24;
|
v1 |= static_cast<std::uint32_t>( static_cast<unsigned char>( *first ) ) << 24;
|
||||||
++first;
|
++first;
|
||||||
|
++n;
|
||||||
|
|
||||||
hash_combine( seed, w );
|
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 hash_detail
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// Copyright 2005-2014 Daniel James.
|
// Copyright 2005-2014 Daniel James.
|
||||||
// Copyright 2021, 2022 Peter Dimov.
|
// Copyright 2021, 2022, 2025 Peter Dimov.
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
// https://www.boost.org/LICENSE_1_0.txt
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
@@ -11,21 +11,24 @@
|
|||||||
#define BOOST_FUNCTIONAL_HASH_HASH_HPP
|
#define BOOST_FUNCTIONAL_HASH_HASH_HPP
|
||||||
|
|
||||||
#include <boost/container_hash/hash_fwd.hpp>
|
#include <boost/container_hash/hash_fwd.hpp>
|
||||||
|
#include <boost/container_hash/hash_is_avalanching.hpp>
|
||||||
#include <boost/container_hash/is_range.hpp>
|
#include <boost/container_hash/is_range.hpp>
|
||||||
#include <boost/container_hash/is_contiguous_range.hpp>
|
#include <boost/container_hash/is_contiguous_range.hpp>
|
||||||
#include <boost/container_hash/is_unordered_range.hpp>
|
#include <boost/container_hash/is_unordered_range.hpp>
|
||||||
#include <boost/container_hash/detail/hash_tuple.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_mix.hpp>
|
||||||
#include <boost/container_hash/detail/hash_range.hpp>
|
#include <boost/container_hash/detail/hash_range.hpp>
|
||||||
#include <boost/type_traits/is_enum.hpp>
|
#include <boost/describe/bases.hpp>
|
||||||
#include <boost/type_traits/is_integral.hpp>
|
#include <boost/describe/members.hpp>
|
||||||
#include <boost/type_traits/is_floating_point.hpp>
|
#include <type_traits>
|
||||||
#include <boost/type_traits/is_signed.hpp>
|
#include <cstdint>
|
||||||
#include <boost/type_traits/is_unsigned.hpp>
|
|
||||||
#include <boost/type_traits/make_unsigned.hpp>
|
#if defined(BOOST_DESCRIBE_CXX14)
|
||||||
#include <boost/type_traits/enable_if.hpp>
|
# include <boost/mp11/algorithm.hpp>
|
||||||
#include <boost/type_traits/conjunction.hpp>
|
#endif
|
||||||
#include <boost/cstdint.hpp>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <complex>
|
#include <complex>
|
||||||
@@ -54,6 +57,10 @@
|
|||||||
#include <variant>
|
#include <variant>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
|
||||||
|
# include <string_view>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -62,95 +69,12 @@ namespace boost
|
|||||||
//
|
//
|
||||||
|
|
||||||
// integral types
|
// integral types
|
||||||
|
// in detail/hash_integral.hpp
|
||||||
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 ) + 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, 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 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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// enumeration types
|
// enumeration types
|
||||||
|
|
||||||
template <typename T>
|
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 )
|
hash_value( T v )
|
||||||
{
|
{
|
||||||
// This should in principle return the equivalent of
|
// This should in principle return the equivalent of
|
||||||
@@ -176,16 +100,15 @@ namespace boost
|
|||||||
{
|
{
|
||||||
template<class T,
|
template<class T,
|
||||||
std::size_t Bits = sizeof(T) * CHAR_BIT,
|
std::size_t Bits = sizeof(T) * CHAR_BIT,
|
||||||
int Digits = std::numeric_limits<T>::digits,
|
int Digits = std::numeric_limits<T>::digits>
|
||||||
std::size_t size_t_bits = sizeof(std::size_t) * CHAR_BIT>
|
|
||||||
struct hash_float_impl;
|
struct hash_float_impl;
|
||||||
|
|
||||||
// float
|
// float
|
||||||
template<class T, int Digits, std::size_t size_t_bits> struct hash_float_impl<T, 32, Digits, size_t_bits>
|
template<class T, int Digits> struct hash_float_impl<T, 32, Digits>
|
||||||
{
|
{
|
||||||
static std::size_t fn( T v )
|
static std::size_t fn( T v )
|
||||||
{
|
{
|
||||||
boost::uint32_t w;
|
std::uint32_t w;
|
||||||
std::memcpy( &w, &v, sizeof( v ) );
|
std::memcpy( &w, &v, sizeof( v ) );
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
@@ -193,107 +116,57 @@ namespace boost
|
|||||||
};
|
};
|
||||||
|
|
||||||
// double
|
// double
|
||||||
template<class T, int Digits> struct hash_float_impl<T, 64, Digits, 64>
|
template<class T, int Digits> struct hash_float_impl<T, 64, Digits>
|
||||||
{
|
{
|
||||||
static std::size_t fn( T v )
|
static std::size_t fn( T v )
|
||||||
{
|
{
|
||||||
boost::uint64_t w;
|
std::uint64_t w;
|
||||||
std::memcpy( &w, &v, sizeof( v ) );
|
std::memcpy( &w, &v, sizeof( v ) );
|
||||||
|
|
||||||
return w;
|
return hash_value( w );
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T, int Digits> struct hash_float_impl<T, 64, Digits, 32>
|
|
||||||
{
|
|
||||||
static std::size_t fn( T v )
|
|
||||||
{
|
|
||||||
boost::uint32_t w[ 2 ];
|
|
||||||
std::memcpy( &w, &v, sizeof( v ) );
|
|
||||||
|
|
||||||
std::size_t seed = 0;
|
|
||||||
|
|
||||||
seed = static_cast<std::size_t>( w[0] ) + hash_detail::hash_mix( seed );
|
|
||||||
seed = static_cast<std::size_t>( w[1] ) + hash_detail::hash_mix( seed );
|
|
||||||
|
|
||||||
return seed;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 80 bit long double in 12 bytes
|
// 80 bit long double in 12 bytes
|
||||||
template<class T> struct hash_float_impl<T, 96, 64, 64>
|
template<class T> struct hash_float_impl<T, 96, 64>
|
||||||
{
|
{
|
||||||
static std::size_t fn( T v )
|
static std::size_t fn( T v )
|
||||||
{
|
{
|
||||||
boost::uint64_t w[ 2 ] = {};
|
std::uint64_t w[ 2 ] = {};
|
||||||
std::memcpy( &w, &v, 80 / CHAR_BIT );
|
std::memcpy( &w, &v, 80 / CHAR_BIT );
|
||||||
|
|
||||||
std::size_t seed = 0;
|
std::size_t seed = 0;
|
||||||
|
|
||||||
seed = static_cast<std::size_t>( w[0] ) + hash_detail::hash_mix( seed );
|
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
|
||||||
seed = static_cast<std::size_t>( w[1] ) + hash_detail::hash_mix( seed );
|
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
|
||||||
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T> struct hash_float_impl<T, 96, 64, 32>
|
|
||||||
{
|
|
||||||
static std::size_t fn( T v )
|
|
||||||
{
|
|
||||||
boost::uint32_t w[ 3 ] = {};
|
|
||||||
std::memcpy( &w, &v, 80 / CHAR_BIT );
|
|
||||||
|
|
||||||
std::size_t seed = 0;
|
|
||||||
|
|
||||||
seed = static_cast<std::size_t>( w[0] ) + hash_detail::hash_mix( seed );
|
|
||||||
seed = static_cast<std::size_t>( w[1] ) + hash_detail::hash_mix( seed );
|
|
||||||
seed = static_cast<std::size_t>( w[2] ) + hash_detail::hash_mix( seed );
|
|
||||||
|
|
||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 80 bit long double in 16 bytes
|
// 80 bit long double in 16 bytes
|
||||||
template<class T> struct hash_float_impl<T, 128, 64, 64>
|
template<class T> struct hash_float_impl<T, 128, 64>
|
||||||
{
|
{
|
||||||
static std::size_t fn( T v )
|
static std::size_t fn( T v )
|
||||||
{
|
{
|
||||||
boost::uint64_t w[ 2 ] = {};
|
std::uint64_t w[ 2 ] = {};
|
||||||
std::memcpy( &w, &v, 80 / CHAR_BIT );
|
std::memcpy( &w, &v, 80 / CHAR_BIT );
|
||||||
|
|
||||||
std::size_t seed = 0;
|
std::size_t seed = 0;
|
||||||
|
|
||||||
seed = static_cast<std::size_t>( w[0] ) + hash_detail::hash_mix( seed );
|
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
|
||||||
seed = static_cast<std::size_t>( w[1] ) + hash_detail::hash_mix( seed );
|
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
|
||||||
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T> struct hash_float_impl<T, 128, 64, 32>
|
|
||||||
{
|
|
||||||
static std::size_t fn( T v )
|
|
||||||
{
|
|
||||||
boost::uint32_t w[ 3 ] = {};
|
|
||||||
std::memcpy( &w, &v, 80 / CHAR_BIT );
|
|
||||||
|
|
||||||
std::size_t seed = 0;
|
|
||||||
|
|
||||||
seed = static_cast<std::size_t>( w[0] ) + hash_detail::hash_mix( seed );
|
|
||||||
seed = static_cast<std::size_t>( w[1] ) + hash_detail::hash_mix( seed );
|
|
||||||
seed = static_cast<std::size_t>( w[2] ) + hash_detail::hash_mix( seed );
|
|
||||||
|
|
||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 128 bit long double
|
// 128 bit long double
|
||||||
template<class T, int Digits, std::size_t size_t_bits> struct hash_float_impl<T, 128, Digits, size_t_bits>
|
template<class T, int Digits> struct hash_float_impl<T, 128, Digits>
|
||||||
{
|
{
|
||||||
static std::size_t fn( T v )
|
static std::size_t fn( T v )
|
||||||
{
|
{
|
||||||
boost::uint64_t w[ 2 ];
|
std::uint64_t w[ 2 ];
|
||||||
std::memcpy( &w, &v, sizeof( v ) );
|
std::memcpy( &w, &v, sizeof( v ) );
|
||||||
|
|
||||||
std::size_t seed = 0;
|
std::size_t seed = 0;
|
||||||
@@ -316,7 +189,7 @@ namespace boost
|
|||||||
} // namespace hash_detail
|
} // namespace hash_detail
|
||||||
|
|
||||||
template <typename T>
|
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 )
|
hash_value( T v )
|
||||||
{
|
{
|
||||||
return boost::hash_detail::hash_float_impl<T>::fn( v + 0 );
|
return boost::hash_detail::hash_float_impl<T>::fn( v + 0 );
|
||||||
@@ -327,7 +200,7 @@ namespace boost
|
|||||||
// `x + (x >> 3)` adjustment by Alberto Barbati and Dave Harris.
|
// `x + (x >> 3)` adjustment by Alberto Barbati and Dave Harris.
|
||||||
template <class T> std::size_t hash_value( T* const& v )
|
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) );
|
return boost::hash_value( x + (x >> 3) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,7 +245,7 @@ namespace boost
|
|||||||
// ranges (list, set, deque...)
|
// ranges (list, set, deque...)
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename boost::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
|
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 )
|
hash_value( T const& v )
|
||||||
{
|
{
|
||||||
return boost::hash_range( v.begin(), v.end() );
|
return boost::hash_range( v.begin(), v.end() );
|
||||||
@@ -381,7 +254,7 @@ namespace boost
|
|||||||
// contiguous ranges (string, vector, array)
|
// contiguous ranges (string, vector, array)
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename boost::enable_if_<container_hash::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 )
|
hash_value( T const& v )
|
||||||
{
|
{
|
||||||
return boost::hash_range( v.data(), v.data() + v.size() );
|
return boost::hash_range( v.data(), v.data() + v.size() );
|
||||||
@@ -390,7 +263,7 @@ namespace boost
|
|||||||
// unordered ranges (unordered_set, unordered_map)
|
// unordered ranges (unordered_set, unordered_map)
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename boost::enable_if_<container_hash::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 )
|
hash_value( T const& v )
|
||||||
{
|
{
|
||||||
return boost::hash_unordered_range( v.begin(), v.end() );
|
return boost::hash_unordered_range( v.begin(), v.end() );
|
||||||
@@ -403,7 +276,7 @@ namespace boost
|
|||||||
// resolve ambiguity with unconstrained stdext::hash_value in <xhash> :-/
|
// resolve ambiguity with unconstrained stdext::hash_value in <xhash> :-/
|
||||||
|
|
||||||
template<template<class...> class L, class... T>
|
template<template<class...> class L, class... T>
|
||||||
typename boost::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
|
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 )
|
hash_value( L<T...> const& v )
|
||||||
{
|
{
|
||||||
return boost::hash_range( v.begin(), v.end() );
|
return boost::hash_range( v.begin(), v.end() );
|
||||||
@@ -412,14 +285,14 @@ namespace boost
|
|||||||
// contiguous ranges (string, vector, array)
|
// contiguous ranges (string, vector, array)
|
||||||
|
|
||||||
template<template<class...> class L, class... T>
|
template<template<class...> class L, class... T>
|
||||||
typename boost::enable_if_<container_hash::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 )
|
hash_value( L<T...> const& v )
|
||||||
{
|
{
|
||||||
return boost::hash_range( v.data(), v.data() + v.size() );
|
return boost::hash_range( v.data(), v.data() + v.size() );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<template<class, std::size_t> class L, class T, std::size_t N>
|
template<template<class, std::size_t> class L, class T, std::size_t N>
|
||||||
typename boost::enable_if_<container_hash::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 )
|
hash_value( L<T, N> const& v )
|
||||||
{
|
{
|
||||||
return boost::hash_range( v.data(), v.data() + v.size() );
|
return boost::hash_range( v.data(), v.data() + v.size() );
|
||||||
@@ -428,12 +301,55 @@ namespace boost
|
|||||||
// unordered ranges (unordered_set, unordered_map)
|
// unordered ranges (unordered_set, unordered_map)
|
||||||
|
|
||||||
template<template<class...> class L, class... T>
|
template<template<class...> class L, class... T>
|
||||||
typename boost::enable_if_<container_hash::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 )
|
hash_value( L<T...> const& v )
|
||||||
{
|
{
|
||||||
return boost::hash_unordered_range( v.begin(), v.end() );
|
return boost::hash_unordered_range( v.begin(), v.end() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// described classes
|
||||||
|
|
||||||
|
#if defined(BOOST_DESCRIBE_CXX14)
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER == 1900
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable: 4100) // unreferenced formal parameter
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename 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
|
#endif
|
||||||
|
|
||||||
// std::unique_ptr, std::shared_ptr
|
// std::unique_ptr, std::shared_ptr
|
||||||
@@ -489,6 +405,19 @@ namespace boost
|
|||||||
return seed;
|
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
|
#endif
|
||||||
|
|
||||||
// std::optional
|
// std::optional
|
||||||
@@ -500,7 +429,7 @@ namespace boost
|
|||||||
{
|
{
|
||||||
if( !v )
|
if( !v )
|
||||||
{
|
{
|
||||||
// Arbitray value for empty optional.
|
// Arbitrary value for empty optional.
|
||||||
return 0x12345678;
|
return 0x12345678;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -526,7 +455,11 @@ namespace boost
|
|||||||
std::size_t seed = 0;
|
std::size_t seed = 0;
|
||||||
|
|
||||||
hash_combine( seed, v.index() );
|
hash_combine( seed, v.index() );
|
||||||
std::visit( [&seed](auto&& x) { hash_combine(seed, x); }, v );
|
|
||||||
|
if( !v.valueless_by_exception() )
|
||||||
|
{
|
||||||
|
std::visit( [&seed](auto&& x) { hash_combine(seed, x); }, v );
|
||||||
|
}
|
||||||
|
|
||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
@@ -628,8 +561,17 @@ namespace boost
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
#undef BOOST_FUNCTIONAL_HASH_ROTL32
|
// 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 boost
|
||||||
|
|
||||||
#endif // #ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP
|
#endif // #ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Copyright 2005-2009 Daniel James.
|
// Copyright 2005-2009 Daniel James.
|
||||||
// Copyright 2021 Peter Dimov.
|
// Copyright 2021, 2022, 2025 Peter Dimov.
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
// https://www.boost.org/LICENSE_1_0.txt
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
@@ -17,6 +17,8 @@ namespace container_hash
|
|||||||
template<class T> struct is_range;
|
template<class T> struct is_range;
|
||||||
template<class T> struct is_contiguous_range;
|
template<class T> struct is_contiguous_range;
|
||||||
template<class T> struct is_unordered_range;
|
template<class T> struct is_unordered_range;
|
||||||
|
template<class T> struct is_described_class;
|
||||||
|
template<class T> struct is_tuple_like;
|
||||||
|
|
||||||
} // namespace container_hash
|
} // namespace container_hash
|
||||||
|
|
||||||
@@ -30,6 +32,8 @@ 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> void hash_unordered_range( std::size_t&, It, It );
|
||||||
template<class It> std::size_t hash_unordered_range( It, It );
|
template<class It> std::size_t hash_unordered_range( It, It );
|
||||||
|
|
||||||
|
template<class Hash> struct hash_is_avalanching;
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
#endif // #ifndef BOOST_FUNCTIONAL_HASH_FWD_HPP
|
#endif // #ifndef BOOST_FUNCTIONAL_HASH_FWD_HPP
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2025 Joaquin M Lopez Munoz.
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
|
#ifndef BOOST_HASH_HASH_IS_AVALANCHING_HPP_INCLUDED
|
||||||
|
#define BOOST_HASH_HASH_IS_AVALANCHING_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
namespace hash_detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<class... Ts> struct make_void
|
||||||
|
{
|
||||||
|
using type = void;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class... Ts> using void_t = typename make_void<Ts...>::type;
|
||||||
|
|
||||||
|
template<class IsAvalanching> struct avalanching_value
|
||||||
|
{
|
||||||
|
static constexpr bool value = IsAvalanching::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// may be explicitly marked as BOOST_DEPRECATED in the future
|
||||||
|
template<> struct avalanching_value<void>
|
||||||
|
{
|
||||||
|
static constexpr bool value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Hash, class = void> struct hash_is_avalanching_impl: std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Hash> struct hash_is_avalanching_impl<Hash, void_t<typename Hash::is_avalanching> >:
|
||||||
|
std::integral_constant<bool, avalanching_value<typename Hash::is_avalanching>::value>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Hash>
|
||||||
|
struct hash_is_avalanching_impl<Hash, typename std::enable_if< ((void)Hash::is_avalanching, true) >::type>
|
||||||
|
{
|
||||||
|
// Hash::is_avalanching is not a type: we don't define value to produce
|
||||||
|
// a compile error downstream
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace hash_detail
|
||||||
|
|
||||||
|
template<class Hash> struct hash_is_avalanching: hash_detail::hash_is_avalanching_impl<Hash>::type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // #ifndef BOOST_HASH_HASH_IS_AVALANCHING_HPP_INCLUDED
|
||||||
@@ -6,15 +6,12 @@
|
|||||||
#define BOOST_HASH_IS_CONTIGUOUS_RANGE_HPP_INCLUDED
|
#define BOOST_HASH_IS_CONTIGUOUS_RANGE_HPP_INCLUDED
|
||||||
|
|
||||||
#include <boost/container_hash/is_range.hpp>
|
#include <boost/container_hash/is_range.hpp>
|
||||||
#include <boost/type_traits/integral_constant.hpp>
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#include <boost/config/workaround.hpp>
|
#include <boost/config/workaround.hpp>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700)
|
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
|
||||||
|
|
||||||
#include <boost/type_traits/is_integral.hpp>
|
|
||||||
#include <boost/type_traits/declval.hpp>
|
|
||||||
#include <boost/type_traits/is_same.hpp>
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
@@ -23,11 +20,11 @@ namespace hash_detail
|
|||||||
{
|
{
|
||||||
|
|
||||||
template<class It, class T, class S>
|
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 >
|
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 );
|
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> 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> false_type is_contiguous_range_( ... );
|
template<class T> std::false_type is_contiguous_range_( ... );
|
||||||
|
|
||||||
template<class T> struct is_contiguous_range: decltype( hash_detail::is_contiguous_range_<T>( 0 ) )
|
template<class T> struct is_contiguous_range: decltype( hash_detail::is_contiguous_range_<T>( 0 ) )
|
||||||
{
|
{
|
||||||
@@ -38,54 +35,64 @@ template<class T> struct is_contiguous_range: decltype( hash_detail::is_contiguo
|
|||||||
namespace container_hash
|
namespace container_hash
|
||||||
{
|
{
|
||||||
|
|
||||||
template<class T> struct is_contiguous_range: integral_constant< bool, is_range<T>::value && hash_detail::is_contiguous_range<T>::value >
|
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 container_hash
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
#else // !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR)
|
#else // !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
namespace container_hash
|
namespace container_hash
|
||||||
{
|
{
|
||||||
|
|
||||||
template<class T> struct is_contiguous_range: false_type
|
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> >: true_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 >: true_type
|
template<class E, class T, class A> struct is_contiguous_range< std::basic_string<E, T, A> const >: std::true_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
|
template<class T, class A> struct is_contiguous_range< std::vector<T, A> >: std::true_type
|
||||||
|
|
||||||
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
|
template<class T, class A> struct is_contiguous_range< std::vector<T, A> const >: std::true_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
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 container_hash
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
#endif // !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR)
|
#endif // !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
|
||||||
|
|
||||||
#endif // #ifndef BOOST_HASH_IS_CONTIGUOUS_RANGE_HPP_INCLUDED
|
#endif // #ifndef BOOST_HASH_IS_CONTIGUOUS_RANGE_HPP_INCLUDED
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -5,28 +5,25 @@
|
|||||||
#ifndef BOOST_HASH_IS_RANGE_HPP_INCLUDED
|
#ifndef BOOST_HASH_IS_RANGE_HPP_INCLUDED
|
||||||
#define BOOST_HASH_IS_RANGE_HPP_INCLUDED
|
#define BOOST_HASH_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>
|
#include <iterator>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700)
|
|
||||||
|
|
||||||
namespace hash_detail
|
namespace hash_detail
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template<class T> struct iterator_traits: std::iterator_traits<T> {};
|
||||||
|
template<> struct iterator_traits< void* > {};
|
||||||
|
template<> struct iterator_traits< void const* > {};
|
||||||
|
|
||||||
template<class T, class It>
|
template<class T, class It>
|
||||||
integral_constant< bool, !is_same<typename remove_cv<T>::type, typename std::iterator_traits<It>::value_type>::value >
|
std::integral_constant< bool, !std::is_same<typename std::remove_cv<T>::type, typename iterator_traits<It>::value_type>::value >
|
||||||
is_range_check( It first, It last );
|
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> decltype( is_range_check<T>( std::declval<T const&>().begin(), std::declval<T const&>().end() ) ) is_range_( int );
|
||||||
template<class T> false_type is_range_( ... );
|
template<class T> std::false_type is_range_( ... );
|
||||||
|
|
||||||
} // namespace hash_detail
|
} // namespace hash_detail
|
||||||
|
|
||||||
@@ -39,35 +36,6 @@ template<class T> struct is_range: decltype( hash_detail::is_range_<T>( 0 ) )
|
|||||||
|
|
||||||
} // namespace container_hash
|
} // namespace container_hash
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
namespace hash_detail
|
|
||||||
{
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace hash_detail
|
|
||||||
|
|
||||||
namespace container_hash
|
|
||||||
{
|
|
||||||
|
|
||||||
template<class T> struct is_range: hash_detail::is_range_<T>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace container_hash
|
|
||||||
|
|
||||||
#endif // !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR)
|
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
#endif // #ifndef BOOST_HASH_IS_RANGE_HPP_INCLUDED
|
#endif // #ifndef BOOST_HASH_IS_RANGE_HPP_INCLUDED
|
||||||
|
|||||||
@@ -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_< typename std::remove_cv<T>::type >
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace container_hash
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // #ifndef BOOST_HASH_IS_TUPLE_LIKE_HPP_INCLUDED
|
||||||
@@ -6,21 +6,20 @@
|
|||||||
#define BOOST_HASH_IS_UNORDERED_RANGE_HPP_INCLUDED
|
#define BOOST_HASH_IS_UNORDERED_RANGE_HPP_INCLUDED
|
||||||
|
|
||||||
#include <boost/container_hash/is_range.hpp>
|
#include <boost/container_hash/is_range.hpp>
|
||||||
#include <boost/type_traits/integral_constant.hpp>
|
#include <type_traits>
|
||||||
#include <boost/type_traits/is_same.hpp>
|
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
namespace hash_detail
|
namespace hash_detail
|
||||||
{
|
{
|
||||||
|
|
||||||
template<class T, class E = true_type> struct has_hasher_: false_type
|
template<class T, class E = std::true_type> struct has_hasher_: std::false_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T> struct has_hasher_< T, integral_constant< bool,
|
template<class T> struct has_hasher_< T, std::integral_constant< bool,
|
||||||
is_same<typename T::hasher, typename T::hasher>::value
|
std::is_same<typename T::hasher, typename T::hasher>::value
|
||||||
> >: true_type
|
> >: std::true_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -29,7 +28,7 @@ template<class T> struct has_hasher_< T, integral_constant< bool,
|
|||||||
namespace container_hash
|
namespace container_hash
|
||||||
{
|
{
|
||||||
|
|
||||||
template<class T> struct is_unordered_range: integral_constant< bool, is_range<T>::value && hash_detail::has_hasher_<T>::value >
|
template<class T> struct is_unordered_range: std::integral_constant< bool, is_range<T>::value && hash_detail::has_hasher_<T>::value >
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -7,7 +7,7 @@
|
|||||||
"Daniel James"
|
"Daniel James"
|
||||||
],
|
],
|
||||||
"maintainers": [
|
"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.",
|
"description": "An STL-compatible hash function object that can be extended to hash user defined types.",
|
||||||
"std": [
|
"std": [
|
||||||
@@ -16,6 +16,6 @@
|
|||||||
"category": [
|
"category": [
|
||||||
"Function-objects"
|
"Function-objects"
|
||||||
],
|
],
|
||||||
"cxxstd": "03"
|
"cxxstd": "11"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
+3
-2
@@ -1,4 +1,4 @@
|
|||||||
# Copyright 2018, 2019, 2021 Peter Dimov
|
# Copyright 2018, 2019, 2021, 2022, 2025 Peter Dimov
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
|
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
@@ -6,6 +6,7 @@ include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
|
|||||||
|
|
||||||
if(HAVE_BOOST_TEST)
|
if(HAVE_BOOST_TEST)
|
||||||
|
|
||||||
boost_test_jamfile(FILE Jamfile.v2 LINK_LIBRARIES Boost::container_hash Boost::core Boost::utility)
|
boost_test_jamfile(FILE Jamfile.v2
|
||||||
|
LINK_LIBRARIES Boost::container_hash Boost::core Boost::utility)
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
+41
-5
@@ -1,5 +1,5 @@
|
|||||||
# Copyright 2005-2012 Daniel James.
|
# Copyright 2005-2012 Daniel James.
|
||||||
# Copyright 2022 Peter Dimov
|
# Copyright 2022, 2025 Peter Dimov
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
# https://www.boost.org/LICENSE_1_0.txt
|
# https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
@@ -10,6 +10,10 @@ local clang-flags = $(gcc-flags) -Wno-c99-extensions ;
|
|||||||
|
|
||||||
project hash-tests
|
project hash-tests
|
||||||
: requirements
|
: requirements
|
||||||
|
<library>/boost/container_hash//boost_container_hash
|
||||||
|
<library>/boost/core//boost_core
|
||||||
|
<library>/boost/type_traits//boost_type_traits
|
||||||
|
|
||||||
<warnings>pedantic
|
<warnings>pedantic
|
||||||
<toolset>intel:<warnings>on
|
<toolset>intel:<warnings>on
|
||||||
<toolset>gcc:<cxxflags>$(gcc-flags)
|
<toolset>gcc:<cxxflags>$(gcc-flags)
|
||||||
@@ -72,13 +76,15 @@ run quick.cpp ;
|
|||||||
|
|
||||||
run hash_number_test2.cpp ;
|
run hash_number_test2.cpp ;
|
||||||
run hash_integral_test.cpp ;
|
run hash_integral_test.cpp ;
|
||||||
run hash_string_test2.cpp ;
|
run hash_string_test2.cpp
|
||||||
|
/boost/utility//boost_utility ;
|
||||||
|
|
||||||
# for gcc-4.8
|
# for gcc-4.8
|
||||||
local fs-path-req = "-<toolset>gcc:<cxxflags>-Wshadow" "-<toolset>gcc:<cxxflags>-Wconversion" ;
|
local fs-path-req = <library>/boost/filesystem//boost_filesystem/<warnings>off "-<toolset>gcc:<cxxflags>-Wshadow" "-<toolset>gcc:<cxxflags>-Wconversion" <toolset>gcc-4.7:<build>no <undefined-sanitizer>norecover:<link>static ;
|
||||||
|
|
||||||
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 ;
|
run hash_fs_path_test.cpp : : : $(fs-path-req) <toolset>msvc-14.0,<cxxstd>latest:<build>no ;
|
||||||
run is_range_test2.cpp : : : $(fs-path-req) <toolset>msvc-8.0:<build>no ;
|
|
||||||
|
run is_range_test2.cpp : : : $(fs-path-req) ;
|
||||||
|
|
||||||
run hash_container_test.cpp ;
|
run hash_container_test.cpp ;
|
||||||
|
|
||||||
@@ -101,3 +107,33 @@ run hash_unordered_map_test.cpp ;
|
|||||||
run is_range_test3.cpp ;
|
run is_range_test3.cpp ;
|
||||||
run is_contiguous_range_test2.cpp ;
|
run is_contiguous_range_test2.cpp ;
|
||||||
run is_unordered_range_test2.cpp ;
|
run is_unordered_range_test2.cpp ;
|
||||||
|
run is_contiguous_range_test3.cpp ;
|
||||||
|
|
||||||
|
run is_described_class_test.cpp
|
||||||
|
: : : <warnings>extra ;
|
||||||
|
run is_described_class_test2.cpp
|
||||||
|
: : : <warnings>extra ;
|
||||||
|
run is_described_class_test3.cpp
|
||||||
|
: : : <warnings>extra ;
|
||||||
|
|
||||||
|
run described_class_test.cpp
|
||||||
|
: : : <warnings>extra ;
|
||||||
|
|
||||||
|
run hash_is_avalanching_test.cpp ;
|
||||||
|
run hash_is_avalanching_test2.cpp ;
|
||||||
|
run hash_is_avalanching_test3.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 ;
|
||||||
|
|
||||||
|
run is_range_test4.cpp ;
|
||||||
|
run hash_container_test2.cpp ;
|
||||||
|
|
||||||
|
run hash_variant_test2.cpp ;
|
||||||
|
|||||||
@@ -14,4 +14,4 @@ target_link_libraries(quick Boost::container_hash)
|
|||||||
enable_testing()
|
enable_testing()
|
||||||
add_test(quick quick)
|
add_test(quick quick)
|
||||||
|
|
||||||
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)
|
add_custom_target(check VERBATIM COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ project(cmake_subdir_test LANGUAGES CXX)
|
|||||||
add_subdirectory(../.. boostorg/container_hash)
|
add_subdirectory(../.. boostorg/container_hash)
|
||||||
|
|
||||||
add_subdirectory(../../../config boostorg/config)
|
add_subdirectory(../../../config boostorg/config)
|
||||||
add_subdirectory(../../../type_traits boostorg/type_traits)
|
add_subdirectory(../../../describe boostorg/describe)
|
||||||
add_subdirectory(../../../static_assert boostorg/static_assert)
|
add_subdirectory(../../../mp11 boostorg/mp11)
|
||||||
|
|
||||||
add_executable(quick ../quick.cpp)
|
add_executable(quick ../quick.cpp)
|
||||||
target_link_libraries(quick Boost::container_hash)
|
target_link_libraries(quick Boost::container_hash)
|
||||||
@@ -18,4 +18,4 @@ target_link_libraries(quick Boost::container_hash)
|
|||||||
enable_testing()
|
enable_testing()
|
||||||
add_test(quick quick)
|
add_test(quick quick)
|
||||||
|
|
||||||
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)
|
add_custom_target(check VERBATIM COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// 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"
|
#include "./config.hpp"
|
||||||
|
|
||||||
#if !defined(BOOST_HASH_TEST_EXTENSIONS)
|
#if !defined(BOOST_HASH_TEST_EXTENSIONS)
|
||||||
|
|||||||
@@ -48,5 +48,13 @@ int main()
|
|||||||
test<float>();
|
test<float>();
|
||||||
test<double>();
|
test<double>();
|
||||||
|
|
||||||
|
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||||
|
test<char8_t>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
|
||||||
|
test<std::byte>();
|
||||||
|
#endif
|
||||||
|
|
||||||
return boost::report_errors();
|
return boost::report_errors();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2024 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>
|
||||||
|
|
||||||
|
struct X1
|
||||||
|
{
|
||||||
|
void* begin() const { return nullptr; }
|
||||||
|
void* end() const { return nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::size_t hash_value( X1 const& )
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct X2
|
||||||
|
{
|
||||||
|
void const* begin() const { return nullptr; }
|
||||||
|
void const* end() const { return nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::size_t hash_value( X2 const& )
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
X1 x1;
|
||||||
|
BOOST_TEST_EQ( boost::hash<X1>()( x1 ), 1u );
|
||||||
|
|
||||||
|
X2 x2;
|
||||||
|
BOOST_TEST_EQ( boost::hash<X2>()( x2 ), 2u );
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// 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"
|
#include "hash_float_test.hpp"
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
|
|||||||
@@ -33,6 +33,11 @@
|
|||||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
// P2614 deprecates has_denorm in C++23
|
||||||
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
#endif
|
||||||
|
|
||||||
char const* float_type(float*) { return "float"; }
|
char const* float_type(float*) { return "float"; }
|
||||||
char const* float_type(double*) { return "double"; }
|
char const* float_type(double*) { return "double"; }
|
||||||
char const* float_type(long double*) { return "long double"; }
|
char const* float_type(long double*) { return "long double"; }
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
#include <boost/core/lightweight_test.hpp>
|
#include <boost/core/lightweight_test.hpp>
|
||||||
#include "./compile_time.hpp"
|
#include "./compile_time.hpp"
|
||||||
|
|
||||||
void void_func1() { static int x = 1; ++x; }
|
void void_func1() { static int x = 1; ++x; (void)x; }
|
||||||
void void_func2() { static int x = 2; --x; }
|
void void_func2() { static int x = 2; --x; (void)x; }
|
||||||
int int_func1(int) { return 0; }
|
int int_func1(int) { return 0; }
|
||||||
int int_func2(int) { return 1; }
|
int int_func2(int) { return 1; }
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include <boost/core/lightweight_test.hpp>
|
#include <boost/core/lightweight_test.hpp>
|
||||||
#include <boost/core/type_name.hpp>
|
#include <boost/core/type_name.hpp>
|
||||||
#include <boost/type_traits/is_signed.hpp>
|
#include <boost/type_traits/is_signed.hpp>
|
||||||
#include <set>
|
#include <boost/config.hpp>
|
||||||
|
|
||||||
#if defined(BOOST_MSVC)
|
#if defined(BOOST_MSVC)
|
||||||
#pragma warning(disable: 4127) // conditional expression is constant
|
#pragma warning(disable: 4127) // conditional expression is constant
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
// Copyright 2022, 2025 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/container_hash/hash_is_avalanching.hpp>
|
||||||
|
#include <boost/core/lightweight_test_trait.hpp>
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
enum my_char { min = 0, max = 255 };
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using boost::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();
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// Copyright 2022, 2025 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/container_hash/hash_is_avalanching.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 <string_view>
|
||||||
|
|
||||||
|
enum my_char { min = 0, max = 255 };
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using boost::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
|
||||||
|
|
||||||
|
#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_view<my_char> > > ));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2025 Joaquin M Lopez Munoz.
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
|
#include <boost/container_hash/hash_is_avalanching.hpp>
|
||||||
|
#include <boost/core/lightweight_test_trait.hpp>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
struct X
|
||||||
|
{
|
||||||
|
using is_avalanching = void;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Y
|
||||||
|
{
|
||||||
|
using is_avalanching = std::true_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Z
|
||||||
|
{
|
||||||
|
using is_avalanching = std::false_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct W
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using boost::hash_is_avalanching;
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< X > ));
|
||||||
|
BOOST_TEST_TRAIT_TRUE(( hash_is_avalanching< Y > ));
|
||||||
|
BOOST_TEST_TRAIT_FALSE(( hash_is_avalanching< Z > ));
|
||||||
|
BOOST_TEST_TRAIT_FALSE(( hash_is_avalanching< W > ));
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// 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"
|
#include "hash_float_test.hpp"
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -171,16 +171,16 @@ int main()
|
|||||||
|
|
||||||
#if SIZE_MAX == 4294967295U
|
#if SIZE_MAX == 4294967295U
|
||||||
|
|
||||||
BOOST_TEST_EQ( hv(1.0), 1072693248U );
|
BOOST_TEST_EQ( hv(1.0), 2619008688U );
|
||||||
BOOST_TEST_EQ( hv(-1.0), 3220176896U );
|
BOOST_TEST_EQ( hv(-1.0), 146497060U );
|
||||||
BOOST_TEST_EQ( hv(3.14), 3972386992U );
|
BOOST_TEST_EQ( hv(3.14), 101651732U );
|
||||||
BOOST_TEST_EQ( hv(-3.14), 1824903344U );
|
BOOST_TEST_EQ( hv(-3.14), 210858151U );
|
||||||
BOOST_TEST_EQ( hv(1e-308), 2213556530U );
|
BOOST_TEST_EQ( hv(1e-308), 3911789313U );
|
||||||
BOOST_TEST_EQ( hv(-1e-308), 66072882U );
|
BOOST_TEST_EQ( hv(-1e-308), 1812507313U );
|
||||||
BOOST_TEST_EQ( hv(1e+308), 2623678890U );
|
BOOST_TEST_EQ( hv(1e+308), 987802568U );
|
||||||
BOOST_TEST_EQ( hv(-1e+308), 476195242U );
|
BOOST_TEST_EQ( hv(-1e+308), 1639042439U );
|
||||||
BOOST_TEST_EQ( hv(std::numeric_limits<double>::infinity()), 2146435072U );
|
BOOST_TEST_EQ( hv(std::numeric_limits<double>::infinity()), 3227645345U );
|
||||||
BOOST_TEST_EQ( hv(-std::numeric_limits<double>::infinity()), 4293918720U );
|
BOOST_TEST_EQ( hv(-std::numeric_limits<double>::infinity()), 2247339177U );
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@@ -207,21 +207,23 @@ int main()
|
|||||||
|
|
||||||
if( ldbits == 64 )
|
if( ldbits == 64 )
|
||||||
{
|
{
|
||||||
BOOST_TEST_EQ( hv(1.0L), 1072693248U );
|
BOOST_TEST_EQ( hv(1.0L), hv(1.0) );
|
||||||
BOOST_TEST_EQ( hv(-1.0L), 3220176896U );
|
BOOST_TEST_EQ( hv(-1.0L), hv(-1.0) );
|
||||||
BOOST_TEST_EQ( hv(3.14L), 3972386992U );
|
BOOST_TEST_EQ( hv(3.14L), hv(3.14) );
|
||||||
BOOST_TEST_EQ( hv(-3.14L), 1824903344U );
|
BOOST_TEST_EQ( hv(-3.14L), hv(-3.14) );
|
||||||
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 2146435072U );
|
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), hv(std::numeric_limits<double>::infinity()) );
|
||||||
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 4293918720U );
|
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), hv(-std::numeric_limits<double>::infinity()) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_TEST_EQ( hv(1.0L), 3770520689U );
|
// ldbits == 96
|
||||||
BOOST_TEST_EQ( hv(-1.0L), 3770553457U );
|
|
||||||
BOOST_TEST_EQ( hv(3.14L), 1150018772U );
|
BOOST_TEST_EQ( hv(1.0L), 3632050780U );
|
||||||
BOOST_TEST_EQ( hv(-3.14L), 1150051540U );
|
BOOST_TEST_EQ( hv(-1.0L), 3632083548U );
|
||||||
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 3770537073U );
|
BOOST_TEST_EQ( hv(3.14L), 1742026549U );
|
||||||
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 3770569841U );
|
BOOST_TEST_EQ( hv(-3.14L), 1742059317U );
|
||||||
|
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 3632067164U );
|
||||||
|
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 3632099932U );
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@@ -246,9 +248,7 @@ int main()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// ldbits == 128 && std::numeric_limits<long double>::digits == 113
|
// ldbits == 128 && std::numeric_limits<long double>::digits == 113
|
||||||
// under ARM64 and S390x, but the values differ presumably because of
|
|
||||||
// __FLOAT_WORD_ORDER__
|
|
||||||
|
|
||||||
BOOST_TEST_EQ( hv(1.0L), 4611404543450677248ULL );
|
BOOST_TEST_EQ( hv(1.0L), 4611404543450677248ULL );
|
||||||
BOOST_TEST_EQ( hv(-1.0L), 13834776580305453056ULL );
|
BOOST_TEST_EQ( hv(-1.0L), 13834776580305453056ULL );
|
||||||
@@ -284,19 +284,19 @@ int main()
|
|||||||
// string
|
// string
|
||||||
#if SIZE_MAX == 4294967295U
|
#if SIZE_MAX == 4294967295U
|
||||||
|
|
||||||
BOOST_TEST_EQ( hv(std::string()), 1580013426U );
|
BOOST_TEST_EQ( hv(std::string()), 1868390524U );
|
||||||
BOOST_TEST_EQ( hv(std::string("abc")), 469308065U );
|
BOOST_TEST_EQ( hv(std::string("abc")), 3674866719U );
|
||||||
BOOST_TEST_EQ( hv(std::string("\0", 1)), 165258820U );
|
BOOST_TEST_EQ( hv(std::string("\0", 1)), 1965885047U );
|
||||||
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 4017288109U );
|
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 54340706U );
|
||||||
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 1352445396U );
|
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 688730713U );
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
BOOST_TEST_EQ( hv(std::string()), 2220755840493918647ULL );
|
BOOST_TEST_EQ( hv(std::string()), 2060355526954642342ULL );
|
||||||
BOOST_TEST_EQ( hv(std::string("abc")), 7565583854499162206ULL );
|
BOOST_TEST_EQ( hv(std::string("abc")), 2539195663733406973ULL );
|
||||||
BOOST_TEST_EQ( hv(std::string("\0", 1)), 1241131678047372712ULL );
|
BOOST_TEST_EQ( hv(std::string("\0", 1)), 18432168439372857722ULL );
|
||||||
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 152341731040131640ULL );
|
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 6494115972580589074ULL );
|
||||||
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 12957252994983528908ULL );
|
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 4419026507380069870ULL );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -344,10 +344,10 @@ int main()
|
|||||||
|
|
||||||
#if SIZE_MAX == 4294967295U
|
#if SIZE_MAX == 4294967295U
|
||||||
|
|
||||||
BOOST_TEST_EQ( hv(std::complex<double>(+1.0, 0.0)), 1072693248U );
|
BOOST_TEST_EQ( hv(std::complex<double>(+1.0, 0.0)), 2619008688U );
|
||||||
BOOST_TEST_EQ( hv(std::complex<double>(-1.0, 0.0)), 3220176896U );
|
BOOST_TEST_EQ( hv(std::complex<double>(-1.0, 0.0)), 146497060U );
|
||||||
BOOST_TEST_EQ( hv(std::complex<double>(0.0, +1.0)), 2619008688U );
|
BOOST_TEST_EQ( hv(std::complex<double>(0.0, +1.0)), 22395692U );
|
||||||
BOOST_TEST_EQ( hv(std::complex<double>(0.0, -1.0)), 146497060U );
|
BOOST_TEST_EQ( hv(std::complex<double>(0.0, -1.0)), 1449221192U );
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@@ -376,17 +376,17 @@ int main()
|
|||||||
// vector<char>
|
// vector<char>
|
||||||
#if SIZE_MAX == 4294967295U
|
#if SIZE_MAX == 4294967295U
|
||||||
|
|
||||||
BOOST_TEST_EQ( hv(std::vector<char>(0)), 1580013426U );
|
BOOST_TEST_EQ( hv(std::vector<char>(0)), 1868390524U );
|
||||||
BOOST_TEST_EQ( hv(std::vector<char>(1)), 165258820U );
|
BOOST_TEST_EQ( hv(std::vector<char>(1)), 1965885047U );
|
||||||
BOOST_TEST_EQ( hv(std::vector<char>(2)), 4017288109U );
|
BOOST_TEST_EQ( hv(std::vector<char>(2)), 54340706U );
|
||||||
BOOST_TEST_EQ( hv(std::vector<char>(3)), 1352445396U );
|
BOOST_TEST_EQ( hv(std::vector<char>(3)), 688730713U );
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
BOOST_TEST_EQ( hv(std::vector<char>(0)), 2220755840493918647ULL );
|
BOOST_TEST_EQ( hv(std::vector<char>(0)), 2060355526954642342ULL );
|
||||||
BOOST_TEST_EQ( hv(std::vector<char>(1)), 1241131678047372712ULL );
|
BOOST_TEST_EQ( hv(std::vector<char>(1)), 18432168439372857722ULL );
|
||||||
BOOST_TEST_EQ( hv(std::vector<char>(2)), 152341731040131640ULL );
|
BOOST_TEST_EQ( hv(std::vector<char>(2)), 6494115972580589074ULL );
|
||||||
BOOST_TEST_EQ( hv(std::vector<char>(3)), 12957252994983528908ULL );
|
BOOST_TEST_EQ( hv(std::vector<char>(3)), 4419026507380069870ULL );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -427,17 +427,17 @@ int main()
|
|||||||
// list<char>
|
// list<char>
|
||||||
#if SIZE_MAX == 4294967295U
|
#if SIZE_MAX == 4294967295U
|
||||||
|
|
||||||
BOOST_TEST_EQ( hv(std::list<char>(0)), 1580013426U );
|
BOOST_TEST_EQ( hv(std::list<char>(0)), 1868390524U );
|
||||||
BOOST_TEST_EQ( hv(std::list<char>(1)), 165258820U );
|
BOOST_TEST_EQ( hv(std::list<char>(1)), 1965885047U );
|
||||||
BOOST_TEST_EQ( hv(std::list<char>(2)), 4017288109U );
|
BOOST_TEST_EQ( hv(std::list<char>(2)), 54340706U );
|
||||||
BOOST_TEST_EQ( hv(std::list<char>(3)), 1352445396U );
|
BOOST_TEST_EQ( hv(std::list<char>(3)), 688730713U );
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
BOOST_TEST_EQ( hv(std::list<char>(0)), 2220755840493918647ULL );
|
BOOST_TEST_EQ( hv(std::list<char>(0)), 2060355526954642342ULL );
|
||||||
BOOST_TEST_EQ( hv(std::list<char>(1)), 1241131678047372712ULL );
|
BOOST_TEST_EQ( hv(std::list<char>(1)), 18432168439372857722ULL );
|
||||||
BOOST_TEST_EQ( hv(std::list<char>(2)), 152341731040131640ULL );
|
BOOST_TEST_EQ( hv(std::list<char>(2)), 6494115972580589074ULL );
|
||||||
BOOST_TEST_EQ( hv(std::list<char>(3)), 12957252994983528908ULL );
|
BOOST_TEST_EQ( hv(std::list<char>(3)), 4419026507380069870ULL );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright 2026 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/config.hpp>
|
||||||
|
#include <boost/config/pragma_message.hpp>
|
||||||
|
|
||||||
|
#if defined(BOOST_NO_CXX17_HDR_VARIANT)
|
||||||
|
|
||||||
|
BOOST_PRAGMA_MESSAGE( "Skipping test because BOOST_NO_CXX17_HDR_VARIANT is defined" )
|
||||||
|
int main() {}
|
||||||
|
|
||||||
|
#elif defined(BOOST_CLANG_VERSION) && BOOST_CLANG_VERSION < 70100
|
||||||
|
|
||||||
|
BOOST_PRAGMA_MESSAGE( "Skipping test because BOOST_CLANG_VERSION < 70100" )
|
||||||
|
int main() {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <boost/core/lightweight_test.hpp>
|
||||||
|
#include <variant>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
struct X
|
||||||
|
{
|
||||||
|
operator std::set<float>() const { throw 5; }
|
||||||
|
};
|
||||||
|
|
||||||
|
using V = std::variant<std::set<int>, std::set<float>>;
|
||||||
|
|
||||||
|
V make_valueless_variant()
|
||||||
|
{
|
||||||
|
V v;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
v.emplace<1>( X() );
|
||||||
|
}
|
||||||
|
catch( int )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_TEST( v.valueless_by_exception() );
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
V v1, v2 = make_valueless_variant();
|
||||||
|
|
||||||
|
BOOST_TEST_NE( (boost::hash<V>()( v1 )), (boost::hash<V>()( v2 )) );
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -50,11 +50,11 @@ int main()
|
|||||||
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<std::wstring>));
|
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<std::wstring>));
|
||||||
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<std::wstring const>));
|
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<std::wstring const>));
|
||||||
|
|
||||||
// std::vector doesn't have data() in C++03
|
|
||||||
#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> >));
|
||||||
BOOST_TEST_TRAIT_TRUE((is_contiguous_range< std::vector<X> const >));
|
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> >));
|
||||||
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::deque<X> const >));
|
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::deque<X> const >));
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ int main()
|
|||||||
{
|
{
|
||||||
using boost::container_hash::is_contiguous_range;
|
using boost::container_hash::is_contiguous_range;
|
||||||
|
|
||||||
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700)
|
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700) && !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
|
||||||
|
|
||||||
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<X1>));
|
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<X1>));
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2022 Peter Dimov.
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
|
#include <boost/container_hash/is_contiguous_range.hpp>
|
||||||
|
#include <boost/core/lightweight_test_trait.hpp>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
struct X1
|
||||||
|
{
|
||||||
|
char const* begin() const;
|
||||||
|
char const* end() const;
|
||||||
|
std::size_t size() const;
|
||||||
|
|
||||||
|
char data[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using boost::container_hash::is_contiguous_range;
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<X1>));
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// Copyright 2022 Peter Dimov.
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
|
#include <boost/container_hash/is_described_class.hpp>
|
||||||
|
#include <boost/describe/class.hpp>
|
||||||
|
#include <boost/core/lightweight_test_trait.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct X1
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct X2
|
||||||
|
{
|
||||||
|
int m;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Y1
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_DESCRIBE_STRUCT( Y1, (), () )
|
||||||
|
|
||||||
|
struct Y2: Y1
|
||||||
|
{
|
||||||
|
int m;
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_DESCRIBE_STRUCT( Y2, (Y1), (m) )
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using boost::container_hash::is_described_class;
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_described_class<void>));
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_described_class<int>));
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_described_class<X1>));
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_described_class<X2>));
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_described_class<int[2]>));
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_described_class<std::string>));
|
||||||
|
|
||||||
|
#if defined(BOOST_DESCRIBE_CXX14)
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_TRUE((is_described_class<Y1>));
|
||||||
|
BOOST_TEST_TRAIT_TRUE((is_described_class<Y2>));
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_described_class<Y1>));
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_described_class<Y2>));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2022 Peter Dimov.
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
|
#include <boost/type_traits/integral_constant.hpp>
|
||||||
|
#include <boost/describe/class.hpp>
|
||||||
|
|
||||||
|
struct X
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_DESCRIBE_STRUCT( X, (), () )
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
namespace container_hash
|
||||||
|
{
|
||||||
|
|
||||||
|
template<class T> struct is_described_class;
|
||||||
|
template<> struct is_described_class<X>: boost::false_type {};
|
||||||
|
|
||||||
|
} // namespace container_hash
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#include <boost/container_hash/is_described_class.hpp>
|
||||||
|
#include <boost/core/lightweight_test_trait.hpp>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using boost::container_hash::is_described_class;
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_described_class<X>));
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// Copyright 2022 Peter Dimov.
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
|
#include <boost/container_hash/is_described_class.hpp>
|
||||||
|
#include <boost/describe/class.hpp>
|
||||||
|
#include <boost/core/lightweight_test_trait.hpp>
|
||||||
|
|
||||||
|
union Y1
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_DESCRIBE_STRUCT( Y1, (), () )
|
||||||
|
|
||||||
|
union Y2
|
||||||
|
{
|
||||||
|
int m1;
|
||||||
|
float m2;
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_DESCRIBE_STRUCT( Y2, (), (m1, m2) )
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using boost::container_hash::is_described_class;
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_described_class<Y1>));
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_described_class<Y2>));
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2024 Peter Dimov.
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
|
#include <boost/container_hash/is_range.hpp>
|
||||||
|
#include <boost/core/lightweight_test_trait.hpp>
|
||||||
|
|
||||||
|
struct X1
|
||||||
|
{
|
||||||
|
void* begin() const;
|
||||||
|
void* end() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct X2
|
||||||
|
{
|
||||||
|
void const* begin() const;
|
||||||
|
void const* end() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using boost::container_hash::is_range;
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_range<X1>));
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_range<X2>));
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
// 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<void const>));
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_tuple_like<int>));
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_tuple_like<int const>));
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_tuple_like<X>));
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_tuple_like<X const>));
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_tuple_like<int[2]>));
|
||||||
|
BOOST_TEST_TRAIT_FALSE((is_tuple_like<int const [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::pair<int, X> const>));
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<> >));
|
||||||
|
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<> const>));
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<X> >));
|
||||||
|
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<X> const>));
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<X, X> >));
|
||||||
|
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<X, X> const>));
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<X, X, X> >));
|
||||||
|
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<X, X, X> const>));
|
||||||
|
|
||||||
|
BOOST_TEST_TRAIT_TRUE((is_tuple_like<user::Y>));
|
||||||
|
BOOST_TEST_TRAIT_TRUE((is_tuple_like<user::Y const>));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user