Compare commits

..

295 Commits

Author SHA1 Message Date
Peter Dimov
20ee3b60fd Update CMakeLists.txt 2022-10-28 21:18:10 +03:00
Peter Dimov
bdd3dcf944 Disable -Wunused-private-field in described_class_test.cpp 2022-10-28 20:04:13 +03:00
Peter Dimov
018fc4e1fa Add support for described classes to hash.hpp 2022-10-28 19:35:10 +03:00
Peter Dimov
7568176bfa is_described_class should be false for unions 2022-10-28 18:42:07 +03:00
Peter Dimov
08864cd1e9 Update cmake_subdir_test/CMakeLists.txt 2022-10-28 14:56:57 +03:00
Peter Dimov
5a616b9b54 Update CMakeLists.txt 2022-10-28 07:07:48 +03:00
Peter Dimov
16fb4cc749 Add is_described_class to hash_fwd.hpp; include it in hash.hpp 2022-10-28 03:32:18 +03:00
Peter Dimov
0171246a61 Add is_described_class<T> 2022-10-28 01:47:27 +03:00
Peter Dimov
29c85559e4 Update .drone.jsonnet 2022-10-27 02:44:38 +03:00
Peter Dimov
412bd51449 Avoid -Wunused-but-set-variable under Clang 15 2022-10-27 02:12:43 +03:00
Peter Dimov
87196a503e Update .drone.jsonnet 2022-10-27 01:16:34 +03:00
Peter Dimov
df1671d593 msvc-14.0 doesn't quite have expression SFINAE. Fixes #28. 2022-10-26 19:38:53 +03:00
Peter Dimov
1996cf36c1 Update ci.yml 2022-10-26 19:32:22 +03:00
Peter Dimov
a4b2048a29 Add is_contiguous_range_test3 (refs #28) 2022-10-26 19:13:27 +03:00
Peter Dimov
85f9f8a97a Update documentation 2022-09-20 21:20:31 +03:00
Peter Dimov
e92eae9eb2 Treat char8_t and std::byte as char types in hash_range 2022-09-20 21:17:41 +03:00
Peter Dimov
8a1335458a Update Acknowledgements section 2022-09-20 21:09:17 +03:00
Peter Dimov
f7e537d1a1 Update Notes section 2022-09-20 21:06:09 +03:00
Peter Dimov
607b73f1e0 Add README.md 2022-09-20 16:08:10 +03:00
Peter Dimov
789261c68c Update 32 bit float reference values (for GCC) 2022-09-20 15:23:13 +03:00
Peter Dimov
29ee19ee7f Update 32 bit float reference values (for MSVC) 2022-09-20 15:08:21 +03:00
Peter Dimov
8bb7d43646 Simplify hash_value for floating point 2022-09-20 15:01:45 +03:00
Peter Dimov
a426a1939f Honor __FLOAT_WORD_ORDER__ for 128 bit long double 2022-09-20 14:52:19 +03:00
Peter Dimov
034b81594d Update 128 bit long double hash_value 2022-09-20 14:49:37 +03:00
Peter Dimov
75ef5a14f5 Cosmetic documentation updates 2022-09-20 12:25:16 +03:00
Peter Dimov
b5bb4405a9 Update Links section 2022-09-20 01:41:38 +03:00
Peter Dimov
d43ae22ab4 Update Notes section 2022-09-20 01:20:26 +03:00
Peter Dimov
e061b3c4c0 Update Notes section 2022-09-19 21:23:52 +03:00
Peter Dimov
9035aa5485 Avoid a warning under g++ 4.8 2022-09-19 15:43:37 +03:00
Peter Dimov
3ae0aea360 Update hash_reference_values for long double 2022-09-19 15:32:51 +03:00
Peter Dimov
fc249670c0 Update test/hash_info.cpp 2022-09-19 14:35:58 +03:00
Peter Dimov
30ffbf9f16 Remove address-model=32 from S390x and ARM64 as it doesn't do anything 2022-09-19 14:32:07 +03:00
Peter Dimov
c36319c878 Run test//hash_info using --verbose-test 2022-09-19 14:14:54 +03:00
Peter Dimov
a2aaefc71a Add -I examples to depinst 2022-09-19 13:50:36 +03:00
Peter Dimov
e3cd2d7de8 Add Drone support 2022-09-19 13:30:02 +03:00
Peter Dimov
4571ec190a Add Recent Changes section 2022-09-19 13:00:41 +03:00
Peter Dimov
478730107d Rename Rationale section to Design and Implementation Notes 2022-09-19 12:29:38 +03:00
Peter Dimov
adcf81c732 Update Links section 2022-09-19 12:19:08 +03:00
Peter Dimov
75a37c2616 Update Reference section 2022-09-19 11:56:03 +03:00
Peter Dimov
c01270b0bd Update Links section 2022-09-18 22:05:30 +03:00
Peter Dimov
123875dc83 Update documentation 2022-09-18 20:58:00 +03:00
Peter Dimov
ed235989ef Add is_unordered_range_test2 2022-09-18 14:32:28 +03:00
Peter Dimov
bf0a77f062 Disable tests using fs::path for msvc-8.0 2022-09-18 14:28:24 +03:00
Peter Dimov
79fff9e1ea Add is_contiguous_range_test2 2022-09-18 14:26:30 +03:00
Peter Dimov
6757bd4f00 Match is_range workaround in is_range_test3 2022-09-18 14:11:49 +03:00
Peter Dimov
20c03417b0 Add is_range_test3 2022-09-18 14:04:05 +03:00
Peter Dimov
60be3b131e Update 64 bit reference values for the new multiplier 2022-09-17 03:31:35 +03:00
Peter Dimov
b148e34818 Fix 64 bit hash_mix multiplier 2022-09-17 02:34:14 +03:00
Peter Dimov
e391cf6841 Change hash_detail::hash_range to take and return by value to avoid It=char* aliasing 2022-09-17 01:09:47 +03:00
Peter Dimov
b4e0643ecd Update 32 bit reference values for container<char> 2022-09-16 21:43:53 +03:00
Peter Dimov
dc9a6e3e68 Update 64 bit reference values for container<char> 2022-09-16 21:33:48 +03:00
Peter Dimov
f47772f6f4 Implement faster hash_range when value_type is char 2022-09-16 21:25:20 +03:00
Peter Dimov
c1e5427e8d Update 32 bit float reference values (for GCC) 2022-09-16 20:36:29 +03:00
Peter Dimov
866cff96e5 Restore full grid size in hash_complex_test 2022-09-16 19:57:45 +03:00
Peter Dimov
9d4971b81d Update complex reference values 2022-09-16 19:56:00 +03:00
Peter Dimov
4b5a1cf0f2 Update complex hashing to use hash_mix 2022-09-16 19:48:36 +03:00
Peter Dimov
435ff87fd7 Update 64 bit reference values (for GCC) 2022-09-16 19:30:02 +03:00
Peter Dimov
58934422fb Update 32 bit reference values (for MSVC) 2022-09-16 19:26:07 +03:00
Peter Dimov
3fe7bbdd6c Update floating point hashing to use hash_mix 2022-09-16 19:23:07 +03:00
Peter Dimov
fba63d4379 Update integral reference values 2022-09-16 19:19:30 +03:00
Peter Dimov
8adcaffcc2 Update integral hashing to use hash_mix 2022-09-16 19:16:45 +03:00
Peter Dimov
eee5e3b7fd Update 32 bit reference values to reflect the new hash_combine 2022-09-16 19:10:18 +03:00
Peter Dimov
e98cae2c31 Update 64 bit reference values to reflect the new hash_combine 2022-09-16 19:05:05 +03:00
Peter Dimov
40ec854466 Add hash_mix, change hash_combine to use it 2022-09-16 18:57:21 +03:00
Peter Dimov
c5b63d2cbb Disable failing tests on msvc-10.0 and msvc-11.0 2022-09-16 11:00:23 +03:00
Peter Dimov
882192ea3a Update workaround for Dinkumware stdext::hash_value 2022-09-16 01:56:24 +03:00
Peter Dimov
03123685c4 Add hash_unordered_map_test 2022-09-15 18:12:52 +03:00
Peter Dimov
95fe6bd9a3 Add hash_unordered_set_test 2022-09-15 18:10:23 +03:00
Peter Dimov
6cb735fda6 Add hash_unordered_multimap_test 2022-09-15 18:05:00 +03:00
Peter Dimov
10b4ad598f Add hash_unordered_multiset_test 2022-09-15 18:02:22 +03:00
Peter Dimov
ce734b435e Implement boost::hash_unordered_range 2022-09-15 18:00:04 +03:00
Peter Dimov
e387d14d36 Add hash_multimap_test 2022-09-15 16:50:39 +03:00
Peter Dimov
1fb41a72ef Add hash_multiset_test 2022-09-15 16:48:18 +03:00
Peter Dimov
c399cf6a38 Add traits to hash_fwd.hpp 2022-09-13 20:10:35 +03:00
Peter Dimov
30c32bb3df Move traits headers from container_hash/detail/ to container_hash/ 2022-09-13 19:45:45 +03:00
Peter Dimov
d1b2640dff Move type classification traits from namespace hash_detail to namespace container_hash 2022-09-13 19:37:15 +03:00
Peter Dimov
f722383d1d Change macos-10.15 to macos-11 in ci.yml 2022-08-31 18:17:01 +03:00
Peter Dimov
21530840e1 Add hash_string_test4.cpp 2022-08-31 15:09:29 +03:00
Peter Dimov
d0c1e36fc1 Add hash_string_test3.cpp 2022-08-31 14:51:47 +03:00
Peter Dimov
e00f53a69c Remove msvc-14.2 from appveyor.yml 2022-07-16 14:10:28 +03:00
Peter Dimov
b0c9904414 Test _MSVC_STL_VERSION instead of BOOST_MSVC because clang-cl 2022-07-16 13:37:15 +03:00
Peter Dimov
2d557a746d Add hash_vector_test2.cpp 2022-07-16 11:16:06 +03:00
Peter Dimov
417180dd03 Update appveyor.yml 2022-07-14 20:16:19 +03:00
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
53c12550fa Define _SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING in hash_reference_values.cpp (refs #23) 2022-06-14 14:42:22 +03:00
Peter Dimov
561cc5d010 Merge branch 'master' into develop 2022-06-13 14:26:03 +03:00
Peter Dimov
bdf4bfe910 Disable C4996 in hash_complex_test.cpp (refs #23) 2022-06-13 14:05:35 +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
b3e424b650 Add gcc-12, clang-13, clang-14 to GHA 2022-05-11 22:23:41 +03:00
Peter Dimov
d2986d9a64 Test boost::core::string_view in hash_string_test2 2022-04-29 02:01:46 +03:00
Peter Dimov
000276988f Add hash_string_test2 2022-04-28 21:13:23 +03:00
Peter Dimov
355603c0c2 Update ci.yml 2022-03-09 16:36:40 +02:00
Peter Dimov
33cd0a5964 Merge pull request #21 from cmazakas/doc-fixes
Doc fixes
2022-02-09 00:06:51 +02:00
Christian Mazakas
fc11122353 Refactor links to no longer open up a new tab 2022-02-08 13:18:06 -08:00
Christian Mazakas
cb233af718 Update [listing]s to become proper source code blocks 2022-02-08 13:18:01 -08:00
Christian Mazakas
8d820ee7d0 Remove unnecessary cross-references 2022-02-08 13:17:19 -08:00
Peter Dimov
3800d712d5 Merge pull request #20 from cmazakas/qbk-cleanup
Remove unneeded QuickBook and sample files from docs
2022-02-08 01:36:02 +02:00
Christian Mazakas
dee871f45c Remove unneeded QuickBook and sample files from docs 2022-02-07 13:11:32 -08:00
Peter Dimov
143a55ea3b Add doc/.gitignore 2022-02-05 02:13:07 +02:00
Peter Dimov
4ab431f12f Update index.html 2022-02-05 02:12:27 +02:00
Christian Mazakas
773307fe1c Add Reference section to AsciiDoc 2022-02-04 15:16:18 -08:00
Christian Mazakas
06db43a56a Add Copyright section to AsciiDoc 2022-02-04 15:16:18 -08:00
Christian Mazakas
5906cba1a0 Add Acknowledgements section 2022-02-04 15:16:18 -08:00
Christian Mazakas
b2222c2755 Add Links section to AsciiDoc 2022-02-04 15:16:18 -08:00
Christian Mazakas
6600a26460 Add Rationale to AsciiDoc 2022-02-04 15:16:18 -08:00
Christian Mazakas
c95e02fe85 Add Change List to AsciiDoc 2022-02-04 15:16:18 -08:00
Christian Mazakas
334eac8166 Add Disabling section to AsciiDoc 2022-02-04 15:16:18 -08:00
Christian Mazakas
21dbdb9b47 Add Portability section to AsciiDoc 2022-02-04 15:16:18 -08:00
Christian Mazakas
74f9abe52c Add Combining Hashes section to AsciiDoc 2022-02-04 15:16:18 -08:00
Christian Mazakas
37f3e6fcb7 Add Extending boost::hash section to AsciiDoc 2022-02-04 15:16:18 -08:00
Christian Mazakas
301c76646c Add Tutorial section to AsciiDoc 2022-02-04 15:16:18 -08:00
Christian Mazakas
a67e350fd9 Add Introduction section to AsciiDoc 2022-02-04 15:16:18 -08:00
Christian Mazakas
2d23e7e056 Update Jamfile to produce AsciiDoc and add corresponding file stubs 2022-02-03 15:33:02 -08:00
Peter Dimov
9bdebb3df4 Merge branch 'develop' into feature/refresh 2021-10-19 17:37:20 +03:00
Peter Dimov
e9ffeceeab Merge branch 'develop' into feature/reference 2021-10-19 01:57:24 +03:00
Peter Dimov
4a685b2b16 Add address-model=32 tests to ci.yml 2021-10-19 01:07:05 +03:00
Peter Dimov
8315ec2ba7 Comment out (uint128)-1 test under GCC 9 and below 2021-10-18 03:20:23 +03:00
Peter Dimov
1a4888cdb4 Add (uint128)-1 comment 2021-10-18 03:01:41 +03:00
Peter Dimov
9e938aca41 Revert "Update (uint128)-1 test"
This reverts commit cab5c6c8d7.
2021-10-18 03:00:17 +03:00
Peter Dimov
7abcf22762 Update long double infinity reference values for 32 bit GCC-like without fpclassify 2021-10-18 02:38:25 +03:00
Peter Dimov
dbb410b7ef Update long double reference values for 32 bit GCC 2021-10-18 02:31:06 +03:00
Peter Dimov
cab5c6c8d7 Update (uint128)-1 test 2021-10-18 02:21:58 +03:00
Peter Dimov
526e4d472d Add reference values for std::complex 2021-10-18 02:16:50 +03:00
Peter Dimov
fca37b0d43 Fix long double infinity 2021-10-18 01:11:24 +03:00
Peter Dimov
0a795c62a3 Update (uint128)-1 and long double infinity values 2021-10-18 00:55:31 +03:00
Peter Dimov
4ff953b568 Fix clang 2021-10-18 00:37:46 +03:00
Peter Dimov
cfbc94b128 Update infinity reference values 2021-10-18 00:15:16 +03:00
Peter Dimov
f0bed67909 Update long double values for g++ 64 bit 2021-10-18 00:01:15 +03:00
Peter Dimov
1c27af1e2e Add hash_reference_values.cpp 2021-10-17 23:54:39 +03:00
Peter Dimov
ebac66dc1e Print hash_info output in ci.yml 2021-10-17 20:22:06 +03:00
Peter Dimov
f0e75dd010 Reenable clang-win in appveyor.yml 2021-10-17 20:20:57 +03:00
Peter Dimov
5959103346 Extend __GNUC__ warning suppression to __clang__ 2021-10-17 20:13:56 +03:00
Peter Dimov
3c3948ccdb Take care of size_t -> int warnings under g++ 4.8 2021-10-17 19:54:23 +03:00
Peter Dimov
998d8da8c8 Disable warning in test/check_float_funcs.cpp 2021-10-17 19:54:12 +03:00
Peter Dimov
bdc2840738 Update test/Jamfile 2021-10-17 19:52:16 +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
Peter Dimov
21f2b5e1db Fix hash_combine_impl to only test for a specific bit width and not for concrete types 2021-10-12 19:52:37 +03:00
Peter Dimov
b55fbc9252 Update key in libraries.json 2021-10-12 19:51:11 +03:00
Peter Dimov
a0465807c7 Switch to 18.04 in ci.yml 2021-10-12 19:06:13 +03:00
Peter Dimov
e03c31c9bc Add -I examples to depinst 2021-10-12 17:56:31 +03:00
Peter Dimov
c4d9a95b82 Update appveyor.yml 2021-10-12 17:40:47 +03:00
Peter Dimov
5f5a5d0648 Merge pull request #14 from eldiener/develop
[skip ci] Add "cxxstd" json field
2021-10-12 17:33:26 +03:00
Peter Dimov
fd2781afc9 Update ci.yml 2021-08-10 17:56:49 +03:00
Peter Dimov
d045cf2ecb Update ci.yml 2021-08-10 17:48:23 +03:00
Peter Dimov
b4e4bf577f Add -I examples to depinst 2021-08-10 17:37:22 +03:00
Peter Dimov
310ca091a2 Add .github/workflows/ci.yml 2021-08-10 17:32:10 +03:00
Peter Dimov
e69c4c830e Update CMakeLists.txt 2021-06-10 01:18:25 +03:00
Edward Diener
aaf0d2525f [skip ci] Add "cxxstd" json field. The "cxxstd" json field is being added to each Boost library's meta json information for libraries in order to specify the minumum C++ standard compilation level. The value of this field matches one of the values for 'cxxstd' in Boost.Build. The purpose of doing this is to provide information for the Boost website documentation for each library which will specify the minimum C++ standard compilation that an end-user must employ in order to use the particular library. This will aid end-users who want to know if they can successfully use a Boost library based on their C++ compiler's compilation level, without having to search the library's documentation to find this out. 2021-01-19 12:42:27 -05:00
Glen Fernandes
171c012d47 Merge pull request #11 from boostorg/mclow-patch-1
Remove use of non-existant Boost.Config macro BOOST_NO_CXX11_HDR_MEMORY
2020-10-25 14:06:10 -04:00
Marshall Clow
e0331c0bd4 Remove use of non-existant Boost.Config macro BOOST_NO_CXX11_HDR_MEMORY
Thanks to Jeff Trull for the catch.
2020-09-10 20:09:23 -07:00
Marshall Clow
e30bbab19f Merge pull request #9 from eldiener/develop
Changes for Embarcadero C++ clang-based compilers, targeting Boost 1.74. Change __BORLANDC__ to BOOST_BORLANDC, which is defined in Boost conf…
2020-04-16 07:53:06 -07:00
Edward Diener
1818113f4c Change __BORLANDC__ to BOOST_BORLANDC, which is defined in Boost config for the Embarcadero non-clang-based compilers. 2020-03-23 11:50:36 -04:00
Peter Dimov
8a7fc581ed Merge branch 'develop' 2019-12-23 17:21:52 +02:00
Marshall Clow
5048576921 Merge pull request #6 from andrascii/develop
Fixed compiler guards for use of `std::unary_function` for C++17 compliance
2019-08-12 23:14:49 -07:00
Andrey
5f858645a0 Removed usage of std::unary_function for C++17 compliance 2019-08-10 12:37:49 +03:00
Andrey
fd310d2706 Removed usage of std::unary_function for C++17 compliance 2019-08-10 11:59:22 +03:00
Andrey
90a0e36638 Removed usage of std::unary_function for C++17 compliance 2019-08-09 17:23:16 +03:00
Peter Dimov
1ce57acc41 Merge pull request #5 from Mike-Devel/min_cmake
[CMake] Add minimal cmake file
2019-01-23 19:23:08 +02:00
Mike Dev
81a65eb01c [CMake] Add minimal cmake file
Only supports "add_subdirectory" workflow and doesn't
run unit-tests. It generates a INTERFACE cmake target
that other libraries can use to express their dependency
on Boost.ContainerHash and get usage requiremments,
such as the include directory.
2019-01-02 23:04:19 +01:00
Daniel James
9fbda1a98a Fix appveyor build (cherry-pick) 2018-04-16 06:43:14 +01:00
Daniel James
62f29ea201 Merge branch 'develop' (early part) 2018-04-16 06:42:45 +01:00
Daniel James
f054fe932f Fix appveyor build 2018-04-15 23:29:47 +01:00
Daniel James
83a874ed49 More general purpose support for iterators with odd reference type (trac #13501)
In the last release I added explicit support for `vector<bool>` which wasn't
working with libc++ because the iterator's `operator*` returned a proxy
reference type. Other implementations return a `bool` for const iterators, so
they happened to work okay.

This solves the problem in a more general purpose way by instantiating
`hash_combine` for the iterator `value_type`. So the type returned by
`operator*` will be implicitly casted to the correct type.
2018-04-15 22:44:33 +01:00
Daniel James
59f9543c10 Use boost 1.67.0 in travis and appveyor 2018-04-15 22:44:19 +01:00
Daniel James
a6da082784 Stop using -Werror
So that there aren't any failures because of warnings in other modules.
2018-04-15 22:44:19 +01:00
Daniel James
e73522f296 Merge branch 'develop' 2018-04-04 00:33:22 +01:00
Daniel James
3e8dbcbcc5 Changelog entry for vector<bool> fix 2018-04-04 00:32:53 +01:00
Daniel James
601b8d0378 Include vector header, needed to get the iterator type 2018-03-29 21:57:52 +01:00
Daniel James
60f5e0d393 Add explicit allocator to vector<bool> overloads
Needed when container_fwd.hpp is used, as it doesn't specify the default
arguments.
2018-03-29 19:57:49 +01:00
Daniel James
e67d20d1c3 Fix std::vector<bool> with libc++
Temporary fix for:

https://svn.boost.org/trac10/ticket/13501

Will have a more general fix in 1.68.0
2018-03-29 19:14:56 +01:00
Daniel James
8c9bd9eccd Test in msvc-14.1 C++17 mode + write out hash_info 2018-03-08 15:52:07 +00:00
Daniel James
88d1c5c395 Update hash_info for Visual C++ 14.13 2018-03-07 10:11:46 +00:00
Daniel James
957818bb97 Merge branch 'develop' 2018-03-06 22:29:30 +00:00
Daniel James
21f32243a8 1.67.0 changes 2018-03-05 14:39:13 +00:00
Daniel James
9fafa9e37b Fix tutorial example (trac #11017)
Extract example into a C++ file, so that it can be tested, unfortunately this
means that it no longer links to the reference documentation.
2018-03-03 18:36:28 +00:00
Daniel James
cc541b71c5 Merge branch 'develop'
- Support std::string_view, std::error_code, std::error_condition,
  std::optional, std::variant, std::monostate
- Improved testing, added appveyor build file
- Move headers from 'container_hash/hash' to 'container_hash', so
  there's not pointless nesting in the new directory layout
2018-02-26 14:07:50 +00:00
Daniel James
d20a68efdb Move headers into top level of container_hash directory 2018-01-27 11:48:59 +00:00
Daniel James
d45e3986f3 Remove forwarding headers in container_hash 2018-01-27 11:47:09 +00:00
Daniel James
1e263669cb Use unsigned for version number in hash_info.cpp
Was getting a `size_t` to `unsigned int` conversion when writing to stream, so
just use `unsigned` from the start.
2018-01-24 13:40:35 +00:00
Daniel James
8ea85f5ad2 Use error codes that are hopefully present on mingw 2018-01-24 13:40:35 +00:00
Daniel James
e01239286c Avoid conversion warning 2018-01-24 12:57:28 +00:00
Daniel James
17809c3cbc Add appveyor tests 2018-01-22 14:46:22 +00:00
Daniel James
8963c38770 Fix hash_info for older Visual C++ 2018-01-22 11:56:43 +00:00
Daniel James
0ad83592af Test g++-7, and display output from hash_info 2018-01-21 21:09:50 +00:00
Daniel James
cb6a0246df Test members in compile_test, rather than inheritance
Inheritance from unary_function is deprecated in recent C++. Better to
check the member types. Could probably drop test altogether.
2018-01-21 21:09:50 +00:00
Daniel James
27b2732916 Make hash_value(monostate) inline 2018-01-21 21:09:50 +00:00
Daniel James
4d9f438823 std::variant, std::monostate support 2018-01-21 19:28:33 +00:00
Daniel James
ddc05d17df std::optional support 2018-01-21 19:28:33 +00:00
Daniel James
b9ae7e7fb6 Clean up header detection for more headers + add optional 2018-01-21 18:21:46 +00:00
Daniel James
42bb81befa Support std::error_code and std::error_condition 2018-01-21 14:31:31 +00:00
Daniel James
f81ee167c5 Add Visual C++ info to hash_info 2018-01-21 11:10:03 +00:00
Daniel James
5c4edf4d7d Fix string_view include on gcc 7.2
If it's included in anything earlier than c++-1z it errors.
2018-01-20 21:53:36 +00:00
Daniel James
b5c3b5d00a Write out __cplusplus in hash_info 2018-01-20 21:53:03 +00:00
Daniel James
def7a785a5 Remove some pointless code 2018-01-20 18:39:46 +00:00
Daniel James
3521c417b5 Small program to write out hash config info 2018-01-20 17:37:55 +00:00
Daniel James
8b77644ea0 Support std::string_view 2018-01-20 17:37:55 +00:00
Daniel James
d41ead127d Merge branch 'develop' 2018-01-14 16:07:58 +00:00
Daniel James
f460c21dd0 Add missing copyright 2018-01-10 15:17:33 +00:00
Daniel James
c3e070a244 Fix some paths 2018-01-10 14:05:25 +00:00
Daniel James
9d5a16c288 Run concurrent test processes in travis 2018-01-06 14:29:05 +00:00
Daniel James
e80c0c84bb Use cxxstd to set language version 2018-01-06 13:51:06 +00:00
Daniel James
c64e516518 Build boost build ourself 2018-01-06 13:50:42 +00:00
Daniel James
b40b795572 Use boost 1.66.0 in travis 2018-01-06 13:45:56 +00:00
Daniel James
8d784ed76d Merge branch 'develop' 2018-01-01 16:02:14 +00:00
Daniel James
6ca88a8146 Add forwarding headers at old locations 2017-12-29 14:12:03 +00:00
Daniel James
53fbb04e88 Move 'functional' headers and update paths 2017-12-29 13:58:48 +00:00
Daniel James
c7fc03d2b9 Rename library in explicit-failures-markup 2017-12-28 23:50:18 +00:00
Daniel James
fc3e0bff4f Add targets for automated doc build 2017-12-28 21:04:48 +00:00
Daniel James
dfa8fa5d91 Merge branch 'develop' 2017-11-11 18:40:05 +00:00
Daniel James
7f3a063064 Merge branch 'develop' 2017-10-27 11:06:13 +01:00
Daniel James
7a6c0f20d5 Merge branch 'develop'
Travis improvements.
2017-09-19 11:08:15 +01:00
Daniel James
955cdaed3d Merge branch 'develop' 2017-06-11 20:49:34 +01:00
Daniel James
4a530f85d0 Merge branch 'develop' 2017-01-01 18:25:51 +00:00
Daniel James
01b81754cf Hash changelog entry 2017-01-01 16:03:48 +00:00
Daniel James
5210c845f5 Link to ticket in changelog 2016-12-05 23:01:20 +00:00
Daniel James
2cdf1c7d9e Add changelog entry for 1.63.0 2016-12-05 22:43:05 +00:00
Daniel James
b9c3499f45 Only support std::wstring when wchar_t is available
This hopefuly fixes #8552.

https://svn.boost.org/trac/boost/ticket/8552
2016-12-05 22:37:45 +00:00
Daniel James
98140b7373 Merge branch 'develop' 2016-10-14 09:24:46 +01:00
Daniel James
9148cde86f Merge branch 'develop' 2016-10-05 09:44:40 +01:00
130 changed files with 10282 additions and 21 deletions

72
.appveyor.yml Normal file
View File

@@ -0,0 +1,72 @@
# Copyright 2017 Daniel James
# Copyright 2016-2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
version: 1.0.{build}-{branch}
shallow_clone: true
branches:
only:
- master
- develop
- /feature\/.*/
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0
ADDRMD: 32
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
TOOLSET: msvc-12.0,msvc-14.0
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: msvc-14.1
CXXSTD: 14,17
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: clang-win
ADDRMD: 64
CXXSTD: 14,17,latest
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: clang-win
CXXSTD: 14,17,latest
ADDRMD: 64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\cygwin\bin;
TOOLSET: gcc
CXXSTD: 03,11,14,1z
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\cygwin64\bin;
TOOLSET: gcc
CXXSTD: 03,11,14,1z
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\mingw\bin;
TOOLSET: gcc
CXXSTD: 03,11,14,1z
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin;
TOOLSET: gcc
CXXSTD: 03,11,14,1z
install:
- set BOOST_BRANCH=develop
- if "%APPVEYOR_REPO_BRANCH%" == "master" set BOOST_BRANCH=master
- cd ..
- git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
- cd boost-root
- git submodule update --init tools/boostdep
- xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\container_hash\
- python tools/boostdep/depinst/depinst.py -I examples container_hash
- cmd /c bootstrap
- b2 -d0 headers
build: off
test_script:
- PATH=%ADDPATH%%PATH%
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
- if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
- b2 -j3 --verbose-test libs/container_hash/test//hash_info toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker
- b2 -j3 libs/container_hash/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker

272
.drone.jsonnet Normal file
View File

@@ -0,0 +1,272 @@
# Copyright 2022 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
local library = "container_hash";
local triggers =
{
branch: [ "master", "develop", "feature/*" ]
};
local ubsan = { UBSAN: '1', UBSAN_OPTIONS: 'print_stacktrace=1' };
local asan = { ASAN: '1' };
local linux_pipeline(name, image, environment, packages = "", sources = [], arch = "amd64") =
{
name: name,
kind: "pipeline",
type: "docker",
trigger: triggers,
platform:
{
os: "linux",
arch: arch
},
steps:
[
{
name: "everything",
image: image,
environment: environment,
commands:
[
'set -e',
'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -',
] +
(if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) +
(if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) +
[
'export LIBRARY=' + library,
'./.drone/drone.sh',
]
}
]
};
local macos_pipeline(name, environment, xcode_version = "12.2", osx_version = "catalina", arch = "amd64") =
{
name: name,
kind: "pipeline",
type: "exec",
trigger: triggers,
platform: {
"os": "darwin",
"arch": arch
},
node: {
"os": osx_version
},
steps: [
{
name: "everything",
environment: environment + { "DEVELOPER_DIR": "/Applications/Xcode-" + xcode_version + ".app/Contents/Developer" },
commands:
[
'export LIBRARY=' + library,
'./.drone/drone.sh',
]
}
]
};
local windows_pipeline(name, image, environment, arch = "amd64") =
{
name: name,
kind: "pipeline",
type: "docker",
trigger: triggers,
platform:
{
os: "windows",
arch: arch
},
"steps":
[
{
name: "everything",
image: image,
environment: environment,
commands:
[
'cmd /C .drone\\\\drone.bat ' + library,
]
}
]
};
[
linux_pipeline(
"Linux 14.04 GCC 4.4",
"cppalliance/droneubuntu1404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-4.4', CXXSTD: '98,0x' },
"g++-4.4",
[ "ppa:ubuntu-toolchain-r/test" ],
),
linux_pipeline(
"Linux 14.04 GCC 4.6 32/64",
"cppalliance/droneubuntu1404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-4.6', CXXSTD: '98,0x', ADDRMD: '32,64' },
"g++-4.6-multilib",
[ "ppa:ubuntu-toolchain-r/test" ],
),
linux_pipeline(
"Linux 14.04 GCC 4.7 32/64",
"cppalliance/droneubuntu1404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-4.7', CXXSTD: '98,0x', ADDRMD: '32,64' },
"g++-4.7-multilib",
[ "ppa:ubuntu-toolchain-r/test" ],
),
linux_pipeline(
"Linux 14.04 GCC 4.8* 32/64",
"cppalliance/droneubuntu1404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 14.04 GCC 4.9 32/64",
"cppalliance/droneubuntu1404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-4.9', CXXSTD: '03,11', ADDRMD: '32,64' },
"g++-4.9-multilib",
[ "ppa:ubuntu-toolchain-r/test" ],
),
linux_pipeline(
"Linux 16.04 GCC 5* 32/64",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 18.04 GCC 7* 32/64",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 20.04 GCC 9* 32/64",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 20.04 GCC 9* ARM64",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
arch="arm64",
),
linux_pipeline(
"Linux 20.04 GCC 9* S390x",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
arch="s390x",
),
linux_pipeline(
"Linux 22.04 GCC 11* 32/64",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 22.04 GCC 12 32 ASAN",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14,17,20,2b', ADDRMD: '32' } + asan,
"g++-12-multilib",
),
linux_pipeline(
"Linux 22.04 GCC 12 64 ASAN",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14,17,20,2b', ADDRMD: '64' } + asan,
"g++-12-multilib",
),
linux_pipeline(
"Linux 16.04 Clang 3.5",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.5', CXXSTD: '03,11' },
"clang-3.5",
),
linux_pipeline(
"Linux 16.04 Clang 3.6",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.6', CXXSTD: '03,11,14' },
"clang-3.6",
),
linux_pipeline(
"Linux 16.04 Clang 3.7",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.7', CXXSTD: '03,11,14' },
"clang-3.7",
),
linux_pipeline(
"Linux 16.04 Clang 3.8",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.8', CXXSTD: '03,11,14' },
"clang-3.8",
),
linux_pipeline(
"Linux 22.04 Clang 14 UBSAN",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20,2b' } + ubsan,
"clang-14",
),
linux_pipeline(
"Linux 22.04 Clang 14 ASAN",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20,2b' } + asan,
"clang-14",
),
linux_pipeline(
"Linux 22.04 Clang 15",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '03,11,14,17,20,2b' },
"clang-15",
["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main"],
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + ubsan,
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 ASAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + asan,
),
windows_pipeline(
"Windows VS2015 msvc-14.0",
"cppalliance/dronevs2015",
{ TOOLSET: 'msvc-14.0', CXXSTD: '14,latest' },
),
windows_pipeline(
"Windows VS2017 msvc-14.1",
"cppalliance/dronevs2017",
{ TOOLSET: 'msvc-14.1', CXXSTD: '14,17,latest' },
),
windows_pipeline(
"Windows VS2019 msvc-14.2",
"cppalliance/dronevs2019",
{ TOOLSET: 'msvc-14.2', CXXSTD: '14,17,20,latest' },
),
windows_pipeline(
"Windows VS2022 msvc-14.3",
"cppalliance/dronevs2022:1",
{ TOOLSET: 'msvc-14.3', CXXSTD: '14,17,20,latest' },
),
]

24
.drone/drone.bat Normal file
View File

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

25
.drone/drone.sh Executable file
View File

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

386
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,386 @@
name: CI
on:
pull_request:
push:
branches:
- master
- develop
- feature/**
env:
UBSAN_OPTIONS: print_stacktrace=1
jobs:
posix:
strategy:
fail-fast: false
matrix:
include:
- toolset: gcc-4.8
cxxstd: "03,11"
os: ubuntu-18.04
install: g++-4.8-multilib
address-model: 32,64
- toolset: gcc-5
cxxstd: "03,11,14,1z"
os: ubuntu-18.04
install: g++-5-multilib
address-model: 32,64
- toolset: gcc-6
cxxstd: "03,11,14,1z"
os: ubuntu-18.04
install: g++-6-multilib
address-model: 32,64
- toolset: gcc-7
cxxstd: "03,11,14,17"
os: ubuntu-18.04
install: g++-7-multilib
address-model: 32,64
- toolset: gcc-8
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
install: g++-8-multilib
address-model: 32,64
- toolset: gcc-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: g++-9-multilib
address-model: 32,64
- toolset: gcc-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: g++-10-multilib
address-model: 32,64
- toolset: gcc-11
cxxstd: "03,11,14,17,20"
os: ubuntu-20.04
install: g++-11-multilib
address-model: 32,64
- toolset: gcc-12
cxxstd: "03,11,14,17,20"
os: ubuntu-22.04
install: g++-12-multilib
address-model: 32,64
- toolset: clang
compiler: clang++-3.9
cxxstd: "03,11,14"
os: ubuntu-18.04
install: clang-3.9
- toolset: clang
compiler: clang++-4.0
cxxstd: "03,11,14"
os: ubuntu-18.04
install: clang-4.0
- toolset: clang
compiler: clang++-5.0
cxxstd: "03,11,14,1z"
os: ubuntu-18.04
install: clang-5.0
- toolset: clang
compiler: clang++-6.0
cxxstd: "03,11,14,17"
os: ubuntu-18.04
install: clang-6.0
- toolset: clang
compiler: clang++-7
cxxstd: "03,11,14,17"
os: ubuntu-18.04
install: clang-7
- toolset: clang
compiler: clang++-8
cxxstd: "03,11,14,17"
os: ubuntu-20.04
install: clang-8
- toolset: clang
compiler: clang++-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: clang-9
- toolset: clang
compiler: clang++-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: clang
compiler: clang++-11
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: clang
compiler: clang++-12
cxxstd: "03,11,14,17,20"
os: ubuntu-20.04
- toolset: clang
compiler: clang++-13
cxxstd: "03,11,14,17,20"
os: ubuntu-22.04
install: clang-13
- toolset: clang
compiler: clang++-14
cxxstd: "03,11,14,17,20"
os: ubuntu-22.04
install: clang-14
- toolset: clang
cxxstd: "03,11,14,17,2a"
os: macos-11
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- 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 -I examples --git_args "--jobs 3" $LIBRARY
./bootstrap.sh
./b2 -d0 headers
- name: Create user-config.jam
if: matrix.compiler
run: |
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
- name: Run tests
run: |
cd ../boost-root
export ADDRMD=${{matrix.address-model}}
./b2 -j3 --verbose-test libs/$LIBRARY/test//hash_info toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} ${ADDRMD:+address-model=$ADDRMD} variant=debug,release
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} ${ADDRMD:+address-model=$ADDRMD} variant=debug,release
windows:
strategy:
fail-fast: false
matrix:
include:
- toolset: msvc-14.0
cxxstd: 14,latest
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.2
cxxstd: "14,17,20,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.3
cxxstd: "14,17,20,latest"
addrmd: 32,64
os: windows-2022
- toolset: clang-win
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2022
- toolset: gcc
cxxstd: "03,11,14,17,2a"
addrmd: 64
os: windows-2019
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py -I examples --git_args "--jobs 3" %LIBRARY%
cmd /c bootstrap
b2 -d0 headers
- name: Run tests
shell: cmd
run: |
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@v3
- 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@v3
- 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@v3
- 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

@@ -8,32 +8,34 @@ dist: trusty
language: c++
addons:
apt:
packages:
- libboost-tools-dev
matrix:
include:
- compiler: gcc
env: |
USER_CONFIG="using gcc : : g++-4.8 -Werror --std=c++03 ;"
- compiler: gcc
USER_CONFIG="using gcc : : g++-4.8 ;"
CXXSTD=03,11
- compiler: g++-7
env: |
USER_CONFIG="using gcc : : g++-4.8 -Werror --std=c++11 ;"
USER_CONFIG="using gcc : : g++-7 ;"
CXXSTD=11,14,17
addons:
apt:
packages:
- g++-7
sources:
- ubuntu-toolchain-r-test
- compiler: clang
env: |
USER_CONFIG="using clang : : clang++ -Werror --std=c++03 ;"
USER_CONFIG="using clang : : clang++ ;"
CXXSTD=03,11
- compiler: clang
env: |
USER_CONFIG="using clang : : clang++ -Werror --std=c++11 ;"
- compiler: clang
env: |
USER_CONFIG="using clang : : clang++ -Werror --std=c++11 -D_HAS_AUTO_PTR_ETC=0 ;"
USER_CONFIG="using clang : : clang++ -D_HAS_AUTO_PTR_ETC=0 ;"
CXXSTD=11
before_script:
- export BOOST_VERSION=1.65.1
- export BOOST_FILENAME=boost_1_65_1
- export BOOST_VERSION=1.67.0
- export BOOST_FILENAME=boost_1_67_0
- export BOOST_ROOT=${HOME}/boost
- cd ${TRAVIS_BUILD_DIR}
- touch Jamroot.jam
@@ -64,9 +66,13 @@ before_script:
cd $HOME/extract
tar -xjf $HOME/download/boost.tar.bz2
mv * ${BOOST_ROOT}
- rm ${BOOST_ROOT}/boost/functional.hpp
- find ${BOOST_ROOT}/boost/functional -type f | grep -v hash | xargs -r rm
- rm -r ${BOOST_ROOT}/boost/functional
- cd ${BOOST_ROOT}/tools/build
- mkdir ${HOME}/opt
- ./bootstrap.sh
- ./b2 install --prefix=$HOME/opt
script:
- cd ${TRAVIS_BUILD_DIR}/test
- bjam -q ${BJAM_TOOLSET} include=${BOOST_ROOT} include=${TRAVIS_BUILD_DIR}/include
- ${HOME}/opt/bin/b2 --verbose-test -j 3 cxxstd=$CXXSTD -q ${BJAM_TOOLSET} include=${BOOST_ROOT} include=${TRAVIS_BUILD_DIR}/include hash_info
- ${HOME}/opt/bin/b2 -j 3 cxxstd=$CXXSTD -q ${BJAM_TOOLSET} include=${BOOST_ROOT} include=${TRAVIS_BUILD_DIR}/include

27
CMakeLists.txt Normal file
View File

@@ -0,0 +1,27 @@
# Generated by `boostdep --cmake container_hash`
# Copyright 2020, 2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.5...3.20)
project(boost_container_hash VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
add_library(boost_container_hash INTERFACE)
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::config
Boost::describe
Boost::mp11
Boost::type_traits
)
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)
endif()

20
README.md Normal file
View File

@@ -0,0 +1,20 @@
# Boost.ContainerHash
The Boost.ContainerHash library, part of [Boost C++ Libraries](https://boost.org),
provides `boost::hash`, an enhanced implementation of the
[hash function](https://en.wikipedia.org/wiki/Hash_function) object specified
by C++11 as `std::hash`, and several support facilities (`hash_combine`,
`hash_range`, `hash_unordered_range`).
`boost::hash` supports most standard types and some user-defined types out of
the box, and is extensible; it's possible for a user-defined type `X` to make
iself hashable via `boost::hash<X>` by defining an appropriate overload of the
function `hash_value`.
See [the documentation of the library](https://www.boost.org/libs/container_hash)
for more information.
## License
Distributed under the
[Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).

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

2
doc/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/html/
/pdf/

22
doc/Jamfile.v2 Normal file
View File

@@ -0,0 +1,22 @@
# Copyright 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)
import asciidoctor ;
html hash.html : hash.adoc ;
install html_ : hash.html : <location>html ;
pdf hash.pdf : hash.adoc ;
explicit hash.pdf ;
install pdf_ : hash.pdf : <location>pdf ;
explicit pdf_ ;
###############################################################################
alias boostdoc ;
explicit boostdoc ;
alias boostrelease : html_ ;
explicit boostrelease ;

30
doc/hash.adoc Normal file
View File

@@ -0,0 +1,30 @@
////
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: 3
:idprefix:
:docinfo: private-footer
:source-highlighter: rouge
:nofooter:
:sectlinks:
:source-language: c++
:leveloffset: +1
include::hash/intro.adoc[]
include::hash/recent.adoc[]
include::hash/tutorial.adoc[]
include::hash/user.adoc[]
include::hash/combine.adoc[]
include::hash/reference.adoc[]
include::hash/notes.adoc[]
include::hash/links.adoc[]
include::hash/thanks.adoc[]
include::hash/changes.adoc[]
include::hash/copyright.adoc[]

161
doc/hash/changes.adoc Normal file
View File

@@ -0,0 +1,161 @@
////
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
:idprefix: changes_
:int128: __int128
== Boost 1.67.0
* Moved library into its own module, `container_hash`.
* Moved headers for new module name, now at: `<boost/container_hash/hash.hpp>`, `<boost/container_hash/hash_fwd.hpp>`, `<boost/container_hash/extensions.hpp>`.
* Added forwarding headers to support the old headers locations.
* Support `std::string_view`, `std::error_code`, `std::error_condition`, `std::optional`, `std::variant`, `std::monostate` where available.
* 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 libc++. Will try to introduce a more general fix in the next release.
== Boost 1.66.0
* Avoid float comparison warning when using Clang - this workaround was already in place for GCC, and was used when Clang pretends to be GCC, but the warning was appearing when running Clang in other contexts.
== 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:
** Improved portablity, as described by Daniel Krügler in http://lists.boost.org/boost-users/2005/08/13418.php[a post to the boost users list].
** Fits more information into each combine loop, which can reduce the the number of times combine is called and hopefully give a better quality hash function.
** Improved the algorithm for hashing floating point numbers.
** On Cygwin use a binary hash function for floating point numbers, as Cygwin doesn't have decent floating point functions for `long double`.
** Never uses `fpclass` which doesn't support `long double`.
** http://svn.boost.org/trac/boost/ticket/1064[Ticket 1064]: Removed unnecessary use of errno.
* Explicitly overload for more built in types.
* Minor improvements to the documentation.
* A few bug and warning fixes:
** 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.
* Add support for the `BOOST_HASH_NO_EXTENSIONS` macro, which disables the extensions to TR1.
* 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

123
doc/hash/combine.adoc Normal file
View File

@@ -0,0 +1,123 @@
////
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:
[source]
----
class point
{
int x;
int y;
public:
point() : x(0), y(0) {}
point(int x, int y) : x(x), y(y) {}
bool operator==(point const& other) const
{
return x == other.x && y == other.y;
}
};
----
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]
----
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);
return 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[examples/point.cpp].
Note that 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);
----
and
[source]
----
std::size_t seed = 0;
boost::hash_combine(seed, 2);
boost::hash_combine(seed, 1);
----
result in a different values in `seed`.
To calculate the hash of an iterator range you can use `boost::hash_range`:
[source]
----
std::vector<std::string> some_strings;
std::size_t hash = boost::hash_range(some_strings.begin(), some_strings.end());
----
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.

18
doc/hash/copyright.adoc Normal file
View File

@@ -0,0 +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:
This documentation is
* Copyright 2005-2008 Daniel James
* Copyright 2022 Peter Dimov
and is distributed under the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].

61
doc/hash/intro.adoc Normal file
View File

@@ -0,0 +1,61 @@
////
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 enhanced implementation of the
https://en.wikipedia.org/wiki/Hash_function[hash function] object specified by
{cpp}11 as `std::hash`. It is the default hash function for
link:../../../unordered/index.html[Boost.Unordered],
link:../../../intrusive/index.html[Boost.Intrusive]'s unordered associative
containers, link:../../../multi_index/index.html[Boost.MultiIndex]'s hash
indices, and link:../../../bimap/index.html[Boost.Bimap]'s `unordered_set_of`.
Out of the box, `boost::hash` supports
* standard integral types (integers, character types, and `bool`);
* standard floating point types (`float`, `double`, `long double`);
* pointers (to objects and to functions, but not pointers to members);
* 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`.
`boost::hash` is extensible; it's possible for a user-defined type `X` to make
iself hashable via `boost::hash<X>` by defining an appropriate overload of the
function `hash_value`. Many, if not most, Boost types already contain the
necessary support.
`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.
`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.

114
doc/hash/links.adoc Normal file
View File

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

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

@@ -0,0 +1,219 @@
////
Copyright 2005-2008 Daniel James
Copyright 2022 Christian Mazakas
Copyright 2022 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#notes]
= Design and Implementation Notes
:idprefix: notes_
== Quality of the Hash Function
Many hash functions strive to have little correlation between the input and
output values. They attempt to uniformally distribute the output values for
very similar inputs. This hash function makes no such attempt. In fact, for
integers, the result of the hash function is often just the input value. So
similar but different input values will often result in similar but different
output values. This means that it is not appropriate as a general hash
function. For example, a hash table may discard bits from the hash function
resulting in likely collisions, or might have poor collision resolution when
hash values are clustered together. In such cases this hash function will
perform poorly.
But the standard has no such requirement for the hash function, it just
requires that the hashes of two different values are unlikely to collide.
Containers or algorithms designed to work with the standard hash function will
have to be implemented to work well when the hash function's output is
correlated to its input. Since they are paying that cost a higher quality hash
function would be wasteful.
== The hash_value Customization Point
The way one customizes the standard `std::hash` function object for user
types is via a specialization. `boost::hash` chooses a different mechanism --
an overload of a free function `hash_value` in the user namespace that is
found via argument-dependent lookup.
Both approaches have their pros and cons. Specializing the function object
is stricter in that it only applies to the exact type, and not to derived
or convertible types. Defining a function, on the other hand, is easier
and more convenient, as it can be done directly in the type definition as
an `inline` `friend`.
The fact that overloads can be invoked via conversions did cause issues in
an earlier iteration of the library that defined `hash_value` for all
integral types separately, including `bool`. Especially under {cpp}03,
which doesn't have `explicit` conversion operators, some types were
convertible to `bool` to allow their being tested in e.g. `if` statements,
which caused them to hash to 0 or 1, rarely what one expects or wants.
This, however, was fixed by declaring the built-in `hash_value` overloads
to be templates constrained on e.g. `std::is_integral` or its moral
equivalent. This causes types convertible to an integral to no longer
match, avoiding the problem.
== hash_combine
The initial implementation of the library was based on Issue 6.18 of the
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf[Library Extension Technical Report Issues List]
(pages 63-67) which proposed the following implementation of `hash_combine`:
[source]
----
template<class T>
void hash_combine(size_t & seed, T const & v)
{
seed ^= hash_value(v) + (seed << 6) + (seed >> 2);
}
----
taken from the paper
"https://people.eng.unimelb.edu.au/jzobel/fulltext/jasist03thz.pdf[Methods for Identifying Versioned and Plagiarised Documents]"
by Timothy C. Hoad and Justin Zobel.
During the Boost formal review, Dave Harris pointed out that this suffers
from the so-called "zero trap"; if `seed` is initially 0, and all the
inputs are 0 (or hash to 0), `seed` remains 0 no matter how many input
values are combined.
This is an undesirable property, because it causes containers of zeroes
to have a zero hash value regardless of their sizes.
To fix this, the arbitrary constant `0x9e3779b9` (the golden ratio in a
32 bit fixed point representation) was added to the computation, yielding
[source]
----
template<class T>
void hash_combine(size_t & seed, T const & v)
{
seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
----
This is what shipped in Boost 1.33, the first release containing the library.
This function was a reasonable compromise between quality and speed for its
time, when the input consisted of ``char``s, but it's less suitable for
combining arbitrary `size_t` inputs.
In Boost 1.56, it was replaced by functions derived from Austin Appleby's
https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash2.cpp#L57-L62[MurmurHash2 hash function round].
In Boost 1.81, it was changed again -- to the equivalent of
`mix(seed + 0x9e3779b9 + hash_value(v))`, where `mix(x)` is a high quality
mixing function that is a bijection over the `size_t` values, of the form
[source]
----
x ^= x >> k1;
x *= m1;
x ^= x >> k2;
x *= m2;
x ^= x >> k3;
----
This type of mixing function was originally devised by Austin Appleby as
the "final mix" part of his MurmurHash3 hash function. He used
[source]
----
x ^= x >> 33;
x *= 0xff51afd7ed558ccd;
x ^= x >> 33;
x *= 0xc4ceb9fe1a85ec53;
x ^= x >> 33;
----
as the https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash2.cpp#L57-L62[64 bit function `fmix64`] and
[source]
----
x ^= x >> 16;
x *= 0x85ebca6b;
x ^= x >> 13;
x *= 0xc2b2ae35;
x ^= x >> 16;
----
as the https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash3.cpp#L68-L77[32 bit function `fmix32`].
Several improvements of the 64 bit function have been subsequently proposed,
by https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html[David Stafford],
https://mostlymangling.blogspot.com/2019/12/stronger-better-morer-moremur-better.html[Pelle Evensen],
and http://jonkagstrom.com/mx3/mx3_rev2.html[Jon Maiga]. We currently use Jon
Maiga's function
[source]
----
x ^= x >> 32;
x *= 0xe9846af9b1a615d;
x ^= x >> 32;
x *= 0xe9846af9b1a615d;
x ^= x >> 28;
----
Under 32 bit, we use a mixing function proposed by "TheIronBorn" in a
https://github.com/skeeto/hash-prospector/issues/19[Github issue] in
the https://github.com/skeeto/hash-prospector[repository] of
https://nullprogram.com/blog/2018/07/31/[Hash Prospector] by Chris Wellons:
[source]
----
x ^= x >> 16;
x *= 0x21f0aaad;
x ^= x >> 15;
x *= 0x735a2d97;
x ^= x >> 15;
----
With this improved `hash_combine`, `boost::hash` for strings now passes the
https://github.com/aappleby/smhasher[SMHasher test suite] by Austin Appleby
(for a 64 bit `size_t`).
== hash_range
The traditional implementation of `hash_range(seed, first, last)` has been
[source]
----
for( ; first != last; ++first )
{
boost::hash_combine<typename std::iterator_traits<It>::value_type>( seed, *first );
}
----
(the explicit template parameter is needed to support iterators with proxy
return types such as `std::vector<bool>::iterator`.)
This is logical, consistent and straightforward. In the common case where
`typename std::iterator_traits<It>::value_type` is `char` -- which it is
in the common case of `boost::hash<std::string>` -- this however leaves a
lot of performance on the table, because processing each `char` individually
is much less efficient than processing several in bulk.
In Boost 1.81, `hash_range` was changed to process elements of type `char`,
`signed char`, `unsigned char`, `std::byte`, or `char8_t`, four of a time.
A `uint32_t` is composed from `first[0]` to `first[3]`, and that `uint32_t`
is fed to `hash_combine`.
In principle, when `size_t` is 64 bit, we could have used `uint64_t` instead.
We do not, because this allows producing an arbitrary hash value by choosing
the input bytes appropriately (because `hash_combine` is reversible.)
Allowing control only over 32 bits of the full 64 bit `size_t` value makes
these "chosen plaintext attacks" harder.
This is not as harmful to performance as it first appears, because the
input to `hash<string>` (e.g. the key in an unordered container) is often
short (9 to 13 bytes in some typical scenarios.)
Note that `hash_range` has also traditionally guaranteed that the same element
sequence yields the same hash value regardless of the iterator type. This
property remains valid after the changes to `char` range hashing. `hash_range`,
applied to the `char` sequence `{ 'a', 'b', 'c' }`, results in the same value
whether the sequence comes from `char[3]`, `std::string`, `std::deque<char>`,
or `std::list<char>`.

29
doc/hash/recent.adoc Normal file
View File

@@ -0,0 +1,29 @@
////
Copyright 2022 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#recent]
= Recent Changes
:idprefix: recent_
== Boost 1.81.0
Major update.
* The specializations of `boost::hash` have been removed; it now
always calls `hash_value`.
* Support for `BOOST_HASH_NO_EXTENSIONS` has been removed. The
extensions are always enabled.
* All standard containers are now supported. This includes
`std::forward_list` and the unordered associative containers.
* User-defined containers (types that have `begin()` and `end()`
member functions that return iterators) are now supported out
of the box.
* `hash_combine` has been improved.
* The performance (and quality, as a result of the above change)
of string hashing has been improved. `boost::hash` for strings
now passes SMHasher in 64 bit mode.
* The documentation has been substantially revised to reflect
the changes.

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

@@ -0,0 +1,635 @@
////
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)`; that is,
it does not lose information from the input. It also implies that
`combine(s, v)`, as a function of `v`, has good avalanche properties;
that is, small (e.g. single bit) perturbations in the input `v` lead to
large perturbations in the return value (half of the output bits changing,
on average).
. For two different seeds `s1` and `s2`, `combine(s1, v)` and
`combine(s2, v)`, treated as functions of `v`, should produce two
different random permutations.
. `combine(0, 0)` should not be 0. Since a common initial value of `seed`
is zero, `combine(0, 0) == 0` would imply that applying `hash_combine` on
any sequence of zeroes, regardless of length, will produce zero. This is
undesirable, as it would lead to e.g. `std::vector<int>()` and
`std::vector<int>(4)` to have the same hash value.
The current implementation uses the function `mix(s + 0x9e3779b9 + v)` as
`combine(s, v)`, where `mix(x)` is a high quality mixing function that is a
bijection over the `std::size_t` values, of the form
[source]
----
x ^= x >> k1;
x *= m1;
x ^= x >> k2;
x *= m2;
x ^= x >> k3;
----
where the constants `k1`, `k2`, `k3`, `m1`, `m2` are suitably chosen.
Note that `mix(0)` is 0. This is why we add the arbitrary constant
`0x9e3779b9` to meet the third requirement above.
--
=== hash_range
[source]
----
template<class It> void hash_range( std::size_t& seed, It first, It last );
----
Effects: ::
+
--
When `typename std::iterator_traits<It>::value_type` is not `char`, `signed char`,
`unsigned char`, `std::byte`, or `char8_t`,
[source]
----
for( ; first != last; ++first )
{
boost::hash_combine<typename std::iterator_traits<It>::value_type>( seed, *first );
}
----
Otherwise, bytes from `[first, last)` are coalesced in an unspecified manner
and then passed to `hash_combine`, more than one at a time. This is done in
order to improve performance when hashing strings.
--
[source]
----
template<class It> std::size_t hash_range( It first, It last );
----
Effects: ::
+
[source]
----
size_t seed = 0;
boost::hash_range( seed, first, last );
return seed;
----
=== hash_unordered_range
[source]
----
template<class It> void hash_unordered_range( std::size_t& seed, It first, It last );
----
Effects: :: Updates `seed` with the values of
`boost::hash<typename std::iterator_traits<It>::value_type>()(*i)`
for each `i` in `[first, last)`, such that the order of elements does
not affect the final result.
[source]
----
template<class It> std::size_t hash_unordered_range( It first, It last );
----
Effects: ::
+
[source]
----
size_t seed = 0;
boost::hash_unordered_range( seed, first, last );
return seed;
----
=== hash_value
[source]
----
// Enabled only when T is an integral type
template<class T>
std::size_t hash_value( T v );
----
Returns: ::
When the value of `v` fits into `std::size_t`, when `T` is an unsigned type,
or into `ssize_t`, when `T` is a signed type, `static_cast<std::size_t>(v)`.
+
Otherwise, an unspecified value obtained by mixing the value bits of `v`.
[source]
----
// Enabled only when T is an enumeration type
template<class T>
std::size_t hash_value( T v );
----
Returns: ::
`static_cast<std::size_t>(v)`.
Remarks: ::
`hash_value(std::to_underlying(v))` would be better, but {cpp}03
compatibility mandates the current implementation.
[source]
----
// Enabled only when T is a floating point type
template<class T>
std::size_t hash_value( T v );
----
Returns: ::
An unspecified value obtained by mixing the value bits of `v`.
Remarks: ::
When `sizeof(v) \<= sizeof(std::size_t)`, the bits of `v` are returned
as-is (except in the case of -0.0, which is treated as +0.0).
[source]
----
template<class T>
std::size_t hash_value( T* const& v );
----
Returns: ::
An unspecified value derived from `reinterpret_cast<std::uintptr_t>(v)`.
[source]
----
template<class T, std::size_t N>
std::size_t hash_value( T const (&v)[N] );
----
Returns: ::
`boost::hash_range( v, v + N )`.
[source]
----
template<class T>
std::size_t hash_value( std::complex<T> const& v );
----
Returns: ::
An unspecified value derived from `boost::hash<T>()(v.real())` and
`boost::hash<T>()(v.imag())` such that, if `v.imag() == 0`, the value
is equal to `boost::hash<T>()(v.real())`.
Remarks: ::
A more straightforward implementation would just have used `hash_combine`
on `v.real()` and `v.imag()`, but the historical guarantee that real-valued
complex numbers should match the hash value of their real part precludes it.
+
This guarantee may be dropped in a future release, as it's of questionable
utility.
[source]
----
template<class A, class B>
std::size_t hash_value( std::pair<A, B> const& v );
----
Effects: ::
+
[source]
----
std::size_t seed = 0;
boost::hash_combine( seed, v.first );
boost::hash_combine( seed, v.second );
return seed;
----
[source]
----
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: ::
`boost::hash_range( v.begin(), v.end() )`.
Remarks: ::
This overload is only enabled when
`container_hash::is_contiguous_range<T>::value` and
`container_hash::is_unordered_range<T>::value` are both `false`.
+
It handles all standard containers that aren't contiguous or unordered, such
as `std::deque`, `std::list`, `std::set`, `std::map`.
[source]
----
// Enabled only when container_hash::is_contiguous_range<T>::value is true
template<class T>
std::size_t hash_value( T const& v );
----
Returns: ::
`boost::hash_range( v.data(), v.data() + v.size() )`.
Remarks: ::
This overload handles all standard contiguous containers, such as
`std::string`, `std::vector`, `std::array`, `std::string_view`.
[source]
----
// Enabled only when container_hash::is_unordered_range<T>::value is true
template<class T>
std::size_t hash_value( T const& v );
----
Returns: ::
`boost::hash_unordered_range( v.begin(), v.end() )`.
Remarks: ::
This overload handles the standard unordered containers, such as
`std::unordered_set` and `std::unordered_map`.
[source]
----
template<class T>
std::size_t hash_value( std::shared_ptr<T> const& v );
template<class T, class D>
std::size_t hash_value( std::unique_ptr<T, D> const& v );
----
Returns: ::
`boost::hash<T*>( v.get() )`.
[source]
----
std::size_t hash_value( std::type_index const& v );
----
Returns: ::
`v.hash_code()`.
[source]
----
std::size_t hash_value( std::error_code const& v );
std::size_t hash_value( std::error_condition const& v );
----
Effects: ::
+
[source]
----
std::size_t seed = 0;
boost::hash_combine( seed, v.value() );
boost::hash_combine( seed, &v.category() );
return seed;
----
[source]
----
template<class T>
std::size_t hash_value( std::optional<T> const& v );
----
Returns: ::
For a disengaged `v`, an unspecified constant value; otherwise,
`boost::hash<T>()( *v )`.
[source]
----
std::size_t hash_value( std::monostate v );
----
Returns: ::
An unspecified constant value.
[source]
----
template<class... T>
std::size_t hash_value( std::variant<T...> const& v );
----
Effects: ::
+
[source]
----
std::size_t seed = 0;
boost::hash_combine( seed, v.index() );
boost::hash_combine( seed, x );
return seed;
----
+
where `x` is the currently contained value in `v`.
Throws: ::
`std::bad_variant_access` when `v.valueless_by_exception()` is `true`.
== <boost/container_hash/{zwsp}is_range.hpp>
Defines the trait `boost::container_hash::is_range`.
[source]
----
namespace boost
{
namespace container_hash
{
template<class T> struct is_range;
} // namespace container_hash
} // namespace boost
----
=== is_range<T>
[source]
----
template<class T> struct is_range
{
static constexpr bool value = /* see below */;
};
----
`is_range<T>::value` is `true` when, for a const value `x` of type
`T`, `x.begin()` and `x.end()` return iterators of the same type
`It` (such that `std::iterator_traits<It>` is a valid specialization.)
Users are allowed to specialize `is_range` for their types if the
default behavior does not deduce the correct value.
== <boost/container_hash/{zwsp}is_contiguous_range.hpp>
Defines the trait `boost::container_hash::is_contiguous_range`.
[source]
----
namespace boost
{
namespace container_hash
{
template<class T> struct is_contiguous_range;
} // namespace container_hash
} // namespace boost
----
=== is_contiguous_range<T>
[source]
----
template<class T> struct is_contiguous_range
{
static constexpr bool value = /* see below */;
};
----
`is_contiguous_range<T>::value` is `true` when `is_range<T>::value` is
`true` and when, for a const value `x` of type `T`, `x.data()` returns
a pointer to a type that matches the `value_type` of the iterator returned
by `x.begin()` and `x.end()`, and `x.size()` returns a value of an integral
type.
Users are allowed to specialize `is_contiguous_range` for their types
if the default behavior does not deduce the correct value.
== <boost/container_hash/{zwsp}is_unordered_range.hpp>
Defines the trait `boost::container_hash::is_unordered_range`.
[source]
----
namespace boost
{
namespace container_hash
{
template<class T> struct is_unordered_range;
} // namespace container_hash
} // namespace boost
----
=== is_unordered_range<T>
[source]
----
template<class T> struct is_unordered_range
{
static constexpr bool value = /* see below */;
};
----
`is_unordered_range<T>::value` is `true` when `is_range<T>::value` is
`true` and when `T::hasher` is a valid type.
Users are allowed to specialize `is_unordered_range` for their types
if the default behavior does not deduce the correct value.

23
doc/hash/thanks.adoc Normal file
View File

@@ -0,0 +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
////
[#thanks]
= Acknowledgements
:idprefix: thanks_
This library is based on the design by Peter Dimov. During the initial development Joaquín M López Muñoz made many useful suggestions and contributed fixes.
The formal review was managed by Thorsten Ottosen, and the library reviewed by: David Abrahams, Alberto Barbati, Topher Cooper, Caleb Epstein, Dave Harris, Chris Jefferson, Bronek Kozicki, John Maddock, Tobias Swinger, Jaap Suter, Rob Stewart and Pavel Vozenilek. Since then, further constructive criticism has been made by Daniel Krügler, Alexander Nasonov and 沈慧峰.
The implementation of the hash function for pointers is based on suggestions made by Alberto Barbati and Dave Harris. Dave Harris also suggested an important improvement to `boost::hash_combine` that was taken up.
Some useful improvements to the floating point hash algorithm were suggested by Daniel Krügler.
The original implementation came from Jeremy B. Maitin-Shepard's hash table library, although this is a complete rewrite.
The documentation was converted from Quickbook to AsciiDoc by Christian Mazakas.

72
doc/hash/tutorial.adoc Normal file
View File

@@ -0,0 +1,72 @@
////
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 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 you wish to use `boost::hash` with the standard unordered associative
containers, pass it as a template parameter:
[source]
----
std::unordered_multiset<int, boost::hash<int> >
set_of_ints;
std::unordered_set<std::pair<int, int>, boost::hash<std::pair<int, int> > >
set_of_pairs;
std::unordered_map<int, std::string, boost::hash<int> > map_int_to_string;
----
To use `boost::hash` directly, create an instance and call it as a function:
[source]
----
#include <boost/container_hash/hash.hpp>
int main()
{
boost::hash<std::string> string_hash;
std::size_t h = string_hash("Hash me");
}
----
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]
----
template <class Container>
std::vector<std::size_t> get_hashes(Container const& x)
{
std::vector<std::size_t> hashes;
std::transform(x.begin(), x.end(), std::back_inserter(hashes),
boost::hash<typename Container::value_type>());
return hashes;
}
----

86
doc/hash/user.adoc Normal file
View File

@@ -0,0 +1,86 @@
////
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
////
[#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 user type, it will get called.
If you have a structure `library::book`, where each book is uniquely defined
by its member `id`:
[source]
----
namespace library
{
struct book
{
int id;
std::string author;
std::string title;
// ....
};
bool operator==(book const& a, book const& b)
{
return a.id == b.id;
}
}
----
Then all you would need to do is write the function `library::hash_value`:
[source]
----
namespace library
{
std::size_t hash_value(book const& b)
{
boost::hash<int> hasher;
return hasher(b.id);
}
}
----
And you can now use `boost::hash` with book:
[source]
----
library::book knife(3458, "Zane Grey", "The Hash Knife Outfit");
library::book dandelion(1354, "Paul J. Shanley",
"Hash & Dandelion Greens");
boost::hash<library::book> book_hasher;
std::size_t knife_hash_value = book_hasher(knife);
// If std::unordered_set is 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"));
assert(books.find(knife) != books.end());
assert(books.find(dandelion) == books.end());
----
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 `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).

9
examples/Jamfile.v2 Normal file
View File

@@ -0,0 +1,9 @@
# Copyright Daniel James 2005. Use, modification, and distribution are
# subject to the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
run books.cpp ;
run point.cpp ;
run portable.cpp ;
run template.cpp : : : <toolset>msvc-8.0:<build>no ;

60
examples/books.cpp Normal file
View File

@@ -0,0 +1,60 @@
// 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)
// 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 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.
int main()
{
library::book knife(3458, "Zane Grey", "The Hash Knife Outfit");
library::book dandelion(1354, "Paul J. Shanley", "Hash & Dandelion Greens");
boost::hash<library::book> book_hasher;
std::size_t knife_hash_value = book_hasher(knife);
(void)knife_hash_value; // suppress unused variable warning
// If std::unordered_set is available:
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET)
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"));
assert(books.find(knife) != books.end());
assert(books.find(dandelion) == books.end());
#endif
}
namespace library
{
bool operator==(book const& a, book const& b)
{
return a.id == b.id;
}
std::size_t hash_value(book const& b)
{
boost::hash<int> hasher;
return hasher(b.id);
}
}

26
examples/books.hpp Normal file
View File

@@ -0,0 +1,26 @@
// 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)
// This example illustrates how to use boost::hash with a custom hash function.
// The implementation is contained in books.cpp
#include <cstddef>
#include <string>
namespace library
{
struct book
{
int id;
std::string author;
std::string title;
book(int i, std::string const& a, std::string const& t)
: id(i), author(a), title(t) {}
};
bool operator==(book const&, book const&);
std::size_t hash_value(book const&);
}

62
examples/point.cpp Normal file
View File

@@ -0,0 +1,62 @@
// Copyright 2005 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)
// Force use of assert.
#if defined(NDEBUG)
#undef NDEBUG
#endif
#include <boost/container_hash/hash.hpp>
#include <cassert>
// This example illustrates how to use boost::hash_combine to generate a hash
// value from the different members of a class. For full details see the hash
// tutorial.
class point
{
int x;
int y;
public:
point() : x(0), y(0) {}
point(int x, int y) : x(x), y(y) {}
bool operator==(point const& other) const
{
return x == other.x && y == other.y;
}
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);
return seed;
}
};
int main()
{
boost::hash<point> point_hasher;
point p1(0, 0);
point p2(1, 2);
point p3(4, 1);
point p4 = p1;
assert(point_hasher(p1) == point_hasher(p4));
// These tests could legally fail, but if they did it'd be a pretty bad
// hash function.
assert(point_hasher(p1) != point_hasher(p2));
assert(point_hasher(p1) != point_hasher(p3));
return 0;
}

59
examples/portable.cpp Normal file
View File

@@ -0,0 +1,59 @@
// 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)
// Force use of assert.
#if defined(NDEBUG)
#undef NDEBUG
#endif
#include <boost/container_hash/hash.hpp>
#include <cassert>
// This example illustrates how to customise boost::hash portably, so that
// it'll work on both compilers that don't implement argument dependent lookup
// and compilers that implement strict two-phase template instantiation.
namespace foo
{
template <class T>
class custom_type
{
T value;
public:
custom_type(T x) : value(x) {}
std::size_t hash() const
{
boost::hash<T> hasher;
return hasher(value);
}
};
}
#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();
}
}
int main()
{
foo::custom_type<int> x(1), y(2), z(1);
boost::hash<foo::custom_type<int> > hasher;
assert(hasher(x) == hasher(x));
assert(hasher(x) != hasher(y));
assert(hasher(x) == hasher(z));
return 0;
}

23
examples/template.cpp Normal file
View File

@@ -0,0 +1,23 @@
// Copyright 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)
// Force use of assert.
#if defined(NDEBUG)
#undef NDEBUG
#endif
#include "template.hpp"
#include <boost/unordered_set.hpp>
#include <cassert>
int main()
{
typedef my_pair<int, float> pair;
boost::unordered_set<pair> pair_set;
pair_set.emplace(10, 0.5f);
assert(pair_set.find(pair(10, 0.5f)) != pair_set.end());
assert(pair_set.find(pair(10, 0.6f)) == pair_set.end());
}

38
examples/template.hpp Normal file
View File

@@ -0,0 +1,38 @@
// Copyright 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)
// This is an example of how to write a hash function for a template
// class.
#include <boost/container_hash/hash_fwd.hpp>
template <typename A, typename B>
class my_pair
{
A value1;
B value2;
public:
my_pair(A const& v1, B const& v2)
: value1(v1), value2(v2)
{}
bool operator==(my_pair const& other) const
{
return value1 == other.value1 &&
value2 == other.value2;
}
friend std::size_t hash_value(my_pair const& p)
{
std::size_t seed = 0;
boost::hash_combine(seed, p.value1);
boost::hash_combine(seed, p.value2);
return seed;
}
};

View File

@@ -0,0 +1,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,173 @@
// 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 {};
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
template<> struct is_char_type<char8_t>: public boost::true_type {};
#endif
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
template<> struct is_char_type<std::byte>: public boost::true_type {};
#endif
#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

@@ -0,0 +1,19 @@
// 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)
#ifndef BOOST_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER
#define BOOST_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER
#include <limits>
namespace boost
{
namespace hash_detail
{
template <class T>
struct limits : std::numeric_limits<T> {};
}
}
#endif // #ifndef BOOST_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER

View File

@@ -0,0 +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)
#ifndef BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP
#define BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP
#include <boost/container_hash/hash.hpp>
#endif // #ifndef BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP

View File

@@ -0,0 +1,634 @@
// Copyright 2005-2014 Daniel James.
// Copyright 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
// Based on Peter Dimov's proposal
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
// issue 6.18.
#ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP
#define BOOST_FUNCTIONAL_HASH_HASH_HPP
#include <boost/container_hash/hash_fwd.hpp>
#include <boost/container_hash/is_range.hpp>
#include <boost/container_hash/is_contiguous_range.hpp>
#include <boost/container_hash/is_unordered_range.hpp>
#include <boost/container_hash/is_described_class.hpp>
#include <boost/container_hash/detail/hash_tuple.hpp>
#include <boost/container_hash/detail/hash_mix.hpp>
#include <boost/container_hash/detail/hash_range.hpp>
#include <boost/type_traits/is_enum.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/is_floating_point.hpp>
#include <boost/type_traits/is_signed.hpp>
#include <boost/type_traits/is_unsigned.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/type_traits/enable_if.hpp>
#include <boost/type_traits/conjunction.hpp>
#include <boost/type_traits/is_union.hpp>
#include <boost/describe/bases.hpp>
#include <boost/describe/members.hpp>
#include <boost/cstdint.hpp>
#if defined(BOOST_DESCRIBE_CXX14)
# include <boost/mp11/algorithm.hpp>
#endif
#include <string>
#include <iterator>
#include <complex>
#include <utility>
#include <limits>
#include <climits>
#include <cstring>
#if !defined(BOOST_NO_CXX11_SMART_PTR)
# include <memory>
#endif
#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
#include <typeindex>
#endif
#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
#include <system_error>
#endif
#if !defined(BOOST_NO_CXX17_HDR_OPTIONAL)
#include <optional>
#endif
#if !defined(BOOST_NO_CXX17_HDR_VARIANT)
#include <variant>
#endif
namespace boost
{
//
// boost::hash_value
//
// integral types
namespace hash_detail
{
template<class T,
bool bigger_than_size_t = (sizeof(T) > sizeof(std::size_t)),
bool is_unsigned = boost::is_unsigned<T>::value,
std::size_t size_t_bits = sizeof(std::size_t) * CHAR_BIT,
std::size_t type_bits = sizeof(T) * CHAR_BIT>
struct hash_integral_impl;
template<class T, bool is_unsigned, std::size_t size_t_bits, std::size_t type_bits> struct hash_integral_impl<T, false, is_unsigned, size_t_bits, type_bits>
{
static std::size_t fn( T v )
{
return static_cast<std::size_t>( v );
}
};
template<class T, std::size_t size_t_bits, std::size_t type_bits> struct hash_integral_impl<T, true, false, size_t_bits, type_bits>
{
static std::size_t fn( T v )
{
typedef typename boost::make_unsigned<T>::type U;
if( v >= 0 )
{
return hash_integral_impl<U>::fn( static_cast<U>( v ) );
}
else
{
return ~hash_integral_impl<U>::fn( static_cast<U>( ~static_cast<U>( v ) ) );
}
}
};
template<class T> struct hash_integral_impl<T, true, true, 32, 64>
{
static std::size_t fn( T v )
{
std::size_t seed = 0;
seed = static_cast<std::size_t>( v >> 32 ) + hash_detail::hash_mix( seed );
seed = static_cast<std::size_t>( v ) + hash_detail::hash_mix( seed );
return seed;
}
};
template<class T> struct hash_integral_impl<T, true, true, 32, 128>
{
static std::size_t fn( T v )
{
std::size_t seed = 0;
seed = static_cast<std::size_t>( v >> 96 ) + hash_detail::hash_mix( seed );
seed = static_cast<std::size_t>( v >> 64 ) + hash_detail::hash_mix( seed );
seed = static_cast<std::size_t>( v >> 32 ) + hash_detail::hash_mix( seed );
seed = static_cast<std::size_t>( v ) + hash_detail::hash_mix( seed );
return seed;
}
};
template<class T> struct hash_integral_impl<T, true, true, 64, 128>
{
static std::size_t fn( T v )
{
std::size_t seed = 0;
seed = static_cast<std::size_t>( v >> 64 ) + hash_detail::hash_mix( seed );
seed = static_cast<std::size_t>( v ) + hash_detail::hash_mix( seed );
return seed;
}
};
} // namespace hash_detail
template <typename T>
typename boost::enable_if_<boost::is_integral<T>::value, std::size_t>::type
hash_value( T v )
{
return hash_detail::hash_integral_impl<T>::fn( v );
}
// enumeration types
template <typename T>
typename boost::enable_if_<boost::is_enum<T>::value, std::size_t>::type
hash_value( T v )
{
// This should in principle return the equivalent of
//
// boost::hash_value( to_underlying(v) );
//
// However, the C++03 implementation of underlying_type,
//
// conditional<is_signed<T>, make_signed<T>, make_unsigned<T>>::type::type
//
// generates a legitimate -Wconversion warning in is_signed,
// because -1 is not a valid enum value when all the enumerators
// are nonnegative.
//
// So the legacy implementation will have to do for now.
return static_cast<std::size_t>( v );
}
// floating point types
namespace hash_detail
{
template<class T,
std::size_t Bits = sizeof(T) * CHAR_BIT,
int Digits = std::numeric_limits<T>::digits>
struct hash_float_impl;
// float
template<class T, int Digits> struct hash_float_impl<T, 32, Digits>
{
static std::size_t fn( T v )
{
boost::uint32_t w;
std::memcpy( &w, &v, sizeof( v ) );
return w;
}
};
// double
template<class T, int Digits> struct hash_float_impl<T, 64, Digits>
{
static std::size_t fn( T v )
{
boost::uint64_t w;
std::memcpy( &w, &v, sizeof( v ) );
return hash_value( w );
}
};
// 80 bit long double in 12 bytes
template<class T> struct hash_float_impl<T, 96, 64>
{
static std::size_t fn( T v )
{
boost::uint64_t w[ 2 ] = {};
std::memcpy( &w, &v, 80 / CHAR_BIT );
std::size_t seed = 0;
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
return seed;
}
};
// 80 bit long double in 16 bytes
template<class T> struct hash_float_impl<T, 128, 64>
{
static std::size_t fn( T v )
{
boost::uint64_t w[ 2 ] = {};
std::memcpy( &w, &v, 80 / CHAR_BIT );
std::size_t seed = 0;
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
return seed;
}
};
// 128 bit long double
template<class T, int Digits> struct hash_float_impl<T, 128, Digits>
{
static std::size_t fn( T v )
{
boost::uint64_t w[ 2 ];
std::memcpy( &w, &v, sizeof( v ) );
std::size_t seed = 0;
#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
#else
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
#endif
return seed;
}
};
} // namespace hash_detail
template <typename T>
typename boost::enable_if_<boost::is_floating_point<T>::value, std::size_t>::type
hash_value( T v )
{
return boost::hash_detail::hash_float_impl<T>::fn( v + 0 );
}
// pointer types
// `x + (x >> 3)` adjustment by Alberto Barbati and Dave Harris.
template <class T> std::size_t hash_value( T* const& v )
{
boost::uintptr_t x = reinterpret_cast<boost::uintptr_t>( v );
return boost::hash_value( x + (x >> 3) );
}
// array types
template<class T, std::size_t N>
inline std::size_t hash_value( T const (&x)[ N ] )
{
return boost::hash_range( x, x + N );
}
template<class T, std::size_t N>
inline std::size_t hash_value( T (&x)[ N ] )
{
return boost::hash_range( x, x + N );
}
// complex
template <class T>
std::size_t hash_value( std::complex<T> const& v )
{
std::size_t re = boost::hash<T>()( v.real() );
std::size_t im = boost::hash<T>()( v.imag() );
return re + hash_detail::hash_mix( im );
}
// pair
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;
}
// ranges (list, set, deque...)
template <typename T>
typename boost::enable_if_<container_hash::is_range<T>::value && !container_hash::is_contiguous_range<T>::value && !container_hash::is_unordered_range<T>::value, std::size_t>::type
hash_value( T const& v )
{
return boost::hash_range( v.begin(), v.end() );
}
// contiguous ranges (string, vector, array)
template <typename T>
typename boost::enable_if_<container_hash::is_contiguous_range<T>::value, std::size_t>::type
hash_value( T const& v )
{
return boost::hash_range( v.data(), v.data() + v.size() );
}
// unordered ranges (unordered_set, unordered_map)
template <typename T>
typename boost::enable_if_<container_hash::is_unordered_range<T>::value, std::size_t>::type
hash_value( T const& v )
{
return boost::hash_unordered_range( v.begin(), v.end() );
}
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ( \
( defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142 ) || \
( !defined(_MSVC_STL_VERSION) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520 ) )
// resolve ambiguity with unconstrained stdext::hash_value in <xhash> :-/
template<template<class...> class L, class... T>
typename boost::enable_if_<container_hash::is_range<L<T...>>::value && !container_hash::is_contiguous_range<L<T...>>::value && !container_hash::is_unordered_range<L<T...>>::value, std::size_t>::type
hash_value( L<T...> const& v )
{
return boost::hash_range( v.begin(), v.end() );
}
// contiguous ranges (string, vector, array)
template<template<class...> class L, class... T>
typename boost::enable_if_<container_hash::is_contiguous_range<L<T...>>::value, std::size_t>::type
hash_value( L<T...> const& v )
{
return boost::hash_range( v.data(), v.data() + v.size() );
}
template<template<class, std::size_t> class L, class T, std::size_t N>
typename boost::enable_if_<container_hash::is_contiguous_range<L<T, N>>::value, std::size_t>::type
hash_value( L<T, N> const& v )
{
return boost::hash_range( v.data(), v.data() + v.size() );
}
// unordered ranges (unordered_set, unordered_map)
template<template<class...> class L, class... T>
typename boost::enable_if_<container_hash::is_unordered_range<L<T...>>::value, std::size_t>::type
hash_value( L<T...> const& v )
{
return boost::hash_unordered_range( v.begin(), v.end() );
}
#endif
// described classes
#if defined(BOOST_DESCRIBE_CXX14)
#if defined(_MSC_VER) && _MSC_VER == 1900
# pragma warning(push)
# pragma warning(disable: 4100) // unreferenced formal parameter
#endif
template <typename T>
typename boost::enable_if_<container_hash::is_described_class<T>::value, std::size_t>::type
hash_value( T const& v )
{
static_assert( !boost::is_union<T>::value, "described unions are not supported" );
std::size_t r = 0;
using Bd = describe::describe_bases<T, describe::mod_any_access>;
mp11::mp_for_each<Bd>([&](auto D){
using B = typename decltype(D)::type;
boost::hash_combine( r, (B const&)v );
});
using Md = describe::describe_members<T, describe::mod_any_access>;
mp11::mp_for_each<Md>([&](auto D){
boost::hash_combine( r, v.*D.pointer );
});
return r;
}
#if defined(_MSC_VER) && _MSC_VER == 1900
# pragma warning(pop)
#endif
#endif
// std::unique_ptr, std::shared_ptr
#if !defined(BOOST_NO_CXX11_SMART_PTR)
template <typename T>
std::size_t hash_value( std::shared_ptr<T> const& x )
{
return boost::hash_value( x.get() );
}
template <typename T, typename Deleter>
std::size_t hash_value( std::unique_ptr<T, Deleter> const& x )
{
return boost::hash_value( x.get() );
}
#endif
// std::type_index
#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
inline std::size_t hash_value( std::type_index const& v )
{
return v.hash_code();
}
#endif
// std::error_code, std::error_condition
#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
inline std::size_t hash_value( std::error_code const& v )
{
std::size_t seed = 0;
boost::hash_combine( seed, v.value() );
boost::hash_combine( seed, &v.category() );
return seed;
}
inline std::size_t hash_value( std::error_condition const& v )
{
std::size_t seed = 0;
boost::hash_combine( seed, v.value() );
boost::hash_combine( seed, &v.category() );
return seed;
}
#endif
// std::optional
#if !defined(BOOST_NO_CXX17_HDR_OPTIONAL)
template <typename T>
std::size_t hash_value( std::optional<T> const& v )
{
if( !v )
{
// Arbitray value for empty optional.
return 0x12345678;
}
else
{
return boost::hash<T>()(*v);
}
}
#endif
// std::variant
#if !defined(BOOST_NO_CXX17_HDR_VARIANT)
inline std::size_t hash_value( std::monostate )
{
return 0x87654321;
}
template <typename... Types>
std::size_t hash_value( std::variant<Types...> const& v )
{
std::size_t seed = 0;
hash_combine( seed, v.index() );
std::visit( [&seed](auto&& x) { hash_combine(seed, x); }, v );
return seed;
}
#endif
//
// boost::hash_combine
//
template <class T>
inline void hash_combine( std::size_t& seed, T const& v )
{
seed = boost::hash_detail::hash_mix( seed + 0x9e3779b9 + boost::hash<T>()( v ) );
}
//
// boost::hash_range
//
template <class It>
inline void hash_range( std::size_t& seed, It first, It last )
{
seed = hash_detail::hash_range( seed, first, last );
}
template <class It>
inline std::size_t hash_range( It first, It last )
{
std::size_t seed = 0;
hash_range( seed, first, last );
return seed;
}
//
// boost::hash_unordered_range
//
template <class It>
inline void hash_unordered_range( std::size_t& seed, It first, It last )
{
std::size_t r = 0;
std::size_t const s2( seed );
for( ; first != last; ++first )
{
std::size_t s3( s2 );
hash_combine<typename std::iterator_traits<It>::value_type>( s3, *first );
r += s3;
}
seed += r;
}
template <class It>
inline std::size_t hash_unordered_range( It first, It last )
{
std::size_t seed = 0;
hash_unordered_range( seed, first, last );
return seed;
}
//
// boost::hash
//
template <class T> struct hash
{
typedef T argument_type;
typedef std::size_t result_type;
std::size_t operator()( T const& val ) const
{
return hash_value( val );
}
};
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ( \
( defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142 ) || \
( !defined(_MSVC_STL_VERSION) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520 ) )
// Dinkumware has stdext::hash_value for basic_string in <xhash> :-/
template<class E, class T, class A> struct hash< std::basic_string<E, T, A> >
{
typedef std::basic_string<E, T, A> argument_type;
typedef std::size_t result_type;
std::size_t operator()( std::basic_string<E, T, A> const& val ) const
{
return boost::hash_value( val );
}
};
#endif
}
#endif // #ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP

View File

@@ -0,0 +1,36 @@
// Copyright 2005-2009 Daniel James.
// Copyright 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_FUNCTIONAL_HASH_FWD_HPP
#define BOOST_FUNCTIONAL_HASH_FWD_HPP
#include <cstddef>
namespace boost
{
namespace container_hash
{
template<class T> struct is_range;
template<class T> struct is_contiguous_range;
template<class T> struct is_unordered_range;
template<class T> struct is_described_class;
} // namespace container_hash
template<class T> struct hash;
template<class T> void hash_combine( std::size_t& seed, T const& v );
template<class It> void hash_range( std::size_t&, It, It );
template<class It> std::size_t hash_range( It, It );
template<class It> void hash_unordered_range( std::size_t&, It, It );
template<class It> std::size_t hash_unordered_range( It, It );
} // namespace boost
#endif // #ifndef BOOST_FUNCTIONAL_HASH_FWD_HPP

View File

@@ -0,0 +1,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) && !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/declval.hpp>
#include <boost/type_traits/is_same.hpp>
#include <iterator>
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,38 @@
// Copyright 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_HASH_IS_DESCRIBED_CLASS_HPP_INCLUDED
#define BOOST_HASH_IS_DESCRIBED_CLASS_HPP_INCLUDED
#include <boost/type_traits/integral_constant.hpp>
#include <boost/type_traits/is_union.hpp>
#include <boost/describe/bases.hpp>
#include <boost/describe/members.hpp>
namespace boost
{
namespace container_hash
{
#if defined(BOOST_DESCRIBE_CXX11)
template<class T> struct is_described_class: boost::integral_constant<bool,
describe::has_describe_bases<T>::value &&
describe::has_describe_members<T>::value &&
!boost::is_union<T>::value>
{
};
#else
template<class T> struct is_described_class: boost::false_type
{
};
#endif
} // namespace container_hash
} // namespace boost
#endif // #ifndef BOOST_HASH_IS_DESCRIBED_CLASS_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

View File

@@ -0,0 +1,6 @@
// 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)
#include <boost/container_hash/hash.hpp>

View File

@@ -0,0 +1,6 @@
// Copyright 2017 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 <boost/container_hash/extensions.hpp>

View File

@@ -0,0 +1,6 @@
// 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)
#include <boost/container_hash/hash.hpp>

View File

@@ -0,0 +1,6 @@
// 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)
#include <boost/container_hash/hash_fwd.hpp>

View File

@@ -0,0 +1,6 @@
// 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)
#include <boost/container_hash/hash_fwd.hpp>

View File

@@ -7,10 +7,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
<html>
<head>
<meta http-equiv="refresh" content="0; URL=../../doc/html/hash.html">
<meta http-equiv="refresh" content="0; URL=doc/html/hash.html">
</head>
<body>
Automatic redirection failed, please go to
<a href="../../doc/html/hash.html">../../doc/html/hash.html</a>
<a href="doc/html/hash.html">doc/html/hash.html</a>
</body>
</html>

View File

@@ -1,3 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018 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)
-->
<explicit-failures-markup>
<!-- container_hash -->
<library name="container_hash">
<mark-expected-failures>
<test name="hash_value_array_test"/>
<toolset name="msvc-6.5*"/>
<toolset name="msvc-7.0*"/>
<note author="Daniel James">
hash_value is not overloaded for arrays for older versions
of Visual C++. There is a work around so that
boost::hash&lt;T[N]&gt;, boost::hash_combine and boost::hash_range
work.
</note>
</mark-expected-failures>
<mark-expected-failures>
<test name="hash_function_pointer_test"/>
<toolset name="msvc-6.5*"/>
<toolset name="msvc-7.0*"/>
<note refid="2" author="Daniel James"/>
</mark-expected-failures>
<mark-expected-failures>
<test name="hash_function_pointer_test"/>
<toolset name="sun-5.7"/>
<toolset name="sun-5.8"/>
<toolset name="sun-5.9"/>
<note author="Daniel James">
On these compilers the wrong overload of hash_value is called
when the argument is a hash function pointer. So calling
hash_value doesn't work but boost::hash does work (and it's
recommended that user never call hash_value directly so this
shouldn't be a problem).
</note>
</mark-expected-failures>
<mark-expected-failures>
<test name="hash_long_double_test"/>
<toolset name="gcc-3.4.3_sunos"/>
<toolset name="*pa_risc"/>
<note author="Daniel James">
This platform has poor support for <code>long double</code> so
the hash function perform poorly for values out of the range
of <code>double</code> or if they differ at a greater precision
that <code>double</code> is capable of representing.
</note>
</mark-expected-failures>
<mark-expected-failures>
<test name="point" />
<test name="books" />
<toolset name="msvc-6.5*"/>
<toolset name="msvc-7.0*"/>
<note author="Daniel James">
These examples only work on compilers with support for ADL.
It is possible to work around this, but I wanted to keep the
example code as clean as possible.
</note>
</mark-expected-failures>
<mark-expected-failures>
<test name="point" />
<toolset name="borland-*"/>
<note author="Daniel James">
It appears that Borland doesn't find friend functions defined
in a class by ADL. This is easily fixed but this example is
meant to show the typical way of customising boost::hash, not
the portable way.
</note>
</mark-expected-failures>
<mark-expected-failures>
<test name="hash_global_namespace_test" />
<toolset name="borland-*"/>
<note author="Daniel James">
The test demonstrates a Borland bug - functions that aren't
in a namespace don't appear to be found by ADL.
</note>
</mark-expected-failures>
<mark-expected-failures>
<test name="container_fwd_gcc_debug"/>
<toolset name="darwin-4.2"/>
<note author="Daniel James">
Debug containers aren't supported on Apple's version of gcc 4.2.
</note>
</mark-expected-failures>
</library>
</explicit-failures-markup>

View File

@@ -1 +1,21 @@
[]
[
{
"key": "container_hash",
"boost-version": "1.33.0",
"name": "Container Hash",
"authors": [
"Daniel James"
],
"maintainers": [
"Daniel James <dnljms -at- gmail.com>"
],
"description": "An STL-compatible hash function object that can be extended to hash user defined types.",
"std": [
"tr1"
],
"category": [
"Function-objects"
],
"cxxstd": "03"
}
]

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

114
test/Jamfile.v2 Normal file
View File

@@ -0,0 +1,114 @@
# Copyright 2005-2012 Daniel James.
# 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>$(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
;
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 ;
run is_contiguous_range_test3.cpp ;
run is_described_class_test.cpp
: : : <warnings>extra ;
run is_described_class_test2.cpp
: : : <warnings>extra ;
run is_described_class_test3.cpp
: : : <warnings>extra ;
run described_class_test.cpp
: : : <warnings>extra ;

View File

@@ -0,0 +1,63 @@
// Copyright 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(__GNUC__)
// in type_traits/is_complete.hpp:47
#pragma GCC diagnostic ignored "-Wconversion"
#endif
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <cmath>
namespace test
{
template <class T1>
struct check_return_type
{
template <class T2>
static void equals(T2)
{
BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
}
template <class T2>
static void equals_ref(T2&)
{
BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
}
template <class T2>
static void convertible(T2)
{
BOOST_STATIC_ASSERT((boost::is_convertible<T2, T1>::value));
}
};
}
int main() {
float f = 0;
double d = 0;
long double l = 0;
test::check_return_type<float>::equals(std::ldexp(f, 0));
test::check_return_type<double>::equals(std::ldexp(d, 0));
test::check_return_type<long double>::equals(std::ldexp(l, 0));
int dummy = 0;
test::check_return_type<float>::equals(std::frexp(f, &dummy));
test::check_return_type<double>::equals(std::frexp(d, &dummy));
test::check_return_type<long double>::equals(std::frexp(l, &dummy));
#if BOOST_HASH_USE_FPCLASSIFY
int (*fpc1)(float) = std::fpclassify;
int (*fpc2)(double) = std::fpclassify;
int (*fpc3)(long double) = std::fpclassify;
#endif
}

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,23 @@
# 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_subdirectory(../../../describe boostorg/describe)
add_subdirectory(../../../mp11 boostorg/mp11)
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>)

20
test/compile_time.hpp Normal file
View File

@@ -0,0 +1,20 @@
// 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)
#include <boost/config.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
template <class T>
void compile_time_tests(T*)
{
BOOST_STATIC_ASSERT((boost::is_same<T,
typename BOOST_HASH_TEST_NAMESPACE::hash<T>::argument_type
>::value));
BOOST_STATIC_ASSERT((boost::is_same<std::size_t,
typename BOOST_HASH_TEST_NAMESPACE::hash<T>::result_type
>::value));
}

25
test/config.hpp Normal file
View File

@@ -0,0 +1,25 @@
// 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_HASH_TEST_STD)
# define BOOST_HASH_TEST_STD_INCLUDES
# define BOOST_HASH_TEST_NAMESPACE std
#else
# define BOOST_HASH_TEST_NAMESPACE boost
# if !defined(BOOST_HASH_NO_EXTENSIONS)
# define BOOST_HASH_TEST_EXTENSIONS
# endif
#endif
#if defined(_WIN32_WCE)
// The standard windows mobile headers trigger this warning so I disable it
// before doing anything else.
#pragma warning(disable:4201) // nonstandard extension used :
// nameless struct/union
#endif
#define HASH_TEST_CAT(x, y) HASH_TEST_CAT2(x, y)
#define HASH_TEST_CAT2(x, y) x##y

View File

@@ -0,0 +1,159 @@
// Copyright 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(__clang__)
# pragma clang diagnostic ignored "-Wunused-private-field"
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/describe/class.hpp>
#include <boost/describe/operators.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#if !defined(BOOST_DESCRIBE_CXX14)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE( "Skipping test because BOOST_DESCRIBE_CXX14 is not defined" )
int main() {}
#else
struct X1
{
int m;
explicit X1( int m_ ): m( m_ ) {}
};
BOOST_DESCRIBE_STRUCT( X1, (), (m) )
struct X2
{
int m;
explicit X2( int m_ ): m( m_ ) {}
};
BOOST_DESCRIBE_STRUCT( X2, (), (m) )
struct X3
{
int m;
explicit X3( int m_ ): m( m_ ) {}
};
BOOST_DESCRIBE_STRUCT( X3, (), (m) )
class Y: public X1, protected X2, private X3
{
public:
int m1;
protected:
int m2;
private:
int m3;
public:
Y( int x1, int x2, int x3, int m1_, int m2_, int m3_ ):
X1( x1 ), X2( x2 ), X3( x3 ), m1( m1_ ), m2( m2_ ), m3( m3_ ) {}
BOOST_DESCRIBE_CLASS( Y, (X1, X2, X3), (m1), (m2), (m3) )
};
using boost::describe::operators::operator==;
using boost::describe::operators::operator!=;
using boost::describe::operators::operator<<;
int main()
{
Y y1( 0, 0, 0, 0, 0, 0 );
BOOST_TEST_EQ( y1, y1 );
BOOST_TEST_EQ( boost::hash<Y>()(y1), boost::hash<Y>()(y1) );
Y y2( 1, 0, 0, 0, 0, 0 );
BOOST_TEST_NE( y1, y2 );
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y2) );
Y y3( 0, 1, 0, 0, 0, 0 );
BOOST_TEST_NE( y1, y3 );
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y3) );
BOOST_TEST_NE( y2, y3 );
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y3) );
Y y4( 0, 0, 1, 0, 0, 0 );
BOOST_TEST_NE( y1, y4 );
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y4) );
BOOST_TEST_NE( y2, y4 );
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y4) );
BOOST_TEST_NE( y3, y4 );
BOOST_TEST_NE( boost::hash<Y>()(y3), boost::hash<Y>()(y4) );
Y y5( 0, 0, 0, 1, 0, 0 );
BOOST_TEST_NE( y1, y5 );
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y5) );
BOOST_TEST_NE( y2, y5 );
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y5) );
BOOST_TEST_NE( y3, y5 );
BOOST_TEST_NE( boost::hash<Y>()(y3), boost::hash<Y>()(y5) );
BOOST_TEST_NE( y4, y5 );
BOOST_TEST_NE( boost::hash<Y>()(y4), boost::hash<Y>()(y5) );
Y y6( 0, 0, 0, 0, 1, 0 );
BOOST_TEST_NE( y1, y6 );
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y6) );
BOOST_TEST_NE( y2, y6 );
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y6) );
BOOST_TEST_NE( y3, y6 );
BOOST_TEST_NE( boost::hash<Y>()(y3), boost::hash<Y>()(y6) );
BOOST_TEST_NE( y4, y6 );
BOOST_TEST_NE( boost::hash<Y>()(y4), boost::hash<Y>()(y6) );
BOOST_TEST_NE( y5, y6 );
BOOST_TEST_NE( boost::hash<Y>()(y5), boost::hash<Y>()(y6) );
Y y7( 0, 0, 0, 0, 0, 1 );
BOOST_TEST_NE( y1, y7 );
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y7) );
BOOST_TEST_NE( y2, y7 );
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y7) );
BOOST_TEST_NE( y3, y7 );
BOOST_TEST_NE( boost::hash<Y>()(y3), boost::hash<Y>()(y7) );
BOOST_TEST_NE( y4, y7 );
BOOST_TEST_NE( boost::hash<Y>()(y4), boost::hash<Y>()(y7) );
BOOST_TEST_NE( y5, y7 );
BOOST_TEST_NE( boost::hash<Y>()(y5), boost::hash<Y>()(y7) );
BOOST_TEST_NE( y6, y7 );
BOOST_TEST_NE( boost::hash<Y>()(y6), boost::hash<Y>()(y7) );
return boost::report_errors();
}
#endif

View File

@@ -0,0 +1,19 @@
// Copyright 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)
// Check that boost/container_hash/extensions.hpp works okay.
//
// It probably should be in boost/container_hash/detail, but since it isn't it
// should work.
#include "./config.hpp"
#include <boost/container_hash/extensions.hpp>
int main() {
int x[2] = { 2, 3 };
boost::hash<int[2]> hf;
hf(x);
}

View File

@@ -0,0 +1,75 @@
// 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)
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_EXTENSIONS
# ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
# else
# include <boost/container_hash/hash.hpp>
# endif
#endif
#include <boost/core/lightweight_test.hpp>
#ifdef BOOST_HASH_TEST_EXTENSIONS
void array_int_test()
{
const int length1 = 25;
int array1[25] = {
26, -43, 32, 65, 45,
12, 67, 32, 12, 23,
0, 0, 0, 0, 0,
8, -12, 23, 65, 45,
-1, 93, -54, 987, 3
};
BOOST_HASH_TEST_NAMESPACE::hash<int[25]> hasher1;
const int length2 = 1;
int array2[1] = {3};
BOOST_HASH_TEST_NAMESPACE::hash<int[1]> hasher2;
const int length3 = 2;
int array3[2] = {2, 3};
BOOST_HASH_TEST_NAMESPACE::hash<int[2]> hasher3;
BOOST_TEST(hasher1(array1)
== BOOST_HASH_TEST_NAMESPACE::hash_range(array1, array1 + length1));
BOOST_TEST(hasher2(array2)
== BOOST_HASH_TEST_NAMESPACE::hash_range(array2, array2 + length2));
BOOST_TEST(hasher3(array3)
== BOOST_HASH_TEST_NAMESPACE::hash_range(array3, array3 + length3));
}
void two_dimensional_array_test()
{
int array[3][2] = {{-5, 6}, {7, -3}, {26, 1}};
BOOST_HASH_TEST_NAMESPACE::hash<int[3][2]> hasher;
std::size_t seed1 = 0;
for(int i = 0; i < 3; ++i)
{
std::size_t seed2 = 0;
for(int j = 0; j < 2; ++j)
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, array[i][j]);
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed1, seed2);
}
BOOST_TEST(hasher(array) == seed1);
BOOST_TEST(hasher(array) == BOOST_HASH_TEST_NAMESPACE::hash_range(array, array + 3));
}
#endif // BOOST_HASH_TEST_EXTENSIONS
int main()
{
#ifdef BOOST_HASH_TEST_EXTENSIONS
array_int_test();
two_dimensional_array_test();
#endif
return boost::report_errors();
}

132
test/hash_complex_test.cpp Normal file
View File

@@ -0,0 +1,132 @@
// 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)
#include "./config.hpp"
#if !defined(BOOST_HASH_TEST_EXTENSIONS)
int main() {}
#else
#ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
#else
# include <boost/container_hash/hash.hpp>
#endif
#include <boost/core/lightweight_test.hpp>
#if defined(BOOST_MSVC)
#pragma warning(disable:4244) // conversion from 'unsigned long' to
// 'unsigned short', possible loss of data
#pragma warning(disable:4245) // conversion from 'int' to
// 'const unsigned short',
// signed/unsigned mismatch
#pragma warning(disable:4305) // truncation from 'double' to
// 'const std::complex<float>::_Ty'
#pragma warning(disable:4309) // truncation of constant value
#pragma warning(disable:4512) // assignment operator could not be generated
#pragma warning(disable:4996) // std::complex<Integer> is deprecated
#if BOOST_MSVC < 1400
#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int',
// possible loss of data
#endif
#endif
#if ( defined(__GNUC__) || defined(__clang__) ) && !defined(BOOST_INTEL_CXX_VERSION)
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
#include <boost/limits.hpp>
#include <complex>
#include <sstream>
#include <set>
template <class T>
void generic_complex_tests(std::complex<T> v)
{
BOOST_HASH_TEST_NAMESPACE::hash<std::complex<T> > complex_hasher;
BOOST_TEST(complex_hasher(v) == complex_hasher(v));
BOOST_HASH_TEST_NAMESPACE::hash<T> real_hasher;
T real = v.real();
T imag = v.imag();
BOOST_TEST(real_hasher(real) == complex_hasher(std::complex<T>(real)));
if(imag != 0 && real_hasher(real) == complex_hasher(v)) {
std::ostringstream os;
os<<"real_hasher("<<real<<") == complex_hasher("
<<v.real()<<" + "<<v.imag()<<"i) == "
<<real_hasher(real)<<" (This might not be a bug).";
BOOST_ERROR(os.str().c_str());
}
}
template <class Float>
void complex_float_tests(Float*)
{
typedef std::complex<Float> complex;
generic_complex_tests(complex(0,0));
generic_complex_tests(complex(0.5,0));
generic_complex_tests(complex(25,0));
generic_complex_tests(complex(25,0));
generic_complex_tests(complex(static_cast<Float>(-67.5324535),static_cast<Float>(56.23578678)));
}
template <class Integer>
void complex_integral_tests(Integer*)
{
typedef std::complex<Integer> complex;
generic_complex_tests(complex(0,0));
generic_complex_tests(complex(15342,124));
generic_complex_tests(complex(25,54356));
generic_complex_tests(complex(5325,2346));
generic_complex_tests(complex(Integer(-243897),Integer(-49923874)));
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
// as they cause warnings and don't really test
// anything that the other tests already deal with.
complex_float_tests((float*) 0);
complex_float_tests((double*) 0);
complex_float_tests((long double*) 0);
//complex_integral_tests((short*) 0);
complex_integral_tests((int*) 0);
complex_integral_tests((long*) 0);
//complex_integral_tests((unsigned short*) 0);
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();
}
#endif // BOOST_HASH_TEST_EXTENSIONS

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/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>();
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
test<char8_t>();
#endif
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
test<std::byte>();
#endif
return boost::report_errors();
}

100
test/hash_custom_test.cpp Normal file
View File

@@ -0,0 +1,100 @@
// 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)
#include "./config.hpp"
#include <boost/config.hpp>
#include <cstddef>
namespace test
{
struct custom
{
int value_;
std::size_t hash() const
{
return static_cast<std::size_t>(value_ * 10);
}
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
friend std::size_t hash_value(custom const& x )
{
return x.hash();
}
#endif
custom(int x) : value_(x) {}
};
}
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace boost
{
std::size_t hash_value(test::custom x)
{
return x.hash();
}
}
#endif
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_EXTENSIONS
# ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
# else
# include <boost/container_hash/hash.hpp>
# endif
#endif
#include <boost/core/lightweight_test.hpp>
#ifdef BOOST_HASH_TEST_EXTENSIONS
#include <vector>
#include <string>
#include <cctype>
void custom_tests()
{
BOOST_HASH_TEST_NAMESPACE::hash<test::custom> custom_hasher;
BOOST_TEST(custom_hasher(10) == 100u);
test::custom x(55);
BOOST_TEST(custom_hasher(x) == 550u);
{
using namespace BOOST_HASH_TEST_NAMESPACE;
BOOST_TEST(custom_hasher(x) == hash_value(x));
}
std::vector<test::custom> custom_vector;
custom_vector.push_back(5);
custom_vector.push_back(25);
custom_vector.push_back(35);
std::size_t seed = 0;
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom(5));
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom(25));
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom(35));
std::size_t seed2 = 0;
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 50u);
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 250u);
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 350u);
BOOST_TEST(seed == BOOST_HASH_TEST_NAMESPACE::hash_range(
custom_vector.begin(), custom_vector.end()));
BOOST_TEST(seed == seed2);
}
#endif // BOOST_HASH_TEST_EXTENSIONS
int main()
{
#ifdef BOOST_HASH_TEST_EXTENSIONS
custom_tests();
#endif
return boost::report_errors();
}

35
test/hash_deque_test.cpp Normal file
View File

@@ -0,0 +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)
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_EXTENSIONS
# ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
# else
# include <boost/container_hash/hash.hpp>
# endif
#endif
#include <boost/core/lightweight_test.hpp>
#ifdef BOOST_HASH_TEST_EXTENSIONS
#include <deque>
using std::deque;
#define CONTAINER_TYPE deque
#include "./hash_sequence_test.hpp"
#endif // BOOST_HASH_TEST_EXTENSIONS
int main()
{
#ifdef BOOST_HASH_TEST_EXTENSIONS
deque_tests::deque_hash_integer_tests();
#endif
return boost::report_errors();
}

63
test/hash_enum_test.cpp Normal file
View File

@@ -0,0 +1,63 @@
// Copyright 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)
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
#else
# include <boost/container_hash/hash.hpp>
#endif
#include <boost/core/lightweight_test.hpp>
#include "./compile_time.hpp"
namespace test {
enum enum_override { enum_override1, enum_override2 };
std::size_t hash_value(enum_override) { return 896532; }
enum enum1 { enum1a };
enum enum2 { enum2a, enum2b };
enum enum3 { enum3a = 574, enum3b };
enum enum4 { enum4a = -12574, enum4b };
}
int main() {
compile_time_tests((test::enum1*) 0);
compile_time_tests((test::enum2*) 0);
compile_time_tests((test::enum3*) 0);
compile_time_tests((test::enum4*) 0);
compile_time_tests((test::enum_override*) 0);
BOOST_HASH_TEST_NAMESPACE::hash<test::enum1> hash1;
BOOST_HASH_TEST_NAMESPACE::hash<test::enum2> hash2;
BOOST_HASH_TEST_NAMESPACE::hash<test::enum3> hash3;
BOOST_HASH_TEST_NAMESPACE::hash<test::enum4> hash4;
BOOST_TEST(hash1(test::enum1a) == hash1(test::enum1a));
BOOST_TEST(hash2(test::enum2a) == hash2(test::enum2a));
BOOST_TEST(hash2(test::enum2a) != hash2(test::enum2b));
BOOST_TEST(hash2(test::enum2b) == hash2(test::enum2b));
BOOST_TEST(hash3(test::enum3a) == hash3(test::enum3a));
BOOST_TEST(hash3(test::enum3a) != hash3(test::enum3b));
BOOST_TEST(hash3(test::enum3b) == hash3(test::enum3b));
BOOST_TEST(hash4(test::enum4a) == hash4(test::enum4a));
BOOST_TEST(hash4(test::enum4a) != hash4(test::enum4b));
BOOST_TEST(hash4(test::enum4b) == hash4(test::enum4b));
BOOST_HASH_TEST_NAMESPACE::hash<test::enum_override> hash_override;
BOOST_TEST(hash_override(test::enum_override1) ==
hash_override(test::enum_override1));
BOOST_TEST(hash_override(test::enum_override1) ==
hash_override(test::enum_override2));
BOOST_TEST(hash_override(test::enum_override1) ==
hash_override(test::enum_override1));
return boost::report_errors();
}

18
test/hash_float_test.cpp Normal file
View File

@@ -0,0 +1,18 @@
// 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)
#include "hash_float_test.hpp"
int main()
{
std::cerr<<"Compiler: "<<BOOST_COMPILER<<"\n";
std::cerr<<"Platform: "<<BOOST_PLATFORM<<"\n";
std::cerr<<"Library: "<<BOOST_STDLIB<<"\n\n";
float_tests("float", (float*) 0);
float_tests("double", (double*) 0);
return boost::report_errors();
}

295
test/hash_float_test.hpp Normal file
View File

@@ -0,0 +1,295 @@
// 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)
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
#else
# include <boost/container_hash/hash.hpp>
#endif
#include <boost/core/lightweight_test.hpp>
#include <cmath>
#include <boost/container_hash/detail/limits.hpp>
#include <boost/config/workaround.hpp>
#include <iostream>
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4127) // conditional expression is constant
#pragma warning(disable:4723) // conditional expression is constant
#if BOOST_MSVC < 1400
#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int',
// possible loss of data
#endif
#endif
#if ( defined(__GNUC__) || defined(__clang__) ) && !defined(BOOST_INTEL_CXX_VERSION)
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
char const* float_type(float*) { return "float"; }
char const* float_type(double*) { return "double"; }
char const* float_type(long double*) { return "long double"; }
template <class T>
void float_tests(char const* name, T* = 0)
{
std::cerr
<< "\n"
<< "Testing " BOOST_STRINGIZE(BOOST_HASH_TEST_NAMESPACE) "::hash<"
<< name
<< ">\n"
<< "\n"
<< "boost::hash_detail::limits<T>::digits = "
<< boost::hash_detail::limits<T>::digits<< "\n"
<< "boost::hash_detail::limits<int>::digits = "
<< boost::hash_detail::limits<int>::digits<< "\n"
<< "boost::hash_detail::limits<std::size_t>::digits = "
<< boost::hash_detail::limits<std::size_t>::digits
<< "\n"
<< "\n"
;
BOOST_HASH_TEST_NAMESPACE::hash<T> x1;
T zero = 0;
T minus_zero = (T) -1 * zero;
BOOST_TEST(zero == minus_zero);
BOOST_TEST(x1(zero) == x1(minus_zero));
#if defined(BOOST_HASH_TEST_EXTENSIONS)
BOOST_TEST(x1(zero) == BOOST_HASH_TEST_NAMESPACE::hash_value(zero));
BOOST_TEST(x1(minus_zero) == BOOST_HASH_TEST_NAMESPACE::hash_value(minus_zero));
#endif
BOOST_TEST(x1(zero) != x1(0.5));
BOOST_TEST(x1(minus_zero) != x1(0.5));
BOOST_TEST(x1(0.5) != x1(-0.5));
BOOST_TEST(x1(1) != x1(-1));
using namespace std;
// Doing anything with infinity causes borland to crash.
#if defined(BOOST_BORLANDC)
std::cerr
<< "Not running infinity checks on Borland, as it causes it to crash."
"\n";
#else
if(boost::hash_detail::limits<T>::has_infinity) {
T infinity = -log(zero);
T infinity2 = (T) 1. / zero;
T infinity3 = (T) -1. / minus_zero;
T infinity4 = boost::hash_detail::limits<T>::infinity();
T minus_infinity = log(zero);
T minus_infinity2 = (T) -1. / zero;
T minus_infinity3 = (T) 1. / minus_zero;
#if defined(BOOST_HASH_TEST_EXTENSIONS)
BOOST_TEST(x1(infinity) == BOOST_HASH_TEST_NAMESPACE::hash_value(infinity));
BOOST_TEST(x1(minus_infinity)
== BOOST_HASH_TEST_NAMESPACE::hash_value(minus_infinity));
#endif
if(infinity == infinity2)
BOOST_TEST(x1(infinity) == x1(infinity2));
if(infinity == infinity3)
BOOST_TEST(x1(infinity) == x1(infinity3));
if(infinity == infinity4)
BOOST_TEST(x1(infinity) == x1(infinity4));
if(minus_infinity == minus_infinity2)
BOOST_TEST(x1(minus_infinity) == x1(minus_infinity2));
if(minus_infinity == minus_infinity3)
BOOST_TEST(x1(minus_infinity) == x1(minus_infinity3));
BOOST_TEST(infinity != minus_infinity);
if(x1(infinity) == x1(minus_infinity)) {
std::cerr<<"x1(infinity) == x1(-infinity) == "<<x1(infinity)<<"\n";
}
// This should really be 'has_denorm == denorm_present' but some
// compilers don't have 'denorm_present'. See also a later use.
if(boost::hash_detail::limits<T>::has_denorm) {
if(x1(boost::hash_detail::limits<T>::denorm_min()) == x1(infinity))
{
std::cerr
<< "x1(denorm_min) == x1(infinity) == "
<< x1(infinity)
<< "\n";
}
if(x1(boost::hash_detail::limits<T>::denorm_min()) ==
x1(minus_infinity))
{
std::cerr
<< "x1(denorm_min) == x1(-infinity) == "
<< x1(minus_infinity)
<< "\n";
}
}
if(boost::hash_detail::limits<T>::has_quiet_NaN) {
if(x1(boost::hash_detail::limits<T>::quiet_NaN()) == x1(infinity))
{
std::cerr
<< "x1(quiet_NaN) == x1(infinity) == "
<< x1(infinity)
<< "\n";
}
if(x1(boost::hash_detail::limits<T>::quiet_NaN()) ==
x1(minus_infinity))
{
std::cerr
<< "x1(quiet_NaN) == x1(-infinity) == "
<< x1(minus_infinity)
<< "\n";
}
}
}
#endif
T max = (boost::hash_detail::limits<T>::max)();
T half_max = max / 2;
T quarter_max = max / 4;
T three_quarter_max = max - quarter_max;
// Check the limits::max is in range.
BOOST_TEST(max != half_max);
BOOST_TEST(max != quarter_max);
BOOST_TEST(max != three_quarter_max);
BOOST_TEST(half_max != quarter_max);
BOOST_TEST(half_max != three_quarter_max);
BOOST_TEST(quarter_max != three_quarter_max);
BOOST_TEST(max != -max);
BOOST_TEST(half_max != -half_max);
BOOST_TEST(quarter_max != -quarter_max);
BOOST_TEST(three_quarter_max != -three_quarter_max);
#if defined(BOOST_HASH_TEST_EXTENSIONS)
BOOST_TEST(x1(max) == BOOST_HASH_TEST_NAMESPACE::hash_value(max));
BOOST_TEST(x1(half_max) == BOOST_HASH_TEST_NAMESPACE::hash_value(half_max));
BOOST_TEST(x1(quarter_max) == BOOST_HASH_TEST_NAMESPACE::hash_value(quarter_max));
BOOST_TEST(x1(three_quarter_max) ==
BOOST_HASH_TEST_NAMESPACE::hash_value(three_quarter_max));
#endif
// The '!=' tests could legitimately fail, but with my hash it indicates a
// bug.
BOOST_TEST(x1(max) == x1(max));
BOOST_TEST(x1(max) != x1(quarter_max));
BOOST_TEST(x1(max) != x1(half_max));
BOOST_TEST(x1(max) != x1(three_quarter_max));
BOOST_TEST(x1(quarter_max) == x1(quarter_max));
BOOST_TEST(x1(quarter_max) != x1(half_max));
BOOST_TEST(x1(quarter_max) != x1(three_quarter_max));
BOOST_TEST(x1(half_max) == x1(half_max));
BOOST_TEST(x1(half_max) != x1(three_quarter_max));
BOOST_TEST(x1(three_quarter_max) == x1(three_quarter_max));
BOOST_TEST(x1(max) != x1(-max));
BOOST_TEST(x1(half_max) != x1(-half_max));
BOOST_TEST(x1(quarter_max) != x1(-quarter_max));
BOOST_TEST(x1(three_quarter_max) != x1(-three_quarter_max));
// Intel with gcc stdlib sometimes segfaults on calls to asin and acos.
#if !((defined(__INTEL_COMPILER) || defined(__ICL) || \
defined(__ICC) || defined(__ECC)) && \
(defined(__GLIBCPP__) || defined(__GLIBCXX__)))
T v1 = asin((T) 1);
T v2 = acos((T) 0);
if(v1 == v2)
BOOST_TEST(x1(v1) == x1(v2));
#if defined(BOOST_HASH_TEST_EXTENSIONS)
BOOST_TEST(x1(v1) == BOOST_HASH_TEST_NAMESPACE::hash_value(v1));
BOOST_TEST(x1(v2) == BOOST_HASH_TEST_NAMESPACE::hash_value(v2));
#endif
#endif
#if defined(BOOST_HASH_TEST_EXTENSIONS)
BOOST_TEST(x1(boost::hash_detail::limits<T>::epsilon()) ==
BOOST_HASH_TEST_NAMESPACE::hash_value(
boost::hash_detail::limits<T>::epsilon()));
#endif
BOOST_TEST(boost::hash_detail::limits<T>::epsilon() != (T) 0);
if(x1(boost::hash_detail::limits<T>::epsilon()) == x1((T) 0))
std::cerr<<"x1(epsilon) == x1(0) == "<<x1((T) 0)<<"\n";
BOOST_TEST(-boost::hash_detail::limits<T>::epsilon() != (T) 0);
if(x1(-boost::hash_detail::limits<T>::epsilon()) == x1((T) 0))
std::cerr<<"x1(-epsilon) == x1(0) == "<<x1((T) 0)<<"\n";
BOOST_TEST((T) 1 + boost::hash_detail::limits<T>::epsilon() != (T) 1);
if(x1((T) 1 + boost::hash_detail::limits<T>::epsilon()) == x1((T) 1))
std::cerr<<"x1(1 + epsilon) == x1(1) == "<<x1((T) 1)<<"\n";
BOOST_TEST((T) 1 - boost::hash_detail::limits<T>::epsilon() != (T) 1);
if(x1((T) 1 - boost::hash_detail::limits<T>::epsilon()) == x1((T) 1))
std::cerr<<"x1(1 - epsilon) == x1(1) == "<<x1((T) 1)<<"\n";
BOOST_TEST((T) -1 + boost::hash_detail::limits<T>::epsilon() != (T) -1);
if(x1((T) -1 + boost::hash_detail::limits<T>::epsilon()) == x1((T) -1))
std::cerr<<"x1(-1 + epsilon) == x1(-1) == "<<x1((T) -1)<<"\n";
BOOST_TEST((T) -1 - boost::hash_detail::limits<T>::epsilon() != (T) -1);
if(x1((T) -1 - boost::hash_detail::limits<T>::epsilon()) == x1((T) -1))
std::cerr<<"x1(-1 - epsilon) == x1(-1) == "<<x1((T) -1)<<"\n";
// As before.
if(boost::hash_detail::limits<T>::has_denorm) {
if(x1(boost::hash_detail::limits<T>::denorm_min()) == x1(zero)) {
std::cerr<<"x1(denorm_min) == x1(zero) == "<<x1(zero)<<"\n";
}
#if !BOOST_WORKAROUND(__DECCXX_VER,<70190006) && defined(BOOST_HASH_TEST_EXTENSIONS)
// The Tru64/CXX standard library prior to 7.1 contains a bug in the
// specialization of boost::hash_detail::limits::denorm_min() for long
// doubles which causes this test to fail.
if(x1(boost::hash_detail::limits<T>::denorm_min()) !=
BOOST_HASH_TEST_NAMESPACE::hash_value(
boost::hash_detail::limits<T>::denorm_min()))
{
std::cerr
<< "x1(boost::hash_detail::limits<T>::denorm_min()) = "
<< x1(boost::hash_detail::limits<T>::denorm_min())
<< "\nhash_value(boost::hash_detail::limits<T>::denorm_min())"
" = "
<< BOOST_HASH_TEST_NAMESPACE::hash_value(
boost::hash_detail::limits<T>::denorm_min())
<< "\nx1(0) = "
<< x1(0)
<< "\n";
}
#endif
}
// NaN also causes borland to crash.
#if !defined(BOOST_BORLANDC) && defined(BOOST_HASH_TEST_EXTENSIONS)
if(boost::hash_detail::limits<T>::has_quiet_NaN) {
if(x1(boost::hash_detail::limits<T>::quiet_NaN()) == x1(1.0)) {
std::cerr<<"x1(quiet_NaN) == x1(1.0) == "<<x1(1.0)<<"\n";
}
BOOST_TEST(x1(boost::hash_detail::limits<T>::quiet_NaN()) ==
BOOST_HASH_TEST_NAMESPACE::hash_value(
boost::hash_detail::limits<T>::quiet_NaN()));
}
#endif
}
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif

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

103
test/hash_friend_test.cpp Normal file
View File

@@ -0,0 +1,103 @@
// 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"
#include <boost/config.hpp>
#include <cstddef>
namespace test
{
template <class T>
struct custom
{
int value_;
std::size_t hash() const
{
return static_cast<std::size_t>(value_ * 10);
}
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
friend std::size_t hash_value(custom const& x)
{
return x.hash();
}
#endif
custom(int x) : value_(x) {}
};
}
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace boost
{
template <class T>
std::size_t hash_value(test::custom<T> x)
{
return x.hash();
}
}
#endif
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_EXTENSIONS
# ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
# else
# include <boost/container_hash/hash.hpp>
# endif
#endif
#include <boost/core/lightweight_test.hpp>
#ifdef BOOST_HASH_TEST_EXTENSIONS
#include <vector>
#include <string>
#include <cctype>
void custom_tests()
{
BOOST_HASH_TEST_NAMESPACE::hash<test::custom<int> > custom_hasher;
BOOST_TEST(custom_hasher(10) == 100u);
test::custom<int> x(55);
BOOST_TEST(custom_hasher(x) == 550u);
{
using namespace BOOST_HASH_TEST_NAMESPACE;
BOOST_TEST(custom_hasher(x) == hash_value(x));
}
std::vector<test::custom<int> > custom_vector;
custom_vector.push_back(5);
custom_vector.push_back(25);
custom_vector.push_back(35);
std::size_t seed = 0;
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom<int>(5));
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom<int>(25));
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom<int>(35));
std::size_t seed2 = 0;
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 50u);
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 250u);
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 350u);
BOOST_TEST(seed == BOOST_HASH_TEST_NAMESPACE::hash_range(
custom_vector.begin(), custom_vector.end()));
BOOST_TEST(seed == seed2);
}
#endif // BOOST_HASH_TEST_EXTENSIONS
int main()
{
#ifdef BOOST_HASH_TEST_EXTENSIONS
custom_tests();
#endif
return boost::report_errors();
}

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

@@ -0,0 +1,57 @@
// 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)
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
#else
# include <boost/container_hash/hash.hpp>
#endif
#include <boost/core/lightweight_test.hpp>
#include "./compile_time.hpp"
void void_func1() { static int x = 1; ++x; (void)x; }
void void_func2() { static int x = 2; --x; (void)x; }
int int_func1(int) { return 0; }
int int_func2(int) { return 1; }
void function_pointer_tests()
{
compile_time_tests((void(**)()) 0);
compile_time_tests((int(**)(int)) 0);
BOOST_HASH_TEST_NAMESPACE::hash<void(*)()> hasher_void;
BOOST_HASH_TEST_NAMESPACE::hash<int(*)(int)> hasher_int;
BOOST_TEST(&void_func1 != &void_func2);
BOOST_TEST(&int_func1 != &int_func2);
BOOST_TEST(hasher_void(0) == hasher_void(0));
BOOST_TEST(hasher_void(&void_func1) == hasher_void(&void_func1));
BOOST_TEST(hasher_void(&void_func1) != hasher_void(&void_func2));
BOOST_TEST(hasher_void(&void_func1) != hasher_void(0));
BOOST_TEST(hasher_int(0) == hasher_int(0));
BOOST_TEST(hasher_int(&int_func1) == hasher_int(&int_func1));
BOOST_TEST(hasher_int(&int_func1) != hasher_int(&int_func2));
BOOST_TEST(hasher_int(&int_func1) != hasher_int(0));
#if defined(BOOST_HASH_TEST_EXTENSIONS)
BOOST_TEST(hasher_void(&void_func1)
== BOOST_HASH_TEST_NAMESPACE::hash_value(&void_func1));
BOOST_TEST(hasher_int(&int_func1)
== BOOST_HASH_TEST_NAMESPACE::hash_value(&int_func1));
// This isn't specified in Peter's proposal:
BOOST_TEST(hasher_void(0) == 0);
#endif
}
int main()
{
function_pointer_tests();
return boost::report_errors();
}

104
test/hash_fwd_test.hpp Normal file
View File

@@ -0,0 +1,104 @@
// 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"
#if defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_HASH_TEST_STD_INCLUDES)
#include <boost/container_hash/hash_fwd.hpp>
#include <boost/config.hpp>
#include <cstddef>
#include <vector>
namespace test {
template <class T>
struct test_type1
{
T value;
test_type1(T const& x) : value(x) {}
};
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
template <class T>
std::size_t hash_value(test_type1<T> const& x)
{
BOOST_HASH_TEST_NAMESPACE::hash<T> hasher;
return hasher(x.value);
}
#endif
template <class T>
struct test_type2
{
T value1, value2;
test_type2(T const& x, T const& y) : value1(x), value2(y) {}
};
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
template <class T>
std::size_t hash_value(test_type2<T> const& x)
{
std::size_t seed = 0;
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, x.value1);
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, x.value2);
return seed;
}
#endif
template <class T>
struct test_type3
{
std::vector<T> values;
test_type3(typename std::vector<T>::iterator x,
typename std::vector<T>::iterator y) : values(x, y) {}
};
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
template <class T>
std::size_t hash_value(test_type3<T> const& x)
{
std::size_t seed =
BOOST_HASH_TEST_NAMESPACE::hash_range(x.values.begin(), x.values.end());
BOOST_HASH_TEST_NAMESPACE::hash_range(seed, x.values.begin(), x.values.end());
return seed;
}
#endif
}
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace boost
{
template <class T>
std::size_t hash_value(test::test_type1<T> const& x)
{
BOOST_HASH_TEST_NAMESPACE::hash<T> hasher;
return hasher(x.value);
}
template <class T>
std::size_t hash_value(test::test_type2<T> const& x)
{
std::size_t seed = 0;
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, x.value1);
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, x.value2);
return seed;
}
template <class T>
std::size_t hash_value(test::test_type3<T> const& x)
{
std::size_t seed =
BOOST_HASH_TEST_NAMESPACE::hash_range(x.values.begin(), x.values.end());
BOOST_HASH_TEST_NAMESPACE::hash_range(seed, x.values.begin(), x.values.end());
return seed;
}
}
#endif
#endif

96
test/hash_fwd_test_1.cpp Normal file
View File

@@ -0,0 +1,96 @@
// 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)
// This checks that template code implemented using hash_fwd will work.
#include "./config.hpp"
#include "./hash_fwd_test.hpp"
#include <boost/core/lightweight_test.hpp>
#if defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_HASH_TEST_STD_INCLUDES)
#include <boost/container_hash/hash.hpp>
#include <string>
void fwd_test1()
{
test::test_type1<int> x(5);
test::test_type1<std::string> y("Test");
BOOST_HASH_TEST_NAMESPACE::hash<int> hasher_int;
BOOST_HASH_TEST_NAMESPACE::hash<std::string> hasher_string;
BOOST_HASH_TEST_NAMESPACE::hash<test::test_type1<int> > hasher_test_int;
BOOST_HASH_TEST_NAMESPACE::hash<test::test_type1<std::string> > hasher_test_string;
BOOST_TEST(hasher_int(5) == hasher_test_int(x));
BOOST_TEST(hasher_string("Test") == hasher_test_string(y));
}
void fwd_test2()
{
test::test_type2<int> x(5, 10);
test::test_type2<std::string> y("Test1", "Test2");
std::size_t seed1 = 0;
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed1, 5);
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed1, 10);
std::size_t seed2 = 0;
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, std::string("Test1"));
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, std::string("Test2"));
BOOST_HASH_TEST_NAMESPACE::hash<test::test_type2<int> > hasher_test_int;
BOOST_HASH_TEST_NAMESPACE::hash<test::test_type2<std::string> > hasher_test_string;
BOOST_TEST(seed1 == hasher_test_int(x));
BOOST_TEST(seed2 == hasher_test_string(y));
}
void fwd_test3()
{
std::vector<int> values1;
values1.push_back(10);
values1.push_back(15);
values1.push_back(20);
values1.push_back(3);
std::vector<std::string> values2;
values2.push_back("Chico");
values2.push_back("Groucho");
values2.push_back("Harpo");
values2.push_back("Gummo");
values2.push_back("Zeppo");
test::test_type3<int> x(values1.begin(), values1.end());
test::test_type3<std::string> y(values2.begin(), values2.end());
std::size_t seed1 =
BOOST_HASH_TEST_NAMESPACE::hash_range(values1.begin(), values1.end());
BOOST_HASH_TEST_NAMESPACE::hash_range(seed1, values1.begin(), values1.end());
std::size_t seed2 =
BOOST_HASH_TEST_NAMESPACE::hash_range(values2.begin(), values2.end());
BOOST_HASH_TEST_NAMESPACE::hash_range(seed2, values2.begin(), values2.end());
BOOST_HASH_TEST_NAMESPACE::hash<test::test_type3<int> > hasher_test_int;
BOOST_HASH_TEST_NAMESPACE::hash<test::test_type3<std::string> > hasher_test_string;
BOOST_TEST(seed1 == hasher_test_int(x));
BOOST_TEST(seed2 == hasher_test_string(y));
}
#endif
int main()
{
#ifdef BOOST_HASH_TEST_EXTENSIONS
fwd_test1();
fwd_test2();
fwd_test3();
#endif
return boost::report_errors();
}

47
test/hash_fwd_test_2.cpp Normal file
View File

@@ -0,0 +1,47 @@
// 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)
// This test just makes sure a header which uses hash_fwd can compile without
// the main hash headers.
#include "./config.hpp"
#if !defined(BOOST_HASH_TEST_EXTENSIONS) || defined(BOOST_HASH_TEST_STD_INCLUDES)
int main() {}
#else
#include "./hash_fwd_test.hpp"
#include <boost/core/lightweight_test.hpp>
template <class T> void unused(T const&) {}
void fwd_test()
{
test::test_type1<int> x1(3);
test::test_type1<std::string> y1("Black");
test::test_type2<int> x2(25, 16);
test::test_type2<std::string> y2("White", "Green");
std::vector<int> empty;
std::vector<std::string> empty2;
test::test_type3<int> x3(empty.begin(), empty.end());
test::test_type3<std::string> y3(empty2.begin(), empty2.end());
// Prevent gcc warnings:
unused(x1); unused(x2); unused(x3);
unused(y1); unused(y2); unused(y3);
}
int main()
{
fwd_test();
return boost::report_errors();
}
#endif // defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_HASH_TEST_STD_INCLUDES)

View File

@@ -0,0 +1,103 @@
// 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)
// This test demonstrates an ADL bug in Borland 5.5 where ADL isn't performed
// in the global namespace.
#include "./config.hpp"
#include <boost/config.hpp>
#include <cstddef>
struct custom
{
int value_;
std::size_t hash() const
{
return static_cast<std::size_t>(value_ * 10);
}
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
friend std::size_t hash_value(custom const& x )
{
return x.hash();
}
#endif
custom(int x) : value_(x) {}
};
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace boost
{
std::size_t hash_value(custom x)
{
return x.hash();
}
}
#endif
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_EXTENSIONS
# ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
# else
# include <boost/container_hash/hash.hpp>
# endif
#endif
#include <boost/core/lightweight_test.hpp>
#ifdef BOOST_HASH_TEST_EXTENSIONS
#include <vector>
#include <string>
#include <cctype>
void custom_tests()
{
BOOST_HASH_TEST_NAMESPACE::hash<custom> custom_hasher;
BOOST_TEST(custom_hasher(10) == 100u);
custom x(55);
BOOST_TEST(custom_hasher(x) == 550u);
{
using namespace BOOST_HASH_TEST_NAMESPACE;
BOOST_TEST(custom_hasher(x) == hash_value(x));
}
std::vector<custom> custom_vector;
custom_vector.push_back(5);
custom_vector.push_back(25);
custom_vector.push_back(35);
std::size_t seed = 0;
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, custom(5));
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, custom(25));
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, custom(35));
std::size_t seed2 = 0;
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 50u);
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 250u);
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 350u);
BOOST_TEST(seed == BOOST_HASH_TEST_NAMESPACE::hash_range(
custom_vector.begin(), custom_vector.end()));
BOOST_TEST(seed == seed2);
}
#endif // BOOST_HASH_TEST_EXTENSIONS
int main()
{
#ifdef BOOST_HASH_TEST_EXTENSIONS
custom_tests();
#endif
return boost::report_errors();
}

126
test/hash_info.cpp Normal file
View File

@@ -0,0 +1,126 @@
// Copyright 2017 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)
// Not a test, just a small program to write out configuration info
#include <boost/container_hash/hash.hpp>
#include <iostream>
#include <algorithm>
#include <limits>
#include <climits>
#if defined(BOOST_MSVC)
struct msvc_version {
unsigned version;
char const* description;
friend bool operator<(msvc_version const& v1, msvc_version const& v2) {
return v1.version < v2.version;
}
};
void write_compiler_info() {
// From:
// https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B
// https://blogs.msdn.microsoft.com/vcblog/2017/11/15/side-by-side-minor-version-msvc-toolsets-in-visual-studio-2017/
msvc_version versions[] = {
{0, "Old Visual C++"},
{1000, "Visual C++ 4.x, VS4.0?"},
{1100, "Visual C++ 5.0, VS97"},
{1200, "Visual C++ 6.0, VS6.0"},
{1300, "Visual C++ 7.0, VS.NET 2002"},
{1310, "Visual C++ 7.1, VS.NET 2003"},
{1400, "Visual C++ 8.0, VS2005"},
{1500, "Visual C++ 9.0, VS2008"},
{1600, "Visual C++ 10.0, VS2010"},
{1700, "Visual C++ 11.0, VS2012"},
{1800, "Visual C++ 12.0, VS2013"},
{1900, "Visual C++ 14.00, VS2015"},
{1910, "Visual C++ 14.1x, VS2017"},
{1920, "Visual C++ 14.2x, VS2019"},
{1930, "Visual C++ 14.3x, VS2022"},
};
msvc_version msvc = { BOOST_MSVC, "" };
msvc_version* v = std::upper_bound(versions,
versions + sizeof(versions) / sizeof(*versions),
msvc) - 1;
unsigned difference = msvc.version - v->version;
std::cout << v->description;
if (difference) {
std::cout << " +" << difference;
}
std::cout << std::endl;
}
#else
void write_compiler_info() {
}
#endif
#define PRINT(x) std::cout << #x ": " << x << std::endl
int main() {
write_compiler_info();
std::cout << 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
#if defined(BOOST_NO_CXX17_HDR_OPTIONAL)
std::cout << "No <optional>" << std::endl;
#else
std::cout << "Has <optional>" << std::endl;
#endif
#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 << "Has <typeindex>" << std::endl;
#endif
#if defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
std::cout << "No <system_error>" << std::endl;
#else
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);
PRINT(std::numeric_limits<std::size_t>::digits);
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();
}

35
test/hash_list_test.cpp Normal file
View File

@@ -0,0 +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)
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_EXTENSIONS
# ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
# else
# include <boost/container_hash/hash.hpp>
# endif
#endif
#include <boost/core/lightweight_test.hpp>
#ifdef BOOST_HASH_TEST_EXTENSIONS
#include <list>
using std::list;
#define CONTAINER_TYPE list
#include "./hash_sequence_test.hpp"
#endif // BOOST_HASH_TEST_EXTENSIONS
int main()
{
#ifdef BOOST_HASH_TEST_EXTENSIONS
list_tests::list_hash_integer_tests();
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,17 @@
// 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)
#include "hash_float_test.hpp"
int main()
{
std::cerr<<"Compiler: "<<BOOST_COMPILER<<"\n";
std::cerr<<"Platform: "<<BOOST_PLATFORM<<"\n";
std::cerr<<"Library: "<<BOOST_STDLIB<<"\n\n";
float_tests("long double", (long double*) 0);
return boost::report_errors();
}

40
test/hash_map_test.cpp Normal file
View File

@@ -0,0 +1,40 @@
// 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)
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_EXTENSIONS
# ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
# else
# include <boost/container_hash/hash.hpp>
# endif
#endif
#include <boost/core/lightweight_test.hpp>
#include <map>
#ifdef BOOST_HASH_TEST_EXTENSIONS
using std::map;
#define CONTAINER_TYPE map
#include "./hash_map_test.hpp"
using std::multimap;
#define CONTAINER_TYPE multimap
#include "./hash_map_test.hpp"
#endif // BOOST_HASH_TEST_EXTENSIONS
int main()
{
#ifdef BOOST_HASH_TEST_EXTENSIONS
map_tests::map_hash_integer_tests();
multimap_tests::multimap_hash_integer_tests();
#endif
return boost::report_errors();
}

83
test/hash_map_test.hpp Normal file
View File

@@ -0,0 +1,83 @@
// 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(CONTAINER_TYPE)
#error "CONTAINER_TYPE not defined"
#else
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4244) // conversion from 'int' to 'float'
#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>
void integer_tests(T* = 0)
{
const int number_of_containers = 10;
T containers[number_of_containers];
typedef BOOST_DEDUCED_TYPENAME T::value_type pair;
typedef BOOST_DEDUCED_TYPENAME T::key_type key;
typedef BOOST_DEDUCED_TYPENAME T::mapped_type value;
for(int i = 0; i < 5; ++i) {
for(int j = 0; j < i; ++j)
containers[i].insert(pair(key(0), value(0)));
}
containers[6].insert(pair(key(1),value(0)));
containers[7].insert(pair(key(1),value(0)));
containers[7].insert(pair(key(1),value(0)));
containers[8].insert(pair(key(-1),value(1)));
containers[9].insert(pair(key(-1),value(3)));
containers[9].insert(pair(key(-1),value(3)));
BOOST_HASH_TEST_NAMESPACE::hash<T> hasher;
for(int i2 = 0; i2 < number_of_containers; ++i2) {
BOOST_TEST(hasher(containers[i2]) == hasher(containers[i2]));
BOOST_TEST(hasher(containers[i2]) ==
BOOST_HASH_TEST_NAMESPACE::hash_value(containers[i2]));
BOOST_TEST(hasher(containers[i2])
== BOOST_HASH_TEST_NAMESPACE::hash_range(
containers[i2].begin(), containers[i2].end()));
for(int j2 = i2 + 1; j2 < number_of_containers; ++j2) {
BOOST_TEST(
(containers[i2] == containers[j2]) ==
(hasher(containers[i2]) == hasher(containers[j2]))
);
}
}
}
void HASH_TEST_CAT(CONTAINER_TYPE, _hash_integer_tests())
{
integer_tests((CONTAINER_TYPE<char, unsigned char>*) 0);
integer_tests((CONTAINER_TYPE<int, float>*) 0);
integer_tests((CONTAINER_TYPE<unsigned long, unsigned long>*) 0);
integer_tests((CONTAINER_TYPE<double, short>*) 0);
}
}
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic pop
#endif
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
#undef CONTAINER_TYPE
#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

@@ -0,0 +1,37 @@
// 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"
#if defined(BOOST_HASH_TEST_EXTENSIONS)
// Include header without BOOST_HASH_NO_EXTENSIONS defined
# if defined(BOOST_HASH_NO_EXTENSIONS)
# undef BOOST_HASH_NO_EXTENSIONS
# endif
# include <boost/container_hash/hash.hpp>
// Include header with BOOST_HASH_NO_EXTENSIONS defined
# define BOOST_HASH_NO_EXTENSIONS
# include <boost/container_hash/hash.hpp>
#endif
#include <boost/core/lightweight_test.hpp>
#include <deque>
int main()
{
#if defined(BOOST_HASH_TEST_EXTENSIONS)
std::deque<int> x;
x.push_back(1);
x.push_back(2);
BOOST_HASH_TEST_NAMESPACE::hash<std::deque<int> > hasher;
BOOST_TEST(hasher(x) == BOOST_HASH_TEST_NAMESPACE::hash_value(x));
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,37 @@
// 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"
#if defined(BOOST_HASH_TEST_EXTENSIONS)
// Include header with BOOST_HASH_NO_EXTENSIONS defined
# if !defined(BOOST_HASH_NO_EXTENSIONS)
# define BOOST_HASH_NO_EXTENSIONS
# endif
# include <boost/container_hash/hash.hpp>
// Include header without BOOST_HASH_NO_EXTENSIONS defined
# undef BOOST_HASH_NO_EXTENSIONS
# include <boost/container_hash/hash.hpp>
#endif
#include <boost/core/lightweight_test.hpp>
#include <map>
int main()
{
#if defined(BOOST_HASH_TEST_EXTENSIONS)
std::map<int, int> x;
x.insert(std::map<int, int>::value_type(53, -42));
x.insert(std::map<int, int>::value_type(14, -75));
BOOST_HASH_TEST_NAMESPACE::hash<std::map<int, int> > hasher;
BOOST_TEST(hasher(x) == BOOST_HASH_TEST_NAMESPACE::hash_value(x));
#endif
return boost::report_errors();
}

201
test/hash_number_test.cpp Normal file
View File

@@ -0,0 +1,201 @@
// 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)
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
#else
# include <boost/container_hash/hash.hpp>
#endif
#include <iostream>
#include <boost/core/lightweight_test.hpp>
#include <boost/container_hash/detail/limits.hpp>
#include <boost/core/enable_if.hpp>
#include "./compile_time.hpp"
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4127) // conditional expression is constant
#pragma warning(disable:4309) // truncation of constant value
#pragma warning(disable:4310) // cast truncates constant value
#endif
#if ( defined(__GNUC__) || defined(__clang__) ) && !defined(BOOST_INTEL_CXX_VERSION)
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
template <class T>
void numeric_extra_tests(typename
boost::enable_if_c<boost::hash_detail::limits<T>::is_integer,
void*>::type = 0)
{
typedef boost::hash_detail::limits<T> limits;
if(limits::is_signed ||
limits::digits <= boost::hash_detail::limits<std::size_t>::digits)
{
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(T(-5)) == (std::size_t)T(-5));
}
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(T(0)) == (std::size_t)T(0u));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(T(10)) == (std::size_t)T(10u));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(T(25)) == (std::size_t)T(25u));
}
template <class T>
void numeric_extra_tests(typename
boost::disable_if_c<boost::hash_detail::limits<T>::is_integer,
void*>::type = 0)
{
}
template <class T>
void numeric_test(T*)
{
compile_time_tests((T*) 0);
BOOST_HASH_TEST_NAMESPACE::hash<T> x1;
BOOST_HASH_TEST_NAMESPACE::hash<T> x2;
T v1 = (T) -5;
BOOST_TEST(x1(v1) == x2(v1));
BOOST_TEST(x1(T(-5)) == x2(T(-5)));
BOOST_TEST(x1(T(0)) == x2(T(0)));
BOOST_TEST(x1(T(10)) == x2(T(10)));
BOOST_TEST(x1(T(25)) == x2(T(25)));
BOOST_TEST(x1(T(5) - T(5)) == x2(T(0)));
BOOST_TEST(x1(T(6) + T(4)) == x2(T(10)));
#if defined(BOOST_HASH_TEST_EXTENSIONS)
BOOST_TEST(x1(T(-5)) == BOOST_HASH_TEST_NAMESPACE::hash_value(T(-5)));
BOOST_TEST(x1(T(0)) == BOOST_HASH_TEST_NAMESPACE::hash_value(T(0)));
BOOST_TEST(x1(T(10)) == BOOST_HASH_TEST_NAMESPACE::hash_value(T(10)));
BOOST_TEST(x1(T(25)) == BOOST_HASH_TEST_NAMESPACE::hash_value(T(25)));
numeric_extra_tests<T>();
#endif
}
template <class T>
void limits_test(T*)
{
typedef boost::hash_detail::limits<T> limits;
if(limits::is_specialized)
{
BOOST_HASH_TEST_NAMESPACE::hash<T> x1;
BOOST_HASH_TEST_NAMESPACE::hash<T> x2;
T min_value = (limits::min)();
T max_value = (limits::max)();
BOOST_TEST(x1(min_value) == x2((limits::min)()));
BOOST_TEST(x1(max_value) == x2((limits::max)()));
#if defined(BOOST_HASH_TEST_EXTENSIONS)
BOOST_TEST(x1(min_value) == BOOST_HASH_TEST_NAMESPACE::hash_value(min_value));
BOOST_TEST(x1(max_value) == BOOST_HASH_TEST_NAMESPACE::hash_value(max_value));
if (limits::is_integer)
{
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
}
}
template <class T>
void poor_quality_tests(T*)
{
typedef boost::hash_detail::limits<T> limits;
BOOST_HASH_TEST_NAMESPACE::hash<T> x1;
BOOST_HASH_TEST_NAMESPACE::hash<T> x2;
// A hash function can legally fail these tests, but it'll not be a good
// sign.
if(T(1) != T(-1))
BOOST_TEST(x1(T(1)) != x2(T(-1)));
if(T(1) != T(2))
BOOST_TEST(x1(T(1)) != x2(T(2)));
// TODO: This test is useless for floating point numbers.
T max_number = static_cast<T>((limits::max)());
T max_minus_one = static_cast<T>(max_number - 1);
if (max_number != max_minus_one) {
BOOST_TEST(x1(max_number) != x1(max_minus_one));
}
}
void bool_test()
{
BOOST_HASH_TEST_NAMESPACE::hash<bool> x1;
BOOST_HASH_TEST_NAMESPACE::hash<bool> x2;
BOOST_TEST(x1(true) == x2(true));
BOOST_TEST(x1(false) == x2(false));
BOOST_TEST(x1(true) != x2(false));
BOOST_TEST(x1(false) != x2(true));
}
#define NUMERIC_TEST(type, name) \
std::cerr<<"Testing: " BOOST_STRINGIZE(name) "\n"; \
numeric_test((type*) 0); \
limits_test((type*) 0); \
poor_quality_tests((type*) 0);
#define NUMERIC_TEST_NO_LIMITS(type, name) \
std::cerr<<"Testing: " BOOST_STRINGIZE(name) "\n"; \
numeric_test((type*) 0); \
poor_quality_tests((type*) 0);
int main()
{
NUMERIC_TEST(char, char)
NUMERIC_TEST(signed char, schar)
NUMERIC_TEST(unsigned char, uchar)
#ifndef BOOST_NO_INTRINSIC_WCHAR_T
NUMERIC_TEST(wchar_t, wchar)
#endif
#ifndef BOOST_NO_CXX11_CHAR16_T
NUMERIC_TEST(char16_t, char16)
#endif
#ifndef BOOST_NO_CXX11_CHAR32_T
NUMERIC_TEST(char32_t, char32)
#endif
NUMERIC_TEST(short, short)
NUMERIC_TEST(unsigned short, ushort)
NUMERIC_TEST(int, int)
NUMERIC_TEST(unsigned int, uint)
NUMERIC_TEST(long, hash_long)
NUMERIC_TEST(unsigned long, ulong)
#if !defined(BOOST_NO_LONG_LONG)
NUMERIC_TEST_NO_LIMITS(boost::long_long_type, long_long)
NUMERIC_TEST_NO_LIMITS(boost::ulong_long_type, ulong_long)
#endif
#if defined(BOOST_HAS_INT128)
NUMERIC_TEST_NO_LIMITS(boost::int128_type, int128)
NUMERIC_TEST_NO_LIMITS(boost::uint128_type, uint128)
#endif
NUMERIC_TEST(float, float)
NUMERIC_TEST(double, double)
NUMERIC_TEST(std::size_t, size_t)
NUMERIC_TEST(std::ptrdiff_t, ptrdiff_t)
bool_test();
return boost::report_errors();
}
#if defined(BOOST_MSVC)
#pragma warning(pop)
#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

@@ -0,0 +1,70 @@
// Copyright 2018 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"
#ifndef BOOST_HASH_TEST_STD_INCLUDES
# include <boost/container_hash/hash.hpp>
#endif
#include <boost/config.hpp>
#include <boost/core/lightweight_test.hpp>
#if !defined(BOOST_NO_CXX17_HDR_OPTIONAL)
#include <optional>
#include <string>
void test_optional_int()
{
std::optional<int> x1a;
std::optional<int> x1b;
std::optional<int> x2a(10);
std::optional<int> x2b(x2a);
std::optional<int> x3(20);
boost::hash<std::optional<int> > hasher;
BOOST_TEST(hasher(x1a) == hasher(x1a));
BOOST_TEST(hasher(x1a) == hasher(x1b));
BOOST_TEST(hasher(x1a) != hasher(x2a));
BOOST_TEST(hasher(x1a) != hasher(x3));
BOOST_TEST(hasher(x2a) == hasher(x2a));
BOOST_TEST(hasher(x2b) == hasher(x2b));
BOOST_TEST(hasher(x2a) != hasher(x3));
BOOST_TEST(hasher(x3) == hasher(x3));
}
void test_optional_string()
{
std::optional<std::string> x1a;
std::optional<std::string> x1b;
std::optional<std::string> x2a("10");
std::optional<std::string> x2b(x2a);
std::optional<std::string> x3("20");
boost::hash<std::optional<std::string> > hasher;
BOOST_TEST(hasher(x1a) == hasher(x1a));
BOOST_TEST(hasher(x1a) == hasher(x1b));
BOOST_TEST(hasher(x1a) != hasher(x2a));
BOOST_TEST(hasher(x1a) != hasher(x3));
BOOST_TEST(hasher(x2a) == hasher(x2a));
BOOST_TEST(hasher(x2b) == hasher(x2b));
BOOST_TEST(hasher(x2a) != hasher(x3));
BOOST_TEST(hasher(x3) == hasher(x3));
}
#endif
int main()
{
#if !defined(BOOST_NO_CXX17_HDR_OPTIONAL)
test_optional_int();
test_optional_string();
#else
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "<optional> not available." << std::endl;
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,45 @@
// 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)
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
#else
# include <boost/container_hash/hash.hpp>
#endif
#include <boost/core/lightweight_test.hpp>
#include <boost/limits.hpp>
#include "./compile_time.hpp"
void pointer_tests()
{
compile_time_tests((int**) 0);
compile_time_tests((void**) 0);
BOOST_HASH_TEST_NAMESPACE::hash<int*> x1;
BOOST_HASH_TEST_NAMESPACE::hash<int*> x2;
int int1;
int int2;
BOOST_TEST(x1(0) == x2(0));
BOOST_TEST(x1(&int1) == x2(&int1));
BOOST_TEST(x1(&int2) == x2(&int2));
#if defined(BOOST_HASH_TEST_EXTENSIONS)
BOOST_TEST(x1(&int1) == BOOST_HASH_TEST_NAMESPACE::hash_value(&int1));
BOOST_TEST(x1(&int2) == BOOST_HASH_TEST_NAMESPACE::hash_value(&int2));
// This isn't specified in Peter's proposal:
BOOST_TEST(x1(0) == 0);
#endif
}
int main()
{
pointer_tests();
return boost::report_errors();
}

85
test/hash_range_test.cpp Normal file
View File

@@ -0,0 +1,85 @@
// 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)
#include "./config.hpp"
#if !defined(BOOST_HASH_TEST_EXTENSIONS)
int main() {}
#else
#ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
#else
# include <boost/container_hash/hash.hpp>
#endif
#include <boost/core/lightweight_test.hpp>
#include <boost/limits.hpp>
#include <vector>
void hash_range_tests()
{
std::vector<int> empty, values1, values2, values3, values4, values5;
values1.push_back(0);
values2.push_back(10);
values3.push_back(10);
values3.push_back(20);
values4.push_back(15);
values4.push_back(75);
values5.push_back(10);
values5.push_back(20);
values5.push_back(15);
values5.push_back(75);
values5.push_back(10);
values5.push_back(20);
std::vector<int> x;
std::size_t x_seed = 0;
BOOST_TEST(x_seed == BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_range(empty.begin(), empty.end())
== BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_range(empty.begin(), empty.end())
!= BOOST_HASH_TEST_NAMESPACE::hash_range(values1.begin(), values1.end()));
x.push_back(10);
BOOST_HASH_TEST_NAMESPACE::hash_combine(x_seed, 10);
BOOST_TEST(x_seed == BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_range(empty.begin(), empty.end())
!= BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_range(values2.begin(), values2.end())
== BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
x.push_back(20);
BOOST_HASH_TEST_NAMESPACE::hash_combine(x_seed, 20);
BOOST_TEST(x_seed == BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_range(empty.begin(), empty.end())
!= BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_range(values2.begin(), values2.end())
!= BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_range(values3.begin(), values3.end())
== BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
std::size_t seed =
BOOST_HASH_TEST_NAMESPACE::hash_range(values3.begin(), values3.end());
BOOST_HASH_TEST_NAMESPACE::hash_range(seed, values4.begin(), values4.end());
BOOST_HASH_TEST_NAMESPACE::hash_range(seed, x.begin(), x.end());
BOOST_TEST(seed ==
BOOST_HASH_TEST_NAMESPACE::hash_range(values5.begin(), values5.end()));
}
int main()
{
hash_range_tests();
return boost::report_errors();
}
#endif // TEST_EXTESNIONS

View File

@@ -0,0 +1,464 @@
// Copyright 2021 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#define _SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING
#include <boost/config/pragma_message.hpp>
#if defined(__GNUC__) && !defined(__clang__) && __cplusplus < 201100L
BOOST_PRAGMA_MESSAGE("Skipping test under GCC in C++98 mode")
int main() {}
#else
#if defined(__clang__)
# pragma clang diagnostic ignored "-Wlong-long"
#endif
#if defined(__GNUC__)
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#if defined(_MSC_VER)
# pragma warning(disable: 4127) // conditional expression is constant
#endif
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <string>
#include <vector>
#include <list>
#include <utility>
#include <complex>
#include <limits>
#include <climits>
#include <cfloat>
#include <cstddef>
// This test checks whether hash values have changed
template<class T> std::size_t hv( T const& t )
{
return boost::hash<T>()( t );
}
int main()
{
// char
BOOST_TEST_EQ( hv('\x00'), 0 );
BOOST_TEST_EQ( hv('A'), 'A' );
BOOST_TEST_EQ( hv('\x7F'), 0x7F );
// signed char
BOOST_TEST_EQ( hv((signed char)0), 0 );
BOOST_TEST_EQ( hv((signed char)+1), +1 );
BOOST_TEST_EQ( hv((signed char)-1), (std::size_t)-1 );
BOOST_TEST_EQ( hv((signed char)+127), 127 );
BOOST_TEST_EQ( hv((signed char)-128), (std::size_t)-128 );
// unsigned char
BOOST_TEST_EQ( hv((unsigned char)0), 0 );
BOOST_TEST_EQ( hv((unsigned char)1), 1 );
BOOST_TEST_EQ( hv((unsigned char)255), 255 );
// short
BOOST_TEST_EQ( hv((short)0), 0 );
BOOST_TEST_EQ( hv((short)+1), 1 );
BOOST_TEST_EQ( hv((short)-1), (std::size_t)-1 );
BOOST_TEST_EQ( hv((short)+32767), 32767 );
BOOST_TEST_EQ( hv((short)-32768), (std::size_t)-32768 );
// unsigned short
BOOST_TEST_EQ( hv((unsigned short)0), 0 );
BOOST_TEST_EQ( hv((unsigned short)1), 1 );
BOOST_TEST_EQ( hv((unsigned short)65535), 65535 );
// int
BOOST_TEST_EQ( hv(0), 0 );
BOOST_TEST_EQ( hv(+1), 1 );
BOOST_TEST_EQ( hv(-1), (std::size_t)-1 );
BOOST_TEST_EQ( hv(+32767), 32767 );
BOOST_TEST_EQ( hv(-32768), (std::size_t)-32768 );
// unsigned int
BOOST_TEST_EQ( hv((unsigned)0), 0 );
BOOST_TEST_EQ( hv((unsigned)1), 1 );
BOOST_TEST_EQ( hv((unsigned)65535), 65535 );
BOOST_TEST_EQ( hv((unsigned)-1), (std::size_t)(unsigned)-1 );
// long
BOOST_TEST_EQ( hv(0L), 0 );
BOOST_TEST_EQ( hv(+1L), 1 );
BOOST_TEST_EQ( hv(-1L), (std::size_t)-1 );
BOOST_TEST_EQ( hv(+32767L), 32767 );
BOOST_TEST_EQ( hv(-32768L), (std::size_t)-32768 );
// unsigned long
BOOST_TEST_EQ( hv(0UL), 0 );
BOOST_TEST_EQ( hv(1UL), 1 );
BOOST_TEST_EQ( hv(65535UL), 65535 );
BOOST_TEST_EQ( hv((unsigned long)-1), (std::size_t)(unsigned long)-1 );
// long long
BOOST_TEST_EQ( hv(0LL), 0 );
BOOST_TEST_EQ( hv(+1LL), 1 );
BOOST_TEST_EQ( hv(-1LL), (std::size_t)-1 );
BOOST_TEST_EQ( hv(+32767LL), 32767 );
BOOST_TEST_EQ( hv(-32768LL), (std::size_t)-32768 );
// unsigned long long
BOOST_TEST_EQ( hv(0ULL), 0 );
BOOST_TEST_EQ( hv(1ULL), 1 );
BOOST_TEST_EQ( hv(65535ULL), 65535 );
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv((unsigned long long)-1), 2578835074U );
#else
BOOST_TEST_EQ( hv((unsigned long long)-1), (std::size_t)-1 );
#endif
#if defined(BOOST_HAS_INT128)
typedef boost::int128_type int128;
BOOST_TEST_EQ( hv((int128)0), 0 );
BOOST_TEST_EQ( hv((int128)1), 1 );
BOOST_TEST_EQ( hv((int128)-1), (std::size_t)-1 );
BOOST_TEST_EQ( hv((int128)+32767), 32767 );
BOOST_TEST_EQ( hv((int128)-32768), (std::size_t)-32768 );
typedef boost::uint128_type uint128;
BOOST_TEST_EQ( hv((uint128)0), 0 );
BOOST_TEST_EQ( hv((uint128)1), 1 );
BOOST_TEST_EQ( hv((uint128)65535), 65535 );
#if defined(BOOST_GCC) && BOOST_GCC < 100000
// This looks like some sort of miscompilation.
// Under CI, both GHA and Appveyor GCCs produce this value.
// But the exact same test on godbolt.org produces the correct
// value, below.
// BOOST_TEST_EQ( hv((uint128)-1), 18446744073709551615ULL );
#else
BOOST_TEST_EQ( hv((uint128)-1), 10400452472442790415ULL );
#endif
#endif
// float
BOOST_TEST_EQ( hv(0.0f), 0 );
BOOST_TEST_EQ( hv(-0.0f), 0 );
BOOST_TEST_EQ( hv(1.0f), 1065353216U );
BOOST_TEST_EQ( hv(-1.0f), 3212836864U );
BOOST_TEST_EQ( hv(3.14f), 1078523331U );
BOOST_TEST_EQ( hv(-3.14f), 3226006979U );
BOOST_TEST_EQ( hv(1e-38f), 7136238U );
BOOST_TEST_EQ( hv(-1e-38f), 2154619886U );
BOOST_TEST_EQ( hv(1e+38f), 2123789977U );
BOOST_TEST_EQ( hv(-1e+38f), 4271273625U );
BOOST_TEST_EQ( hv(std::numeric_limits<float>::infinity()), 2139095040U );
BOOST_TEST_EQ( hv(-std::numeric_limits<float>::infinity()), 4286578688U );
// double
BOOST_TEST_EQ( hv(0.0), 0 );
BOOST_TEST_EQ( hv(-0.0), 0 );
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(1.0), 2619008688U );
BOOST_TEST_EQ( hv(-1.0), 146497060U );
BOOST_TEST_EQ( hv(3.14), 101651732U );
BOOST_TEST_EQ( hv(-3.14), 210858151U );
BOOST_TEST_EQ( hv(1e-308), 3911789313U );
BOOST_TEST_EQ( hv(-1e-308), 1812507313U );
BOOST_TEST_EQ( hv(1e+308), 987802568U );
BOOST_TEST_EQ( hv(-1e+308), 1639042439U );
BOOST_TEST_EQ( hv(std::numeric_limits<double>::infinity()), 3227645345U );
BOOST_TEST_EQ( hv(-std::numeric_limits<double>::infinity()), 2247339177U );
#else
BOOST_TEST_EQ( hv(1.0), 4607182418800017408ULL );
BOOST_TEST_EQ( hv(-1.0), 13830554455654793216ULL );
BOOST_TEST_EQ( hv(3.14), 4614253070214989087ULL );
BOOST_TEST_EQ( hv(-3.14), 13837625107069764895ULL );
BOOST_TEST_EQ( hv(1e-308), 2024022533073106ULL );
BOOST_TEST_EQ( hv(-1e-308), 9225396059387848914ULL );
BOOST_TEST_EQ( hv(1e+308), 9214871658872686752ULL );
BOOST_TEST_EQ( hv(-1e+308), 18438243695727462560ULL );
BOOST_TEST_EQ( hv(std::numeric_limits<double>::infinity()), 9218868437227405312ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<double>::infinity()), 18442240474082181120ULL );
#endif
// long double
BOOST_TEST_EQ( hv(0.0L), 0 );
BOOST_TEST_EQ( hv(-0.0L), 0 );
std::size_t const ldbits = sizeof( long double ) * CHAR_BIT;
#if SIZE_MAX == 4294967295U
if( ldbits == 64 )
{
BOOST_TEST_EQ( hv(1.0L), hv(1.0) );
BOOST_TEST_EQ( hv(-1.0L), hv(-1.0) );
BOOST_TEST_EQ( hv(3.14L), hv(3.14) );
BOOST_TEST_EQ( hv(-3.14L), hv(-3.14) );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), hv(std::numeric_limits<double>::infinity()) );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), hv(-std::numeric_limits<double>::infinity()) );
}
else
{
// ldbits == 96
BOOST_TEST_EQ( hv(1.0L), 3632050780U );
BOOST_TEST_EQ( hv(-1.0L), 3632083548U );
BOOST_TEST_EQ( hv(3.14L), 1742026549U );
BOOST_TEST_EQ( hv(-3.14L), 1742059317U );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 3632067164U );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 3632099932U );
}
#else
if( ldbits == 64 )
{
BOOST_TEST_EQ( hv(1.0L), 4607182418800017408ULL );
BOOST_TEST_EQ( hv(-1.0L), 13830554455654793216ULL );
BOOST_TEST_EQ( hv(3.14L), 4614253070214989087ULL );
BOOST_TEST_EQ( hv(-3.14L), 13837625107069764895ULL );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 9218868437227405312ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 18442240474082181120ULL );
}
else if( ldbits == 128 && std::numeric_limits<long double>::digits == 64 )
{
BOOST_TEST_EQ( hv(1.0L), 18308860000934227808ULL );
BOOST_TEST_EQ( hv(-1.0L), 18308860000934260576ULL );
BOOST_TEST_EQ( hv(3.14L), 13482288377848558187ULL );
BOOST_TEST_EQ( hv(-3.14L), 13482288377848590955ULL );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 18308860000934244192ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 18308860000934276960ULL );
}
else
{
// ldbits == 128 && std::numeric_limits<long double>::digits == 113
BOOST_TEST_EQ( hv(1.0L), 4611404543450677248ULL );
BOOST_TEST_EQ( hv(-1.0L), 13834776580305453056ULL );
BOOST_TEST_EQ( hv(3.14L), 5967435363179612952ULL );
BOOST_TEST_EQ( hv(-3.14L), 15190807400034388760ULL );
BOOST_TEST_EQ( hv(std::numeric_limits<long double>::infinity()), 9223090561878065152ULL );
BOOST_TEST_EQ( hv(-std::numeric_limits<long double>::infinity()), 18446462598732840960ULL );
}
#endif
// C array
{
int a1[] = { 0 };
int a2[] = { 0, 0 };
int a3[] = { 0, 0, 0 };
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(a1), 1684164658U );
BOOST_TEST_EQ( hv(a2), 3385628684U );
BOOST_TEST_EQ( hv(a3), 354805152U );
#else
BOOST_TEST_EQ( hv(a1), 11915877628236072130ULL );
BOOST_TEST_EQ( hv(a2), 17303869719317669699ULL );
BOOST_TEST_EQ( hv(a3), 14973878137098559850ULL );
#endif
}
// string
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::string()), 1580013426U );
BOOST_TEST_EQ( hv(std::string("abc")), 469308065U );
BOOST_TEST_EQ( hv(std::string("\0", 1)), 165258820U );
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 4017288109U );
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 1352445396U );
#else
BOOST_TEST_EQ( hv(std::string()), 2220755840493918647ULL );
BOOST_TEST_EQ( hv(std::string("abc")), 7565583854499162206ULL );
BOOST_TEST_EQ( hv(std::string("\0", 1)), 1241131678047372712ULL );
BOOST_TEST_EQ( hv(std::string("\0\0", 2)), 152341731040131640ULL );
BOOST_TEST_EQ( hv(std::string("\0\0\0", 3)), 12957252994983528908ULL );
#endif
// pointer
BOOST_TEST_EQ( hv((void*)0), 0 );
BOOST_TEST_EQ( hv((void*)0x200014A0), 603985716U );
// complex<int>
BOOST_TEST_EQ( hv(std::complex<int>(0, 0)), 0U );
BOOST_TEST_EQ( hv(std::complex<int>(+1, 0)), 1U );
#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)), 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)), 10400452472442790416ULL );
#endif
// complex<float>
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, 0.0f)), 0U );
BOOST_TEST_EQ( hv(std::complex<float>(+1.0f, 0.0f)), 1065353216U );
BOOST_TEST_EQ( hv(std::complex<float>(-1.0f, 0.0f)), 3212836864U );
#if SIZE_MAX == 4294967295U
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)), 15274800114361806457ULL );
BOOST_TEST_EQ( hv(std::complex<float>(0.0f, -1.0f)), 4238815378092176215ULL );
#endif
// complex<double>
BOOST_TEST_EQ( hv(std::complex<double>(0.0, 0.0)), 0U );
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::complex<double>(+1.0, 0.0)), 2619008688U );
BOOST_TEST_EQ( hv(std::complex<double>(-1.0, 0.0)), 146497060U );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, +1.0)), 22395692U );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, -1.0)), 1449221192U );
#else
BOOST_TEST_EQ( hv(std::complex<double>(+1.0, 0.0)), 4607182418800017408ULL );
BOOST_TEST_EQ( hv(std::complex<double>(-1.0, 0.0)), 13830554455654793216ULL );
BOOST_TEST_EQ( hv(std::complex<double>(0.0, +1.0)), 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)), 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)), 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)), 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)), 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
// vector<int>
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::vector<int>(0)), 0 );
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)), 11915877628236072130ULL );
BOOST_TEST_EQ( hv(std::vector<int>(2)), 17303869719317669699ULL );
BOOST_TEST_EQ( hv(std::vector<int>(3)), 14973878137098559850ULL );
#endif
// vector<vector<int>>
#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)), 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)), 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)), 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)), 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
// list<int>
#if SIZE_MAX == 4294967295U
BOOST_TEST_EQ( hv(std::list<int>(0)), 0 );
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)), 11915877628236072130ULL );
BOOST_TEST_EQ( hv(std::list<int>(2)), 17303869719317669699ULL );
BOOST_TEST_EQ( hv(std::list<int>(3)), 14973878137098559850ULL );
#endif
return boost::report_errors();
}
#endif

View File

@@ -0,0 +1,85 @@
// 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(CONTAINER_TYPE)
#error "CONTAINER_TYPE not defined"
#else
#if defined(BOOST_MSVC)
#pragma warning(push)
#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>
void integer_tests(T* = 0)
{
typedef typename T::value_type value_type;
const int number_of_containers = 11;
T containers[number_of_containers];
for(int i = 0; i < 5; ++i) {
for(int j = 0; j < i; ++j)
containers[i].push_back(0);
}
containers[5].push_back(value_type(1));
containers[6].push_back(value_type(1));
containers[6].push_back(value_type(1));
containers[7].push_back(value_type(-1));
containers[8].push_back(value_type(-1));
containers[8].push_back(value_type(-1));
containers[9].push_back(value_type(1));
containers[9].push_back(value_type(-1));
containers[10].push_back(value_type(-1));
containers[10].push_back(value_type(1));
BOOST_HASH_TEST_NAMESPACE::hash<T> hasher;
for(int i2 = 0; i2 < number_of_containers; ++i2) {
BOOST_TEST(hasher(containers[i2]) == hasher(containers[i2]));
BOOST_TEST(hasher(containers[i2]) ==
BOOST_HASH_TEST_NAMESPACE::hash_value(containers[i2]));
BOOST_TEST(hasher(containers[i2])
== BOOST_HASH_TEST_NAMESPACE::hash_range(
containers[i2].begin(), containers[i2].end()));
for(int j2 = i2 + 1; j2 < number_of_containers; ++j2) {
BOOST_TEST(
(containers[i2] == containers[j2]) ==
(hasher(containers[i2]) == hasher(containers[j2]))
);
}
}
}
void HASH_TEST_CAT(CONTAINER_TYPE, _hash_integer_tests())
{
integer_tests((CONTAINER_TYPE<char>*) 0);
integer_tests((CONTAINER_TYPE<int>*) 0);
integer_tests((CONTAINER_TYPE<unsigned long>*) 0);
integer_tests((CONTAINER_TYPE<double>*) 0);
}
}
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic pop
#endif
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
#undef CONTAINER_TYPE
#endif

40
test/hash_set_test.cpp Normal file
View File

@@ -0,0 +1,40 @@
// 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)
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_EXTENSIONS
# ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
# else
# include <boost/container_hash/hash.hpp>
# endif
#endif
#include <boost/core/lightweight_test.hpp>
#ifdef BOOST_HASH_TEST_EXTENSIONS
#include <set>
using std::set;
#define CONTAINER_TYPE set
#include "./hash_set_test.hpp"
using std::multiset;
#define CONTAINER_TYPE multiset
#include "./hash_set_test.hpp"
#endif
int main()
{
#ifdef BOOST_HASH_TEST_EXTENSIONS
set_tests::set_hash_integer_tests();
multiset_tests::multiset_hash_integer_tests();
#endif
return boost::report_errors();
}

88
test/hash_set_test.hpp Normal file
View File

@@ -0,0 +1,88 @@
// 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(CONTAINER_TYPE)
#error "CONTAINER_TYPE not defined"
#else
#if defined(BOOST_MSVC)
#pragma warning(push)
#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>
void integer_tests(T* = 0)
{
typedef typename T::value_type value_type;
const int number_of_containers = 12;
T containers[number_of_containers];
for(int i = 0; i < 5; ++i) {
for(int j = 0; j < i; ++j)
containers[i].insert(0);
}
containers[6].insert(value_type(1));
containers[7].insert(value_type(1));
containers[7].insert(value_type(1));
containers[8].insert(value_type(-1));
containers[9].insert(value_type(-1));
containers[9].insert(value_type(-1));
containers[10].insert(value_type(-1));
containers[10].insert(value_type(1));
containers[11].insert(value_type(1));
containers[11].insert(value_type(2));
containers[11].insert(value_type(3));
containers[11].insert(value_type(4));
containers[11].insert(value_type(5));
BOOST_HASH_TEST_NAMESPACE::hash<T> hasher;
for(int i2 = 0; i2 < number_of_containers; ++i2) {
BOOST_TEST(hasher(containers[i2]) == hasher(containers[i2]));
BOOST_TEST(hasher(containers[i2]) ==
BOOST_HASH_TEST_NAMESPACE::hash_value(containers[i2]));
BOOST_TEST(hasher(containers[i2])
== BOOST_HASH_TEST_NAMESPACE::hash_range(
containers[i2].begin(), containers[i2].end()));
for(int j2 = i2 + 1; j2 < number_of_containers; ++j2) {
BOOST_TEST(
(containers[i2] == containers[j2]) ==
(hasher(containers[i2]) == hasher(containers[j2]))
);
}
}
}
void HASH_TEST_CAT(CONTAINER_TYPE, _hash_integer_tests())
{
integer_tests((CONTAINER_TYPE<char>*) 0);
integer_tests((CONTAINER_TYPE<int>*) 0);
integer_tests((CONTAINER_TYPE<unsigned long>*) 0);
integer_tests((CONTAINER_TYPE<double>*) 0);
}
}
#if defined(__GNUC__) && __GNUC__ == 8
# pragma GCC diagnostic pop
#endif
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
#undef CONTAINER_TYPE
#endif

View File

@@ -0,0 +1,103 @@
// Copyright 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)
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_EXTENSIONS
# ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
# else
# include <boost/container_hash/hash.hpp>
# endif
#endif
#include <boost/config.hpp>
#include <boost/core/lightweight_test.hpp>
#if defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_NO_CXX11_HDR_ARRAY)
#define TEST_ARRAY
#include <array>
#include <vector>
#endif
#ifdef TEST_ARRAY
template <typename T>
void array_tests(T const& v) {
boost::hash<typename T::value_type> hf;
for(typename T::const_iterator i = v.begin(); i != v.end(); ++i) {
for(typename T::const_iterator j = v.begin(); j != v.end(); ++j) {
if (i != j)
BOOST_TEST(hf(*i) != hf(*j));
else
BOOST_TEST(hf(*i) == hf(*j));
}
}
}
void empty_array_test() {
/*
boost::hash<std::array<int, 0> > empty_array_hash;
std::array<int, 0> empty_array;
BOOST_TEST(empty_array_hash(empty_array) == boost::hash_value(empty_array));
*/
}
void int_1_array_test()
{
std::vector<std::array<int, 1> > arrays;
std::array<int, 1> val;
val[0] = 0;
arrays.push_back(val);
val[0] = 1;
arrays.push_back(val);
val[0] = 2;
arrays.push_back(val);
array_tests(arrays);
}
void string_1_array_test()
{
std::vector<std::array<std::string, 1> > arrays;
std::array<std::string, 1> val;
arrays.push_back(val);
val[0] = "one";
arrays.push_back(val);
val[0] = "two";
arrays.push_back(val);
array_tests(arrays);
}
void string_3_array_test()
{
std::vector<std::array<std::string,3 > > arrays;
std::array<std::string, 3> val;
arrays.push_back(val);
val[0] = "one";
arrays.push_back(val);
val[0] = ""; val[1] = "one"; val[2] = "";
arrays.push_back(val);
val[0] = ""; val[1] = ""; val[2] = "one";
arrays.push_back(val);
val[0] = "one"; val[1] = "one"; val[2] = "one";
arrays.push_back(val);
val[0] = "one"; val[1] = "two"; val[2] = "three";
arrays.push_back(val);
array_tests(arrays);
}
#endif // TEST_ARRAY
int main()
{
#ifdef TEST_ARRAY
empty_array_test();
int_1_array_test();
string_1_array_test();
string_3_array_test();
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,80 @@
// Copyright 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)
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
#else
# include <boost/container_hash/hash.hpp>
#endif
#include <boost/core/lightweight_test.hpp>
#include "./compile_time.hpp"
#if defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_NO_CXX11_SMART_PTR)
#define TEST_SMART_PTRS
#include <memory>
#endif
#ifdef TEST_SMART_PTRS
void shared_ptr_tests()
{
std::shared_ptr<int> x;
compile_time_tests(&x);
BOOST_HASH_TEST_NAMESPACE::hash<std::shared_ptr<int> > x1;
BOOST_HASH_TEST_NAMESPACE::hash<std::shared_ptr<int> > x2;
std::shared_ptr<int> ptr1(new int(10));
std::shared_ptr<int> ptr2;
BOOST_TEST(x1(x) == x2(ptr2));
BOOST_TEST(x1(x) != x2(ptr1));
ptr2.reset(new int(10));
BOOST_TEST(x1(ptr1) == x2(ptr1));
BOOST_TEST(x1(ptr1) != x2(ptr2));
ptr2 = ptr1;
BOOST_TEST(x1(ptr1) == x2(ptr2));
#if defined(BOOST_HASH_TEST_EXTENSIONS)
BOOST_TEST(x1(x) == BOOST_HASH_TEST_NAMESPACE::hash_value(x));
BOOST_TEST(x1(ptr1) == BOOST_HASH_TEST_NAMESPACE::hash_value(ptr2));
#endif
}
void unique_ptr_tests()
{
std::unique_ptr<int> x;
compile_time_tests(&x);
BOOST_HASH_TEST_NAMESPACE::hash<std::unique_ptr<int> > x1;
BOOST_HASH_TEST_NAMESPACE::hash<std::unique_ptr<int> > x2;
std::unique_ptr<int> ptr1(new int(10));
std::unique_ptr<int> ptr2;
BOOST_TEST(x1(x) == x2(ptr2));
BOOST_TEST(x1(x) != x2(ptr1));
ptr2.reset(new int(10));
BOOST_TEST(x1(ptr1) == x2(ptr1));
BOOST_TEST(x1(ptr1) != x2(ptr2));
#if defined(BOOST_HASH_TEST_EXTENSIONS)
BOOST_TEST(x1(x) == BOOST_HASH_TEST_NAMESPACE::hash_value(x));
#endif
}
#endif
int main()
{
#ifdef TEST_SMART_PTRS
shared_ptr_tests();
unique_ptr_tests();
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,77 @@
// Copyright 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)
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_EXTENSIONS
# ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
# else
# include <boost/container_hash/hash.hpp>
# endif
#endif
#include <boost/config.hpp>
#include <boost/core/lightweight_test.hpp>
#if defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
#define TEST_TUPLE
#include <tuple>
#include <vector>
#endif
#ifdef TEST_TUPLE
template <typename T>
void tuple_tests(T const& v) {
boost::hash<typename T::value_type> hf;
for(typename T::const_iterator i = v.begin(); i != v.end(); ++i) {
for(typename T::const_iterator j = v.begin(); j != v.end(); ++j) {
if (i != j)
BOOST_TEST(hf(*i) != hf(*j));
else
BOOST_TEST(hf(*i) == hf(*j));
}
}
}
void empty_tuple_test() {
boost::hash<std::tuple<> > empty_tuple_hash;
std::tuple<> empty_tuple;
BOOST_TEST(empty_tuple_hash(empty_tuple) == boost::hash_value(empty_tuple));
}
void int_tuple_test() {
std::vector<std::tuple<int> > int_tuples;
int_tuples.push_back(std::make_tuple(0));
int_tuples.push_back(std::make_tuple(1));
int_tuples.push_back(std::make_tuple(2));
tuple_tests(int_tuples);
}
void int_string_tuple_test() {
std::vector<std::tuple<int, std::string> > int_string_tuples;
int_string_tuples.push_back(std::make_tuple(0, std::string("zero")));
int_string_tuples.push_back(std::make_tuple(1, std::string("one")));
int_string_tuples.push_back(std::make_tuple(2, std::string("two")));
int_string_tuples.push_back(std::make_tuple(0, std::string("one")));
int_string_tuples.push_back(std::make_tuple(1, std::string("zero")));
int_string_tuples.push_back(std::make_tuple(0, std::string("")));
int_string_tuples.push_back(std::make_tuple(1, std::string("")));
tuple_tests(int_string_tuples);
}
#endif // TEST_TUPLE
int main()
{
#ifdef TEST_TUPLE
empty_tuple_test();
int_tuple_test();
int_string_tuple_test();
#endif
return boost::report_errors();
}

184
test/hash_string_test.cpp Normal file
View File

@@ -0,0 +1,184 @@
// 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)
#include "./config.hpp"
#ifdef BOOST_HASH_TEST_STD_INCLUDES
# include <functional>
#else
# include <boost/container_hash/hash.hpp>
#endif
#include <boost/core/lightweight_test.hpp>
#include <string>
#include "./compile_time.hpp"
void string_tests()
{
compile_time_tests((std::string*) 0);
BOOST_HASH_TEST_NAMESPACE::hash<std::string> x1;
BOOST_HASH_TEST_NAMESPACE::hash<std::string> x2;
BOOST_TEST(x1("Hello") == x2(std::string("Hel") + "lo"));
BOOST_TEST(x1("") == x2(std::string()));
#if defined(BOOST_HASH_TEST_EXTENSIONS)
std::string value1;
std::string value2("Hello");
BOOST_TEST(x1(value1) == BOOST_HASH_TEST_NAMESPACE::hash_value(value1));
BOOST_TEST(x1(value2) == BOOST_HASH_TEST_NAMESPACE::hash_value(value2));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value1) ==
BOOST_HASH_TEST_NAMESPACE::hash_range(value1.begin(), value1.end()));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value2) ==
BOOST_HASH_TEST_NAMESPACE::hash_range(value2.begin(), value2.end()));
#endif
}
void string0_tests()
{
std::string x1(1, '\0');
std::string x2(2, '\0');
std::string x3(3, '\0');
std::string x4(10, '\0');
BOOST_HASH_TEST_NAMESPACE::hash<std::string> hasher;
BOOST_TEST(hasher(x1) != hasher(x2));
BOOST_TEST(hasher(x1) != hasher(x3));
BOOST_TEST(hasher(x1) != hasher(x4));
BOOST_TEST(hasher(x2) != hasher(x3));
BOOST_TEST(hasher(x2) != hasher(x4));
BOOST_TEST(hasher(x3) != hasher(x4));
}
#if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
void wstring_tests()
{
compile_time_tests((std::wstring*) 0);
BOOST_HASH_TEST_NAMESPACE::hash<std::wstring> x1;
BOOST_HASH_TEST_NAMESPACE::hash<std::wstring> x2;
BOOST_TEST(x1(L"Hello") == x2(std::wstring(L"Hel") + L"lo"));
BOOST_TEST(x1(L"") == x2(std::wstring()));
#if defined(BOOST_HASH_TEST_EXTENSIONS)
std::wstring value1;
std::wstring value2(L"Hello");
BOOST_TEST(x1(value1) == BOOST_HASH_TEST_NAMESPACE::hash_value(value1));
BOOST_TEST(x1(value2) == BOOST_HASH_TEST_NAMESPACE::hash_value(value2));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value1) ==
BOOST_HASH_TEST_NAMESPACE::hash_range(value1.begin(), value1.end()));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value2) ==
BOOST_HASH_TEST_NAMESPACE::hash_range(value2.begin(), value2.end()));
#endif
}
#endif
#if !defined(BOOST_NO_CXX11_CHAR16_T)
void u16string_tests()
{
compile_time_tests((std::u16string*) 0);
BOOST_HASH_TEST_NAMESPACE::hash<std::u16string> x1;
BOOST_HASH_TEST_NAMESPACE::hash<std::u16string> x2;
BOOST_TEST(x1(u"Hello") == x2(std::u16string(u"Hel") + u"lo"));
BOOST_TEST(x1(u"") == x2(std::u16string()));
#if defined(BOOST_HASH_TEST_EXTENSIONS)
std::u16string value1;
std::u16string value2(u"Hello");
BOOST_TEST(x1(value1) == BOOST_HASH_TEST_NAMESPACE::hash_value(value1));
BOOST_TEST(x1(value2) == BOOST_HASH_TEST_NAMESPACE::hash_value(value2));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value1) ==
BOOST_HASH_TEST_NAMESPACE::hash_range(value1.begin(), value1.end()));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value2) ==
BOOST_HASH_TEST_NAMESPACE::hash_range(value2.begin(), value2.end()));
#endif
}
#endif
#if !defined(BOOST_NO_CXX11_CHAR32_T)
void u32string_tests()
{
compile_time_tests((std::u32string*) 0);
BOOST_HASH_TEST_NAMESPACE::hash<std::u32string> x1;
BOOST_HASH_TEST_NAMESPACE::hash<std::u32string> x2;
BOOST_TEST(x1(U"Hello") == x2(std::u32string(U"Hel") + U"lo"));
BOOST_TEST(x1(U"") == x2(std::u32string()));
#if defined(BOOST_HASH_TEST_EXTENSIONS)
std::u32string value1;
std::u32string value2(U"Hello");
BOOST_TEST(x1(value1) == BOOST_HASH_TEST_NAMESPACE::hash_value(value1));
BOOST_TEST(x1(value2) == BOOST_HASH_TEST_NAMESPACE::hash_value(value2));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value1) ==
BOOST_HASH_TEST_NAMESPACE::hash_range(value1.begin(), value1.end()));
BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value2) ==
BOOST_HASH_TEST_NAMESPACE::hash_range(value2.begin(), value2.end()));
#endif
}
#endif
template <typename StringType>
void generic_string_tests(StringType*)
{
std::string x1(1, '\0');
std::string x2(2, '\0');
std::string x3(3, '\0');
std::string x4(10, '\0');
std::string x5 = x2 + "hello" + x2;
StringType strings[] = {
"",
"hello",
x1,
x2,
x3,
x4,
x5
};
std::size_t const strings_length = sizeof(strings) / sizeof(StringType);
boost::hash<StringType> hash;
for (std::size_t i = 0; i < strings_length; ++i) {
std::size_t hash_i = hash(strings[i]);
for (std::size_t j = 0; j < strings_length; ++j) {
std::size_t hash_j = hash(strings[j]);
BOOST_TEST((hash_i == hash_j) == (i == j));
}
}
}
int main()
{
string_tests();
string0_tests();
#if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
wstring_tests();
#endif
#if !defined(BOOST_NO_CXX11_CHAR16_T)
u16string_tests();
#endif
#if !defined(BOOST_NO_CXX11_CHAR32_T)
u32string_tests();
#endif
generic_string_tests((std::string*) 0);
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
generic_string_tests((std::string_view*) 0);
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,51 @@
// Copyright 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/utility/string_view.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/container_hash/hash.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config.hpp>
#include <string>
#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
// important for unordered heterogeneous lookups.
template<class T> std::size_t hv( T const& t )
{
return boost::hash<T>()( t );
}
int main()
{
std::string s( "Test." );
std::size_t h0 = hv( 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( 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();
}

Some files were not shown because too many files have changed in this diff Show More