Compare commits

...

125 Commits

Author SHA1 Message Date
Peter Dimov
c01270b0bd Update Links section 2022-09-18 22:05:30 +03:00
Peter Dimov
123875dc83 Update documentation 2022-09-18 20:58:00 +03:00
Peter Dimov
ed235989ef Add is_unordered_range_test2 2022-09-18 14:32:28 +03:00
Peter Dimov
bf0a77f062 Disable tests using fs::path for msvc-8.0 2022-09-18 14:28:24 +03:00
Peter Dimov
79fff9e1ea Add is_contiguous_range_test2 2022-09-18 14:26:30 +03:00
Peter Dimov
6757bd4f00 Match is_range workaround in is_range_test3 2022-09-18 14:11:49 +03:00
Peter Dimov
20c03417b0 Add is_range_test3 2022-09-18 14:04:05 +03:00
Peter Dimov
60be3b131e Update 64 bit reference values for the new multiplier 2022-09-17 03:31:35 +03:00
Peter Dimov
b148e34818 Fix 64 bit hash_mix multiplier 2022-09-17 02:34:14 +03:00
Peter Dimov
e391cf6841 Change hash_detail::hash_range to take and return by value to avoid It=char* aliasing 2022-09-17 01:09:47 +03:00
Peter Dimov
b4e0643ecd Update 32 bit reference values for container<char> 2022-09-16 21:43:53 +03:00
Peter Dimov
dc9a6e3e68 Update 64 bit reference values for container<char> 2022-09-16 21:33:48 +03:00
Peter Dimov
f47772f6f4 Implement faster hash_range when value_type is char 2022-09-16 21:25:20 +03:00
Peter Dimov
c1e5427e8d Update 32 bit float reference values (for GCC) 2022-09-16 20:36:29 +03:00
Peter Dimov
866cff96e5 Restore full grid size in hash_complex_test 2022-09-16 19:57:45 +03:00
Peter Dimov
9d4971b81d Update complex reference values 2022-09-16 19:56:00 +03:00
Peter Dimov
4b5a1cf0f2 Update complex hashing to use hash_mix 2022-09-16 19:48:36 +03:00
Peter Dimov
435ff87fd7 Update 64 bit reference values (for GCC) 2022-09-16 19:30:02 +03:00
Peter Dimov
58934422fb Update 32 bit reference values (for MSVC) 2022-09-16 19:26:07 +03:00
Peter Dimov
3fe7bbdd6c Update floating point hashing to use hash_mix 2022-09-16 19:23:07 +03:00
Peter Dimov
fba63d4379 Update integral reference values 2022-09-16 19:19:30 +03:00
Peter Dimov
8adcaffcc2 Update integral hashing to use hash_mix 2022-09-16 19:16:45 +03:00
Peter Dimov
eee5e3b7fd Update 32 bit reference values to reflect the new hash_combine 2022-09-16 19:10:18 +03:00
Peter Dimov
e98cae2c31 Update 64 bit reference values to reflect the new hash_combine 2022-09-16 19:05:05 +03:00
Peter Dimov
40ec854466 Add hash_mix, change hash_combine to use it 2022-09-16 18:57:21 +03:00
Peter Dimov
c5b63d2cbb Disable failing tests on msvc-10.0 and msvc-11.0 2022-09-16 11:00:23 +03:00
Peter Dimov
882192ea3a Update workaround for Dinkumware stdext::hash_value 2022-09-16 01:56:24 +03:00
Peter Dimov
03123685c4 Add hash_unordered_map_test 2022-09-15 18:12:52 +03:00
Peter Dimov
95fe6bd9a3 Add hash_unordered_set_test 2022-09-15 18:10:23 +03:00
Peter Dimov
6cb735fda6 Add hash_unordered_multimap_test 2022-09-15 18:05:00 +03:00
Peter Dimov
10b4ad598f Add hash_unordered_multiset_test 2022-09-15 18:02:22 +03:00
Peter Dimov
ce734b435e Implement boost::hash_unordered_range 2022-09-15 18:00:04 +03:00
Peter Dimov
e387d14d36 Add hash_multimap_test 2022-09-15 16:50:39 +03:00
Peter Dimov
1fb41a72ef Add hash_multiset_test 2022-09-15 16:48:18 +03:00
Peter Dimov
c399cf6a38 Add traits to hash_fwd.hpp 2022-09-13 20:10:35 +03:00
Peter Dimov
30c32bb3df Move traits headers from container_hash/detail/ to container_hash/ 2022-09-13 19:45:45 +03:00
Peter Dimov
d1b2640dff Move type classification traits from namespace hash_detail to namespace container_hash 2022-09-13 19:37:15 +03:00
Peter Dimov
f722383d1d Change macos-10.15 to macos-11 in ci.yml 2022-08-31 18:17:01 +03:00
Peter Dimov
21530840e1 Add hash_string_test4.cpp 2022-08-31 15:09:29 +03:00
Peter Dimov
d0c1e36fc1 Add hash_string_test3.cpp 2022-08-31 14:51:47 +03:00
Peter Dimov
e00f53a69c Remove msvc-14.2 from appveyor.yml 2022-07-16 14:10:28 +03:00
Peter Dimov
b0c9904414 Test _MSVC_STL_VERSION instead of BOOST_MSVC because clang-cl 2022-07-16 13:37:15 +03:00
Peter Dimov
2d557a746d Add hash_vector_test2.cpp 2022-07-16 11:16:06 +03:00
Peter Dimov
417180dd03 Update appveyor.yml 2022-07-14 20:16:19 +03:00
Peter Dimov
5ba74cd3a9 Update hash_value for pointers to handle the case when uintptr_t is larger than size_t 2022-07-03 23:35:46 +03:00
Peter Dimov
c14d3a1e2b Add a comment explaining why to_underlying isn't used in hash_value for enums 2022-07-03 21:08:14 +03:00
Peter Dimov
a3cac265b1 Disable examples/template.cpp for msvc-8.0 2022-07-03 20:28:28 +03:00
Peter Dimov
c28d0b813b Directly cast to size_t all integrals no wider than size_t 2022-06-26 01:25:45 +03:00
Peter Dimov
e39bf42dfc Update hash_string_test2.cpp 2022-06-15 22:56:57 +03:00
Peter Dimov
58502fddca Add hash_container_test.cpp 2022-06-15 22:52:56 +03:00
Peter Dimov
5701dd3119 Merge branch 'master' into develop 2022-06-14 15:38:19 +03:00
Peter Dimov
561cc5d010 Merge branch 'master' into develop 2022-06-13 14:26:03 +03:00
Peter Dimov
06e1b613f0 Add benchmark/char_seq.cpp 2022-06-08 17:48:06 +03:00
Peter Dimov
12be64b71e Update benchmark/unordered.cpp 2022-06-08 14:18:28 +03:00
Peter Dimov
4e2811c4e1 Add old_boost_hash to benchmark/unordered.cpp 2022-06-07 02:33:18 +03:00
Peter Dimov
2dc57b745f Output number of collisions in benchmark/unordered.cpp 2022-06-07 02:08:00 +03:00
Peter Dimov
de618bf974 Add benchmark/unordered.cpp 2022-06-06 22:45:49 +03:00
Peter Dimov
87c9eefe6e Add ubuntu-22.04 to posix-cmake jobs 2022-06-04 18:17:35 +03:00
Peter Dimov
98bbd2ba56 Disable hash_fs_path_test for msvc-14.0 cxxstd=latest 2022-06-04 15:53:54 +03:00
Peter Dimov
08ea1677be Disable -Wshadow and -Wconversion for the fs path tests because of gcc-4.8 2022-06-04 14:25:47 +03:00
Peter Dimov
3d3350646f Disable use of <filesystem> under MinGW (fails on GHA) 2022-06-04 14:19:01 +03:00
Peter Dimov
884ce4b708 Disable -Wsign-conversion for GCC 8 2022-06-04 02:01:50 +03:00
Peter Dimov
db1e23b611 Disable -Wsign-conversion for GCC in hash_reference_values.cpp 2022-06-04 01:49:26 +03:00
Peter Dimov
5ddcd7c8e7 Disable detail_is_range_test2.cpp under CMake 2022-06-03 22:44:32 +03:00
Peter Dimov
0e2e911df5 Attempt to fix -Wsign-conversion warnings under some GCC versions 2022-06-03 22:43:04 +03:00
Peter Dimov
b3c9b35a13 Disable -Wc99-extensions for Clang 2022-06-03 21:38:02 +03:00
Peter Dimov
c9c77cb104 Update warning suppressions 2022-06-03 20:59:41 +03:00
Peter Dimov
873a60d009 Disable -Wvariadic-macros for Clang as well 2022-06-03 20:19:01 +03:00
Peter Dimov
b8d315fac5 Update is_range, disable -Wvariadic-macros for GCC 2022-06-03 20:14:07 +03:00
Peter Dimov
e0e86a1413 Add detail_is_range_test2.cpp 2022-06-03 20:01:26 +03:00
Peter Dimov
866bd60dd3 Reject ranges that have themselves as their value_type (e.g. filesystem::path) 2022-06-03 19:52:03 +03:00
Peter Dimov
6781cff622 Add hash_fs_path_test.cpp 2022-06-03 19:31:33 +03:00
Peter Dimov
dd605d0d1c Link CMake tests to Boost::utility 2022-05-30 03:05:54 +03:00
Peter Dimov
dd172db079 Remove infinity special cases for libstdc++ 2022-05-30 02:52:22 +03:00
Peter Dimov
e04ca1f442 Match floating point hash values in 32 bit mode 2022-05-30 02:35:00 +03:00
Peter Dimov
0eada2ae93 Revert hash_combine for floats 2022-05-30 02:26:12 +03:00
Peter Dimov
943ef0ab82 Avoid -Wconversion with is_signed and enums 2022-05-30 02:19:54 +03:00
Peter Dimov
14f8934bff Revert integral hashing 2022-05-30 01:57:56 +03:00
Peter Dimov
f08204e29a Revert hash_value for std::complex 2022-05-29 21:59:17 +03:00
Peter Dimov
7ad0365048 Merge branch 'develop' into feature/refresh 2022-05-12 18:00:03 +03:00
Peter Dimov
9bdebb3df4 Merge branch 'develop' into feature/refresh 2021-10-19 17:37:20 +03:00
Peter Dimov
56f790d896 Add hash_integral_test.cpp 2021-10-17 19:36:53 +03:00
Peter Dimov
355c1cd7a4 Add hash_number_test2 2021-10-17 19:28:51 +03:00
Peter Dimov
c9b2d6fc90 Reenable clang-win in appveyor.yml 2021-10-17 19:08:15 +03:00
Peter Dimov
2424ada9f9 Bias integral values so that small integers hash to themselves even when having a wide type 2021-10-17 19:03:15 +03:00
Peter Dimov
faea988310 Revert change to hash_number_test.cpp 2021-10-17 17:49:10 +03:00
Peter Dimov
64c367734d Print hash_info output in ci.yml 2021-10-17 16:45:40 +03:00
Peter Dimov
6d84f9a41b Print size_t and floating point widths in hash_info 2021-10-17 16:43:02 +03:00
Peter Dimov
aaa1f441ac GCC 32 bit under Windows has an 80 bit long double in 12 bytes, not 16 2021-10-17 16:17:44 +03:00
Peter Dimov
3487450f62 Add CMake tests to ci.yml 2021-10-17 08:46:35 +03:00
Peter Dimov
8f163568f4 Add test/CMakeLists.txt 2021-10-17 08:37:07 +03:00
Peter Dimov
a4cbaa95b3 Regenerate CMakeLists.txt 2021-10-17 08:35:11 +03:00
Peter Dimov
6ffc99adb7 Update test/Jamfile 2021-10-17 08:22:24 +03:00
Peter Dimov
bb99a2b1ae Leave detail/limits.hpp a stub; update test 2021-10-17 08:15:10 +03:00
Peter Dimov
f05e8840d2 Remove float support files 2021-10-17 08:14:35 +03:00
Peter Dimov
dff8843bb2 Remove unnecessary include 2021-10-17 07:52:03 +03:00
Peter Dimov
15ae39e176 Implement floating point hashing inline in hash.hpp 2021-10-17 07:47:34 +03:00
Peter Dimov
39e4a4f184 Switch to type_traits/enable_if to eliminate the Core dependency 2021-10-17 07:10:47 +03:00
Peter Dimov
88fbad7438 Remove Borland workarounds 2021-10-17 04:00:10 +03:00
Peter Dimov
0737c56fec Move boost::hash into hash.hpp, delete specializations 2021-10-17 03:54:41 +03:00
Peter Dimov
2b9251069f Move std::tuple support to detail/hash_tuple.hpp 2021-10-17 02:40:29 +03:00
Peter Dimov
a63c85007f Move std::unique_ptr, std::shared_ptr support into hash.hpp 2021-10-17 02:14:19 +03:00
Peter Dimov
7a29dee42a Move std::pair support into hash.hpp 2021-10-17 02:11:51 +03:00
Peter Dimov
a0a6fa0616 Move std::complex support to hash.hpp 2021-10-17 02:03:50 +03:00
Peter Dimov
fe66085fbc Add hash_forward_list_test.cpp 2021-10-17 01:15:01 +03:00
Peter Dimov
24598bd45f Take care of g++ warning on 4294967291 2021-10-17 00:47:28 +03:00
Peter Dimov
7f2a43226e Take care of size_t -> int warnings under g++ 4.8 2021-10-17 00:31:08 +03:00
Peter Dimov
668f28660d Disable warning in test/check_float_funcs.cpp 2021-10-17 00:17:01 +03:00
Peter Dimov
9348a89fb4 Fix msvc-14.1 errors caused by their unconstrained stdext::hash_value overload (!) 2021-10-17 00:09:20 +03:00
Peter Dimov
3f2612d36e Update test/Jamfile, turn warnings-as-errors=on, fix g++ warning 2021-10-16 22:22:29 +03:00
Peter Dimov
3cf502b34c Add generic hash_value functions for ranges to hash.hpp, remove those from extensions.hpp 2021-10-16 22:12:31 +03:00
Peter Dimov
b2e3beea3f Remove unnecessary warning suppression 2021-10-16 21:02:28 +03:00
Peter Dimov
d308495a67 Add detail/is_unordered_range.hpp 2021-10-16 21:01:07 +03:00
Peter Dimov
00c837d523 Add detail/is_contiguous_range.hpp 2021-10-16 20:54:51 +03:00
Peter Dimov
415f2fafe2 Add detail/is_range.hpp 2021-10-16 20:44:32 +03:00
Peter Dimov
9bbedce029 Add missing include 2021-10-16 18:46:00 +03:00
Peter Dimov
2fc970b6ae Simplify hash_value for integrals 2021-10-16 17:29:02 +03:00
Peter Dimov
4e11c855cb Remove use of <functional> 2021-10-16 16:55:27 +03:00
Peter Dimov
bd379e1a46 Remove VMS workaround 2021-10-16 16:54:08 +03:00
Peter Dimov
b201ff97a8 Use Config macros for detecting C++17 headers 2021-10-16 16:43:11 +03:00
Peter Dimov
e89fe04479 Remove more BOOST_NO_FUNCTION_TEMPLATE_ORDERING workarounds 2021-10-16 16:26:42 +03:00
Peter Dimov
7ce3f759ec Remove __DMC__ workarounds 2021-10-16 16:24:56 +03:00
Peter Dimov
917ac6a88a Remove BOOST_HASH_CHAR_TRAITS 2021-10-16 16:22:33 +03:00
Peter Dimov
9782883434 Remove BOOST_NO_FUNCTION_TEMPLATE_ORDERING workarounds 2021-10-16 16:20:54 +03:00
Peter Dimov
f0ef7b8e84 Remove BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION workarounds 2021-10-16 16:18:02 +03:00
74 changed files with 4459 additions and 2526 deletions

