mirror of
https://github.com/boostorg/container_hash.git
synced 2026-03-07 14:34:11 +01:00
Compare commits
45 Commits
feature/nu
...
boost-1.83
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
30560ada18 | ||
|
|
c61a4f691e |
@@ -207,6 +207,13 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 23.04 GCC 13 32/64",
|
||||
"cppalliance/droneubuntu2304:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '03,11,14,17,20,2b', ADDRMD: '32,64' },
|
||||
"g++-13-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.5",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
@@ -308,40 +315,58 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 13",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '03,11,14,17,20' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '03,11,14,17,20,2b' },
|
||||
"clang-13",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 14 UBSAN",
|
||||
"Linux 22.04 Clang 14",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20,2b' } + ubsan,
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20,2b' },
|
||||
"clang-14",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 14 ASAN",
|
||||
"Linux 22.04 Clang 15 UBSAN",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20,2b' } + asan,
|
||||
"clang-14",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 15",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '03,11,14,17,20,2b' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '03,11,14,17,20,2b' } + ubsan,
|
||||
"clang-15",
|
||||
["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main"],
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 15 ASAN",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '03,11,14,17,20,2b' } + asan,
|
||||
"clang-15",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 23.04 Clang 16",
|
||||
"cppalliance/droneubuntu2304:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-16', CXXSTD: '03,11,14,17,20,2b' },
|
||||
"clang-16",
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
"MacOS 10.15 Xcode 12.2 UBSAN",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + ubsan,
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,17,2a' } + ubsan,
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
"MacOS 10.15 Xcode 12.2 ASAN",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + asan,
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,17,2a' } + asan,
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
"MacOS 12.4 Xcode 13.4.1 UBSAN",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,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: '03,11,14,17,20,2b' } + asan,
|
||||
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
set -ex
|
||||
export PATH=~/.local/bin:/usr/local/bin:$PATH
|
||||
|
||||
DRONE_BUILD_DIR=$(pwd)
|
||||
|
||||
|
||||
265
.github/workflows/ci.yml
vendored
265
.github/workflows/ci.yml
vendored
@@ -19,27 +19,30 @@ jobs:
|
||||
include:
|
||||
- toolset: gcc-4.8
|
||||
cxxstd: "03,11"
|
||||
os: ubuntu-18.04
|
||||
os: ubuntu-latest
|
||||
container: ubuntu:18.04
|
||||
install: g++-4.8-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-5
|
||||
cxxstd: "03,11,14,1z"
|
||||
os: ubuntu-18.04
|
||||
os: ubuntu-latest
|
||||
container: ubuntu:18.04
|
||||
install: g++-5-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-6
|
||||
cxxstd: "03,11,14,1z"
|
||||
os: ubuntu-18.04
|
||||
os: ubuntu-latest
|
||||
container: ubuntu:18.04
|
||||
install: g++-6-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-7
|
||||
cxxstd: "03,11,14,17"
|
||||
os: ubuntu-18.04
|
||||
os: ubuntu-20.04
|
||||
install: g++-7-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-8
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-18.04
|
||||
os: ubuntu-20.04
|
||||
install: g++-8-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-9
|
||||
@@ -49,12 +52,12 @@ jobs:
|
||||
address-model: 32,64
|
||||
- toolset: gcc-10
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
install: g++-10-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-11
|
||||
cxxstd: "03,11,14,17,20"
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
install: g++-11-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-12
|
||||
@@ -62,30 +65,39 @@ jobs:
|
||||
os: ubuntu-22.04
|
||||
install: g++-12-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-13
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
os: ubuntu-latest
|
||||
container: ubuntu:23.04
|
||||
install: g++-13-multilib
|
||||
address-model: 32,64
|
||||
- toolset: clang
|
||||
compiler: clang++-3.9
|
||||
cxxstd: "03,11,14"
|
||||
os: ubuntu-18.04
|
||||
os: ubuntu-latest
|
||||
container: ubuntu:18.04
|
||||
install: clang-3.9
|
||||
- toolset: clang
|
||||
compiler: clang++-4.0
|
||||
cxxstd: "03,11,14"
|
||||
os: ubuntu-18.04
|
||||
os: ubuntu-latest
|
||||
container: ubuntu:18.04
|
||||
install: clang-4.0
|
||||
- toolset: clang
|
||||
compiler: clang++-5.0
|
||||
cxxstd: "03,11,14,1z"
|
||||
os: ubuntu-18.04
|
||||
os: ubuntu-latest
|
||||
container: ubuntu:18.04
|
||||
install: clang-5.0
|
||||
- toolset: clang
|
||||
compiler: clang++-6.0
|
||||
cxxstd: "03,11,14,17"
|
||||
os: ubuntu-18.04
|
||||
os: ubuntu-20.04
|
||||
install: clang-6.0
|
||||
- toolset: clang
|
||||
compiler: clang++-7
|
||||
cxxstd: "03,11,14,17"
|
||||
os: ubuntu-18.04
|
||||
os: ubuntu-20.04
|
||||
install: clang-7
|
||||
- toolset: clang
|
||||
compiler: clang++-8
|
||||
@@ -119,18 +131,48 @@ jobs:
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
os: ubuntu-22.04
|
||||
install: clang-14
|
||||
- toolset: clang
|
||||
compiler: clang++-15
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
os: ubuntu-22.04
|
||||
install: clang-15
|
||||
- toolset: clang
|
||||
compiler: clang++-16
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
os: ubuntu-latest
|
||||
container: ubuntu:23.04
|
||||
install: clang-16
|
||||
- toolset: clang
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: macos-11
|
||||
- toolset: clang
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
os: macos-12
|
||||
- toolset: clang
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
os: macos-13
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
container: ${{matrix.container}}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup container environment
|
||||
if: matrix.container
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get -y install sudo python3 git g++
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt install ${{matrix.install}}
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
@@ -150,7 +192,7 @@ jobs:
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py -I examples --git_args "--jobs 3" $LIBRARY
|
||||
python3 tools/boostdep/depinst/depinst.py -I examples --git_args "--jobs 3" $LIBRARY
|
||||
./bootstrap.sh
|
||||
./b2 -d0 headers
|
||||
|
||||
@@ -231,10 +273,11 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
- os: macos-11
|
||||
- os: macos-12
|
||||
- os: macos-13
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
@@ -243,7 +286,7 @@ jobs:
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt install ${{matrix.install}}
|
||||
run: sudo apt-get -y install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
@@ -278,10 +321,11 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
- os: macos-11
|
||||
- os: macos-12
|
||||
- os: macos-13
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
@@ -290,7 +334,7 @@ jobs:
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt install ${{matrix.install}}
|
||||
run: sudo apt-get -y install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
@@ -335,10 +379,11 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
- os: macos-11
|
||||
- os: macos-12
|
||||
- os: macos-13
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
@@ -347,7 +392,7 @@ jobs:
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt install ${{matrix.install}}
|
||||
run: sudo apt-get -y install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
@@ -384,3 +429,183 @@ jobs:
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
windows-cmake-subdir:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-2019
|
||||
- os: windows-2022
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
|
||||
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
|
||||
echo LIBRARY: %LIBRARY%
|
||||
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
|
||||
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
|
||||
echo GITHUB_REF: %GITHUB_REF%
|
||||
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
|
||||
|
||||
- name: Use library with add_subdirectory (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/libs/%LIBRARY%/test/cmake_subdir_test
|
||||
mkdir __build__ && cd __build__
|
||||
cmake ..
|
||||
cmake --build . --config Debug
|
||||
ctest --output-on-failure --no-tests=error -C Debug
|
||||
|
||||
- name: Use library with add_subdirectory (Release)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/libs/%LIBRARY%/test/cmake_subdir_test/__build__
|
||||
cmake --build . --config Release
|
||||
ctest --output-on-failure --no-tests=error -C Release
|
||||
|
||||
windows-cmake-install:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-2019
|
||||
- os: windows-2022
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
|
||||
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
|
||||
echo LIBRARY: %LIBRARY%
|
||||
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
|
||||
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
|
||||
echo GITHUB_REF: %GITHUB_REF%
|
||||
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
|
||||
|
||||
- name: Configure
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=%LIBRARY% -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix ..
|
||||
|
||||
- name: Install (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target install --config Debug
|
||||
|
||||
- name: Install (Release)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target install --config Release
|
||||
|
||||
- name: Use the installed library (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/libs/%LIBRARY%/test/cmake_install_test && mkdir __build__ && cd __build__
|
||||
cmake -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix ..
|
||||
cmake --build . --config Debug
|
||||
ctest --output-on-failure --no-tests=error -C Debug
|
||||
|
||||
- name: Use the installed library (Release)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/libs/%LIBRARY%/test/cmake_install_test/__build__
|
||||
cmake --build . --config Release
|
||||
ctest --output-on-failure --no-tests=error -C Release
|
||||
|
||||
windows-cmake-test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-2019
|
||||
- os: windows-2022
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
|
||||
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
|
||||
echo LIBRARY: %LIBRARY%
|
||||
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
|
||||
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
|
||||
echo GITHUB_REF: %GITHUB_REF%
|
||||
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
|
||||
|
||||
- name: Configure
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=%LIBRARY% -DBUILD_TESTING=ON ..
|
||||
|
||||
- name: Build tests (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target tests --config Debug
|
||||
|
||||
- name: Run tests (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
ctest --output-on-failure --no-tests=error -C Debug
|
||||
|
||||
- name: Build tests (Release)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target tests --config Release
|
||||
|
||||
- name: Run tests (Release)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
ctest --output-on-failure --no-tests=error -C Release
|
||||
|
||||
1
benchmark/.gitignore
vendored
1
benchmark/.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
enwik8
|
||||
enwik9
|
||||
*.exe
|
||||
*.obj
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
#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
|
||||
@@ -178,14 +181,6 @@ struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits > {
|
||||
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
|
||||
struct mulxp0_hash_
|
||||
{
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return mulxp0_hash( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp1_hash_
|
||||
{
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
@@ -194,14 +189,6 @@ struct mulxp1_hash_
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp2_hash_
|
||||
{
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return mulxp2_hash( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp3_hash_
|
||||
{
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
@@ -210,6 +197,14 @@ struct mulxp3_hash_
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
@@ -245,11 +240,11 @@ template<class H, class V> void test_hash_speed( int N, V const& v )
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
|
||||
std::printf( "%53s : q=%20Iu, %lld ms\n", hash.c_str(), q, ms1 );
|
||||
std::printf( "%57s : q=%20Iu, %lld ms\n", hash.c_str(), q, ms1 );
|
||||
|
||||
#else
|
||||
|
||||
std::printf( "%53s : q=%20zu, %lld ms\n", hash.c_str(), q, ms1 );
|
||||
std::printf( "%57s : q=%20zu, %lld ms\n", hash.c_str(), q, ms1 );
|
||||
|
||||
#endif
|
||||
}
|
||||
@@ -270,11 +265,11 @@ template<class H, class V> void test_hash_collision( int N, V const& v, std::siz
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
|
||||
std::printf( "%53s : c=%Iu\n", hash.c_str(), n - s.size() );
|
||||
std::printf( "%57s : c=%Iu\n", hash.c_str(), n - s.size() );
|
||||
|
||||
#else
|
||||
|
||||
std::printf( "%53s : c=%zu\n", hash.c_str(), n - s.size() );
|
||||
std::printf( "%57s : c=%zu\n", hash.c_str(), n - s.size() );
|
||||
|
||||
#endif
|
||||
}
|
||||
@@ -327,11 +322,11 @@ template<class V, class S> void test4( int N, V const& v, char const * hash, S s
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
|
||||
std::printf( "%53s : n=%Iu, m=%Iu, c=%Iu, q=%Iu, %4lld + %4lld = %4lld ms\n", hash, n, m, c, q, ms1, ms2, ms1 + ms2 );
|
||||
std::printf( "%57s : n=%Iu, m=%Iu, c=%Iu, q=%Iu, %4lld + %4lld = %4lld ms\n", hash, n, m, c, q, ms1, ms2, ms1 + ms2 );
|
||||
|
||||
#else
|
||||
|
||||
std::printf( "%53s : n=%zu, m=%zu, c=%zu, q=%zu, %4lld + %4lld = %4lld ms\n", hash, n, m, c, q, ms1, ms2, 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
|
||||
}
|
||||
@@ -383,11 +378,13 @@ int main()
|
||||
#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<mulxp0_hash_>( N * 16, v );
|
||||
test_hash_speed<mulxp1_hash_>( N * 16, v );
|
||||
test_hash_speed<mulxp2_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
|
||||
|
||||
@@ -418,11 +415,13 @@ int main()
|
||||
#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<mulxp0_hash_>( N * 16, v, n );
|
||||
test_hash_collision<mulxp1_hash_>( N * 16, v, n );
|
||||
test_hash_collision<mulxp2_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
|
||||
}
|
||||
@@ -431,7 +430,7 @@ int main()
|
||||
|
||||
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_x4_hash>( N, v );
|
||||
@@ -442,11 +441,13 @@ int main()
|
||||
#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, mulxp0_hash_>( N, v );
|
||||
test_container_speed<K, mulxp1_hash_>( N, v );
|
||||
test_container_speed<K, mulxp2_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
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#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
|
||||
@@ -210,118 +213,6 @@ template<class Hash> BOOST_NOINLINE void test( char const* label )
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// mul31_hash
|
||||
|
||||
struct mul31_hash
|
||||
{
|
||||
// not avalanching
|
||||
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
char const * p = st.data();
|
||||
std::size_t n = st.size();
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
std::size_t h = 0xCBF29CE484222325ull;
|
||||
#else
|
||||
std::size_t h = 0x811C9DC5u;
|
||||
#endif
|
||||
|
||||
for( std::size_t i = 0; i < n; ++i )
|
||||
{
|
||||
h = h * 31 + static_cast<unsigned char>( p[i] );
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
// mul31_x4_hash
|
||||
|
||||
struct mul31_x4_hash
|
||||
{
|
||||
// not avalanching
|
||||
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
char const * p = st.data();
|
||||
std::size_t n = st.size();
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
std::size_t h = 0xCBF29CE484222325ull;
|
||||
#else
|
||||
std::size_t h = 0x811C9DC5u;
|
||||
#endif
|
||||
|
||||
while( n >= 4 )
|
||||
{
|
||||
h = h * (31u * 31u * 31u * 31u)
|
||||
+ static_cast<unsigned char>( p[0] ) * (31u * 31u * 31u)
|
||||
+ static_cast<unsigned char>( p[1] ) * (31u * 31u)
|
||||
+ static_cast<unsigned char>( p[2] ) * 31u
|
||||
+ static_cast<unsigned char>( p[3] );
|
||||
|
||||
p += 4;
|
||||
n -= 4;
|
||||
}
|
||||
|
||||
while( n > 0 )
|
||||
{
|
||||
h = h * 31u + static_cast<unsigned char>( *p );
|
||||
|
||||
++p;
|
||||
--n;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
// mul31_x8_hash
|
||||
|
||||
struct mul31_x8_hash
|
||||
{
|
||||
// not avalanching
|
||||
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
char const * p = st.data();
|
||||
std::size_t n = st.size();
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
boost::uint64_t h = 0xCBF29CE484222325ull;
|
||||
#else
|
||||
boost::uint64_t h = 0x811C9DC5u;
|
||||
#endif
|
||||
|
||||
while( n >= 8 )
|
||||
{
|
||||
h = h * (31ull * 31ull * 31ull * 31ull * 31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[0] ) * (31ull * 31ull * 31ull * 31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[1] ) * (31ull * 31ull * 31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[2] ) * (31ull * 31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[3] ) * (31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[4] ) * (31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[5] ) * (31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[6] ) * 31ull
|
||||
+ static_cast<unsigned char>( p[7] );
|
||||
|
||||
p += 8;
|
||||
n -= 8;
|
||||
}
|
||||
|
||||
while( n > 0 )
|
||||
{
|
||||
h = h * 31u + static_cast<unsigned char>( *p );
|
||||
|
||||
++p;
|
||||
--n;
|
||||
}
|
||||
|
||||
return static_cast<std::size_t>( h );
|
||||
}
|
||||
};
|
||||
|
||||
// fnv1a_hash
|
||||
|
||||
template<int Bits> struct fnv1a_hash_impl;
|
||||
@@ -391,16 +282,6 @@ struct absl_hash: absl::Hash<std::string>
|
||||
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
|
||||
struct mulxp0_hash_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return mulxp0_hash( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp1_hash_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
@@ -411,16 +292,6 @@ struct mulxp1_hash_
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp2_hash_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return mulxp2_hash( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp3_hash_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
@@ -431,6 +302,24 @@ struct mulxp3_hash_
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
@@ -459,9 +348,6 @@ int main()
|
||||
|
||||
test< boost::hash<std::string> >( "boost::hash" );
|
||||
test< std_hash >( "std::hash" );
|
||||
test< mul31_hash >( "mul31_hash" );
|
||||
test< mul31_x4_hash >( "mul31_x4_hash" );
|
||||
test< mul31_x8_hash >( "mul31_x8_hash" );
|
||||
test< fnv1a_hash >( "fnv1a_hash" );
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
@@ -470,12 +356,17 @@ int main()
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test< ankerl::unordered_dense::hash<std::string> >( "ankerl::unordered_dense::hash" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
|
||||
test< mulxp0_hash_ >( "mulxp0_hash" );
|
||||
test< mulxp1_hash_ >( "mulxp1_hash" );
|
||||
test< mulxp2_hash_ >( "mulxp2_hash" );
|
||||
test< mulxp3_hash_ >( "mulxp3_hash" );
|
||||
test< mulxp1_hash32_ >( "mulxp1_hash32" );
|
||||
test< mulxp3_hash32_ >( "mulxp3_hash32" );
|
||||
|
||||
#endif
|
||||
@@ -484,7 +375,7 @@ int main()
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 22 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms\n";
|
||||
std::cout << std::setw( 32 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#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
|
||||
@@ -38,8 +41,16 @@ 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 );
|
||||
@@ -137,118 +148,6 @@ template<class Hash> BOOST_NOINLINE void test( char const* label )
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// mul31_hash
|
||||
|
||||
struct mul31_hash
|
||||
{
|
||||
// not avalanching
|
||||
|
||||
std::size_t operator()( std::string_view const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
char const * p = st.data();
|
||||
std::size_t n = st.size();
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
std::size_t h = 0xCBF29CE484222325ull;
|
||||
#else
|
||||
std::size_t h = 0x811C9DC5u;
|
||||
#endif
|
||||
|
||||
for( std::size_t i = 0; i < n; ++i )
|
||||
{
|
||||
h = h * 31 + static_cast<unsigned char>( p[i] );
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
// mul31_x4_hash
|
||||
|
||||
struct mul31_x4_hash
|
||||
{
|
||||
// not avalanching
|
||||
|
||||
std::size_t operator()( std::string_view const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
char const * p = st.data();
|
||||
std::size_t n = st.size();
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
std::size_t h = 0xCBF29CE484222325ull;
|
||||
#else
|
||||
std::size_t h = 0x811C9DC5u;
|
||||
#endif
|
||||
|
||||
while( n >= 4 )
|
||||
{
|
||||
h = h * (31u * 31u * 31u * 31u)
|
||||
+ static_cast<unsigned char>( p[0] ) * (31u * 31u * 31u)
|
||||
+ static_cast<unsigned char>( p[1] ) * (31u * 31u)
|
||||
+ static_cast<unsigned char>( p[2] ) * 31u
|
||||
+ static_cast<unsigned char>( p[3] );
|
||||
|
||||
p += 4;
|
||||
n -= 4;
|
||||
}
|
||||
|
||||
while( n > 0 )
|
||||
{
|
||||
h = h * 31u + static_cast<unsigned char>( *p );
|
||||
|
||||
++p;
|
||||
--n;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
// mul31_x8_hash
|
||||
|
||||
struct mul31_x8_hash
|
||||
{
|
||||
// not avalanching
|
||||
|
||||
std::size_t operator()( std::string_view const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
char const * p = st.data();
|
||||
std::size_t n = st.size();
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
boost::uint64_t h = 0xCBF29CE484222325ull;
|
||||
#else
|
||||
boost::uint64_t h = 0x811C9DC5u;
|
||||
#endif
|
||||
|
||||
while( n >= 8 )
|
||||
{
|
||||
h = h * (31ull * 31ull * 31ull * 31ull * 31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[0] ) * (31ull * 31ull * 31ull * 31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[1] ) * (31ull * 31ull * 31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[2] ) * (31ull * 31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[3] ) * (31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[4] ) * (31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[5] ) * (31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[6] ) * 31ull
|
||||
+ static_cast<unsigned char>( p[7] );
|
||||
|
||||
p += 8;
|
||||
n -= 8;
|
||||
}
|
||||
|
||||
while( n > 0 )
|
||||
{
|
||||
h = h * 31u + static_cast<unsigned char>( *p );
|
||||
|
||||
++p;
|
||||
--n;
|
||||
}
|
||||
|
||||
return static_cast<std::size_t>( h );
|
||||
}
|
||||
};
|
||||
|
||||
// fnv1a_hash
|
||||
|
||||
template<int Bits> struct fnv1a_hash_impl;
|
||||
@@ -316,16 +215,6 @@ struct absl_hash: absl::Hash<std::string_view>
|
||||
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
|
||||
struct mulxp0_hash_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
|
||||
std::size_t operator()( std::string_view const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return mulxp0_hash( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp1_hash_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
@@ -336,16 +225,6 @@ struct mulxp1_hash_
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp2_hash_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
|
||||
std::size_t operator()( std::string_view const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return mulxp2_hash( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp3_hash_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
@@ -374,6 +253,24 @@ struct mulxp3_hash32_
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
//
|
||||
@@ -384,9 +281,6 @@ int main()
|
||||
|
||||
test< boost::hash<std::string_view> >( "boost::hash" );
|
||||
test< std_hash >( "std::hash" );
|
||||
test< mul31_hash >( "mul31_hash" );
|
||||
test< mul31_x4_hash >( "mul31_x4_hash" );
|
||||
test< mul31_x8_hash >( "mul31_x8_hash" );
|
||||
test< fnv1a_hash >( "fnv1a_hash" );
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
@@ -395,12 +289,17 @@ int main()
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test< ankerl::unordered_dense::hash<std::string_view> >( "ankerl::unordered_dense::hash" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
|
||||
test< mulxp0_hash_ >( "mulxp0_hash" );
|
||||
test< mulxp1_hash_ >( "mulxp1_hash" );
|
||||
test< mulxp2_hash_ >( "mulxp2_hash" );
|
||||
test< mulxp3_hash_ >( "mulxp3_hash" );
|
||||
test< mulxp1_hash32_ >( "mulxp1_hash32" );
|
||||
test< mulxp3_hash32_ >( "mulxp3_hash32" );
|
||||
|
||||
#endif
|
||||
@@ -409,7 +308,7 @@ int main()
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 22 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms\n";
|
||||
std::cout << std::setw( 32 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,11 +22,13 @@ Out of the box, `boost::hash` supports
|
||||
|
||||
* standard integral types (integers, character types, and `bool`);
|
||||
* standard floating point types (`float`, `double`, `long double`);
|
||||
* pointers (to objects and to functions, but not pointers to members);
|
||||
* pointers (to objects and to functions, but not pointers to members)
|
||||
and `nullptr`;
|
||||
* enumeration types;
|
||||
* C arrays;
|
||||
* `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
|
||||
have `begin()` and `end()` member functions returning iterators);
|
||||
* unordered sequences, standard or user-defined (sequences for which the hash
|
||||
|
||||
@@ -55,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
|
||||
match, avoiding the problem.
|
||||
|
||||
== Hash Value Stability
|
||||
|
||||
In general, the library does not promise that the hash values will stay
|
||||
the same from release to release (otherwise improvements would be
|
||||
impossible). However, historically values have been quite stable. Before
|
||||
release 1.81, the previous changes have been in 1.56 (a better
|
||||
`hash_combine`) and 1.78 (macOS-specific change to `hash_combine`.)
|
||||
|
||||
Code should generally not depend on specific hash values, but for those
|
||||
willing to take the risk of occasional breaks due to hash value changes,
|
||||
the library now has a test that checks hash values for a number of types
|
||||
against reference values (`test/hash_reference_values.cpp`),
|
||||
whose https://github.com/boostorg/container_hash/commits/develop/test/hash_reference_values.cpp[version history]
|
||||
can be used as a rough guide to when hash values have changed, and for what
|
||||
types.
|
||||
|
||||
== hash_combine
|
||||
|
||||
The initial implementation of the library was based on Issue 6.18 of the
|
||||
@@ -200,16 +216,9 @@ In Boost 1.81, `hash_range` was changed to process elements of type `char`,
|
||||
A `uint32_t` is composed from `first[0]` to `first[3]`, and that `uint32_t`
|
||||
is fed to `hash_combine`.
|
||||
|
||||
In principle, when `size_t` is 64 bit, we could have used `uint64_t` instead.
|
||||
We do not, because this allows producing an arbitrary hash value by choosing
|
||||
the input bytes appropriately (because `hash_combine` is reversible.)
|
||||
|
||||
Allowing control only over 32 bits of the full 64 bit `size_t` value makes
|
||||
these "chosen plaintext attacks" harder.
|
||||
|
||||
This is not as harmful to performance as it first appears, because the
|
||||
input to `hash<string>` (e.g. the key in an unordered container) is often
|
||||
short (9 to 13 bytes in some typical scenarios.)
|
||||
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
|
||||
|
||||
@@ -8,6 +8,17 @@ https://www.boost.org/LICENSE_1_0.txt
|
||||
= Recent Changes
|
||||
:idprefix: recent_
|
||||
|
||||
== Boost 1.82.0
|
||||
|
||||
* Added an overload of `hash_value` for `std::nullptr_t`.
|
||||
* Added `is_tuple_like` and an overload of `hash_value` for
|
||||
tuple-like types.
|
||||
* Changed string hashing to use
|
||||
https://github.com/pdimov/mulxp_hash[`mulxp1_hash`],
|
||||
improving both quality and speed. This changes the hash values
|
||||
for string-like types (ranges of `char`, `signed char`,
|
||||
`unsigned char`, `std::byte`, `char8_t`).
|
||||
|
||||
== Boost 1.81.0
|
||||
|
||||
Major update.
|
||||
@@ -24,9 +35,18 @@ Major update.
|
||||
* Described structs and classes (those annotated with
|
||||
`BOOST_DESCRIBE_STRUCT` or `BOOST_DESCRIBE_CLASS`) are now
|
||||
supported out of the box.
|
||||
* `hash_combine` has been improved.
|
||||
* `hash_combine` has been improved. This changes the hash values
|
||||
of composite (container and tuple) types and of scalar types
|
||||
bigger than `size_t`.
|
||||
* The performance (and quality, as a result of the above change)
|
||||
of string hashing has been improved. `boost::hash` for strings
|
||||
now passes SMHasher in 64 bit mode.
|
||||
* The documentation has been substantially revised to reflect
|
||||
the changes.
|
||||
|
||||
== Boost 1.78.0
|
||||
|
||||
* Fixed `hash_combine` so that its behavior no longer depends
|
||||
on whether `size_t` is the exact same type as `boost::uint64_t`
|
||||
(which wasn't the case on macOS). This changes the hash values
|
||||
of composite (container and tuple) types on macOS.
|
||||
|
||||
@@ -30,6 +30,7 @@ template<class T> struct is_range;
|
||||
template<class T> struct is_contiguous_range;
|
||||
template<class T> struct is_unordered_range;
|
||||
template<class T> struct is_described_class;
|
||||
template<class T> struct is_tuple_like;
|
||||
|
||||
} // namespace container_hash
|
||||
|
||||
@@ -89,8 +90,9 @@ template<class T>
|
||||
template<class A, class B>
|
||||
std::size_t hash_value( std::pair<A, B> const& v );
|
||||
|
||||
template<class... T>
|
||||
std::size_t hash_value( std::tuple<T...> const& v );
|
||||
// Enabled only when container_hash::is_tuple_like<T>::value is true
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
|
||||
// Enabled only when container_hash::is_range<T>::value is true
|
||||
template<class T>
|
||||
@@ -240,11 +242,16 @@ for( ; first != last; ++first )
|
||||
}
|
||||
----
|
||||
|
||||
Otherwise, bytes from `[first, last)` are coalesced in an unspecified manner
|
||||
and then passed to `hash_combine`, more than one at a time. This is done in
|
||||
order to improve performance when hashing strings.
|
||||
Otherwise, bytes from `[first, last)` are coalesced and hashed in an
|
||||
unspecified manner. This is done in order to improve performance when hashing
|
||||
strings.
|
||||
--
|
||||
|
||||
Remarks: ::
|
||||
For chars, the current implementation uses
|
||||
https://github.com/pdimov/mulxp_hash[`mulxp1_hash`] when `std::size_t` is
|
||||
64 bit, and `mulxp1_hash32` when it's 32 bit.
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class It> std::size_t hash_range( It first, It last );
|
||||
@@ -385,8 +392,9 @@ return seed;
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class... T>
|
||||
std::size_t hash_value( std::tuple<T...> const& v );
|
||||
// Enabled only when container_hash::is_tuple_like<T>::value is true
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
----
|
||||
|
||||
Effects: ::
|
||||
@@ -395,15 +403,21 @@ Effects: ::
|
||||
----
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_combine( seed, std::get<0>(v) );
|
||||
boost::hash_combine( seed, std::get<1>(v) );
|
||||
using std::get;
|
||||
|
||||
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;
|
||||
----
|
||||
+
|
||||
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]
|
||||
----
|
||||
@@ -703,3 +717,38 @@ template<class T> struct is_described_class
|
||||
|
||||
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.
|
||||
|
||||
@@ -6,13 +6,16 @@
|
||||
#define BOOST_HASH_DETAIL_HASH_RANGE_HPP
|
||||
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
#include <boost/container_hash/detail/mulx.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/type_traits/enable_if.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <cstddef>
|
||||
#include <climits>
|
||||
#include <iterator>
|
||||
#include <cstring>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -37,6 +40,8 @@ template<> struct is_char_type<std::byte>: public boost::true_type {};
|
||||
|
||||
#endif
|
||||
|
||||
// generic version
|
||||
|
||||
template<class It>
|
||||
inline typename boost::enable_if_<
|
||||
!is_char_type<typename std::iterator_traits<It>::value_type>::value,
|
||||
@@ -51,120 +56,352 @@ std::size_t >::type
|
||||
return seed;
|
||||
}
|
||||
|
||||
template<class It>
|
||||
inline typename boost::enable_if_<
|
||||
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::size_t>::type
|
||||
hash_range( std::size_t seed, It first, It last )
|
||||
// specialized char[] version, 32 bit
|
||||
|
||||
template<class It> inline boost::uint32_t read32le( It p )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
// 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
|
||||
boost::uint32_t w =
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( p[0] ) ) |
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( p[1] ) ) << 8 |
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( p[2] ) ) << 16 |
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( p[3] ) ) << 24;
|
||||
|
||||
boost::uint32_t 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;
|
||||
return w;
|
||||
}
|
||||
|
||||
hash_combine( seed, w );
|
||||
}
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
|
||||
{
|
||||
// add a trailing suffix byte of 0x01 because otherwise sequences of
|
||||
// trailing zeroes are indistinguishable from end of string
|
||||
template<class T> inline boost::uint32_t read32le( T* p )
|
||||
{
|
||||
boost::uint32_t w;
|
||||
|
||||
boost::uint32_t w = 0x01u;
|
||||
std::memcpy( &w, p, 4 );
|
||||
return w;
|
||||
}
|
||||
|
||||
switch( n )
|
||||
{
|
||||
case 1:
|
||||
#endif
|
||||
|
||||
w =
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[0] ) ) |
|
||||
0x0100u;
|
||||
|
||||
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;
|
||||
inline boost::uint64_t mul32( boost::uint32_t x, boost::uint32_t y )
|
||||
{
|
||||
return static_cast<boost::uint64_t>( x ) * y;
|
||||
}
|
||||
|
||||
template<class It>
|
||||
inline typename boost::enable_if_<
|
||||
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,
|
||||
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 );
|
||||
|
||||
boost::uint32_t const q = 0x9e3779b9U;
|
||||
boost::uint32_t const k = 0xe35e67b1U; // q * q
|
||||
|
||||
boost::uint64_t h = mul32( static_cast<boost::uint32_t>( seed ) + q, k );
|
||||
boost::uint32_t w = static_cast<boost::uint32_t>( h & 0xFFFFFFFF );
|
||||
|
||||
h ^= n;
|
||||
|
||||
while( n >= 4 )
|
||||
{
|
||||
boost::uint32_t v1 = read32le( p );
|
||||
|
||||
w += q;
|
||||
h ^= mul32( v1 + w, k );
|
||||
|
||||
p += 4;
|
||||
n -= 4;
|
||||
}
|
||||
|
||||
{
|
||||
boost::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<boost::uint32_t>( static_cast<unsigned char>( p[ static_cast<std::ptrdiff_t>( x1 ) ] ) ) << x1 * 8 |
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( p[ static_cast<std::ptrdiff_t>( x2 ) ] ) ) << x2 * 8 |
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( p[ 0 ] ) );
|
||||
}
|
||||
|
||||
w += q;
|
||||
h ^= mul32( v1 + w, k );
|
||||
}
|
||||
|
||||
w += q;
|
||||
h ^= mul32( static_cast<boost::uint32_t>( h & 0xFFFFFFFF ) + w, static_cast<boost::uint32_t>( h >> 32 ) + w + k );
|
||||
|
||||
return static_cast<boost::uint32_t>( h & 0xFFFFFFFF ) ^ static_cast<boost::uint32_t>( h >> 32 );
|
||||
}
|
||||
|
||||
template<class It>
|
||||
inline typename boost::enable_if_<
|
||||
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::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;
|
||||
|
||||
boost::uint32_t const q = 0x9e3779b9U;
|
||||
boost::uint32_t const k = 0xe35e67b1U; // q * q
|
||||
|
||||
boost::uint64_t h = mul32( static_cast<boost::uint32_t>( seed ) + q, k );
|
||||
boost::uint32_t w = static_cast<boost::uint32_t>( h & 0xFFFFFFFF );
|
||||
|
||||
boost::uint32_t v1 = 0;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
boost::uint32_t w = 0;
|
||||
v1 = 0;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
hash_combine( seed, w | 0x01u );
|
||||
return seed;
|
||||
break;
|
||||
}
|
||||
|
||||
w |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) );
|
||||
v1 |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) );
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
hash_combine( seed, w | 0x0100u );
|
||||
return seed;
|
||||
break;
|
||||
}
|
||||
|
||||
w |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) ) << 8;
|
||||
v1 |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) ) << 8;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
hash_combine( seed, w | 0x010000u );
|
||||
return seed;
|
||||
break;
|
||||
}
|
||||
|
||||
w |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) ) << 16;
|
||||
v1 |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) ) << 16;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
hash_combine( seed, w | 0x01000000u );
|
||||
return seed;
|
||||
break;
|
||||
}
|
||||
|
||||
w |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) ) << 24;
|
||||
v1 |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) ) << 24;
|
||||
++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<boost::uint32_t>( h & 0xFFFFFFFF ) + w, static_cast<boost::uint32_t>( h >> 32 ) + w + k );
|
||||
|
||||
return static_cast<boost::uint32_t>( h & 0xFFFFFFFF ) ^ static_cast<boost::uint32_t>( h >> 32 );
|
||||
}
|
||||
|
||||
// specialized char[] version, 64 bit
|
||||
|
||||
template<class It> inline boost::uint64_t read64le( It p )
|
||||
{
|
||||
boost::uint64_t w =
|
||||
static_cast<boost::uint64_t>( static_cast<unsigned char>( p[0] ) ) |
|
||||
static_cast<boost::uint64_t>( static_cast<unsigned char>( p[1] ) ) << 8 |
|
||||
static_cast<boost::uint64_t>( static_cast<unsigned char>( p[2] ) ) << 16 |
|
||||
static_cast<boost::uint64_t>( static_cast<unsigned char>( p[3] ) ) << 24 |
|
||||
static_cast<boost::uint64_t>( static_cast<unsigned char>( p[4] ) ) << 32 |
|
||||
static_cast<boost::uint64_t>( static_cast<unsigned char>( p[5] ) ) << 40 |
|
||||
static_cast<boost::uint64_t>( static_cast<unsigned char>( p[6] ) ) << 48 |
|
||||
static_cast<boost::uint64_t>( static_cast<unsigned char>( p[7] ) ) << 56;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
|
||||
template<class T> inline boost::uint64_t read64le( T* p )
|
||||
{
|
||||
boost::uint64_t w;
|
||||
|
||||
std::memcpy( &w, p, 8 );
|
||||
return w;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template<class It>
|
||||
inline typename boost::enable_if_<
|
||||
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::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 );
|
||||
|
||||
boost::uint64_t const q = static_cast<boost::uint64_t>( 0x9e3779b9 ) << 32 | 0x7f4a7c15;
|
||||
boost::uint64_t const k = static_cast<boost::uint64_t>( 0xdf442d22 ) << 32 | 0xce4859b9; // q * q
|
||||
|
||||
boost::uint64_t w = mulx( seed + q, k );
|
||||
boost::uint64_t h = w ^ n;
|
||||
|
||||
while( n >= 8 )
|
||||
{
|
||||
boost::uint64_t v1 = read64le( p );
|
||||
|
||||
w += q;
|
||||
h ^= mulx( v1 + w, k );
|
||||
|
||||
p += 8;
|
||||
n -= 8;
|
||||
}
|
||||
|
||||
{
|
||||
boost::uint64_t v1 = 0;
|
||||
|
||||
if( n >= 4 )
|
||||
{
|
||||
v1 = static_cast<boost::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<boost::uint64_t>( static_cast<unsigned char>( p[ static_cast<std::ptrdiff_t>( x1 ) ] ) ) << x1 * 8 |
|
||||
static_cast<boost::uint64_t>( static_cast<unsigned char>( p[ static_cast<std::ptrdiff_t>( x2 ) ] ) ) << x2 * 8 |
|
||||
static_cast<boost::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 boost::enable_if_<
|
||||
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::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;
|
||||
|
||||
boost::uint64_t const q = static_cast<boost::uint64_t>( 0x9e3779b9 ) << 32 | 0x7f4a7c15;
|
||||
boost::uint64_t const k = static_cast<boost::uint64_t>( 0xdf442d22 ) << 32 | 0xce4859b9; // q * q
|
||||
|
||||
boost::uint64_t w = mulx( seed + q, k );
|
||||
boost::uint64_t h = w;
|
||||
|
||||
boost::uint64_t v1 = 0;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
v1 = 0;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<boost::uint64_t>( static_cast<unsigned char>( *first ) );
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<boost::uint64_t>( static_cast<unsigned char>( *first ) ) << 8;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<boost::uint64_t>( static_cast<unsigned char>( *first ) ) << 16;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<boost::uint64_t>( static_cast<unsigned char>( *first ) ) << 24;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<boost::uint64_t>( static_cast<unsigned char>( *first ) ) << 32;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<boost::uint64_t>( static_cast<unsigned char>( *first ) ) << 40;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<boost::uint64_t>( static_cast<unsigned char>( *first ) ) << 48;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<boost::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
|
||||
|
||||
@@ -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
|
||||
156
include/boost/container_hash/detail/hash_tuple_like.hpp
Normal file
156
include/boost/container_hash/detail/hash_tuple_like.hpp
Normal file
@@ -0,0 +1,156 @@
|
||||
// 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 <boost/type_traits/enable_if.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
|
||||
#if defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
// no support for tuple-likes
|
||||
|
||||
#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_like( 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_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
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1800)
|
||||
|
||||
template <class T>
|
||||
inline
|
||||
typename boost::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 );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename... T>
|
||||
inline std::size_t hash_value( std::tuple<T...> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
inline std::size_t hash_value( std::tuple<> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
template<typename A0>
|
||||
inline std::size_t hash_value( std::tuple<A0> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
template<typename A0, typename A1>
|
||||
inline std::size_t hash_value( std::tuple<A0, A1> const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( 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_like( 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_like( 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_like( 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_like( 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_like( 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_like( 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_like( 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_like( 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
|
||||
79
include/boost/container_hash/detail/mulx.hpp
Normal file
79
include/boost/container_hash/detail/mulx.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright 2022, 2023 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_HASH_DETAIL_MULX_HPP
|
||||
#define BOOST_HASH_DETAIL_MULX_HPP
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#if defined(_MSC_VER)
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_X64) && !defined(__clang__)
|
||||
|
||||
__forceinline boost::uint64_t mulx( boost::uint64_t x, boost::uint64_t y )
|
||||
{
|
||||
boost::uint64_t r2;
|
||||
boost::uint64_t r = _umul128( x, y, &r2 );
|
||||
return r ^ r2;
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__)
|
||||
|
||||
__forceinline boost::uint64_t mulx( boost::uint64_t x, boost::uint64_t y )
|
||||
{
|
||||
boost::uint64_t r = x * y;
|
||||
boost::uint64_t r2 = __umulh( x, y );
|
||||
return r ^ r2;
|
||||
}
|
||||
|
||||
#elif defined(__SIZEOF_INT128__)
|
||||
|
||||
inline boost::uint64_t mulx( boost::uint64_t x, boost::uint64_t y )
|
||||
{
|
||||
__uint128_t r = static_cast<__uint128_t>( x ) * y;
|
||||
return static_cast<boost::uint64_t>( r ) ^ static_cast<boost::uint64_t>( r >> 64 );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline boost::uint64_t mulx( boost::uint64_t x, boost::uint64_t y )
|
||||
{
|
||||
boost::uint64_t x1 = static_cast<boost::uint32_t>( x );
|
||||
boost::uint64_t x2 = x >> 32;
|
||||
|
||||
boost::uint64_t y1 = static_cast<boost::uint32_t>( y );
|
||||
boost::uint64_t y2 = y >> 32;
|
||||
|
||||
boost::uint64_t r3 = x2 * y2;
|
||||
|
||||
boost::uint64_t r2a = x1 * y2;
|
||||
|
||||
r3 += r2a >> 32;
|
||||
|
||||
boost::uint64_t r2b = x2 * y1;
|
||||
|
||||
r3 += r2b >> 32;
|
||||
|
||||
boost::uint64_t r1 = x1 * y1;
|
||||
|
||||
boost::uint64_t r2 = (r1 >> 32) + static_cast<boost::uint32_t>( r2a ) + static_cast<boost::uint32_t>( r2b );
|
||||
|
||||
r1 = (r2 << 32) + static_cast<boost::uint32_t>( r1 );
|
||||
r3 += r2 >> 32;
|
||||
|
||||
return r1 ^ r3;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace hash_detail
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_DETAIL_MULX_HPP
|
||||
22
include/boost/container_hash/detail/requires_cxx11.hpp
Normal file
22
include/boost/container_hash/detail/requires_cxx11.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef BOOST_HASH_DETAIL_REQUIRES_CXX11_HPP_INCLUDED
|
||||
#define BOOST_HASH_DETAIL_REQUIRES_CXX11_HPP_INCLUDED
|
||||
|
||||
// Copyright 2023 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || \
|
||||
defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \
|
||||
defined(BOOST_NO_CXX11_DECLTYPE) || \
|
||||
defined(BOOST_NO_CXX11_CONSTEXPR) || \
|
||||
defined(BOOST_NO_CXX11_NOEXCEPT) || \
|
||||
defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
BOOST_PRAGMA_MESSAGE("C++03 support was deprecated in Boost.ContainerHash 1.82 and will be removed in Boost.ContainerHash 1.84. Please open an issue in https://github.com/boostorg/container_hash if you want it retained.")
|
||||
|
||||
#endif
|
||||
|
||||
#endif // #ifndef BOOST_HASH_DETAIL_REQUIRES_CXX11_HPP_INCLUDED
|
||||
@@ -11,11 +11,12 @@
|
||||
#define BOOST_FUNCTIONAL_HASH_HASH_HPP
|
||||
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
#include <boost/container_hash/detail/requires_cxx11.hpp>
|
||||
#include <boost/container_hash/is_range.hpp>
|
||||
#include <boost/container_hash/is_contiguous_range.hpp>
|
||||
#include <boost/container_hash/is_unordered_range.hpp>
|
||||
#include <boost/container_hash/is_described_class.hpp>
|
||||
#include <boost/container_hash/detail/hash_tuple.hpp>
|
||||
#include <boost/container_hash/detail/hash_tuple_like.hpp>
|
||||
#include <boost/container_hash/detail/hash_mix.hpp>
|
||||
#include <boost/container_hash/detail/hash_range.hpp>
|
||||
#include <boost/type_traits/is_enum.hpp>
|
||||
@@ -118,7 +119,7 @@ namespace boost
|
||||
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 );
|
||||
seed = static_cast<std::size_t>( v & 0xFFFFFFFF ) + hash_detail::hash_mix( seed );
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ template<class T> struct is_range;
|
||||
template<class T> struct is_contiguous_range;
|
||||
template<class T> struct is_unordered_range;
|
||||
template<class T> struct is_described_class;
|
||||
template<class T> struct is_tuple_like;
|
||||
|
||||
} // namespace container_hash
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef BOOST_HASH_IS_CONTIGUOUS_RANGE_HPP_INCLUDED
|
||||
#define BOOST_HASH_IS_CONTIGUOUS_RANGE_HPP_INCLUDED
|
||||
|
||||
#include <boost/container_hash/detail/requires_cxx11.hpp>
|
||||
#include <boost/container_hash/is_range.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef BOOST_HASH_IS_RANGE_HPP_INCLUDED
|
||||
#define BOOST_HASH_IS_RANGE_HPP_INCLUDED
|
||||
|
||||
#include <boost/container_hash/detail/requires_cxx11.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/type_traits/declval.hpp>
|
||||
|
||||
42
include/boost/container_hash/is_tuple_like.hpp
Normal file
42
include/boost/container_hash/is_tuple_like.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#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 <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
template<class T, class E = true_type> struct is_tuple_like_: false_type
|
||||
{
|
||||
};
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && !BOOST_WORKAROUND(BOOST_MSVC, <= 1800)
|
||||
|
||||
template<class T> struct is_tuple_like_<T, integral_constant<bool, std::tuple_size<T>::value == std::tuple_size<T>::value> >: true_type
|
||||
{
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace hash_detail
|
||||
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_tuple_like: hash_detail::is_tuple_like_<T>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace container_hash
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_IS_TUPLE_LIKE_HPP_INCLUDED
|
||||
@@ -77,7 +77,7 @@ run hash_string_test2.cpp ;
|
||||
# for gcc-4.8
|
||||
local fs-path-req = "-<toolset>gcc:<cxxflags>-Wshadow" "-<toolset>gcc:<cxxflags>-Wconversion" ;
|
||||
|
||||
run hash_fs_path_test.cpp /boost//filesystem/<warnings>off : : : $(fs-path-req) <toolset>msvc-14.0,<cxxstd>latest:<build>no <toolset>msvc-8.0:<build>no ;
|
||||
run hash_fs_path_test.cpp /boost//filesystem/<warnings>off : : : $(fs-path-req) <toolset>msvc-14.0,<cxxstd>latest:<build>no <toolset>msvc-8.0:<build>no <undefined-sanitizer>norecover:<link>static ;
|
||||
run is_range_test2.cpp : : : $(fs-path-req) <toolset>msvc-8.0:<build>no ;
|
||||
|
||||
run hash_container_test.cpp ;
|
||||
@@ -116,4 +116,12 @@ run described_class_test.cpp
|
||||
run hash_is_avalanching_test.cpp ;
|
||||
run hash_is_avalanching_test2.cpp ;
|
||||
|
||||
run hash_integral_test2.cpp ;
|
||||
|
||||
run hash_nullptr_test.cpp ;
|
||||
|
||||
run is_tuple_like_test.cpp ;
|
||||
|
||||
run hash_tuple_like_test.cpp ;
|
||||
run hash_tuple_like_test2.cpp
|
||||
: : : <warnings>extra ;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/core/type_name.hpp>
|
||||
#include <boost/type_traits/is_signed.hpp>
|
||||
#include <set>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(disable: 4127) // conditional expression is constant
|
||||
|
||||
52
test/hash_integral_test2.cpp
Normal file
52
test/hash_integral_test2.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Copyright 2021 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/core/type_name.hpp>
|
||||
#include <boost/type_traits/is_signed.hpp>
|
||||
#include <boost/type_traits/make_unsigned.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
// This test checks that values representable in a signed
|
||||
// and the corresponding unsigned type hash to the same value
|
||||
|
||||
template<class T>
|
||||
void signed_unsigned_test()
|
||||
{
|
||||
BOOST_STATIC_ASSERT( boost::is_signed<T>::value );
|
||||
|
||||
typedef typename boost::make_unsigned<T>::type U;
|
||||
|
||||
T x = std::numeric_limits<T>::max();
|
||||
|
||||
do
|
||||
{
|
||||
BOOST_TEST_EQ( boost::hash<T>()( x ), boost::hash<U>()( static_cast<U>( x ) ) );
|
||||
x /= 3;
|
||||
}
|
||||
while( x > 0 );
|
||||
}
|
||||
|
||||
#define TEST(type) std::cerr << "Testing: " #type " (" << boost::core::type_name<type>() << ")\n"; signed_unsigned_test<type>();
|
||||
|
||||
int main()
|
||||
{
|
||||
TEST(signed char)
|
||||
TEST(short)
|
||||
TEST(int)
|
||||
TEST(long)
|
||||
|
||||
#if !defined(BOOST_NO_LONG_LONG)
|
||||
TEST(boost::long_long_type)
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_INT128)
|
||||
TEST(boost::int128_type)
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -35,7 +35,11 @@ int main()
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
@@ -284,19 +284,19 @@ int main()
|
||||
// string
|
||||
#if SIZE_MAX == 4294967295U
|
||||
|
||||
BOOST_TEST_EQ( hv(std::string()), 1580013426U );
|
||||
BOOST_TEST_EQ( hv(std::string("abc")), 469308065U );
|
||||
BOOST_TEST_EQ( hv(std::string("\0", 1)), 165258820U );
|
||||
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 4017288109U );
|
||||
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 1352445396U );
|
||||
BOOST_TEST_EQ( hv(std::string()), 1868390524U );
|
||||
BOOST_TEST_EQ( hv(std::string("abc")), 3674866719U );
|
||||
BOOST_TEST_EQ( hv(std::string("\0", 1)), 1965885047U );
|
||||
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 54340706U );
|
||||
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 688730713U );
|
||||
|
||||
#else
|
||||
|
||||
BOOST_TEST_EQ( hv(std::string()), 2220755840493918647ULL );
|
||||
BOOST_TEST_EQ( hv(std::string("abc")), 7565583854499162206ULL );
|
||||
BOOST_TEST_EQ( hv(std::string("\0", 1)), 1241131678047372712ULL );
|
||||
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 152341731040131640ULL );
|
||||
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 12957252994983528908ULL );
|
||||
BOOST_TEST_EQ( hv(std::string()), 2060355526954642342ULL );
|
||||
BOOST_TEST_EQ( hv(std::string("abc")), 2539195663733406973ULL );
|
||||
BOOST_TEST_EQ( hv(std::string("\0", 1)), 18432168439372857722ULL );
|
||||
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 6494115972580589074ULL );
|
||||
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 4419026507380069870ULL );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -376,17 +376,17 @@ int main()
|
||||
// vector<char>
|
||||
#if SIZE_MAX == 4294967295U
|
||||
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(0)), 1580013426U );
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(1)), 165258820U );
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(2)), 4017288109U );
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(3)), 1352445396U );
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(0)), 1868390524U );
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(1)), 1965885047U );
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(2)), 54340706U );
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(3)), 688730713U );
|
||||
|
||||
#else
|
||||
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(0)), 2220755840493918647ULL );
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(1)), 1241131678047372712ULL );
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(2)), 152341731040131640ULL );
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(3)), 12957252994983528908ULL );
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(0)), 2060355526954642342ULL );
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(1)), 18432168439372857722ULL );
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(2)), 6494115972580589074ULL );
|
||||
BOOST_TEST_EQ( hv(std::vector<char>(3)), 4419026507380069870ULL );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -427,17 +427,17 @@ int main()
|
||||
// list<char>
|
||||
#if SIZE_MAX == 4294967295U
|
||||
|
||||
BOOST_TEST_EQ( hv(std::list<char>(0)), 1580013426U );
|
||||
BOOST_TEST_EQ( hv(std::list<char>(1)), 165258820U );
|
||||
BOOST_TEST_EQ( hv(std::list<char>(2)), 4017288109U );
|
||||
BOOST_TEST_EQ( hv(std::list<char>(3)), 1352445396U );
|
||||
BOOST_TEST_EQ( hv(std::list<char>(0)), 1868390524U );
|
||||
BOOST_TEST_EQ( hv(std::list<char>(1)), 1965885047U );
|
||||
BOOST_TEST_EQ( hv(std::list<char>(2)), 54340706U );
|
||||
BOOST_TEST_EQ( hv(std::list<char>(3)), 688730713U );
|
||||
|
||||
#else
|
||||
|
||||
BOOST_TEST_EQ( hv(std::list<char>(0)), 2220755840493918647ULL );
|
||||
BOOST_TEST_EQ( hv(std::list<char>(1)), 1241131678047372712ULL );
|
||||
BOOST_TEST_EQ( hv(std::list<char>(2)), 152341731040131640ULL );
|
||||
BOOST_TEST_EQ( hv(std::list<char>(3)), 12957252994983528908ULL );
|
||||
BOOST_TEST_EQ( hv(std::list<char>(0)), 2060355526954642342ULL );
|
||||
BOOST_TEST_EQ( hv(std::list<char>(1)), 18432168439372857722ULL );
|
||||
BOOST_TEST_EQ( hv(std::list<char>(2)), 6494115972580589074ULL );
|
||||
BOOST_TEST_EQ( hv(std::list<char>(3)), 4419026507380069870ULL );
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
204
test/hash_tuple_like_test.cpp
Normal file
204
test/hash_tuple_like_test.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||
#endif
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/type_traits/enable_if.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <utility>
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace user
|
||||
{
|
||||
|
||||
struct Y1
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
template<std::size_t I> int& get( Y1& v );
|
||||
template<std::size_t I> int const& get( Y1 const& v );
|
||||
|
||||
template<> int& get<0>( Y1& v )
|
||||
{
|
||||
return v.a;
|
||||
}
|
||||
|
||||
template<> int const& get<0>( Y1 const& v )
|
||||
{
|
||||
return v.a;
|
||||
}
|
||||
|
||||
template<> int& get<1>( Y1& v )
|
||||
{
|
||||
return v.b;
|
||||
}
|
||||
|
||||
template<> int const& get<1>( Y1 const& v )
|
||||
{
|
||||
return v.b;
|
||||
}
|
||||
|
||||
struct Y2
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
|
||||
template<class T> friend
|
||||
typename boost::enable_if_<boost::is_same<T, Y2>::value, std::size_t>::type
|
||||
hash_value( T const& v )
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_combine( seed, v.a );
|
||||
boost::hash_combine( seed, v.b );
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace user
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<> struct tuple_size<user::Y1>: std::integral_constant<std::size_t, 2>
|
||||
{
|
||||
};
|
||||
|
||||
template<> struct tuple_size<user::Y2>: std::integral_constant<std::size_t, 2>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<> struct is_tuple_like<user::Y2>: boost::false_type {};
|
||||
|
||||
} // namespace container_hash
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
template<class T> std::size_t hv( T const& t )
|
||||
{
|
||||
return boost::hash<T>()( t );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
std::pair<int, int> tp( 1, 2 );
|
||||
int const a[] = { 1, 2 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
{
|
||||
std::tuple<> tp;
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), 0u );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int> tp( 1 );
|
||||
int const a[] = { 1 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int> tp( 1, 2 );
|
||||
int const a[] = { 1, 2 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int, int> tp( 1, 2, 3 );
|
||||
int const a[] = { 1, 2, 3 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int, int, int> tp( 1, 2, 3, 4 );
|
||||
int const a[] = { 1, 2, 3, 4 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int, int, int, int> tp( 1, 2, 3, 4, 5 );
|
||||
int const a[] = { 1, 2, 3, 4, 5 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6 );
|
||||
int const a[] = { 1, 2, 3, 4, 5, 6 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6, 7 );
|
||||
int const a[] = { 1, 2, 3, 4, 5, 6, 7 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int, int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6, 7, 8 );
|
||||
int const a[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
{
|
||||
std::tuple<int, int, int, int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6, 7, 8, 9 );
|
||||
int const a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1800)
|
||||
|
||||
{
|
||||
user::Y1 tp = { 1, 2 };
|
||||
int const a[] = { 1, 2 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
{
|
||||
user::Y2 tp = { 1, 2 };
|
||||
int const a[] = { 1, 2 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
78
test/hash_tuple_like_test2.cpp
Normal file
78
test/hash_tuple_like_test2.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||
#endif
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/describe/class.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
#include <utility>
|
||||
|
||||
#if defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
BOOST_PRAGMA_MESSAGE( "Skipping test because BOOST_NO_CXX11_HDR_TUPLE is defined" )
|
||||
int main() {}
|
||||
|
||||
#elif !defined(BOOST_DESCRIBE_CXX14)
|
||||
|
||||
BOOST_PRAGMA_MESSAGE( "Skipping test because BOOST_DESCRIBE_CXX14 is not defined" )
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
|
||||
namespace user
|
||||
{
|
||||
|
||||
struct Y3
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT(Y3, (), (a, b))
|
||||
|
||||
} // namespace user
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<> struct tuple_size<user::Y3>: std::integral_constant<std::size_t, 2>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<> struct is_tuple_like<user::Y3>: boost::false_type {};
|
||||
|
||||
} // namespace container_hash
|
||||
} // namespace boost
|
||||
|
||||
template<class T> std::size_t hv( T const& t )
|
||||
{
|
||||
return boost::hash<T>()( t );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
user::Y3 tp = { 1, 2 };
|
||||
int const a[] = { 1, 2 };
|
||||
|
||||
BOOST_TEST_EQ( hv(tp), hv(a) );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
91
test/is_tuple_like_test.cpp
Normal file
91
test/is_tuple_like_test.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright 2017, 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||
#endif
|
||||
|
||||
#include <boost/container_hash/is_tuple_like.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <utility>
|
||||
|
||||
struct X
|
||||
{
|
||||
};
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace user
|
||||
{
|
||||
|
||||
struct Y
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
template<std::size_t I> int& get( Y& v );
|
||||
template<std::size_t I> int const& get( Y const& v );
|
||||
|
||||
template<> int& get<0>( Y& v )
|
||||
{
|
||||
return v.a;
|
||||
}
|
||||
|
||||
template<> int const& get<0>( Y const& v )
|
||||
{
|
||||
return v.a;
|
||||
}
|
||||
|
||||
template<> int& get<1>( Y& v )
|
||||
{
|
||||
return v.b;
|
||||
}
|
||||
|
||||
template<> int const& get<1>( Y const& v )
|
||||
{
|
||||
return v.b;
|
||||
}
|
||||
|
||||
} // namespace user
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<> struct tuple_size<user::Y>: std::integral_constant<std::size_t, 2>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // #if !defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
int main()
|
||||
{
|
||||
using boost::container_hash::is_tuple_like;
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE((is_tuple_like<void>));
|
||||
BOOST_TEST_TRAIT_FALSE((is_tuple_like<int>));
|
||||
BOOST_TEST_TRAIT_FALSE((is_tuple_like<X>));
|
||||
BOOST_TEST_TRAIT_FALSE((is_tuple_like<int[2]>));
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && !BOOST_WORKAROUND(BOOST_MSVC, <= 1800)
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::pair<int, X> >));
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<> >));
|
||||
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<X> >));
|
||||
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<X, X> >));
|
||||
BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<X, X, X> >));
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE((is_tuple_like<user::Y>));
|
||||
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
Reference in New Issue
Block a user