Compare commits

...

45 Commits

Author SHA1 Message Date
Peter Dimov
226eb066e9 Update .drone.jsonnet 2023-06-29 14:38:53 +03:00
Peter Dimov
d9cb23d96a Update ci.yml 2023-06-29 11:50:12 +03:00
Peter Dimov
bd8a5cb867 Merge pull request #34 from ecatmur/libcxx-16
Fix libc++16 failures
2023-06-29 11:22:13 +03:00
Ed Catmur
b43ce472fa Fix libc++16 failures
Similar to de8fe4fad7
2023-06-28 11:12:42 -05:00
Peter Dimov
e798972130 Update C++03 deprecation message 2023-06-03 02:27:41 +03:00
Peter Dimov
ebb49fa459 Update ci.yml 2023-05-21 15:28:59 +03:00
Peter Dimov
1e1c0ea38c Update ci.yml 2023-05-21 04:08:58 +03:00
Peter Dimov
e62a268566 Update documentation 2023-04-05 17:34:08 +03:00
Peter Dimov
ad89c02360 Use link=static for /boost//filesystem under UBSan 2023-03-05 04:59:42 +02:00
Peter Dimov
64948e5f57 Update .drone.jsonnet 2023-03-05 04:21:10 +02:00
Peter Dimov
1958e96561 Add C++03 deprecation notice 2023-03-05 02:38:16 +02:00
Peter Dimov
4a7287d371 Update ci.yml 2023-03-02 21:12:54 +02:00
Peter Dimov
5638134081 Update notes.adoc 2023-03-02 19:45:18 +02:00
Peter Dimov
7c49f0bfb1 Document switch to mulxp1_hash 2023-02-15 20:44:10 +02:00
Peter Dimov
9ae5790657 Update ci.yml 2023-02-04 01:22:15 +02:00
Peter Dimov
8ce81c361d Fix /RTCc violations because Unordered tests with it 2023-02-03 20:57:47 +02:00
Peter Dimov
4315faf470 Update ci.yml 2023-02-02 14:54:38 +02:00
Peter Dimov
eb049e0cae Update .drone.jsonnet 2023-02-02 14:19:37 +02:00
Peter Dimov
6373656710 Avoid -Wlong-long under C++03 2023-02-02 07:29:03 +02:00
Peter Dimov
ec1503bbc8 Hardcode q*q to avoid 'integral constant overflow' warnings 2023-02-02 06:15:01 +02:00
Peter Dimov
ee064dc7f8 Avoid -Wconversion warnings 2023-02-02 06:11:47 +02:00
Peter Dimov
b505e06b3c Update 64 bit reference values to reflect the change to mulxp1_hash 2023-02-02 06:06:36 +02:00
Peter Dimov
6075f3e1f5 Change 64 bit hash_range for char[] to mulxp1_hash 2023-02-02 06:00:00 +02:00
Peter Dimov
0bfeabfd63 Hardcode q*q to avoid 'integral constant overflow' warnings 2023-02-02 05:20:06 +02:00
Peter Dimov
758596533d Temporarily update 64 bit reference values to match mulxp1_hash32 2023-02-02 04:58:15 +02:00
Peter Dimov
640bd48f51 Avoid -Wconversion warning for p[x1] 2023-02-02 04:54:10 +02:00
Peter Dimov
b25fd745ca Update 32 bit reference values to reflect the change to mulxp1_hash32 2023-02-02 04:52:42 +02:00
Peter Dimov
6fe3469a8b Replace hash_range for char[] with mulxp1_hash32 2023-02-02 04:42:42 +02:00
Peter Dimov
c07630ac60 Add read32le to detail/hash_range.hpp 2023-02-02 04:09:54 +02:00
Peter Dimov
45270ae11e Update benchmark/unordered.cpp 2022-12-12 21:08:00 +02:00
Peter Dimov
5bef4901b9 Add a pointer overload for detail::hash_range under msvc 2022-12-09 21:12:30 +02:00
Peter Dimov
d724bcd0ef Update benchmark/.gitignore 2022-12-09 20:54:04 +02:00
Peter Dimov
ceb8303601 Add mulxp1_hash32 to benchmarks 2022-12-08 17:57:00 +02:00
Peter Dimov
cf87e304f6 Remove mul31, mulxp0, mulxp2 from the unordered_flat and word_count benchmarks 2022-12-01 18:53:34 +02:00
Peter Dimov
4d9f7b8931 Add ankerl::unordered_dense::hash to benchmarks 2022-12-01 02:22:07 +02:00
Peter Dimov
2f4efbced4 Document support for nullptr and tuple-like types 2022-11-29 02:00:06 +02:00
Peter Dimov
bf7a78594e Add a test with a tuple-like described struct 2022-11-28 18:46:13 +02:00
Peter Dimov
c0c70e5b3e Add support for tuple-like types. Refs #30. 2022-11-28 16:59:35 +02:00
Peter Dimov
891a64d45d Add is_tuple_like to hash_fwd.hpp 2022-11-28 15:55:25 +02:00
Peter Dimov
08d69c31b1 Merge branch 'develop' into feature/is_tuple_like 2022-11-28 15:50:36 +02:00
Peter Dimov
6526b24900 Add hash_integral_test2.cpp 2022-11-28 14:20:44 +02:00
Peter Dimov
1a8dca4f2c Disable is_tuple_like for msvc-12.0 and earlier 2022-11-28 05:15:06 +02:00
Peter Dimov
8761157a19 Merge branch 'develop' into feature/is_tuple_like 2022-11-28 03:13:35 +02:00
Peter Dimov
30560ada18 Disable -Wmismatched-tags under Clang 2022-11-28 00:57:19 +02:00
Peter Dimov
c61a4f691e Add boost::container_hash::is_tuple_like. Refs #30. 2022-11-27 21:20:19 +02:00
29 changed files with 1565 additions and 598 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,79 @@
// Copyright 2022, 2023 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_DETAIL_MULX_HPP
#define BOOST_HASH_DETAIL_MULX_HPP
#include <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