View File

@@ -25,10 +25,10 @@ environment:
TOOLSET: msvc-14.1
CXXSTD: 14,17
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: msvc-14.2
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: clang-win
ADDRMD: 64
CXXSTD: 14,17,latest
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: clang-win
CXXSTD: 14,17,latest

View File

@@ -121,7 +121,7 @@ jobs:
install: clang-14
- toolset: clang
cxxstd: "03,11,14,17,2a"
os: macos-10.15
os: macos-11
runs-on: ${{matrix.os}}
@@ -225,3 +225,162 @@ jobs:
cd ../boost-root
b2 -j3 --verbose-test libs/%LIBRARY%/test//hash_info toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker
posix-cmake-subdir:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $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
run: |
cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test
mkdir __build__ && cd __build__
cmake ..
cmake --build .
ctest --output-on-failure --no-tests=error
posix-cmake-install:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local ..
- name: Install
run: |
cd ../boost-root/__build__
cmake --build . --target install
- name: Use the installed library
run: |
cd ../boost-root/libs/$LIBRARY/test/cmake_install_test && mkdir __build__ && cd __build__
cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
cmake --build .
ctest --output-on-failure --no-tests=error
posix-cmake-test:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON ..
- name: Build tests
run: |
cd ../boost-root/__build__
cmake --build . --target tests
- name: Run tests
run: |
cd ../boost-root/__build__
ctest --output-on-failure --no-tests=error

View File

@@ -1,8 +1,10 @@
# Copyright 2018 Mike Dev
# Generated by `boostdep --cmake container_hash`
# Copyright 2020, 2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
# https://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.5...3.20)
project(boost_container_hash VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
add_library(boost_container_hash INTERFACE)
@@ -11,12 +13,13 @@ add_library(Boost::container_hash ALIAS boost_container_hash)
target_include_directories(boost_container_hash INTERFACE include)
target_link_libraries(boost_container_hash
INTERFACE
Boost::assert
Boost::config
Boost::core
Boost::detail
Boost::integer
Boost::static_assert
Boost::type_traits
INTERFACE
Boost::config
Boost::type_traits
)
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)
endif()

101
benchmark/char_seq.cpp Normal file
View File

@@ -0,0 +1,101 @@
// Copyright 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#define _CRT_SECURE_NO_WARNINGS
#include <boost/container_hash/hash.hpp>
#include <boost/core/detail/splitmix64.hpp>
#include <boost/core/type_name.hpp>
#include <boost/config.hpp>
#include <cstddef>
#include <cstdio>
#include <cstdint>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <chrono>
// test_hash_speed
template<class T, class V> void test_hash_speed( int N, V const& v )
{
std::vector<T> w;
w.reserve( N );
for( int i = 0; i < N; ++i )
{
w.emplace_back( v[i].begin(), v[i].end() );
}
typedef std::chrono::steady_clock clock_type;
clock_type::time_point t1 = clock_type::now();
std::size_t q = 0;
boost::hash<T> const h;
for( int i = 0; i < N; ++i )
{
q += h( w[i] );
}
clock_type::time_point t2 = clock_type::now();
long long ms1 = std::chrono::duration_cast<std::chrono::milliseconds>( t2 - t1 ).count();
std::string type = boost::core::type_name<T>();
#if defined( _MSC_VER )
std::printf( "%25s : q=%20Iu, %lld ms\n", type.c_str(), q, ms1 );
#else
std::printf( "%25s : q=%20zu, %lld ms\n", type.c_str(), q, ms1 );
#endif
}
int main()
{
int const N = 1048576 * 8;
std::vector<std::string> v;
{
v.reserve( N );
boost::detail::splitmix64 rnd;
for( int i = 0; i < N; ++i )
{
char buffer[ 64 ];
unsigned long long k = rnd();
if( k & 1 )
{
sprintf( buffer, "prefix_%llu_suffix", k );
}
else
{
sprintf( buffer, "{%u}", static_cast<unsigned>( k ) );
}
v.push_back( buffer );
}
}
std::puts( "Char sequence hashing test:\n" );
test_hash_speed< std::string >( N, v );
test_hash_speed< std::vector<char> >( N, v );
test_hash_speed< std::deque<char> >( N, v );
test_hash_speed< std::list<char> >( N, v );
std::puts( "" );
}

389
benchmark/unordered.cpp Normal file
View File

@@ -0,0 +1,389 @@
// Copyright 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#define _CRT_SECURE_NO_WARNINGS
#include <boost/container_hash/hash.hpp>
#include <boost/unordered_set.hpp>
#include <boost/core/detail/splitmix64.hpp>
#include <boost/core/type_name.hpp>
#include <boost/config.hpp>
#include <cstddef>
#include <cstdio>
#include <cstdint>
#include <string>
#include <vector>
#include <chrono>
#include <functional>
// mul31_hash
class mul31_hash
{
public:
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_unrolled_hash
template<int Bits> struct mul31_unrolled_hash_impl;
template<> struct mul31_unrolled_hash_impl<32>
{
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
{
char const * p = st.data();
std::size_t n = st.size();
std::size_t h = 0x811C9DC5u;
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;
}
};
template<> struct mul31_unrolled_hash_impl<64>
{
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
{
char const * p = st.data();
std::size_t n = st.size();
std::size_t h = 0xCBF29CE484222325ull;
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 h;
}
};
struct mul31_unrolled_hash: mul31_unrolled_hash_impl< std::numeric_limits<std::size_t>::digits > {};
// fnv1a_hash
template<int Bits> struct fnv1a_hash_impl;
template<> struct fnv1a_hash_impl<32>
{
std::size_t operator()( std::string const& s ) const
{
std::size_t h = 0x811C9DC5u;
char const * first = s.data();
char const * last = first + s.size();
for( ; first != last; ++first )
{
h ^= static_cast<unsigned char>( *first );
h *= 0x01000193ul;
}
return h;
}
};
template<> struct fnv1a_hash_impl<64>
{
std::size_t operator()( std::string const& s ) const
{
std::size_t h = 0xCBF29CE484222325ull;
char const * first = s.data();
char const * last = first + s.size();
for( ; first != last; ++first )
{
h ^= static_cast<unsigned char>( *first );
h *= 0x00000100000001B3ull;
}
return h;
}
};
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits > {};
// old_boost_hash
class old_boost_hash
{
public:
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
{
char const * p = st.data();
std::size_t n = st.size();
std::size_t h = 0;
for( std::size_t i = 0; i < n; ++i )
{
h ^= static_cast<unsigned char>( p[i] ) + 0x9e3779b9 + ( h << 6 ) + ( h >> 2 );
}
return h;
}
};
// test_hash_speed
template<class H, class V> void test_hash_speed( int N, V const& v )
{
typedef std::chrono::steady_clock clock_type;
clock_type::time_point t1 = clock_type::now();
std::size_t q = 0;
H const h;
for( int i = 0; i < N; ++i )
{
q += h( v[i] );
}
clock_type::time_point t2 = clock_type::now();
long long ms1 = std::chrono::duration_cast<std::chrono::milliseconds>( t2 - t1 ).count();
std::string hash = boost::core::type_name<H>();
#if defined( _MSC_VER )
std::printf( "%25s : q=%20Iu, %lld ms\n", hash.c_str(), q, ms1 );
#else
std::printf( "%25s : q=%20zu, %lld ms\n", hash.c_str(), q, ms1 );
#endif
}
// test_hash_collision
template<class H, class V> void test_hash_collision( int N, V const& v, std::size_t n )
{
boost::unordered_set<std::size_t> s;
H const h;
for( int i = 0; i < N; ++i )
{
s.insert( h( v[i] ) );
}
std::string hash = boost::core::type_name<H>();
#if defined( _MSC_VER )
std::printf( "%25s : c=%Iu\n", hash.c_str(), n - s.size() );
#else
std::printf( "%25s : c=%zu\n", hash.c_str(), n - s.size() );
#endif
}
// test_container_speed
template<class V, class S> void test4( int N, V const& v, char const * hash, S s )
{
typedef std::chrono::steady_clock clock_type;
clock_type::time_point t1 = clock_type::now();
for( int i = 0; i < N; ++i )
{
s.insert( v[ i * 16 ] );
}
clock_type::time_point t2 = clock_type::now();
std::size_t q = 0;
for( int i = 0; i < 16 * N; ++i )
{
q += s.count( v[ i ] );
}
clock_type::time_point t3 = clock_type::now();
long long ms1 = std::chrono::duration_cast<std::chrono::milliseconds>( t2 - t1 ).count();
long long ms2 = std::chrono::duration_cast<std::chrono::milliseconds>( t3 - t2 ).count();
std::size_t n = s.bucket_count();
std::size_t m = 0;
std::size_t c = 0;
for( std::size_t i = 0; i < n; ++i )
{
std::size_t k = s.bucket_size( i );
if( k > 1 )
{
c += k - 1;
}
if( k > m )
{
m = k;
}
}
#if defined( _MSC_VER )
std::printf( "%25s : n=%Iu, m=%Iu, c=%Iu, q=%Iu, %lld + %lld ms\n", hash, n, m, c, q, ms1, ms2 );
#else
std::printf( "%25s : n=%zu, m=%zu, c=%zu, q=%zu, %lld + %lld ms\n", hash, n, m, c, q, ms1, ms2 );
#endif
}
template<class K, class H, class V> void test_container_speed( int N, V const& v )
{
boost::unordered_set<K, H> s( 0 );
test4( N, v, boost::core::type_name<H>().c_str(), s );
}
int main()
{
int const N = 1048576 / 2; // 1048576 is too much for 32 bit
std::vector<std::string> v;
{
v.reserve( N * 16 );
boost::detail::splitmix64 rnd;
for( int i = 0; i < 16 * N; ++i )
{
char buffer[ 64 ];
unsigned long long k = rnd();
if( k & 1 )
{
sprintf( buffer, "prefix_%llu_suffix", k );
}
else
{
sprintf( buffer, "{%u}", static_cast<unsigned>( k ) );
}
v.push_back( buffer );
}
}
std::puts( "Hash speed test:\n" );
test_hash_speed<mul31_hash>( N * 16, v );
test_hash_speed<mul31_unrolled_hash>( N * 16, v );
test_hash_speed<fnv1a_hash>( N * 16, v );
test_hash_speed<old_boost_hash>( N * 16, v );
test_hash_speed<boost::hash<std::string> >( N * 16, v );
test_hash_speed<std::hash<std::string> >( N * 16, v );
std::puts( "" );
std::puts( "Hash collision test:\n" );
{
std::size_t n = 0;
{
boost::unordered_set<std::string> s;
for( int i = 0; i < N * 16; ++i )
{
s.insert( v[i] );
}
n = s.size();
}
test_hash_collision<mul31_hash>( N * 16, v, n );
test_hash_collision<mul31_unrolled_hash>( N * 16, v, n );
test_hash_collision<fnv1a_hash>( N * 16, v, n );
test_hash_collision<old_boost_hash>( N * 16, v, n );
test_hash_collision<boost::hash<std::string> >( N * 16, v, n );
test_hash_collision<std::hash<std::string> >( N * 16, v, n );
}
std::puts( "" );
typedef std::string K;
std::puts( "Container speed test:\n" );
test_container_speed<K, mul31_hash>( N, v );
test_container_speed<K, mul31_unrolled_hash>( N, v );
test_container_speed<K, fnv1a_hash>( N, v );
test_container_speed<K, old_boost_hash>( N, v );
test_container_speed<K, boost::hash<std::string> >( N, v );
test_container_speed<K, std::hash<std::string> >( N, v );
std::puts( "" );
}

View File

@@ -1,6 +1,13 @@
////
Copyright 2022 Christian Mazakas
Copyright 2022 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
= Boost.ContainerHash
:toc: left
:toclevels: 2
:toclevels: 3
:idprefix:
:docinfo: private-footer
:source-highlighter: rouge
@@ -12,13 +19,11 @@
include::hash/intro.adoc[]
include::hash/tutorial.adoc[]
include::hash/custom.adoc[]
include::hash/user.adoc[]
include::hash/combine.adoc[]
include::hash/portability.adoc[]
include::hash/disable.adoc[]
include::hash/changes.adoc[]
include::hash/reference.adoc[]
include::hash/rationale.adoc[]
include::hash/ref.adoc[]
include::hash/links.adoc[]
include::hash/thanks.adoc[]
include::hash/copyright.adoc[]
include::hash/changes.adoc[]
include::hash/copyright.adoc[]

View File

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

View File

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

View File

@@ -1,10 +1,18 @@
////
Copyright 2005-2008 Daniel James
Copyright 2022 Christian Mazakas
Copyright 2022 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#copyright]
= Copyright and License
:idprefix:
:idprefix: copyright_
This documentation is
*Daniel James*
* Copyright 2005-2008 Daniel James
* Copyright 2022 Peter Dimov
Copyright (C) 2005-2008 Daniel James
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
and is distributed under the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].

View File

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

View File

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

View File

@@ -1,12 +1,99 @@
////
Copyright 2005-2008 Daniel James
Copyright 2022 Christian Mazakas
Copyright 2022 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#links]
= Links
:idprefix: links_
*A Proposal to Add Hash Tables to the Standard Library* http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1456.html The hash table proposal explains much of the design. The hash function object is discussed in Section D.
*A Proposal to Add Hash Tables to the Standard Library* +
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1456.html
*The C++ Standard Library Technical Report.* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf Contains the hash function specification in section 6.3.2.
The hash table proposal explains much of the design. The hash function object is discussed in Section D.
*Library Extension Technical Report Issues List.* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf The library implements the extension described in Issue 6.18, pages 63-67.
---
*Methods for Identifying Versioned and Plagiarised Documents* Timothy C. Hoad, Justin Zobel http://www.cs.rmit.edu.au/~jz/fulltext/jasist-tch.pdf Contains the hash function that `boost::hash_combine` is based on.
*The {cpp} Standard Library Technical Report* +
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf
Contains the hash function specification in section 6.3.2.
---
*Library Extension Technical Report Issues List* +
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf
The library implements the extension described in Issue 6.18, pages 63-67.
---
*Methods for Identifying Versioned and Plagiarised Documents* +
_Timothy C. Hoad, Justin Zobel_ +
http://www.cs.rmit.edu.au/~jz/fulltext/jasist-tch.pdf
Contains the hash function that the initial implementation of `boost::hash_combine` was based on.
---
*MurmurHash3 hash function source* +
_Austin Appleby_ +
https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash3.cpp#L65-L90
Austin Appleby's 32 and 64 bit finalization mixing functions that
introduced the "xmxmx" general form of a high quality bijective
transformation that approximates a random permutation.
---
*SMHasher hash function test suite* +
_Austin Appleby_ +
https://github.com/aappleby/smhasher
Contains a battery of tests for evaluating hash functions.
---
*Better Bit Mixing - Improving on MurmurHash3's 64-bit Finalizer* +
_David Stafford_ +
https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
Describes the so-called "variant 13" mixing function, an improvement
over `fmix64` from MurmurHash3, made famous by its adoption by the `splitmix64`
http://xorshift.di.unimi.it/splitmix64.c[random number generator].
---
*Stronger, better, morer, Moremur; a better Murmur3-type mixer* +
_Pelle Evensen_ +
https://mostlymangling.blogspot.com/2019/12/stronger-better-morer-moremur-better.html
Describes Moremur, an improvement over MurmurHash3 fmix64 and Stafford "variant 13".
---
*Improved mx3 and the RRC test* +
_John Maiga_ +
http://jonkagstrom.com/mx3/mx3_rev2.html
Contains another improvement over MurmurHash3 fmix64 and "variant 13".
---
*Prospecting for Hash Functions* +
_Chris Wellons_ +
https://nullprogram.com/blog/2018/07/31/
Describes https://github.com/skeeto/hash-prospector[Hash Prospector],
a utility for discovering and evaluating mixing functions.
---
*New best known functions* +
_"TheIronBorn"_ +
https://github.com/skeeto/hash-prospector/issues/19
Describes a good 32 bit mixing function.

View File

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

View File

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

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

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

View File

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

View File

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

View File

@@ -6,4 +6,4 @@
run books.cpp ;
run point.cpp ;
run portable.cpp ;
run template.cpp ;
run template.cpp : : : <toolset>msvc-8.0:<build>no ;

View File

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

View File

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

View File

@@ -3,9 +3,14 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Force use of assert.
#if defined(NDEBUG)
#undef NDEBUG
#endif
#include "template.hpp"
#include <cassert>
#include <boost/unordered_set.hpp>
#include <cassert>
int main()
{

View File

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

View File

@@ -1,336 +0,0 @@
// Copyright 2005-2009 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_FUNCTIONAL_HASH_DETAIL_FLOAT_FUNCTIONS_HPP)
#define BOOST_FUNCTIONAL_HASH_DETAIL_FLOAT_FUNCTIONS_HPP
#include <boost/config.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif
#include <boost/config/no_tr1/cmath.hpp>
// Set BOOST_HASH_CONFORMANT_FLOATS to 1 for libraries known to have
// sufficiently good floating point support to not require any
// workarounds.
//
// When set to 0, the library tries to automatically
// use the best available implementation. This normally works well, but
// breaks when ambiguities are created by odd namespacing of the functions.
//
// Note that if this is set to 0, the library should still take full
// advantage of the platform's floating point support.
#if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
# define BOOST_HASH_CONFORMANT_FLOATS 0
#elif defined(__LIBCOMO__)
# define BOOST_HASH_CONFORMANT_FLOATS 0
#elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER)
// Rogue Wave library:
# define BOOST_HASH_CONFORMANT_FLOATS 0
#elif defined(_LIBCPP_VERSION)
// libc++
# define BOOST_HASH_CONFORMANT_FLOATS 1
#elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
// GNU libstdc++ 3
# if defined(__GNUC__) && __GNUC__ >= 4
# define BOOST_HASH_CONFORMANT_FLOATS 1
# else
# define BOOST_HASH_CONFORMANT_FLOATS 0
# endif
#elif defined(__STL_CONFIG_H)
// generic SGI STL
# define BOOST_HASH_CONFORMANT_FLOATS 0
#elif defined(__MSL_CPP__)
// MSL standard lib:
# define BOOST_HASH_CONFORMANT_FLOATS 0
#elif defined(__IBMCPP__)
// VACPP std lib (probably conformant for much earlier version).
# if __IBMCPP__ >= 1210
# define BOOST_HASH_CONFORMANT_FLOATS 1
# else
# define BOOST_HASH_CONFORMANT_FLOATS 0
# endif
#elif defined(MSIPL_COMPILE_H)
// Modena C++ standard library
# define BOOST_HASH_CONFORMANT_FLOATS 0
#elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER)
// Dinkumware Library (this has to appear after any possible replacement libraries):
# if _CPPLIB_VER >= 405
# define BOOST_HASH_CONFORMANT_FLOATS 1
# else
# define BOOST_HASH_CONFORMANT_FLOATS 0
# endif
#else
# define BOOST_HASH_CONFORMANT_FLOATS 0
#endif
#if BOOST_HASH_CONFORMANT_FLOATS
// The standard library is known to be compliant, so don't use the
// configuration mechanism.
namespace boost {
namespace hash_detail {
template <typename Float>
struct call_ldexp {
typedef Float float_type;
inline Float operator()(Float x, int y) const {
return std::ldexp(x, y);
}
};
template <typename Float>
struct call_frexp {
typedef Float float_type;
inline Float operator()(Float x, int* y) const {
return std::frexp(x, y);
}
};
template <typename Float>
struct select_hash_type
{
typedef Float type;
};
}
}
#else // BOOST_HASH_CONFORMANT_FLOATS == 0
// The C++ standard requires that the C float functions are overloarded
// for float, double and long double in the std namespace, but some of the older
// library implementations don't support this. On some that don't, the C99
// float functions (frexpf, frexpl, etc.) are available.
//
// The following tries to automatically detect which are available.
namespace boost {
namespace hash_detail {
// Returned by dummy versions of the float functions.
struct not_found {
// Implicitly convertible to float and long double in order to avoid
// a compile error when the dummy float functions are used.
inline operator float() const { return 0; }
inline operator long double() const { return 0; }
};
// A type for detecting the return type of functions.
template <typename T> struct is;
template <> struct is<float> { char x[10]; };
template <> struct is<double> { char x[20]; };
template <> struct is<long double> { char x[30]; };
template <> struct is<boost::hash_detail::not_found> { char x[40]; };
// Used to convert the return type of a function to a type for sizeof.
template <typename T> is<T> float_type(T);
// call_ldexp
//
// This will get specialized for float and long double
template <typename Float> struct call_ldexp
{
typedef double float_type;
inline double operator()(double a, int b) const
{
using namespace std;
return ldexp(a, b);
}
};
// call_frexp
//
// This will get specialized for float and long double
template <typename Float> struct call_frexp
{
typedef double float_type;
inline double operator()(double a, int* b) const
{
using namespace std;
return frexp(a, b);
}
};
}
}
// A namespace for dummy functions to detect when the actual function we want
// isn't available. ldexpl, ldexpf etc. might be added tby the macros below.
//
// AFAICT these have to be outside of the boost namespace, as if they're in
// the boost namespace they'll always be preferable to any other function
// (since the arguments are built in types, ADL can't be used).
namespace boost_hash_detect_float_functions {
template <class Float> boost::hash_detail::not_found ldexp(Float, int);
template <class Float> boost::hash_detail::not_found frexp(Float, int*);
}
// Macros for generating specializations of call_ldexp and call_frexp.
//
// check_cpp and check_c99 check if the C++ or C99 functions are available.
//
// Then the call_* functions select an appropriate implementation.
//
// I used c99_func in a few places just to get a unique name.
//
// Important: when using 'using namespace' at namespace level, include as
// little as possible in that namespace, as Visual C++ has an odd bug which
// can cause the namespace to be imported at the global level. This seems to
// happen mainly when there's a template in the same namesapce.
#define BOOST_HASH_CALL_FLOAT_FUNC(cpp_func, c99_func, type1, type2) \
namespace boost_hash_detect_float_functions { \
template <class Float> \
boost::hash_detail::not_found c99_func(Float, type2); \
} \
\
namespace boost { \
namespace hash_detail { \
namespace c99_func##_detect { \
using namespace std; \
using namespace boost_hash_detect_float_functions; \
\
struct check { \
static type1 x; \
static type2 y; \
BOOST_STATIC_CONSTANT(bool, cpp = \
sizeof(float_type(cpp_func(x,y))) \
== sizeof(is<type1>)); \
BOOST_STATIC_CONSTANT(bool, c99 = \
sizeof(float_type(c99_func(x,y))) \
== sizeof(is<type1>)); \
}; \
} \
\
template <bool x> \
struct call_c99_##c99_func : \
boost::hash_detail::call_##cpp_func<double> {}; \
\
template <> \
struct call_c99_##c99_func<true> { \
typedef type1 float_type; \
\
template <typename T> \
inline type1 operator()(type1 a, T b) const \
{ \
using namespace std; \
return c99_func(a, b); \
} \
}; \
\
template <bool x> \
struct call_cpp_##c99_func : \
call_c99_##c99_func< \
::boost::hash_detail::c99_func##_detect::check::c99 \
> {}; \
\
template <> \
struct call_cpp_##c99_func<true> { \
typedef type1 float_type; \
\
template <typename T> \
inline type1 operator()(type1 a, T b) const \
{ \
using namespace std; \
return cpp_func(a, b); \
} \
}; \
\
template <> \
struct call_##cpp_func<type1> : \
call_cpp_##c99_func< \
::boost::hash_detail::c99_func##_detect::check::cpp \
> {}; \
} \
}
#define BOOST_HASH_CALL_FLOAT_MACRO(cpp_func, c99_func, type1, type2) \
namespace boost { \
namespace hash_detail { \
\
template <> \
struct call_##cpp_func<type1> { \
typedef type1 float_type; \
inline type1 operator()(type1 x, type2 y) const { \
return c99_func(x, y); \
} \
}; \
} \
}
#if defined(ldexpf)
BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpf, float, int)
#else
BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpf, float, int)
#endif
#if defined(ldexpl)
BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpl, long double, int)
#else
BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpl, long double, int)
#endif
#if defined(frexpf)
BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpf, float, int*)
#else
BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpf, float, int*)
#endif
#if defined(frexpl)
BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpl, long double, int*)
#else
BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpl, long double, int*)
#endif
#undef BOOST_HASH_CALL_FLOAT_MACRO
#undef BOOST_HASH_CALL_FLOAT_FUNC
namespace boost
{
namespace hash_detail
{
template <typename Float1, typename Float2>
struct select_hash_type_impl {
typedef double type;
};
template <>
struct select_hash_type_impl<float, float> {
typedef float type;
};
template <>
struct select_hash_type_impl<long double, long double> {
typedef long double type;
};
// select_hash_type
//
// If there is support for a particular floating point type, use that
// otherwise use double (there's always support for double).
template <typename Float>
struct select_hash_type : select_hash_type_impl<
BOOST_DEDUCED_TYPENAME call_ldexp<Float>::float_type,
BOOST_DEDUCED_TYPENAME call_frexp<Float>::float_type
> {};
}
}
#endif // BOOST_HASH_CONFORMANT_FLOATS
#endif

View File