View 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

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,204 @@
// Copyright 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(__clang__)
# pragma clang diagnostic ignored "-Wmismatched-tags"
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/type_traits/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/config.hpp>
#include <utility>
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
#include <tuple>
namespace user
{
struct Y1
{
int a;
int b;
};
template<std::size_t I> int& get( Y1& v );
template<std::size_t I> int const& get( Y1 const& v );
template<> int& get<0>( Y1& v )
{
return v.a;
}
template<> int const& get<0>( Y1 const& v )
{
return v.a;
}
template<> int& get<1>( Y1& v )
{
return v.b;
}
template<> int const& get<1>( Y1 const& v )
{
return v.b;
}
struct Y2
{
int a;
int b;
template<class T> friend
typename boost::enable_if_<boost::is_same<T, Y2>::value, std::size_t>::type
hash_value( T const& v )
{
std::size_t seed = 0;
boost::hash_combine( seed, v.a );
boost::hash_combine( seed, v.b );
return seed;
}
};
} // namespace user
namespace std
{
template<> struct tuple_size<user::Y1>: std::integral_constant<std::size_t, 2>
{
};
template<> struct tuple_size<user::Y2>: std::integral_constant<std::size_t, 2>
{
};
} // namespace std
namespace boost
{
namespace container_hash
{
template<> struct is_tuple_like<user::Y2>: boost::false_type {};
} // namespace container_hash
} // namespace boost
#endif
template<class T> std::size_t hv( T const& t )
{
return boost::hash<T>()( t );
}
int main()
{
{
std::pair<int, int> tp( 1, 2 );
int const a[] = { 1, 2 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
{
std::tuple<> tp;
BOOST_TEST_EQ( hv(tp), 0u );
}
{
std::tuple<int> tp( 1 );
int const a[] = { 1 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int> tp( 1, 2 );
int const a[] = { 1, 2 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int, int> tp( 1, 2, 3 );
int const a[] = { 1, 2, 3 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int, int, int> tp( 1, 2, 3, 4 );
int const a[] = { 1, 2, 3, 4 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int, int, int, int> tp( 1, 2, 3, 4, 5 );
int const a[] = { 1, 2, 3, 4, 5 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6 );
int const a[] = { 1, 2, 3, 4, 5, 6 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6, 7 );
int const a[] = { 1, 2, 3, 4, 5, 6, 7 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int, int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6, 7, 8 );
int const a[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
{
std::tuple<int, int, int, int, int, int, int, int, int> tp( 1, 2, 3, 4, 5, 6, 7, 8, 9 );
int const a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1800)
{
user::Y1 tp = { 1, 2 };
int const a[] = { 1, 2 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
#endif
{
user::Y2 tp = { 1, 2 };
int const a[] = { 1, 2 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,78 @@
// Copyright 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(__clang__)
# pragma clang diagnostic ignored "-Wmismatched-tags"
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/describe/class.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#include <utility>
#if defined(BOOST_NO_CXX11_HDR_TUPLE)
BOOST_PRAGMA_MESSAGE( "Skipping test because BOOST_NO_CXX11_HDR_TUPLE is defined" )
int main() {}
#elif !defined(BOOST_DESCRIBE_CXX14)
BOOST_PRAGMA_MESSAGE( "Skipping test because BOOST_DESCRIBE_CXX14 is not defined" )
int main() {}
#else
namespace user
{
struct Y3
{
int a;
int b;
};
BOOST_DESCRIBE_STRUCT(Y3, (), (a, b))
} // namespace user
namespace std
{
template<> struct tuple_size<user::Y3>: std::integral_constant<std::size_t, 2>
{
};
} // namespace std
namespace boost
{
namespace container_hash
{
template<> struct is_tuple_like<user::Y3>: boost::false_type {};
} // namespace container_hash
} // namespace boost
template<class T> std::size_t hv( T const& t )
{
return boost::hash<T>()( t );
}
int main()
{
{
user::Y3 tp = { 1, 2 };
int const a[] = { 1, 2 };
BOOST_TEST_EQ( hv(tp), hv(a) );
}
return boost::report_errors();
}
#endif

View File

@@ -0,0 +1,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();
}