@@ -1,271 +0,0 @@
// Copyright 2005-2012 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_FUNCTIONAL_HASH_DETAIL_HASH_FLOAT_HEADER)
#define BOOST_FUNCTIONAL_HASH_DETAIL_HASH_FLOAT_HEADER
#include <boost/config.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif
#include <boost/container_hash/detail/float_functions.hpp>
#include <boost/container_hash/detail/limits.hpp>
#include <boost/core/enable_if.hpp>
#include <boost/integer/static_log2.hpp>
#include <boost/cstdint.hpp>
#include <boost/assert.hpp>
#include <boost/limits.hpp>
#include <cstring>
#if defined(BOOST_MSVC)
#pragma warning(push)
#if BOOST_MSVC >= 1400
#pragma warning(disable:6294) // Ill-defined for-loop: initial condition does
// not satisfy test. Loop body not executed
#endif
#endif
// Can we use fpclassify?
// STLport
#if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
#define BOOST_HASH_USE_FPCLASSIFY 0
// GNU libstdc++ 3
#elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
# if (defined(__USE_ISOC99) || defined(_GLIBCXX_USE_C99_MATH)) && \
!(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
# define BOOST_HASH_USE_FPCLASSIFY 1
# else
# define BOOST_HASH_USE_FPCLASSIFY 0
# endif
// Everything else
#else
# define BOOST_HASH_USE_FPCLASSIFY 0
#endif
namespace boost
{
namespace hash_detail
{
inline void hash_float_combine(std::size_t& seed, std::size_t value)
{
seed ^= value + (seed<<6) + (seed>>2);
}
////////////////////////////////////////////////////////////////////////
// Binary hash function
//
// Only used for floats with known iec559 floats, and certain values in
// numeric_limits
inline std::size_t hash_binary(char* ptr, std::size_t length)
{
std::size_t seed = 0;
if (length >= sizeof(std::size_t)) {
std::memcpy(&seed, ptr, sizeof(std::size_t));
length -= sizeof(std::size_t);
ptr += sizeof(std::size_t);
while(length >= sizeof(std::size_t)) {
std::size_t buffer = 0;
std::memcpy(&buffer, ptr, sizeof(std::size_t));
hash_float_combine(seed, buffer);
length -= sizeof(std::size_t);
ptr += sizeof(std::size_t);
}
}
if (length > 0) {
std::size_t buffer = 0;
std::memcpy(&buffer, ptr, length);
hash_float_combine(seed, buffer);
}
return seed;
}
template <typename Float, unsigned digits, unsigned max_exponent>
struct enable_binary_hash
{
BOOST_STATIC_CONSTANT(bool, value =
std::numeric_limits<Float>::is_iec559 &&
std::numeric_limits<Float>::digits == digits &&
std::numeric_limits<Float>::radix == 2 &&
std::numeric_limits<Float>::max_exponent == max_exponent);
};
template <typename Float>
inline std::size_t float_hash_impl(Float v,
BOOST_DEDUCED_TYPENAME boost::enable_if_c<
enable_binary_hash<Float, 24, 128>::value,
std::size_t>::type)
{
return hash_binary((char*) &v, 4);
}
template <typename Float>
inline std::size_t float_hash_impl(Float v,
BOOST_DEDUCED_TYPENAME boost::enable_if_c<
enable_binary_hash<Float, 53, 1024>::value,
std::size_t>::type)
{
return hash_binary((char*) &v, 8);
}
template <typename Float>
inline std::size_t float_hash_impl(Float v,
BOOST_DEDUCED_TYPENAME boost::enable_if_c<
enable_binary_hash<Float, 64, 16384>::value,
std::size_t>::type)
{
return hash_binary((char*) &v, 10);
}
template <typename Float>
inline std::size_t float_hash_impl(Float v,
BOOST_DEDUCED_TYPENAME boost::enable_if_c<
enable_binary_hash<Float, 113, 16384>::value,
std::size_t>::type)
{
return hash_binary((char*) &v, 16);
}
////////////////////////////////////////////////////////////////////////
// Portable hash function
//
// Used as a fallback when the binary hash function isn't supported.
template <class T>
inline std::size_t float_hash_impl2(T v)
{
boost::hash_detail::call_frexp<T> frexp;
boost::hash_detail::call_ldexp<T> ldexp;
int exp = 0;
v = frexp(v, &exp);
// A postive value is easier to hash, so combine the
// sign with the exponent and use the absolute value.
if(v < 0) {
v = -v;
exp += limits<T>::max_exponent -
limits<T>::min_exponent;
}
v = ldexp(v, limits<std::size_t>::digits);
std::size_t seed = static_cast<std::size_t>(v);
v -= static_cast<T>(seed);
// ceiling(digits(T) * log2(radix(T))/ digits(size_t)) - 1;
std::size_t const length
= (limits<T>::digits *
boost::static_log2<limits<T>::radix>::value
+ limits<std::size_t>::digits - 1)
/ limits<std::size_t>::digits;
for(std::size_t i = 0; i != length; ++i)
{
v = ldexp(v, limits<std::size_t>::digits);
std::size_t part = static_cast<std::size_t>(v);
v -= static_cast<T>(part);
hash_float_combine(seed, part);
}
hash_float_combine(seed, static_cast<std::size_t>(exp));
return seed;
}
#if !defined(BOOST_HASH_DETAIL_TEST_WITHOUT_GENERIC)
template <class T>
inline std::size_t float_hash_impl(T v, ...)
{
typedef BOOST_DEDUCED_TYPENAME select_hash_type<T>::type type;
return float_hash_impl2(static_cast<type>(v));
}
#endif
}
}
#if BOOST_HASH_USE_FPCLASSIFY
#include <boost/config/no_tr1/cmath.hpp>
namespace boost
{
namespace hash_detail
{
template <class T>
inline std::size_t float_hash_value(T v)
{
#if defined(fpclassify)
switch (fpclassify(v))
#elif BOOST_HASH_CONFORMANT_FLOATS
switch (std::fpclassify(v))
#else
using namespace std;
switch (fpclassify(v))
#endif
{
case FP_ZERO:
return 0;
case FP_INFINITE:
return (std::size_t)(v > 0 ? -1 : -2);
case FP_NAN:
return (std::size_t)(-3);
case FP_NORMAL:
case FP_SUBNORMAL:
return float_hash_impl(v, 0);
default:
BOOST_ASSERT(0);
return 0;
}
}
}
}
#else // !BOOST_HASH_USE_FPCLASSIFY
namespace boost
{
namespace hash_detail
{
template <class T>
inline bool is_zero(T v)
{
#if !defined(__GNUC__) && !defined(__clang__)
return v == 0;
#else
// GCC's '-Wfloat-equal' will complain about comparing
// v to 0, but because it disables warnings for system
// headers it won't complain if you use std::equal_to to
// compare with 0. Resulting in this silliness:
return std::equal_to<T>()(v, 0);
#endif
}
template <class T>
inline std::size_t float_hash_value(T v)
{
return boost::hash_detail::is_zero(v) ? 0 : float_hash_impl(v, 0);
}
}
}
#endif // BOOST_HASH_USE_FPCLASSIFY
#undef BOOST_HASH_USE_FPCLASSIFY
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
#endif

View File

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

View File

@@ -0,0 +1,165 @@
// Copyright 2022 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_DETAIL_HASH_RANGE_HPP
#define BOOST_HASH_DETAIL_HASH_RANGE_HPP
#include <boost/container_hash/hash_fwd.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/type_traits/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/cstdint.hpp>
#include <cstddef>
#include <climits>
#include <iterator>
namespace boost
{
namespace hash_detail
{
template<class T> struct is_char_type: public boost::false_type {};
#if CHAR_BIT == 8
template<> struct is_char_type<char>: public boost::true_type {};
template<> struct is_char_type<signed char>: public boost::true_type {};
template<> struct is_char_type<unsigned char>: public boost::true_type {};
#endif
template<class It>
inline typename boost::enable_if_<
!is_char_type<typename std::iterator_traits<It>::value_type>::value,
std::size_t >::type
hash_range( std::size_t seed, It first, It last )
{
for( ; first != last; ++first )
{
hash_combine<typename std::iterator_traits<It>::value_type>( seed, *first );
}
return seed;
}
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 )
{
std::size_t n = static_cast<std::size_t>( last - first );
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>( first[0] ) ) |
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[1] ) ) << 8 |
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[2] ) ) << 16 |
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[3] ) ) << 24;
hash_combine( seed, w );
}
{
// add a trailing suffix byte of 0x01 because otherwise sequences of
// trailing zeroes are indistinguishable from end of string
boost::uint32_t w = 0x01u;
switch( n )
{
case 1:
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;
}
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 )
{
for( ;; )
{
boost::uint32_t w = 0;
if( first == last )
{
hash_combine( seed, w | 0x01u );
return seed;
}
w |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) );
++first;
if( first == last )
{
hash_combine( seed, w | 0x0100u );
return seed;
}
w |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) ) << 8;
++first;
if( first == last )
{
hash_combine( seed, w | 0x010000u );
return seed;
}
w |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) ) << 16;
++first;
if( first == last )
{
hash_combine( seed, w | 0x01000000u );
return seed;
}
w |= static_cast<boost::uint32_t>( static_cast<unsigned char>( *first ) ) << 24;
++first;
hash_combine( seed, w );
}
}
} // namespace hash_detail
} // namespace boost
#endif // #ifndef BOOST_HASH_DETAIL_HASH_RANGE_HPP

View File

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

@@ -1,28 +1,11 @@
// Copyright 2005-2009 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// On some platforms std::limits gives incorrect values for long double.
// This tries to work around them.
#if !defined(BOOST_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER)
#ifndef BOOST_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER
#define BOOST_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER
#include <boost/config.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif
#include <boost/limits.hpp>
// On OpenBSD, numeric_limits is not reliable for long doubles, but
// the macros defined in <float.h> are and support long double when STLport
// doesn't.
#if defined(__OpenBSD__) || defined(_STLP_NO_LONG_DOUBLE)
#include <float.h>
#endif
#include <limits>
namespace boost
{
@@ -30,33 +13,7 @@ namespace boost
{
template <class T>
struct limits : std::numeric_limits<T> {};
#if defined(__OpenBSD__) || defined(_STLP_NO_LONG_DOUBLE)
template <>
struct limits<long double>
: std::numeric_limits<long double>
{
static long double epsilon() {
return LDBL_EPSILON;
}
static long double (max)() {
return LDBL_MAX;
}
static long double (min)() {
return LDBL_MIN;
}
BOOST_STATIC_CONSTANT(int, digits = LDBL_MANT_DIG);
BOOST_STATIC_CONSTANT(int, max_exponent = LDBL_MAX_EXP);
BOOST_STATIC_CONSTANT(int, min_exponent = LDBL_MIN_EXP);
#if defined(_STLP_NO_LONG_DOUBLE)
BOOST_STATIC_CONSTANT(int, radix = FLT_RADIX);
#endif
};
#endif // __OpenBSD__
}
}
#endif
#endif // #ifndef BOOST_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER

View File

@@ -1,361 +1,10 @@
// Copyright 2005-2009 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Based on Peter Dimov's proposal
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
// issue 6.18.
// This implements the extensions to the standard.
// It's undocumented, so you shouldn't use it....
#if !defined(BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP)
#ifndef BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP
#define BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP
#include <boost/config.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/detail/container_fwd.hpp>
#include <boost/core/enable_if.hpp>
#include <boost/static_assert.hpp>
#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
# include <array>
#endif
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
# include <tuple>
#endif
#include <memory>
#if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
#include <boost/type_traits/is_array.hpp>
#endif
namespace boost
{
template <class A, class B>
std::size_t hash_value(std::pair<A, B> const&);
template <class T, class A>
std::size_t hash_value(std::vector<T, A> const&);
template <class T, class A>
std::size_t hash_value(std::list<T, A> const& v);
template <class T, class A>
std::size_t hash_value(std::deque<T, A> const& v);
template <class K, class C, class A>
std::size_t hash_value(std::set<K, C, A> const& v);
template <class K, class C, class A>
std::size_t hash_value(std::multiset<K, C, A> const& v);
template <class K, class T, class C, class A>
std::size_t hash_value(std::map<K, T, C, A> const& v);
template <class K, class T, class C, class A>
std::size_t hash_value(std::multimap<K, T, C, A> const& v);
template <class T>
std::size_t hash_value(std::complex<T> const&);
template <class A, class B>
std::size_t hash_value(std::pair<A, B> const& v)
{
std::size_t seed = 0;
boost::hash_combine(seed, v.first);
boost::hash_combine(seed, v.second);
return seed;
}
template <class T, class A>
std::size_t hash_value(std::vector<T, A> const& v)
{
return boost::hash_range(v.begin(), v.end());
}
template <class T, class A>
std::size_t hash_value(std::list<T, A> const& v)
{
return boost::hash_range(v.begin(), v.end());
}
template <class T, class A>
std::size_t hash_value(std::deque<T, A> const& v)
{
return boost::hash_range(v.begin(), v.end());
}
template <class K, class C, class A>
std::size_t hash_value(std::set<K, C, A> const& v)
{
return boost::hash_range(v.begin(), v.end());
}
template <class K, class C, class A>
std::size_t hash_value(std::multiset<K, C, A> const& v)
{
return boost::hash_range(v.begin(), v.end());
}
template <class K, class T, class C, class A>
std::size_t hash_value(std::map<K, T, C, A> const& v)
{
return boost::hash_range(v.begin(), v.end());
}
template <class K, class T, class C, class A>
std::size_t hash_value(std::multimap<K, T, C, A> const& v)
{
return boost::hash_range(v.begin(), v.end());
}
template <class T>
std::size_t hash_value(std::complex<T> const& v)
{
boost::hash<T> hasher;
std::size_t seed = hasher(v.imag());
seed ^= hasher(v.real()) + (seed<<6) + (seed>>2);
return seed;
}
#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
template <class T, std::size_t N>
std::size_t hash_value(std::array<T, N> const& v)
{
return boost::hash_range(v.begin(), v.end());
}
#endif
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
namespace hash_detail {
template <std::size_t I, typename T>
inline typename boost::enable_if_c<(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_c<(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;
}
}
#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
#endif
#if !defined(BOOST_NO_CXX11_SMART_PTR)
template <typename T>
inline std::size_t hash_value(std::shared_ptr<T> const& x) {
return boost::hash_value(x.get());
}
template <typename T, typename Deleter>
inline std::size_t hash_value(std::unique_ptr<T, Deleter> const& x) {
return boost::hash_value(x.get());
}
#endif
//
// call_hash_impl
//
// On compilers without function template ordering, this deals with arrays.
#if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
namespace hash_detail
{
template <bool IsArray>
struct call_hash_impl
{
template <class T>
struct inner
{
static std::size_t call(T const& v)
{
using namespace boost;
return hash_value(v);
}
};
};
template <>
struct call_hash_impl<true>
{
template <class Array>
struct inner
{
static std::size_t call(Array const& v)
{
const int size = sizeof(v) / sizeof(*v);
return boost::hash_range(v, v + size);
}
};
};
template <class T>
struct call_hash
: public call_hash_impl<boost::is_array<T>::value>
::BOOST_NESTED_TEMPLATE inner<T>
{
};
}
#endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING
//
// boost::hash
//
#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
template <class T> struct hash
: boost::hash_detail::hash_base<T>
{
#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
std::size_t operator()(T const& val) const
{
return hash_value(val);
}
#else
std::size_t operator()(T const& val) const
{
return hash_detail::call_hash<T>::call(val);
}
#endif
};
#if BOOST_WORKAROUND(__DMC__, <= 0x848)
template <class T, unsigned int n> struct hash<T[n]>
: boost::hash_detail::hash_base<T[n]>
{
std::size_t operator()(const T* val) const
{
return boost::hash_range(val, val+n);
}
};
#endif
#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
// On compilers without partial specialization, boost::hash<T>
// has already been declared to deal with pointers, so just
// need to supply the non-pointer version of hash_impl.
namespace hash_detail
{
template <bool IsPointer>
struct hash_impl;
template <>
struct hash_impl<false>
{
template <class T>
struct inner
: boost::hash_detail::hash_base<T>
{
#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
std::size_t operator()(T const& val) const
{
return hash_value(val);
}
#else
std::size_t operator()(T const& val) const
{
return hash_detail::call_hash<T>::call(val);
}
#endif
};
};
}
#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
}
#endif
#endif // #ifndef BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -1,36 +1,35 @@
// Copyright 2005-2009 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright 2021 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
// Based on Peter Dimov's proposal
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
// issue 6.18.
#if !defined(BOOST_FUNCTIONAL_HASH_FWD_HPP)
#ifndef BOOST_FUNCTIONAL_HASH_FWD_HPP
#define BOOST_FUNCTIONAL_HASH_FWD_HPP
#include <boost/config/workaround.hpp>
#include <cstddef>
#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif
namespace boost
{
template <class T> struct hash;
template <class T> void hash_combine(std::size_t& seed, T const& v);
namespace container_hash
{
template <class It> std::size_t hash_range(It, It);
template <class It> void hash_range(std::size_t&, It, It);
template<class T> struct is_range;
template<class T> struct is_contiguous_range;
template<class T> struct is_unordered_range;
#if BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x551))
template <class T> inline std::size_t hash_range(T*, T*);
template <class T> inline void hash_range(std::size_t&, T*, T*);
#endif
}
} // namespace container_hash
#endif
template<class T> struct hash;
template<class T> void hash_combine( std::size_t& seed, T const& v );
template<class It> void hash_range( std::size_t&, It, It );
template<class It> std::size_t hash_range( It, It );
template<class It> void hash_unordered_range( std::size_t&, It, It );
template<class It> std::size_t hash_unordered_range( It, It );
} // namespace boost
#endif // #ifndef BOOST_FUNCTIONAL_HASH_FWD_HPP

View File

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

View File

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

View File

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

11
test/CMakeLists.txt Normal file
View File

@@ -0,0 +1,11 @@
# Copyright 2018, 2019, 2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
if(HAVE_BOOST_TEST)
boost_test_jamfile(FILE Jamfile.v2 LINK_LIBRARIES Boost::container_hash Boost::core Boost::utility)
endif()

View File

@@ -1,89 +1,103 @@
# Copyright 2005-2012 Daniel James.
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
# Copyright 2022 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
import testing ;
local gcc-flags = -Wunused-parameter -Wconversion -Wsign-conversion -Wfloat-equal -Wshadow -Wno-variadic-macros ;
local clang-flags = $(gcc-flags) -Wno-c99-extensions ;
project hash-tests
: requirements
<warnings>pedantic
<toolset>intel:<warnings>on
<toolset>gcc:<cxxflags>"-Wstrict-aliasing -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
<toolset>darwin:<cxxflags>"-Wstrict-aliasing -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
<toolset>clang:<cxxflags>"-Wstrict-aliasing -Wsign-promo -Wunused-parameter -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow"
<toolset>gcc:<cxxflags>$(gcc-flags)
<toolset>darwin:<cxxflags>$(gcc-flags)
<toolset>clang:<cxxflags>$(clang-flags)
<toolset>msvc:<warnings-as-errors>on
<toolset>gcc:<warnings-as-errors>on
<toolset>clang:<warnings-as-errors>on
;
test-suite container_hash/hash
:
[ run hash_info.cpp : : : <test-info>always_show_run_output ]
[ compile check_float_funcs.cpp ]
[ run hash_fwd_test_1.cpp ]
[ run hash_fwd_test_2.cpp ]
[ run hash_number_test.cpp ]
[ run hash_enum_test.cpp ]
[ run hash_pointer_test.cpp ]
[ run hash_function_pointer_test.cpp ]
[ run hash_float_test.cpp ]
[ run hash_long_double_test.cpp ]
[ run hash_string_test.cpp ]
[ run hash_range_test.cpp ]
[ run hash_custom_test.cpp ]
[ run hash_global_namespace_test.cpp ]
[ run hash_friend_test.cpp ]
[ run hash_built_in_array_test.cpp ]
[ run hash_value_array_test.cpp ]
[ run hash_vector_test.cpp ]
[ run hash_list_test.cpp ]
[ run hash_deque_test.cpp ]
[ run hash_set_test.cpp ]
[ run hash_map_test.cpp ]
[ run hash_complex_test.cpp ]
[ run hash_optional_test.cpp ]
[ run hash_variant_test.cpp ]
[ run hash_type_index_test.cpp ]
[ run hash_system_error_test.cpp ]
[ run hash_std_array_test.cpp ]
[ run hash_std_tuple_test.cpp ]
[ run hash_std_smart_ptr_test.cpp ]
[ run link_test.cpp link_test_2.cpp ]
[ run link_ext_test.cpp link_no_ext_test.cpp ]
[ run extensions_hpp_test.cpp ]
[ compile-fail hash_no_ext_fail_test.cpp ]
[ compile-fail namespace_fail_test.cpp ]
[ run implicit_test.cpp ]
[ run hash_no_ext_macro_1.cpp ]
[ run hash_no_ext_macro_2.cpp ]
;
test-suite container_hash/hash_no_ext
:
[ run hash_number_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_number_test ]
[ run hash_pointer_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_pointer_test ]
[ run hash_function_pointer_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_function_pointer_test ]
[ run hash_float_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_float_test ]
[ run hash_long_double_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_long_double_test ]
[ run hash_string_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_string_test ]
[ run link_test.cpp link_test_2.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_link_test ]
;
# Tests to see if the floating point hash is using the binary hash.
# Not run normally because on some platforms these should fail.
test-suite container_hash/hash_no_generic_float
:
[ run hash_float_test.cpp
: : : <define>BOOST_HASH_DETAIL_TEST_WITHOUT_GENERIC
: hash_float_test_no_generic ]
[ run hash_long_double_test.cpp
: : : <define>BOOST_HASH_DETAIL_TEST_WITHOUT_GENERIC
: hash_long_double_test_no_generic ]
;
explicit container_hash/hash_no_generic_float ;
run hash_info.cpp : : : <test-info>always_show_run_output ;
compile check_float_funcs.cpp ;
run hash_fwd_test_1.cpp ;
run hash_fwd_test_2.cpp ;
run hash_number_test.cpp ;
run hash_enum_test.cpp ;
run hash_pointer_test.cpp ;
run hash_function_pointer_test.cpp ;
run hash_float_test.cpp ;
run hash_long_double_test.cpp ;
run hash_string_test.cpp ;
run hash_range_test.cpp ;
run hash_custom_test.cpp ;
run hash_global_namespace_test.cpp ;
run hash_friend_test.cpp ;
run hash_built_in_array_test.cpp ;
run hash_value_array_test.cpp ;
run hash_vector_test.cpp ;
run hash_list_test.cpp ;
run hash_deque_test.cpp ;
run hash_set_test.cpp ;
run hash_map_test.cpp ;
run hash_complex_test.cpp ;
run hash_optional_test.cpp ;
run hash_variant_test.cpp ;
run hash_type_index_test.cpp ;
run hash_system_error_test.cpp ;
run hash_std_array_test.cpp ;
run hash_std_tuple_test.cpp ;
run hash_std_smart_ptr_test.cpp ;
run link_test.cpp link_test_2.cpp ;
run link_ext_test.cpp link_no_ext_test.cpp ;
run extensions_hpp_test.cpp ;
compile-fail namespace_fail_test.cpp ;
run implicit_test.cpp ;
run hash_no_ext_macro_1.cpp ;
run hash_no_ext_macro_2.cpp ;
build-project ../examples ;
run hash_reference_values.cpp ;
run is_range_test.cpp ;
run is_contiguous_range_test.cpp ;
run is_unordered_range_test.cpp ;
run hash_forward_list_test.cpp ;
run quick.cpp ;
run hash_number_test2.cpp ;
run hash_integral_test.cpp ;
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 is_range_test2.cpp : : : $(fs-path-req) <toolset>msvc-8.0:<build>no ;
run hash_container_test.cpp ;
run hash_vector_test2.cpp ;
run hash_string_test3.cpp ;
run hash_string_test4.cpp ;
run hash_multiset_test.cpp ;
run hash_multimap_test.cpp ;
run hash_unordered_range_test.cpp ;
run hash_unordered_multiset_test.cpp ;
run hash_unordered_multimap_test.cpp ;
run hash_unordered_set_test.cpp ;
run hash_unordered_map_test.cpp ;
run is_range_test3.cpp ;
run is_contiguous_range_test2.cpp ;
run is_unordered_range_test2.cpp ;

View File

@@ -0,0 +1,17 @@
# Copyright 2018, 2019, 2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.5...3.20)
project(cmake_install_test LANGUAGES CXX)
find_package(boost_container_hash REQUIRED)
add_executable(quick ../quick.cpp)
target_link_libraries(quick Boost::container_hash)
enable_testing()
add_test(quick quick)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)

View File

@@ -0,0 +1,21 @@
# Copyright 2018, 2019, 2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.5...3.20)
project(cmake_subdir_test LANGUAGES CXX)
add_subdirectory(../.. boostorg/container_hash)
add_subdirectory(../../../config boostorg/config)
add_subdirectory(../../../type_traits boostorg/type_traits)
add_subdirectory(../../../static_assert boostorg/static_assert)
add_executable(quick ../quick.cpp)
target_link_libraries(quick Boost::container_hash)
enable_testing()
add_test(quick quick)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)

View File

@@ -40,9 +40,10 @@ int main() {}
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
#include <boost/limits.hpp>
#include <complex>
#include <sstream>
#include <boost/limits.hpp>
#include <set>
template <class T>
void generic_complex_tests(std::complex<T> v)
@@ -89,6 +90,21 @@ void complex_integral_tests(Integer*)
generic_complex_tests(complex(Integer(-543),Integer(763)));
}
template<class T> void complex_grid_test( short N )
{
std::set<std::size_t> hashes;
for( short i = 0; i < N; ++i )
{
for( short j = 0; j < N; ++j )
{
hashes.insert( boost::hash< std::complex<T> >()( std::complex<T>( i, j ) ) );
}
}
BOOST_TEST_EQ( hashes.size(), static_cast<std::size_t>( N * N ) );
}
int main()
{
// I've comments out the short and unsigned short tests
@@ -105,6 +121,11 @@ int main()
complex_integral_tests((unsigned int*) 0);
complex_integral_tests((unsigned long*) 0);
complex_grid_test<int>( 16 );
complex_grid_test<float>( 16 );
complex_grid_test<double>( 16 );
complex_grid_test<long double>( 16 );
return boost::report_errors();
}

View File

@@ -0,0 +1,52 @@
// Copyright 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config.hpp>
#include <vector>
#include <deque>
#include <list>
#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST)
# include <forward_list>
#endif
template<class T> std::size_t hv( T const& t )
{
return boost::hash<T>()( t );
}
template<class T> void test()
{
for( std::size_t i = 0; i < 8; ++i )
{
std::vector<T> v( i );
std::size_t h0 = hv( v );
std::deque<T> d( v.begin(), v.end() );
BOOST_TEST_EQ( h0, hv( d ) );
std::list<T> l( v.begin(), v.end() );
BOOST_TEST_EQ( h0, hv( l ) );
#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST)
std::forward_list<T> f( v.begin(), v.end() );
BOOST_TEST_EQ( h0, hv( f ) );
#endif
}
}
int main()
{
test<char>();
test<unsigned char>();
test<signed char>();
test<int>();
test<float>();
test<double>();
return boost::report_errors();
}

View File

@@ -15,7 +15,6 @@
#include <cmath>
#include <boost/container_hash/detail/limits.hpp>
#include <boost/container_hash/detail/float_functions.hpp>
#include <boost/config/workaround.hpp>
#include <iostream>
@@ -55,19 +54,6 @@ void float_tests(char const* name, T* = 0)
<< boost::hash_detail::limits<std::size_t>::digits
<< "\n"
<< "\n"
<< "boost::hash_detail::call_ldexp<T>::float_type = "
<< float_type(static_cast<BOOST_DEDUCED_TYPENAME
boost::hash_detail::call_ldexp<T>::float_type*>(0))
<< "\n"
<< "boost::hash_detail::call_frexp<T>::float_type = "
<< float_type(static_cast<BOOST_DEDUCED_TYPENAME
boost::hash_detail::call_frexp<T>::float_type*>(0))
<< "\n"
<< "boost::hash_detail::select_hash_type<T>::type = "
<< float_type(static_cast<BOOST_DEDUCED_TYPENAME
boost::hash_detail::select_hash_type<T>::type*>(0))
<< "\n"
<< "\n"
;
BOOST_HASH_TEST_NAMESPACE::hash<T> x1;

View File

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

View File

@@ -0,0 +1,30 @@
// Copyright 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(_MSC_VER)
# pragma warning(disable: 4714) // forceinline not inlined
#endif
#if defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#include <boost/filesystem/path.hpp>
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
template<class T> std::size_t hv( T const& t )
{
return boost::hash<T>()( t );
}
int main()
{
boost::filesystem::path p1( "/foo/bar" );
boost::filesystem::path p2( "/foo/baz" );
BOOST_TEST_NE( hv( p1 ), hv( p2 ) );
return boost::report_errors();
}

View File

@@ -8,6 +8,8 @@
#include <boost/container_hash/hash.hpp>
#include <iostream>
#include <algorithm>
#include <limits>
#include <climits>
#if defined(BOOST_MSVC)
@@ -37,10 +39,9 @@ void write_compiler_info() {
{1700, "Visual C++ 11.0, VS2012"},
{1800, "Visual C++ 12.0, VS2013"},
{1900, "Visual C++ 14.00, VS2015"},
{1910, "Visual C++ 14.10, VS2017 15.1/2"},
{1911, "Visual C++ 14.11, VS2017 15.3/4"},
{1912, "Visual C++ 14.12, VS2017 15.5"},
{1913, "Visual C++ 14.13, VS2017 15.6"}
{1910, "Visual C++ 14.1x, VS2017"},
{1920, "Visual C++ 14.2x, VS2019"},
{1930, "Visual C++ 14.3x, VS2022"},
};
msvc_version msvc = { BOOST_MSVC, "" };
@@ -62,41 +63,62 @@ void write_compiler_info() {
#endif
#define PRINT(x) std::cout << #x ": " << x << std::endl
int main() {
write_compiler_info();
std::cout << std::endl;
#if defined(__cplusplus)
std::cout << "__cplusplus: "
<< __cplusplus
<< std::endl;
PRINT(__cplusplus);
PRINT(BOOST_CXX_VERSION);
std::cout << std::endl;
#if defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
std::cout << "No <string_view>" << std::endl;
#else
std::cout << "Has <string_view>" << std::endl;
#endif
std::cout << "BOOST_HASH_CXX17: "
<< BOOST_HASH_CXX17
<< std::endl;
#if defined(BOOST_NO_CXX17_HDR_OPTIONAL)
std::cout << "No <optional>" << std::endl;
#else
std::cout << "Has <optional>" << std::endl;
#endif
std::cout << "BOOST_HASH_HAS_STRING_VIEW: "
<< BOOST_HASH_HAS_STRING_VIEW
<< std::endl;
std::cout << "BOOST_HASH_HAS_OPTIONAL: "
<< BOOST_HASH_HAS_OPTIONAL
<< std::endl;
std::cout << "BOOST_HASH_HAS_VARIANT: "
<< BOOST_HASH_HAS_VARIANT
<< std::endl;
#if defined(BOOST_NO_CXX17_HDR_VARIANT)
std::cout << "No <variant>" << std::endl;
#else
std::cout << "Has <variant>" << std::endl;
#endif
#if defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
std::cout << "No <typeindex>" << std::endl;
#else
std::cout << "<typeindex>" << std::endl;
std::cout << "Has <typeindex>" << std::endl;
#endif
#if defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
std::cout << "No <system_error>" << std::endl;
#else
std::cout << "<system_error>" << std::endl;
std::cout << "Has <system_error>" << std::endl;
#endif
std::cout << std::endl;
PRINT(CHAR_BIT);
std::cout << std::endl;
PRINT(sizeof(std::size_t)*CHAR_BIT);
std::cout << std::endl;
PRINT(sizeof(float)*CHAR_BIT);
PRINT(std::numeric_limits<float>::digits);
std::cout << std::endl;
PRINT(sizeof(double)*CHAR_BIT);
PRINT(std::numeric_limits<double>::digits);
std::cout << std::endl;
PRINT(sizeof(long double)*CHAR_BIT);
PRINT(std::numeric_limits<long double>::digits);
}

View File

@@ -0,0 +1,75 @@
// 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 <set>
#if defined(BOOST_MSVC)
#pragma warning(disable: 4127) // conditional expression is constant
#endif
// This test checks that small numbers hash to themselves even if
// their type is wider than size_t
template<class T>
void identity_test()
{
if( boost::is_signed<T>::value )
{
for( int i = -128; i <= 127; ++i )
{
BOOST_TEST_EQ( boost::hash<T>()( static_cast<T>( i ) ), static_cast<std::size_t>( i ) );
}
}
else
{
for( int i = 0; i <= 255; ++i )
{
BOOST_TEST_EQ( boost::hash<T>()( static_cast<T>( i ) ), static_cast<std::size_t>( i ) );
}
}
}
#define TEST(type) std::cerr << "Testing: " #type " (" << boost::core::type_name<type>() << ")\n"; identity_test<type>();
int main()
{
TEST(char)
TEST(signed char)
TEST(unsigned char)
#ifndef BOOST_NO_INTRINSIC_WCHAR_T
TEST(wchar_t)
#endif
#ifndef BOOST_NO_CXX11_CHAR16_T
TEST(char16_t)
#endif
#ifndef BOOST_NO_CXX11_CHAR32_T
TEST(char32_t)
#endif
TEST(short)
TEST(unsigned short)
TEST(int)
TEST(unsigned int)
TEST(long)
TEST(unsigned long)
#if !defined(BOOST_NO_LONG_LONG)
TEST(boost::long_long_type)
TEST(boost::ulong_long_type)
#endif
#if defined(BOOST_HAS_INT128)
TEST(boost::int128_type)
TEST(boost::uint128_type)
#endif
TEST(std::size_t)
TEST(std::ptrdiff_t)
return boost::report_errors();
}

View File

@@ -13,6 +13,11 @@
#pragma warning(disable:4245) // signed/unsigned mismatch
#endif
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
namespace HASH_TEST_CAT(CONTAINER_TYPE, _tests)
{
template <class T>
@@ -66,6 +71,10 @@ namespace HASH_TEST_CAT(CONTAINER_TYPE, _tests)
}
}
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic pop
#endif
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif

View File

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

View File

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

View File

@@ -1,28 +0,0 @@
// Copyright 2006-2009 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "./config.hpp"
// Simple test to make sure BOOST_HASH_NO_EXTENSIONS does disable extensions
// (or at least one of them).
#if !defined(BOOST_HASH_NO_EXTENSIONS)
# define BOOST_HASH_NO_EXTENSIONS
#endif
#ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
#else
# include <boost/container_hash/hash.hpp>
#endif
template <class T> void ignore(T const&) {}
int main()
{
BOOST_HASH_TEST_NAMESPACE::hash< int[10] > hasher;
ignore(hasher);
return 0;
}

View File

@@ -103,10 +103,8 @@ void limits_test(T*)
if (limits::is_integer)
{
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(min_value)
== std::size_t(min_value));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(max_value)
== std::size_t(max_value));
BOOST_TEST_EQ(BOOST_HASH_TEST_NAMESPACE::hash_value(min_value), std::size_t(min_value));
BOOST_TEST_EQ(BOOST_HASH_TEST_NAMESPACE::hash_value(max_value), std::size_t(max_value));
}
#endif
}

View File

@@ -0,0 +1,90 @@
// 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 <set>
#if defined(BOOST_MSVC)
# pragma warning(disable: 4244) // conversion from int to float
#endif
#if defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic ignored "-Wconversion"
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
// This test checks for collisions in a small range of numbers
template<class T, int M>
void collision_test_()
{
std::set<std::size_t> hashes;
for( int i = -128; i <= 127; ++i )
{
hashes.insert( boost::hash<T>()( i * M ) );
}
BOOST_TEST_EQ( hashes.size(), 256u );
}
template <class T>
void collision_test()
{
collision_test_<T, 1>();
collision_test_<T, 2>();
collision_test_<T, 3>();
collision_test_<T, 4>();
collision_test_<T, 5>();
collision_test_<T, 8>();
collision_test_<T, 10>();
collision_test_<T, 16>();
collision_test_<T, 32>();
collision_test_<T, 64>();
collision_test_<T, 100>();
collision_test_<T, 128>();
}
#define TEST(type) std::cerr << "Testing: " #type " (" << boost::core::type_name<type>() << ")\n"; collision_test<type>();
int main()
{
#ifndef BOOST_NO_INTRINSIC_WCHAR_T
TEST(wchar_t)
#endif
#ifndef BOOST_NO_CXX11_CHAR16_T
TEST(char16_t)
#endif
#ifndef BOOST_NO_CXX11_CHAR32_T
TEST(char32_t)
#endif
TEST(short)
TEST(unsigned short)
TEST(int)
TEST(unsigned int)
TEST(long)
TEST(unsigned long)
#if !defined(BOOST_NO_LONG_LONG)
TEST(boost::long_long_type)
TEST(boost::ulong_long_type)
#endif
#if defined(BOOST_HAS_INT128)
TEST(boost::int128_type)
TEST(boost::uint128_type)
#endif
TEST(float)
TEST(double)
TEST(long double)
TEST(std::size_t)
TEST(std::ptrdiff_t)
return boost::report_errors();
}

View File

@@ -11,7 +11,7 @@
#include <boost/config.hpp>
#include <boost/core/lightweight_test.hpp>
#if BOOST_HASH_HAS_OPTIONAL
#if !defined(BOOST_NO_CXX17_HDR_OPTIONAL)
#include <optional>
#include <string>
@@ -60,7 +60,7 @@ void test_optional_string()
int main()
{
#if BOOST_HASH_HAS_OPTIONAL
#if !defined(BOOST_NO_CXX17_HDR_OPTIONAL)
test_optional_int();
test_optional_string();
#else

View File

@@ -17,6 +17,10 @@ int main() {}
# pragma clang diagnostic ignored "-Wlong-long"
#endif
#if defined(__GNUC__)
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <string>
@@ -105,7 +109,7 @@ int main()
BOOST_TEST_EQ( hv(1ULL), 1 );
BOOST_TEST_EQ( hv(65535ULL), 65535 );
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv((unsigned long long)-1), 3221225537U );
BOOST_TEST_EQ( hv((unsigned long long)-1), 2578835074U );
#else
BOOST_TEST_EQ( hv((unsigned long long)-1), (std::size_t)-1 );
#endif
@@ -137,7 +141,7 @@ int main()
#else
BOOST_TEST_EQ( hv((uint128)-1), 13835058055282163777ULL );
BOOST_TEST_EQ( hv((uint128)-1), 10400452472442790415ULL );
#endif
@@ -154,24 +158,9 @@ int main()
BOOST_TEST_EQ( hv(-1e-38f), 2154619886U );
BOOST_TEST_EQ( hv(1e+38f), 2123789977U );
BOOST_TEST_EQ( hv(-1e+38f), 4271273625U );
#if !defined(__GLIBCXX__)
BOOST_TEST_EQ( hv(std::numeric_limits<float>::infinity()), 2139095040U );
BOOST_TEST_EQ( hv(-std::numeric_limits<float>::infinity()), 4286578688U );
#elif SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::numeric_limits<float>::infinity()), 4294967295U );
BOOST_TEST_EQ( hv(-std::numeric_limits<float>::infinity()), 4294967294U );
#else
BOOST_TEST_EQ( hv(std::numeric_limits<float>::infinity()), 18446744073709551615ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<float>::infinity()), 18446744073709551614ULL );
#endif
// double
BOOST_TEST_EQ( hv(0.0), 0 );
BOOST_TEST_EQ( hv(-0.0), 0 );
@@ -180,25 +169,15 @@ int main()
BOOST_TEST_EQ( hv(1.0), 1072693248U );
BOOST_TEST_EQ( hv(-1.0), 3220176896U );
BOOST_TEST_EQ( hv(3.14), 2660156064U );
BOOST_TEST_EQ( hv(-3.14), 512672416U );
BOOST_TEST_EQ( hv(1e-308), 1553872728U );
BOOST_TEST_EQ( hv(-1e-308), 3701356376U );
BOOST_TEST_EQ( hv(1e+308), 2577739707U );
BOOST_TEST_EQ( hv(-1e+308), 430256059U );
#if !defined(__GLIBCXX__)
BOOST_TEST_EQ( hv(3.14), 3972386992U );
BOOST_TEST_EQ( hv(-3.14), 1824903344U );
BOOST_TEST_EQ( hv(1e-308), 2213556530U );
BOOST_TEST_EQ( hv(-1e-308), 66072882U );
BOOST_TEST_EQ( hv(1e+308), 2623678890U );
BOOST_TEST_EQ( hv(-1e+308), 476195242U );
BOOST_TEST_EQ( hv(std::numeric_limits<double>::infinity()), 2146435072U );
BOOST_TEST_EQ( hv(-std::numeric_limits<double>::infinity()), 4293918720U );
#else
BOOST_TEST_EQ( hv(std::numeric_limits<double>::infinity()), 4294967295U );
BOOST_TEST_EQ( hv(-std::numeric_limits<double>::infinity()), 4294967294U );
#endif
#else
BOOST_TEST_EQ( hv(1.0), 4607182418800017408ULL );
@@ -209,19 +188,9 @@ int main()
BOOST_TEST_EQ( hv(-1e-308), 9225396059387848914ULL );
BOOST_TEST_EQ( hv(1e+308), 9214871658872686752ULL );
BOOST_TEST_EQ( hv(-1e+308), 18438243695727462560ULL );
#if !defined(__GLIBCXX__)
BOOST_TEST_EQ( hv(std::numeric_limits<double>::infinity()), 9218868437227405312ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<double>::infinity()), 18442240474082181120ULL );
#else
BOOST_TEST_EQ( hv(std::numeric_limits<double>::infinity()), 18446744073709551615ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<double>::infinity()), 18446744073709551614ULL );
#endif
#endif
// long double
@@ -234,8 +203,8 @@ int main()
BOOST_TEST_EQ( hv(1.0L), 1072693248U );
BOOST_TEST_EQ( hv(-1.0L), 3220176896U );
BOOST_TEST_EQ( hv(3.14L), 2660156064U );
BOOST_TEST_EQ( hv(-3.14L), 512672416U );
BOOST_TEST_EQ( hv(3.14L), 3972386992U );
BOOST_TEST_EQ( hv(-3.14L), 1824903344U );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 2146435072U );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 4293918720U );
@@ -254,41 +223,21 @@ int main()
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(1.0L), 2684370943U );
BOOST_TEST_EQ( hv(-1.0L), 2684403711U );
BOOST_TEST_EQ( hv(3.14L), 83002659U );
BOOST_TEST_EQ( hv(-3.14L), 82969891U );
#if !defined(__GLIBCXX__)
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 0xA0007FFFu );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 0xA000FFFFu );
BOOST_TEST_EQ( hv(1.0L), 3770520689U );
BOOST_TEST_EQ( hv(-1.0L), 3770553457U );
BOOST_TEST_EQ( hv(3.14L), 1150018772U );
BOOST_TEST_EQ( hv(-3.14L), 1150051540U );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 3770537073U );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 3770569841U );
#else
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 4294967295U );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 4294967294U );
#endif
#else
BOOST_TEST_EQ( hv(1.0L), 11529215046068486143ULL );
BOOST_TEST_EQ( hv(-1.0L), 11529215046068518911ULL );
BOOST_TEST_EQ( hv(3.14L), 12059468778148142067ULL );
BOOST_TEST_EQ( hv(-3.14L), 12059468778147191795ULL );
#if !defined(__GLIBCXX__)
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 11529215046068502527ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 11529215046068535295ULL );
#else
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 18446744073709551615ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 18446744073709551614ULL );
#endif
BOOST_TEST_EQ( hv(1.0L), 18308860000934227808ULL );
BOOST_TEST_EQ( hv(-1.0L), 18308860000934260576ULL );
BOOST_TEST_EQ( hv(3.14L), 13482288377848558187ULL );
BOOST_TEST_EQ( hv(-3.14L), 13482288377848590955ULL );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 18308860000934244192ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 18308860000934276960ULL );
#endif
@@ -302,15 +251,15 @@ int main()
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(a1), 3864292196U );
BOOST_TEST_EQ( hv(a2), 2842917718U );
BOOST_TEST_EQ( hv(a3), 325752138U );
BOOST_TEST_EQ( hv(a1), 1684164658U );
BOOST_TEST_EQ( hv(a2), 3385628684U );
BOOST_TEST_EQ( hv(a3), 354805152U );
#else
BOOST_TEST_EQ( hv(a1), 3864292196ULL );
BOOST_TEST_EQ( hv(a2), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(a3), 17867750819888810972ULL );
BOOST_TEST_EQ( hv(a1), 11915877628236072130ULL );
BOOST_TEST_EQ( hv(a2), 17303869719317669699ULL );
BOOST_TEST_EQ( hv(a3), 14973878137098559850ULL );
#endif
}
@@ -318,19 +267,19 @@ int main()
// string
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::string()), 0 );
BOOST_TEST_EQ( hv(std::string("abc")), 1849538372U );
BOOST_TEST_EQ( hv(std::string("\0", 1)), 3864292196U );
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 2842917718U );
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 325752138U );
BOOST_TEST_EQ( hv(std::string()), 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 );
#else
BOOST_TEST_EQ( hv(std::string()), 0 );
BOOST_TEST_EQ( hv(std::string("abc")), 6420922261882292859ULL );
BOOST_TEST_EQ( hv(std::string("\0", 1)), 3864292196ULL );
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 17867750819888810972ULL );
BOOST_TEST_EQ( hv(std::string()), 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 );
#endif
@@ -341,17 +290,18 @@ int main()
// complex<int>
BOOST_TEST_EQ( hv(std::complex<int>(0, 0)), 0U );
BOOST_TEST_EQ( hv(std::complex<int>(+1, 0)), 1U );
BOOST_TEST_EQ( hv(std::complex<int>(0, +1)), 65U );
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::complex<int>(0, +1)), 2261973619U );
BOOST_TEST_EQ( hv(std::complex<int>(-1, 0)), 4294967295U );
BOOST_TEST_EQ( hv(std::complex<int>(0, -1)), 3221225536U );
BOOST_TEST_EQ( hv(std::complex<int>(0, -1)), 2578835075U );
#else
BOOST_TEST_EQ( hv(std::complex<int>(0, +1)), 4326460912318144697U );
BOOST_TEST_EQ( hv(std::complex<int>(-1, 0)), 18446744073709551615ULL );
BOOST_TEST_EQ( hv(std::complex<int>(0, -1)), 13835058055282163776ULL );
BOOST_TEST_EQ( hv(std::complex<int>(0, -1)), 10400452472442790416ULL );
#endif
@@ -362,13 +312,13 @@ int main()
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, +1.0f)), 3495952384U );
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, -1.0f)), 2959081472U );
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, +1.0f)), 1867597054U );
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, -1.0f)), 1969397420U );
#else
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, +1.0f)), 67920461824ULL );
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, -1.0f)), 209117511680ULL );
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, +1.0f)), 15274800114361806457ULL );
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, -1.0f)), 4238815378092176215ULL );
#endif
@@ -379,47 +329,47 @@ int main()
BOOST_TEST_EQ( hv(std::complex<double>(+1.0, 0.0)), 1072693248U );
BOOST_TEST_EQ( hv(std::complex<double>(-1.0, 0.0)), 3220176896U );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, +1.0)), 873201664U );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, -1.0)), 2483814400U );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, +1.0)), 2619008688U );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, -1.0)), 146497060U );
#else
BOOST_TEST_EQ( hv(std::complex<double>(+1.0, 0.0)), 4607182418800017408ULL );
BOOST_TEST_EQ( hv(std::complex<double>(-1.0, 0.0)), 13830554455654793216ULL );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, +1.0)), 3750372589692780544ULL );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, -1.0)), 10667901617333862400ULL );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, +1.0)), 837908647691372762ULL );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, -1.0)), 3605795203555706515ULL );
#endif
// pair
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::make_pair(0, 0)), 2842917718U );
BOOST_TEST_EQ( hv(std::make_pair(1, 2)), 2507434894U );
BOOST_TEST_EQ( hv(std::make_pair(-1, -2)), 1874100199 );
BOOST_TEST_EQ( hv(std::make_pair(0, 0)), 3385628684U );
BOOST_TEST_EQ( hv(std::make_pair(1, 2)), 1013020961U );
BOOST_TEST_EQ( hv(std::make_pair(-1, -2)), 1207763712U );
#else
BOOST_TEST_EQ( hv(std::make_pair(0, 0)), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(std::make_pair(1, 2)), 3370697991563800380ULL );
BOOST_TEST_EQ( hv(std::make_pair(-1, -2)), 4139767141999124554ULL );
BOOST_TEST_EQ( hv(std::make_pair(0, 0)), 17303869719317669699ULL );
BOOST_TEST_EQ( hv(std::make_pair(1, 2)), 3509426265802930590ULL );
BOOST_TEST_EQ( hv(std::make_pair(-1, -2)), 9712138927275741808ULL );
#endif
// vector<char>
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::vector<char>(0)), 0 );
BOOST_TEST_EQ( hv(std::vector<char>(1)), 3864292196U );
BOOST_TEST_EQ( hv(std::vector<char>(2)), 2842917718U );
BOOST_TEST_EQ( hv(std::vector<char>(3)), 325752138U );
BOOST_TEST_EQ( hv(std::vector<char>(0)), 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 );
#else
BOOST_TEST_EQ( hv(std::vector<char>(0)), 0 );
BOOST_TEST_EQ( hv(std::vector<char>(1)), 3864292196ULL );
BOOST_TEST_EQ( hv(std::vector<char>(2)), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(std::vector<char>(3)), 17867750819888810972ULL );
BOOST_TEST_EQ( hv(std::vector<char>(0)), 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 );
#endif
@@ -427,16 +377,16 @@ int main()
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::vector<int>(0)), 0 );
BOOST_TEST_EQ( hv(std::vector<int>(1)), 3864292196U );
BOOST_TEST_EQ( hv(std::vector<int>(2)), 2842917718U );
BOOST_TEST_EQ( hv(std::vector<int>(3)), 325752138U );
BOOST_TEST_EQ( hv(std::vector<int>(1)), 1684164658U );
BOOST_TEST_EQ( hv(std::vector<int>(2)), 3385628684U );
BOOST_TEST_EQ( hv(std::vector<int>(3)), 354805152U );
#else
BOOST_TEST_EQ( hv(std::vector<int>(0)), 0 );
BOOST_TEST_EQ( hv(std::vector<int>(1)), 3864292196ULL );
BOOST_TEST_EQ( hv(std::vector<int>(2)), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(std::vector<int>(3)), 17867750819888810972ULL );
BOOST_TEST_EQ( hv(std::vector<int>(1)), 11915877628236072130ULL );
BOOST_TEST_EQ( hv(std::vector<int>(2)), 17303869719317669699ULL );
BOOST_TEST_EQ( hv(std::vector<int>(3)), 14973878137098559850ULL );
#endif
@@ -444,33 +394,33 @@ int main()
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(0)), 0 );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(1)), 3864292196U );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(2)), 2842917718U );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(3)), 325752138U );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(1)), 1684164658U );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(2)), 3385628684U );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(3)), 354805152U );
#else
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(0)), 0 );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(1)), 3864292196ULL );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(2)), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(3)), 17867750819888810972ULL );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(1)), 11915877628236072130ULL );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(2)), 17303869719317669699ULL );
BOOST_TEST_EQ( hv(std::vector<std::vector<int> >(3)), 14973878137098559850ULL );
#endif
// list<char>
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::list<char>(0)), 0 );
BOOST_TEST_EQ( hv(std::list<char>(1)), 3864292196U );
BOOST_TEST_EQ( hv(std::list<char>(2)), 2842917718U );
BOOST_TEST_EQ( hv(std::list<char>(3)), 325752138U );
BOOST_TEST_EQ( hv(std::list<char>(0)), 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 );
#else
BOOST_TEST_EQ( hv(std::list<char>(0)), 0 );
BOOST_TEST_EQ( hv(std::list<char>(1)), 3864292196ULL );
BOOST_TEST_EQ( hv(std::list<char>(2)), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(std::list<char>(3)), 17867750819888810972ULL );
BOOST_TEST_EQ( hv(std::list<char>(0)), 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 );
#endif
@@ -478,16 +428,16 @@ int main()
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::list<int>(0)), 0 );
BOOST_TEST_EQ( hv(std::list<int>(1)), 3864292196U );
BOOST_TEST_EQ( hv(std::list<int>(2)), 2842917718U );
BOOST_TEST_EQ( hv(std::list<int>(3)), 325752138U );
BOOST_TEST_EQ( hv(std::list<int>(1)), 1684164658U );
BOOST_TEST_EQ( hv(std::list<int>(2)), 3385628684U );
BOOST_TEST_EQ( hv(std::list<int>(3)), 354805152U );
#else
BOOST_TEST_EQ( hv(std::list<int>(0)), 0 );
BOOST_TEST_EQ( hv(std::list<int>(1)), 3864292196ULL );
BOOST_TEST_EQ( hv(std::list<int>(2)), 14642545639667855512ULL );
BOOST_TEST_EQ( hv(std::list<int>(3)), 17867750819888810972ULL );
BOOST_TEST_EQ( hv(std::list<int>(1)), 11915877628236072130ULL );
BOOST_TEST_EQ( hv(std::list<int>(2)), 17303869719317669699ULL );
BOOST_TEST_EQ( hv(std::list<int>(3)), 14973878137098559850ULL );
#endif

View File

@@ -12,6 +12,11 @@
#pragma warning(disable:4245) // signed/unsigned mismatch
#endif
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
namespace HASH_TEST_CAT(CONTAINER_TYPE, _tests)
{
template <class T>
@@ -68,6 +73,10 @@ namespace HASH_TEST_CAT(CONTAINER_TYPE, _tests)
}
}
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic pop
#endif
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif

View File

@@ -12,6 +12,11 @@
#pragma warning(disable:4245) // signed/unsigned mismatch
#endif
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
namespace HASH_TEST_CAT(CONTAINER_TYPE, _tests)
{
template <class T>
@@ -71,6 +76,10 @@ namespace HASH_TEST_CAT(CONTAINER_TYPE, _tests)
}
}
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic pop
#endif
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif

View File

@@ -176,7 +176,7 @@ int main()
#endif
generic_string_tests((std::string*) 0);
#if BOOST_HASH_HAS_STRING_VIEW
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
generic_string_tests((std::string_view*) 0);
#endif

View File

@@ -11,6 +11,12 @@
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
#include <string_view>
#endif
#include <vector>
#include <deque>
#include <list>
#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST)
# include <forward_list>
#endif
// Test whether the hash values of a string and a
// string_view that refers to it match. This is
@@ -24,12 +30,21 @@ template<class T> std::size_t hv( T const& t )
int main()
{
std::string s( "Test." );
std::size_t h0 = hv( s );
BOOST_TEST_EQ( hv( s ), hv( boost::string_view( s ) ) );
BOOST_TEST_EQ( hv( s ), hv( boost::core::string_view( s ) ) );
BOOST_TEST_EQ( h0, hv( boost::string_view( s ) ) );
BOOST_TEST_EQ( h0, hv( boost::core::string_view( s ) ) );
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
BOOST_TEST_EQ( hv( s ), hv( std::string_view( s ) ) );
BOOST_TEST_EQ( h0, hv( std::string_view( s ) ) );
#endif
BOOST_TEST_EQ( h0, hv( std::vector<char>( s.begin(), s.end() ) ) );
BOOST_TEST_EQ( h0, hv( std::deque<char>( s.begin(), s.end() ) ) );
BOOST_TEST_EQ( h0, hv( std::list<char>( s.begin(), s.end() ) ) );
#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST)
BOOST_TEST_EQ( h0, hv( std::forward_list<char>( s.begin(), s.end() ) ) );
#endif
return boost::report_errors();

View File

@@ -0,0 +1,42 @@
// Copyright 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <string>
void test( unsigned char ch )
{
typedef boost::hash<std::string> hash;
int const N = 32;
std::size_t h[ N ];
std::string v;
for( int i = 0; i < N; ++i )
{
h[ i ] = hash()( v );
BOOST_TEST_EQ( h[ i ], hash()( v ) );
for( int j = 0; j < i; ++j )
{
BOOST_TEST_NE( h[ j ], h[ i ] );
}
v.push_back( static_cast<char>( ch ) );
}
}
int main()
{
for( unsigned ch = 0; ch < 256; ++ch )
{
test( static_cast<unsigned char>( ch ) );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,41 @@
// Copyright 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <string>
#include <cstddef>
void test( std::size_t n, unsigned char ch )
{
typedef boost::hash<std::string> hash;
std::string const v( n, static_cast<char>( ch ) );
for( std::size_t i = 0; i < n * 8; ++i )
{
std::string w( v );
unsigned char ch2 = static_cast<unsigned char>( w[ i / 8 ] );
ch2 = static_cast<unsigned char>( ch2 ^ ( 1 << ( i % 8 ) ) );
w[ i / 8 ] = static_cast<char>( ch2 );
BOOST_TEST_NE( hash()( v ), hash()( w ) );
}
}
int main()
{
for( unsigned ch = 0; ch < 256; ++ch )
{
for( std::size_t n = 1; n < 32; ++n )
{
test( n, static_cast<unsigned char>( ch ) );
}
}
return boost::report_errors();
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,33 @@
// Copyright 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <algorithm>
#include <vector>
int main()
{
int const N = 16;
std::vector<int> v;
for( int i = 0; i < N; ++i )
{
v.push_back( i );
}
std::size_t h0 = boost::hash_unordered_range( v.begin(), v.end() );
int const M = 256;
for( int i = 0; i < M; ++i )
{
std::next_permutation( v.begin(), v.end() );
std::size_t h1 = boost::hash_unordered_range( v.begin(), v.end() );
BOOST_TEST_EQ( h0, h1 );
}
return boost::report_errors();
}

View File

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

View File

@@ -11,7 +11,7 @@
#include <boost/config.hpp>
#include <boost/core/lightweight_test.hpp>
#if BOOST_HASH_HAS_VARIANT
#if !defined(BOOST_NO_CXX17_HDR_VARIANT)
#include <variant>
#include <string>
@@ -90,7 +90,7 @@ void test_variant_unique_types()
int main()
{
#if BOOST_HASH_HAS_VARIANT
#if !defined(BOOST_NO_CXX17_HDR_VARIANT)
test_variant_int();
test_variant_unique_types();
#else

View File

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

View File

@@ -0,0 +1,101 @@
// Copyright 2017, 2018 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/container_hash/is_contiguous_range.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config.hpp>
#include <string>
#include <vector>
#include <list>
#include <deque>
#include <set>
#include <map>
#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
# include <array>
#endif
#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST)
# include <forward_list>
#endif
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET)
# include <unordered_set>
#endif
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP)
# include <unordered_map>
#endif
struct X
{
};
int main()
{
using boost::container_hash::is_contiguous_range;
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<void>));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<void const>));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<int>));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<int const>));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<X>));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<X const>));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<int[2]>));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<int const[2]>));
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<std::string>));
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<std::string const>));
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<std::wstring>));
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<std::wstring const>));
// std::vector doesn't have data() in C++03
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700)
BOOST_TEST_TRAIT_TRUE((is_contiguous_range< std::vector<X> >));
BOOST_TEST_TRAIT_TRUE((is_contiguous_range< std::vector<X> const >));
#endif
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::deque<X> >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::deque<X> const >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::set<int> >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::set<int> const >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::multiset<int> >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::multiset<int> const >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::map<int, X> >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::map<int, X> const >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::multimap<int, X> >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::multimap<int, X> const >));
#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
BOOST_TEST_TRAIT_TRUE((is_contiguous_range< std::array<X, 2> >));
BOOST_TEST_TRAIT_TRUE((is_contiguous_range< std::array<X, 2> const >));
#endif
#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST)
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::forward_list<X> >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::forward_list<X> const >));
#endif
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET)
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::unordered_set<int> >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::unordered_set<int> const >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::unordered_multiset<int> >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::unordered_multiset<int> const >));
#endif
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP)
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::unordered_map<int, X> >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::unordered_map<int, X> const >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::unordered_multimap<int, X> >));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range< std::unordered_multimap<int, X> const >));
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,63 @@
// Copyright 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/type_traits/integral_constant.hpp>
#include <cstddef>
struct X1
{
char const* begin() const;
char const* end() const;
char const* data() const;
std::size_t size() const;
};
struct X2
{
char const* begin() const;
char const* end() const;
char const* data() const;
std::size_t size() const;
};
struct X3
{
char const* begin() const;
char const* end() const;
char const* data() const;
std::size_t size() const;
};
namespace boost
{
namespace container_hash
{
template<class T> struct is_contiguous_range;
template<> struct is_contiguous_range<X2>: boost::false_type {};
template<class T> struct is_range;
template<> struct is_range<X3>: boost::false_type {};
} // namespace container_hash
} // namespace boost
#include <boost/container_hash/is_contiguous_range.hpp>
#include <boost/core/lightweight_test_trait.hpp>
int main()
{
using boost::container_hash::is_contiguous_range;
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700)
BOOST_TEST_TRAIT_TRUE((is_contiguous_range<X1>));
#endif
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<X2>));
BOOST_TEST_TRAIT_FALSE((is_contiguous_range<X3>));
return boost::report_errors();
}

98
test/is_range_test.cpp Normal file
View File

@@ -0,0 +1,98 @@
// Copyright 2017 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/container_hash/is_range.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config.hpp>
#include <string>
#include <vector>
#include <list>
#include <deque>
#include <set>
#include <map>
#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
# include <array>
#endif
#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST)
# include <forward_list>
#endif
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET)
# include <unordered_set>
#endif
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP)
# include <unordered_map>
#endif
struct X
{
};
int main()
{
using boost::container_hash::is_range;
BOOST_TEST_TRAIT_FALSE((is_range<void>));
BOOST_TEST_TRAIT_FALSE((is_range<void const>));
BOOST_TEST_TRAIT_FALSE((is_range<int>));
BOOST_TEST_TRAIT_FALSE((is_range<int const>));
BOOST_TEST_TRAIT_FALSE((is_range<X>));
BOOST_TEST_TRAIT_FALSE((is_range<X const>));
BOOST_TEST_TRAIT_FALSE((is_range<int[2]>));
BOOST_TEST_TRAIT_FALSE((is_range<int const[2]>));
BOOST_TEST_TRAIT_TRUE((is_range<std::string>));
BOOST_TEST_TRAIT_TRUE((is_range<std::string const>));
BOOST_TEST_TRAIT_TRUE((is_range<std::wstring>));
BOOST_TEST_TRAIT_TRUE((is_range<std::wstring const>));
BOOST_TEST_TRAIT_TRUE((is_range< std::vector<X> >));
BOOST_TEST_TRAIT_TRUE((is_range< std::vector<X> const >));
BOOST_TEST_TRAIT_TRUE((is_range< std::deque<X> >));
BOOST_TEST_TRAIT_TRUE((is_range< std::deque<X> const >));
BOOST_TEST_TRAIT_TRUE((is_range< std::set<int> >));
BOOST_TEST_TRAIT_TRUE((is_range< std::set<int> const >));
BOOST_TEST_TRAIT_TRUE((is_range< std::multiset<int> >));
BOOST_TEST_TRAIT_TRUE((is_range< std::multiset<int> const >));
BOOST_TEST_TRAIT_TRUE((is_range< std::map<int, X> >));
BOOST_TEST_TRAIT_TRUE((is_range< std::map<int, X> const >));
BOOST_TEST_TRAIT_TRUE((is_range< std::multimap<int, X> >));
BOOST_TEST_TRAIT_TRUE((is_range< std::multimap<int, X> const >));
#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
BOOST_TEST_TRAIT_TRUE((is_range< std::array<X, 2> >));
BOOST_TEST_TRAIT_TRUE((is_range< std::array<X, 2> const >));
#endif
#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST)
BOOST_TEST_TRAIT_TRUE((is_range< std::forward_list<X> >));
BOOST_TEST_TRAIT_TRUE((is_range< std::forward_list<X> const >));
#endif
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET)
BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_set<int> >));
BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_set<int> const >));
BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_multiset<int> >));
BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_multiset<int> const >));
#endif
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP)
BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_map<int, X> >));
BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_map<int, X> const >));
BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_multimap<int, X> >));
BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_multimap<int, X> const >));
#endif
return boost::report_errors();
}

37
test/is_range_test2.cpp Normal file
View File

@@ -0,0 +1,37 @@
// Copyright 2022 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(_MSC_VER)
# pragma warning(disable: 4714) // forceinline not inlined
#endif
#if defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#include <boost/container_hash/is_range.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config.hpp>
#include <boost/filesystem/path.hpp>
#if !defined(BOOST_NO_CXX17_HDR_FILESYSTEM) && !defined(__MINGW32__)
# include <filesystem>
#endif
int main()
{
using boost::container_hash::is_range;
BOOST_TEST_TRAIT_FALSE((is_range< boost::filesystem::path >));
BOOST_TEST_TRAIT_FALSE((is_range< boost::filesystem::path const >));
#if !defined(BOOST_NO_CXX17_HDR_FILESYSTEM) && !defined(__MINGW32__)
BOOST_TEST_TRAIT_FALSE((is_range< std::filesystem::path >));
BOOST_TEST_TRAIT_FALSE((is_range< std::filesystem::path const >));
#endif
return boost::report_errors();
}

46
test/is_range_test3.cpp Normal file
View File

@@ -0,0 +1,46 @@
// Copyright 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/type_traits/integral_constant.hpp>
struct X1
{
char const* begin() const;
char const* end() const;
};
struct X2
{
char const* begin() const;
char const* end() const;
};
namespace boost
{
namespace container_hash
{
template<class T> struct is_range;
template<> struct is_range<X2>: boost::false_type {};
} // namespace container_hash
} // namespace boost
#include <boost/container_hash/is_range.hpp>
#include <boost/core/lightweight_test_trait.hpp>
int main()
{
using boost::container_hash::is_range;
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700)
BOOST_TEST_TRAIT_TRUE((is_range<X1>));
#endif
BOOST_TEST_TRAIT_FALSE((is_range<X2>));
return boost::report_errors();
}

View File

@@ -0,0 +1,98 @@
// Copyright 2017 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/container_hash/is_unordered_range.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config.hpp>
#include <string>
#include <vector>
#include <list>
#include <deque>
#include <set>
#include <map>
#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
# include <array>
#endif
#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST)
# include <forward_list>
#endif
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET)
# include <unordered_set>
#endif
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP)
# include <unordered_map>
#endif
struct X
{
};
int main()
{
using boost::container_hash::is_unordered_range;
BOOST_TEST_TRAIT_FALSE((is_unordered_range<void>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range<void const>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range<int>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range<int const>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range<X>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range<X const>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range<int[2]>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range<int const[2]>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range<std::string>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range<std::string const>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range<std::wstring>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range<std::wstring const>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::vector<X> >));
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::vector<X> const >));
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::deque<X> >));
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::deque<X> const >));
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::set<int> >));
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::set<int> const >));
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::multiset<int> >));
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::multiset<int> const >));
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::map<int, X> >));
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::map<int, X> const >));
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::multimap<int, X> >));
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::multimap<int, X> const >));
#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::array<X, 2> >));
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::array<X, 2> const >));
#endif
#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST)
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::forward_list<X> >));
BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::forward_list<X> const >));
#endif
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET)
BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_set<int> >));
BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_set<int> const >));
BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_multiset<int> >));
BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_multiset<int> const >));
#endif
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP)
BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_map<int, X> >));
BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_map<int, X> const >));
BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_multimap<int, X> >));
BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_multimap<int, X> const >));
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,60 @@
// Copyright 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/type_traits/integral_constant.hpp>
#include <cstddef>
struct X1
{
char const* begin() const;
char const* end() const;
typedef void hasher;
};
struct X2
{
char const* begin() const;
char const* end() const;
typedef void hasher;
};
struct X3
{
char const* begin() const;
char const* end() const;
typedef void hasher;
};
namespace boost
{
namespace container_hash
{
template<class T> struct is_unordered_range;
template<> struct is_unordered_range<X2>: boost::false_type {};
template<class T> struct is_range;
template<> struct is_range<X3>: boost::false_type {};
} // namespace container_hash
} // namespace boost
#include <boost/container_hash/is_unordered_range.hpp>
#include <boost/core/lightweight_test_trait.hpp>
int main()
{
using boost::container_hash::is_unordered_range;
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC, < 40700)
BOOST_TEST_TRAIT_TRUE((is_unordered_range<X1>));
#endif
BOOST_TEST_TRAIT_FALSE((is_unordered_range<X2>));
BOOST_TEST_TRAIT_FALSE((is_unordered_range<X3>));
return boost::report_errors();
}

17
test/quick.cpp Normal file
View File

@@ -0,0 +1,17 @@
// Copyright 2006-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 <deque>
int main()
{
std::deque<int> x;
x.push_back( 1 );
x.push_back( 2 );
return boost::hash< std::deque<int> >()( x ) == boost::hash_value( x )? 0: 1;
}