Compare commits

..

133 Commits

Author SHA1 Message Date
joaquintides 668abe4b0a Merge pull request #146 from cmazakas/feature/rehash-doc-updates
Rehash Doc Updates
2022-09-15 19:33:54 +02:00
Christian Mazakas 5dcccfda3b Update docs for rehash/reserve for unordered_multimap 2022-09-15 07:59:53 -07:00
Christian Mazakas 56b271850a Update docs for rehash/reserve for unordered_multiset 2022-09-15 07:59:53 -07:00
Christian Mazakas d338e94267 Update docs for rehash/reserve for unordered_set 2022-09-15 07:59:53 -07:00
Christian Mazakas 42abfe3c7d Update docs for rehash/reserve for unordered_map 2022-09-15 07:59:53 -07:00
joaquintides 6ef6540378 Merge pull request #144 from cmazakas/feature/rehashing-conformity
Rehashing Conformity
2022-09-13 23:53:15 +02:00
Christian Mazakas 9a9b8e0a7b Update rehashing implementation to better reflect STL conformance 2022-09-13 12:33:21 -07:00
Christian Mazakas 5ad86f559f Clean up implementation of recalculate_max_load() to avoid std::floor/std::ceil 2022-09-13 12:33:21 -07:00
Christian Mazakas a8b0e19a33 Update rehashing tests to better stress test them for conformity with libc++ and other STL implementations 2022-09-13 12:33:21 -07:00
joaquintides 2b61fbb8df Merge pull request #145 from cmazakas/bugfix/noexcept-move-assign
Fix move assign noexcept violation/perf regression
2022-09-13 20:46:38 +02:00
Christian Mazakas dea6ce164c Remove erroneous unconditional call to reserve() from move_assign() when pocma is false 2022-09-12 13:16:45 -07:00
Christian Mazakas 9ebb705e75 Update noexcept_tests to cover both values of POCMA and to also test move-assigning into larger and smaller hash tables 2022-09-12 13:16:45 -07:00
Christian Mazakas 010dfa52e3 Merge pull request #143 from cmazakas/feature/no-alloc-default-construction
Update internal table to no longer allocate on default constructions and when the bucket count is 0
2022-08-31 09:21:13 -07:00
Christian Mazakas db9d9d1f77 Update implementation to support a default-constructible table and grouped_bucket_array 2022-08-30 15:20:31 -07:00
Christian Mazakas 6f342bf119 Set default_bucket_count to zero 2022-08-30 15:20:31 -07:00
Christian Mazakas 48765e82e0 Update tests to account for a default-constructed container having no buckets 2022-08-30 15:20:31 -07:00
Peter Dimov f141cd1dea Merge pull request #141 from cmazakas/fix/appveyor-timeout
Split 64-bit mingw appveyor job into two to help prevent timeouts
2022-08-20 11:21:40 +03:00
Christian Mazakas 6258856d2b Split 64-bit mingw appveyor job into two to help prevent timeouts 2022-08-19 13:31:02 -07:00
Peter Dimov c93ea188f7 Merge pull request #142 from sdarwin/droneconfig
drone.jsonnet update
2022-08-19 23:15:26 +03:00
sdarwin 329eb419f5 drone.jsonnet update 2022-08-19 10:58:56 -06:00
Peter Dimov e83c42ca26 Merge pull request #140 from boostorg/bugfix/valid-post-move
Fix use-after-move segfault
2022-08-19 00:54:07 +03:00
Christian Mazakas f9eae4153f Update code to be valid when the internal buckets_ data member is moved-from 2022-08-18 09:04:53 -07:00
Christian Mazakas 7b41f4783f Update value type used by test allocators in move_tests so that the STL containers can be swapped in 2022-08-17 14:12:29 -07:00
Christian Mazakas 7227cfc68a Add post-move tests to verify the container is valid after a move 2022-08-17 14:12:29 -07:00
Christian Mazakas 6b87a43162 Update benchmarking diagrams based on new erase(iterator) implementation 2022-07-27 08:29:03 -07:00
Peter Dimov a4c6bf90aa Merge pull request #138 from cmazakas/feature/erase-perf
erase(iterator) perf
2022-07-27 14:41:07 +03:00
Christian Mazakas a31e894411 Update implementation to use erase_node() where applicable 2022-07-25 11:35:38 -07:00
Christian Mazakas 91e78fd746 Add erase_node() function to table, creating an optimizer-friendly function 2022-07-25 11:35:23 -07:00
Peter Dimov 3abe5de533 Switch from macos-10.15 (deprecated) to macos-11 2022-07-22 20:44:54 +03:00
Peter Dimov dfa3c7311f Remove unnecessary RNG 2022-07-22 19:12:39 +03:00
Peter Dimov 2c5b8577aa Add tsl::robin_map to string.cpp 2022-07-22 19:10:50 +03:00
Peter Dimov 4e804a9d4d Add tsl::robin_map to uint64.cpp, string_view.cpp 2022-07-22 18:52:47 +03:00
Peter Dimov 0ca8c5f56f Add tsl::robin_map to uint32.cpp 2022-07-22 18:36:50 +03:00
Peter Dimov 912798e5cb Change uint64.cpp to use byteswapped indices instead of shifted indices 2022-07-22 18:22:34 +03:00
Peter Dimov 5bcdd7fdf0 Change uint32.cpp to use byteswapped indices instead of shifted indices 2022-07-22 18:18:35 +03:00
Peter Dimov 78ffc4c192 Fix tsl allocator 2022-07-01 19:32:19 +03:00
Peter Dimov 966b76182f Add tsl::hopscotch_map to string_view.cpp 2022-07-01 19:28:57 +03:00
Peter Dimov b7101494f2 Add tsl::hopscotch_map to string.cpp 2022-07-01 19:15:28 +03:00
Peter Dimov be467b3dc4 Add tsl::hopscotch_map to uint64.cpp 2022-07-01 19:03:52 +03:00
Peter Dimov ee70d96c75 Add tsl::hopscotch_map to uint32.cpp 2022-07-01 18:48:10 +03:00
Peter Dimov 8fbd380879 Merge pull request #136 from cmazakas/feature/prime-fmod-cleanup
`prime_fmod_size` cleanup
2022-07-01 17:58:38 +03:00
Christian Mazakas 7746518c0a Remove conditional usage of #pragma once from fca.hpp and prime_fmod.hpp, reorder config.hpp inclusion to come last 2022-06-30 13:07:11 -07:00
Christian Mazakas c8a98e27e0 Add boost:: namespace qualification to uint64_t and uint32_t for prime_fmod.hpp 2022-06-30 13:07:11 -07:00
Christian Mazakas 3df902af23 Pull prime_fmod_size into its own dedicated header, update #include list for fca.hpp and prime_fmod_test.hpp 2022-06-30 13:07:11 -07:00
Peter Dimov 45542e26cb Update ci.yml 2022-06-30 12:29:47 +03:00
Peter Dimov 49f73b118c Update .appveyor.yml 2022-06-30 05:23:44 +03:00
Peter Dimov 6e3dcfddb0 Merge branch 'feature/gha' into develop 2022-06-28 14:19:00 +03:00
joaquintides 09088045ac Merge pull request #135 from boostorg/bugfix/gcc-4-6-is_nothrow_swappable
bypassed check in GCC<=4.6 (boost::is_nothrow_swappable not properly …
2022-06-28 10:09:02 +02:00
joaquintides e466232757 bypassed check in GCC<=4.6 (boost::is_nothrow_swappable not properly supported) 2022-06-28 09:27:15 +02:00
Peter Dimov 2ccd6654c1 Update ci.yml 2022-06-28 03:29:35 +03:00
joaquintides 7d7a6b881e Merge pull request #134 from boostorg/bugfix/gcc-4-7
Bugfix/gcc 4 7
2022-06-27 21:48:25 +02:00
joaquintides 9661227d00 Merge remote-tracking branch 'remotes/origin/bugfix/gcc-4-7-scoped_allocator' into bugfix/gcc-4-7 2022-06-27 20:39:07 +02:00
joaquintides 5855c67d4d added Drone support to this branch 2022-06-27 20:35:59 +02:00
joaquintides 3edfe2b76f Merge branch 'develop' into bugfix/gcc-4-7-scoped_allocator 2022-06-27 20:35:27 +02:00
joaquintides f36bfe24f6 added Drone support to this branch 2022-06-27 20:35:01 +02:00
joaquintides 9da4b3a45a Merge branch 'develop' into bugfix/gcc-4-7-ref-qualified_memfuns 2022-06-27 20:34:06 +02:00
joaquintides 95524a6af4 bypassed scoped_allocator test for GCC 4.7 and prior 2022-06-27 19:58:22 +02:00
joaquintides d4b61541b5 used proper Boost.Config macro 2022-06-27 19:31:47 +02:00
Peter Dimov 143c378ba6 Update test/Jamfile 2022-06-27 20:24:25 +03:00
joaquintides dfac93aebb workaround for lack of ref-qualified memfun support in GCC<=4.7 2022-06-27 19:21:34 +02:00
Peter Dimov b6daca37d5 Update test/Jamfile 2022-06-27 19:56:22 +03:00
Peter Dimov 4937619ea0 Update .drone.jsonnet 2022-06-27 19:55:23 +03:00
Peter Dimov 6d34532301 Add Drone support 2022-06-27 18:53:36 +03:00
joaquintides fb733483c6 made fast_modulo universally available in 64 bits and never used in 32 bits 2022-06-26 19:13:54 +02:00
joaquintides 2670bb149d added Peter Dimov's portable implementation of get_remainder 2022-06-25 17:35:43 +02:00
Peter Dimov d49eda63f8 Merge branch 'feature/prime-fmod-tests' into develop 2022-06-25 04:21:20 +03:00
Peter Dimov 08e0fee141 Enable fastmod on clang-cl and other pretenders such as Intel 2022-06-25 01:44:14 +03:00
Peter Dimov d204b9b408 Remove unnecessary include 2022-06-25 01:17:50 +03:00
Peter Dimov c53e0228c5 Check BOOST_UNORDERED_FCA_HAS_64B_SIZE_T in the 32 bit case as well 2022-06-25 01:16:32 +03:00
Peter Dimov 31cffd8412 Fix reversed condition 2022-06-25 01:06:15 +03:00
Peter Dimov 0f71fe28a2 Fix typos; do not undefine macros needed for tests 2022-06-25 01:04:22 +03:00
Christian Mazakas f00a29d3df Add tests for the internal prime_fmod_size policy 2022-06-24 11:09:38 -07:00
Peter Dimov e111389d6c Update .appveyor.yml 2022-06-24 01:03:53 +03:00
Peter Dimov 7079341416 Merge pull request #130 from cmazakas/bugfix/cmake-subdir-dependencies
Update the list of required dependencies for the subdir CML test
2022-06-23 03:53:02 +03:00
Christian Mazakas 7fdbfc0c1a Update the list of required dependencies in for the CMake subdirectory test 2022-06-22 14:42:09 -07:00
Peter Dimov e1dff1c931 Merge pull request #128 from cmazakas/feature/iterator-independence
Remove dependencies on Iterator, Detail
2022-06-21 21:45:12 +03:00
Christian Mazakas 90b2536a99 Relace usage of BOOST_FORCEINLINE with plain inline to prevent warnings from certain versions of msvc 2022-06-21 08:42:52 -07:00
Christian Mazakas 97f54318e3 Add Boost::concept_check to CMake test suite dependencies 2022-06-21 08:42:52 -07:00
Christian Mazakas f1481f0deb Remove dependency on Boost.Detail 2022-06-21 08:42:52 -07:00
Christian Mazakas b1a9cde690 Remove dependency on Boost.Iterator 2022-06-21 08:42:52 -07:00
Christian Mazakas 1ed2a0a0f1 Merge pull request #127 from cmazakas/doc-updates
1.80 Doc Updates
2022-06-16 12:46:33 -07:00
Christian Mazakas 759645cab6 Merge pull request #126 from cmazakas/img-link-fixes
Fix broken image links for VS benchmarks (successful lookup)
2022-06-16 08:57:49 -07:00
Christian Mazakas 3203251539 Update changelog for 1.80 release 2022-06-16 07:52:37 -07:00
Christian Mazakas b84b94b4db Update copyright notice for documentation 2022-06-16 07:52:27 -07:00
Christian Mazakas 3dd77edd16 Pull benchmarks into their own file 2022-06-14 08:50:28 -07:00
Christian Mazakas a24165083f Fix link paths for VS successful lookup benchmarks 2022-06-14 08:16:39 -07:00
Christian Mazakas 8878482ca1 Merge pull request #125 from cmazakas/develop-build-instructions
Add PREVIEW markdown file
2022-06-10 09:06:59 -07:00
Christian Mazakas 19c7bbf97d Add PREVIEW markdown file containing instructions for how to quickly build Boost from the tip of develop 2022-06-10 09:03:18 -07:00
Christian Mazakas 23f15947d3 Merge pull request #122 from Flamefire/readme
Add LICENSE and README
2022-06-09 13:50:20 -07:00
Christian Mazakas 152129bf70 Merge pull request #121 from Flamefire/appveyor_ci
Update Appveyor from Boost.CI
2022-06-09 11:02:38 -07:00
Christian Mazakas 20ac32c34c Merge pull request #114 from Flamefire/ci
Update GithubActions CI from boost-ci
2022-06-09 11:02:32 -07:00
Alexander Grund 707b40e8c2 Workaround Segfault of Clang 3.8
Clang 3.8 segfaults during name mangling of `make_index_seq`.
Hence replace it by using type aliases.
2022-06-09 11:04:20 +02:00
Alexander Grund 0d1d9f4634 CI: Test only default (shared) linkage on GHA
As there is no actual compiled library there is no need to test shared
and static linking. This effectively halfes the number of compile jobs.
2022-06-09 11:04:20 +02:00
Alexander Grund 5a64ca48ad Update CI from boost-ci
Sync with upstream adding improved CMake builds and coverage collection
2022-06-09 11:04:20 +02:00
Alexander Grund f4ddf18124 Add LICENSE and README
Show project description and CI badges on the repo site.
2022-06-09 10:40:52 +02:00
Alexander Grund 657cf68e55 Remove unused download-boost-snapshot.py file
Boost.CI is now used.
2022-06-09 10:19:23 +02:00
Alexander Grund f0013a4d65 Split jobs which take over 1h to complete and timeout
See #120
2022-06-08 21:26:15 +02:00
Alexander Grund 83fe0249b3 Allow MinGW32 and Cygwin-latest jobs to fail
Needs some more work
2022-06-08 21:26:15 +02:00
Alexander Grund 3701199cfa Update Appveyor from Boost.CI
Adds MinGW, Cygwin and newer compilers
2022-06-08 21:26:15 +02:00
Peter Dimov 4b56bfac05 Merge pull request #119 from cmazakas/laundry
Fix `-Wmaybe-unitialized` warning in gcc-12
2022-06-07 20:55:32 +03:00
Christian Mazakas 613a997694 Fix -Wmaybe-unitialized warning in gcc-12 by laundering the result of reinterpret_cast<> in functions helper 2022-06-07 09:03:48 -07:00
Peter Dimov e690e8910c Merge branch 'feature/gha-gcc12-nosan' into develop 2022-06-03 22:54:39 +03:00
joaquintides 34b9a8d21f Merge pull request #118 from cmazakas/fastmod-cleanup
Rename functions used to efficiently calculate modulo
2022-06-03 20:02:42 +02:00
Christian Mazakas 0106ed3d91 Rename functions used to efficiently calculate modulo, update associated comments 2022-06-03 09:28:17 -07:00
Peter Dimov f8342e4b04 Add a GCC 12 job without sanitization 2022-06-03 17:08:51 +03:00
Peter Dimov 8a74b192b0 Merge pull request #117 from Flamefire/clang3_8_compat
Fix compilation on Clang < 3.8
2022-06-03 16:49:43 +03:00
Flamefire d0ac539d09 Fix compilation on Clang < 3.8
`val_alloc` is used in the other branch of the #ifdef too.
2022-06-03 11:07:49 +02:00
Peter Dimov 0be4856144 Add GCC 12, Clang 13, 14 to ci.yml 2022-06-03 05:41:53 +03:00
Peter Dimov 7503b85f6a Add posix-cmake-subdir, posix-cmake-install jobs to ci.yml 2022-06-03 01:36:57 +03:00
Peter Dimov 4a9abf20b3 Add test/cmake_install_test, test/cmake_subdir_test 2022-06-03 01:35:32 +03:00
Peter Dimov 2836bb5c41 Merge branch 'feature/quick-test' into feature/gha-cmake 2022-06-03 01:29:56 +03:00
Peter Dimov e2925ba01b Add test/quick.cpp 2022-06-02 22:53:12 +03:00
Peter Dimov f2724b745b Regenerate CMakeLists.txt 2022-06-02 21:46:56 +03:00
Peter Dimov 712d20079a Fix alignment_of include 2022-06-02 21:46:07 +03:00
Peter Dimov 99a5409b39 Merge branch 'develop' into feature/gha-cmake 2022-06-02 21:41:51 +03:00
Peter Dimov 72fe06aa00 Remove unused include, removes dependency on Detail 2022-06-02 19:15:12 +03:00
Peter Dimov 8081a3f9ff Add CMake tests to ci.yml 2022-06-02 18:43:12 +03:00
Peter Dimov f218f9b5a2 Add test/CMakeLists.txt 2022-06-02 18:41:31 +03:00
Peter Dimov 4e38751187 Update test/Jamfile.v2 2022-06-02 18:41:14 +03:00
Christian Mazakas e36e3bcf96 Merge pull request #112 from boostorg/feature/fca-unordered
Update internal implementation to use FCA
2022-06-01 15:44:05 -07:00
Christian Mazakas 18503e5eb8 Update documentation for new FCA implementation 2022-06-01 11:49:09 -07:00
Christian Mazakas 110c5dcf10 Remove unnecessary test files due to FCA refactor 2022-06-01 11:49:09 -07:00
Christian Mazakas 37f5a462e4 Update reserve_tests to handle the space requirements for new FCA implementation 2022-06-01 11:49:09 -07:00
Christian Mazakas a1fb756831 Fix bug in rebind semantics for test allocator in reserve_tests 2022-06-01 11:49:09 -07:00
Christian Mazakas 5a456eb295 Refactor internal implementation to use "fast closed-addressing" aka fca 2022-06-01 11:49:09 -07:00
Christian Mazakas ad639ffb61 Lower version of dinkumware check as msvc-12.0 supports piecewise construction 2022-06-01 11:49:09 -07:00
Christian Mazakas 2ae686c366 Add tests for testing the SCARY-ness of iterators 2022-06-01 11:49:09 -07:00
Christian Mazakas 641c9fba9c Update operator() implementations for predicate classes to properly return a bool 2022-06-01 11:49:09 -07:00
Christian Mazakas 8473d8120f Mark test Hasher and KeyEqual as final to extend test coverage 2022-06-01 11:49:09 -07:00
Christian Mazakas 954db4e246 Extend fancy pointer types used by test allocators to support a wider array of semantic operations 2022-06-01 11:49:09 -07:00
Christian Mazakas 4f43bc5ec7 Add missing #include for usage of BOOST_TEST macro 2022-06-01 11:49:09 -07:00
Christian Mazakas 0bcc79baab Update test allocators to be C++11 compliant by making them templates on the pointer type 2022-06-01 11:49:09 -07:00
Christian Mazakas e7d34a5ab1 Remove unsupported Windows image from GHA CI 2022-05-20 13:53:40 -07:00
108 changed files with 6312 additions and 2886 deletions
+101 -37
View File
@@ -1,4 +1,6 @@
# Copyright 2017 Daniel James
# Copyright 2016, 2017 Peter Dimov
# Copyright 2017 - 2019 James E. King III
# Copyright 2019 - 2021 Alexander Grund
# 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)
@@ -10,48 +12,110 @@ branches:
only:
- master
- develop
- /bugfix\/.*/
- /feature\/.*/
- /fix\/.*/
- /pr\/.*/
matrix:
fast_finish: false
# Adding MAYFAIL to any matrix job allows it to fail but the build stays green:
allow_failures:
- MAYFAIL: true
environment:
global:
B2_CI_VERSION: 1
GIT_FETCH_JOBS: 4
B2_ADDRESS_MODEL: 32,64
B2_VARIANT: debug,release
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 2019
TOOLSET: clang-win
CXXSTD: 14
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: clang-win
CXXSTD: 17
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: clang-win
CXXSTD: latest
ADDRMD: 32,64
- FLAVOR: Visual Studio 2008, 2010, 2012
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
B2_TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0
B2_ADDRESS_MODEL: 32 # No 64bit support
- FLAVOR: Visual Studio 2013, 2015
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
B2_TOOLSET: msvc-12.0,msvc-14.0
- FLAVOR: Visual Studio 2017
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
B2_CXXSTD: 14,17,latest
B2_TOOLSET: msvc-14.1
- FLAVOR: cygwin (32-bit)
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
ADDPATH: C:\cygwin\bin;
B2_ADDRESS_MODEL: 32
B2_CXXSTD: 03,11,14,1z
B2_TOOLSET: gcc
- FLAVOR: cygwin (64-bit)
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
ADDPATH: C:\cygwin64\bin;
B2_ADDRESS_MODEL: 64
B2_CXXSTD: 03,11,14,1z
B2_TOOLSET: gcc
- FLAVOR: cygwin (64-bit, latest)
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
ADDPATH: C:\cygwin64\bin;
B2_ADDRESS_MODEL: 64
B2_CXXSTD: 03,11
B2_TOOLSET: gcc
B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception"
- FLAVOR: cygwin (64-bit, latest)
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
ADDPATH: C:\cygwin64\bin;
B2_ADDRESS_MODEL: 64
B2_CXXSTD: 14,1z
B2_TOOLSET: gcc
B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception"
- FLAVOR: mingw-w64, 32 bit
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin;
B2_CXXSTD: 03,11,14,17,2a
B2_TOOLSET: gcc
B2_ADDRESS_MODEL: 32
- FLAVOR: mingw-w64, 64 bit
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
B2_CXXSTD: 03,11,14
B2_TOOLSET: gcc
B2_ADDRESS_MODEL: 64
- FLAVOR: mingw-w64, 64 bit
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
B2_CXXSTD: 17,2a
B2_TOOLSET: gcc
B2_ADDRESS_MODEL: 64
#- FLAVOR: CodeCov (VS 2019)
# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
# B2_CXXFLAGS: -permissive-
# B2_CXXSTD: 14
# B2_TOOLSET: msvc-14.2
# COVERAGE: true
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\unordered\
- python tools/boostdep/depinst/depinst.py unordered
- cmd /c bootstrap
- b2 -d0 headers
- git clone --depth 1 https://github.com/boostorg/boost-ci.git C:\boost-ci-cloned
# Copy ci folder if not testing Boost.CI
- if NOT "%APPVEYOR_PROJECT_NAME%" == "boost-ci" xcopy /s /e /q /i /y C:\boost-ci-cloned\ci .\ci
- rmdir /s /q C:\boost-ci-cloned
- ci\appveyor\install.bat
build: off
test_script:
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
- if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
- b2 -j3 libs/unordered/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker
test_script: ci\build.bat
for:
# CodeCov coverage build
- matrix:
only: [COVERAGE: true]
test_script: [ps: ci\codecov.ps1]
+23
View File
@@ -0,0 +1,23 @@
# Copyright 2019 - 2021 Alexander Grund
# 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)
#
# Sample codecov configuration file. Edit as required
codecov:
max_report_age: off
require_ci_to_pass: yes
notify:
# Increase this if you have multiple coverage collection jobs
after_n_builds: 1
wait_for_ci: yes
# Change how pull request comments look
comment:
layout: "reach,diff,flags,files,footer"
# Ignore specific files or folders. Glob patterns are supported.
# See https://docs.codecov.com/docs/ignoring-paths
ignore:
- extra/**/*
# - test/**/*
+184
View File
@@ -0,0 +1,184 @@
# Copyright 2022 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
local library = "unordered";
local triggers =
{
branch: [ "master", "develop", "feature/*", "bugfix/*" ]
};
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',
'uname -a',
'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:
[
'uname -a',
'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:
[
'echo $env:DRONE_STAGE_MACHINE',
'cmd /C .drone\\\\drone.bat ' + library,
]
}
]
};
[
linux_pipeline(
"Linux 14.04 GCC 4.4 32/64",
"cppalliance/droneubuntu1404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-4.4', CXXSTD: '98,0x', ADDRMD: '32,64' },
"g++-4.4-multilib",
[ "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 20.04 GCC 9* ARM64 32",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32' },
arch="arm64",
),
linux_pipeline(
"Linux 20.04 GCC 9* ARM64 64",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '64' },
arch="arm64",
),
linux_pipeline(
"Linux 20.04 GCC 9* S390x 32",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32' },
arch="s390x",
),
linux_pipeline(
"Linux 20.04 GCC 9* S390x 64",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '64' },
arch="s390x",
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + ubsan,
),
macos_pipeline(
"MacOS 12.4 Xcode 13.4.1 ASAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + asan,
xcode_version = "13.4.1", osx_version = "monterey",
),
windows_pipeline(
"Windows VS2017 msvc-14.1",
"cppalliance/dronevs2017",
{ TOOLSET: 'msvc-14.1', CXXSTD: '14,17,latest' },
),
]
+23
View File
@@ -0,0 +1,23 @@
@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 %LIBRARY%
cmd /c bootstrap
b2 -d0 headers
if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
b2 -j3 libs/%LIBRARY%/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker
+25
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
export PATH=~/.local/bin:/usr/local/bin:$PATH
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 $LIBRARY
./bootstrap.sh
./b2 -d0 headers
echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam
./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}
+353 -168
View File
@@ -1,3 +1,11 @@
# Copyright 2020-2021 Peter Dimov
# Copyright 2021 Andrey Semashev
# Copyright 2021 Alexander Grund
# Copyright 2022 James E. King III
#
# 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)
---
name: CI
on:
@@ -6,207 +14,384 @@ on:
branches:
- master
- develop
- bugfix/**
- feature/**
- fix/**
- pr/**
concurrency:
group: ${{format('{0}:{1}', github.repository, github.ref)}}
cancel-in-progress: true
env:
UBSAN_OPTIONS: print_stacktrace=1
GIT_FETCH_JOBS: 8
NET_RETRY_COUNT: 5
B2_CI_VERSION: 1
B2_VARIANT: debug,release
LCOV_BRANCH_COVERAGE: 0
CODECOV_NAME: Github Actions
jobs:
posix:
defaults:
run:
shell: bash
strategy:
fail-fast: false
matrix:
include:
- toolset: gcc-4.8
cxxstd: "03,11"
os: ubuntu-18.04
install: g++-4.8
- toolset: gcc-5
cxxstd: "03,11,14,1z"
os: ubuntu-18.04
install: g++-5
- toolset: gcc-6
cxxstd: "03,11,14,1z"
os: ubuntu-18.04
install: g++-6
- toolset: gcc-7
cxxstd: "03,11,14,17"
os: ubuntu-18.04
- toolset: gcc-8
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
install: g++-8
- toolset: gcc-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
- toolset: gcc-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: gcc-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: gcc-11
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: g++-11
sanitizers: true
- 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"
os: ubuntu-20.04
install: clang-9
- toolset: clang
compiler: clang++-10
cxxstd: "03,11,14,17"
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,2a"
os: ubuntu-20.04
sanitizers: true
- toolset: clang
cxxstd: "03,11,14,17"
os: macos-10.15
sanitizers: true
# Linux, gcc
- { compiler: gcc-4.8, cxxstd: '03,11', os: ubuntu-18.04, install: 'g++-4.8-multilib', address-model: '32,64' }
- { compiler: gcc-4.9, cxxstd: '03,11', os: ubuntu-20.04, container: 'ubuntu:16.04' }
- { compiler: gcc-5, cxxstd: '03,11,14,1z', os: ubuntu-18.04, install: 'g++-5-multilib', address-model: '32,64' }
- { compiler: gcc-6, cxxstd: '03,11,14,17', os: ubuntu-18.04, install: 'g++-6-multilib', address-model: '32,64' }
- { compiler: gcc-7, cxxstd: '03,11,14,17', os: ubuntu-18.04, install: 'g++-7-multilib', address-model: '32,64' }
- { compiler: gcc-8, cxxstd: '03,11,14,17,2a', os: ubuntu-18.04, install: 'g++-8-multilib', address-model: '32,64' }
- { compiler: gcc-9, cxxstd: '03,11,14,17,2a', os: ubuntu-18.04, install: 'g++-9-multilib', address-model: '32,64' }
- { compiler: gcc-10, cxxstd: '03,11,14,17,20', os: ubuntu-20.04, install: 'g++-10-multilib', address-model: '32,64' }
- { compiler: gcc-11, cxxstd: '03,11,14,17,20', os: ubuntu-20.04, install: 'g++-11-multilib', address-model: '32,64' }
- { compiler: gcc-12, cxxstd: '03,11,14,17,20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '32,64' }
- { name: GCC w/ sanitizers, sanitize: yes,
compiler: gcc-12, cxxstd: '03,11,14,17,20', os: ubuntu-22.04 }
- { name: Collect coverage, coverage: yes,
compiler: gcc-8, cxxstd: '03,11', os: ubuntu-20.04, install: 'g++-8-multilib', address-model: '32,64' }
# Linux, clang
- { compiler: clang-3.7, cxxstd: '03,11,14', os: ubuntu-20.04, container: 'ubuntu:16.04' }
- { compiler: clang-3.8, cxxstd: '03,11,14', os: ubuntu-20.04, container: 'ubuntu:16.04' }
- { compiler: clang-3.9, cxxstd: '03,11,14', os: ubuntu-18.04 }
- { compiler: clang-4.0, cxxstd: '03,11,14', os: ubuntu-18.04 }
- { compiler: clang-5.0, cxxstd: '03,11,14,1z', os: ubuntu-18.04 }
- { compiler: clang-6.0, cxxstd: '03,11,14,17', os: ubuntu-18.04 }
- { compiler: clang-7, cxxstd: '03,11,14,17', os: ubuntu-18.04 }
- { compiler: clang-8, cxxstd: '03,11,14,17', os: ubuntu-18.04 }
- { compiler: clang-9, cxxstd: '03,11,14,17,2a', os: ubuntu-20.04 }
- { compiler: clang-10, cxxstd: '03,11,14,17,20', os: ubuntu-20.04 }
- { compiler: clang-11, cxxstd: '03,11,14,17,20', os: ubuntu-20.04 }
- { compiler: clang-12, cxxstd: '03,11,14,17,20', os: ubuntu-20.04 }
- { compiler: clang-13, cxxstd: '03,11,14,17,20', os: ubuntu-22.04 }
- { compiler: clang-14, cxxstd: '03,11,14,17,20', os: ubuntu-22.04 }
# libc++
- { compiler: clang-6.0, cxxstd: '03,11,14', os: ubuntu-18.04, stdlib: libc++, install: 'clang-6.0 libc++-dev libc++abi-dev' }
- { compiler: clang-12, cxxstd: '03,11,14,17,20', os: ubuntu-20.04, stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev' }
- { name: Clang w/ sanitizers, sanitize: yes,
compiler: clang-12, cxxstd: '03,11,14,17,20', os: ubuntu-20.04, stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev' }
# OSX, clang
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-11, sanitize: yes }
timeout-minutes: 120
runs-on: ${{matrix.os}}
container: ${{matrix.container}}
env: {B2_USE_CCACHE: 1}
steps:
- uses: actions/checkout@v2
- name: Setup environment
run: |
if [ -f "/etc/debian_version" ]; then
echo "DEBIAN_FRONTEND=noninteractive" >> $GITHUB_ENV
export DEBIAN_FRONTEND=noninteractive
fi
if [ -n "${{matrix.container}}" ] && [ -f "/etc/debian_version" ]; then
apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common
# Need (newer) git, and the older Ubuntu container may require requesting the key manually using port 80
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys E1DD270288B4E6030699E45FA1715D88E1DF1F24
for i in {1..${NET_RETRY_COUNT:-3}}; do sudo -E add-apt-repository -y ppa:git-core/ppa && break || sleep 10; done
apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y g++ python libpython-dev git
fi
# For jobs not compatible with ccache, use "ccache: no" in the matrix
if [[ "${{ matrix.ccache }}" == "no" ]]; then
echo "B2_USE_CCACHE=0" >> $GITHUB_ENV
fi
git config --global pack.threads 0
- uses: actions/checkout@v3
with:
# For coverage builds fetch the whole history, else only 1 commit using a 'fake ternary'
fetch-depth: ${{ matrix.coverage && '0' || '1' }}
- name: Cache ccache
uses: actions/cache@v3
if: env.B2_USE_CCACHE
with:
path: ~/.ccache
key: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{github.sha}}
restore-keys: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-
- name: Fetch Boost.CI
uses: actions/checkout@v3
with:
repository: boostorg/boost-ci
ref: master
path: boost-ci-cloned
- name: Get CI scripts folder
run: |
# Copy ci folder if not testing Boost.CI
[[ "$GITHUB_REPOSITORY" =~ "boost-ci" ]] || cp -r boost-ci-cloned/ci .
rm -rf boost-ci-cloned
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
if: startsWith(matrix.os, 'ubuntu')
run: |
SOURCE_KEYS=(${{join(matrix.source_keys, ' ')}})
SOURCES=(${{join(matrix.sources, ' ')}})
# Add this by default
SOURCES+=(ppa:ubuntu-toolchain-r/test)
for key in "${SOURCE_KEYS[@]}"; do
for i in {1..$NET_RETRY_COUNT}; do
wget -O - "$key" | sudo apt-key add - && break || sleep 10
done
done
for source in "${SOURCES[@]}"; do
for i in {1..$NET_RETRY_COUNT}; do
sudo add-apt-repository $source && break || sleep 10
done
done
sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
if [[ -z "${{matrix.install}}" ]]; then
pkgs="${{matrix.compiler}}"
pkgs="${pkgs/gcc-/g++-}"
else
pkgs="${{matrix.install}}"
fi
sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y $pkgs
- name: Setup GCC Toolchain
if: matrix.gcc_toolchain
run: |
GCC_TOOLCHAIN_ROOT="$HOME/gcc-toolchain"
echo "GCC_TOOLCHAIN_ROOT=$GCC_TOOLCHAIN_ROOT" >> $GITHUB_ENV
MULTIARCH_TRIPLET="$(dpkg-architecture -qDEB_HOST_MULTIARCH)"
mkdir -p "$GCC_TOOLCHAIN_ROOT"
ln -s /usr/include "$GCC_TOOLCHAIN_ROOT/include"
ln -s /usr/bin "$GCC_TOOLCHAIN_ROOT/bin"
mkdir -p "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET"
ln -s "/usr/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}"
- name: Setup multiarch
if: matrix.multiarch
run: |
sudo apt-get install --no-install-recommends -y binfmt-support qemu-user-static
sudo docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
git clone https://github.com/jeking3/bdde.git
echo "$(pwd)/bdde/bin/linux" >> ${GITHUB_PATH}
echo "BDDE_DISTRO=${{ matrix.distro }}" >> ${GITHUB_ENV}
echo "BDDE_EDITION=${{ matrix.edition }}" >> ${GITHUB_ENV}
echo "BDDE_ARCH=${{ matrix.arch }}" >> ${GITHUB_ENV}
echo "B2_WRAPPER=bdde" >> ${GITHUB_ENV}
- 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
./bootstrap.sh
./b2 -d0 headers
env:
B2_ADDRESS_MODEL: ${{matrix.address-model}}
B2_COMPILER: ${{matrix.compiler}}
B2_CXXSTD: ${{matrix.cxxstd}}
B2_SANITIZE: ${{matrix.sanitize}}
B2_STDLIB: ${{matrix.stdlib}}
# More entries can be added in the same way, see the B2_ARGS assignment in ci/enforce.sh for the possible keys.
# B2_DEFINES: ${{matrix.defines}}
# Variables set here (to non-empty) will override the top-level environment variables, e.g.
# B2_VARIANT: ${{matrix.variant}}
run: source ci/github/install.sh
- name: Create user-config.jam
if: matrix.compiler
run: |
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
- name: Setup coverage collection
if: matrix.coverage
run: ci/github/codecov.sh "setup"
- name: Run tests
run: |
cd ../boost-root
./b2 -j3 libs/$LIBRARY/test \
toolset=${{matrix.toolset}} \
cxxstd=${{matrix.cxxstd}} \
variant=debug,release \
${{(matrix.sanitizers && 'address-sanitizer=norecover undefined-sanitizer=norecover') || ''}}
if: '!matrix.coverity'
run: ci/build.sh
- name: Upload coverage
if: matrix.coverage
run: ci/codecov.sh "upload"
- name: Run coverity
if: matrix.coverity && github.event_name == 'push' && (github.ref_name == 'develop' || github.ref_name == 'master')
run: ci/github/coverity.sh
env:
COVERITY_SCAN_NOTIFICATION_EMAIL: ${{ secrets.COVERITY_SCAN_NOTIFICATION_EMAIL }}
COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
windows:
defaults:
run:
shell: cmd
strategy:
fail-fast: false
matrix:
include:
- toolset: msvc-14.0
cxxstd: 14,latest
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.1
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2016
- 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
- { 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@v2
- uses: actions/checkout@v3
- name: Fetch Boost.CI
uses: actions/checkout@v3
with:
repository: boostorg/boost-ci
ref: master
path: boost-ci-cloned
- name: Get CI scripts folder
run: |
REM Copy ci folder if not testing Boost.CI
if "%GITHUB_REPOSITORY%" == "%GITHUB_REPOSITORY:boost-ci=%" xcopy /s /e /q /i /y boost-ci-cloned\ci .\ci
rmdir /s /q boost-ci-cloned
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
cmd /c bootstrap
b2 -d0 headers
run: ci\github\install.bat
- name: Run tests
shell: cmd
if: '!matrix.coverage'
run: ci\build.bat
env:
B2_TOOLSET: ${{matrix.toolset}}
B2_CXXSTD: ${{matrix.cxxstd}}
B2_ADDRESS_MODEL: ${{matrix.addrmd}}
- name: Collect coverage
shell: powershell
if: matrix.coverage
run: ci\opencppcoverage.ps1
env:
B2_TOOLSET: ${{matrix.toolset}}
B2_CXXSTD: ${{matrix.cxxstd}}
B2_ADDRESS_MODEL: ${{matrix.addrmd}}
- name: Upload coverage
if: matrix.coverage
uses: codecov/codecov-action@v2
with:
files: __out/cobertura.xml
MSYS2:
defaults:
run:
shell: msys2 {0}
strategy:
fail-fast: false
matrix:
include:
- { sys: MINGW32, compiler: gcc, cxxstd: '03,11,17,20' }
- { sys: MINGW64, compiler: gcc, cxxstd: '03,11,17,20' }
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: Setup MSYS2 environment
uses: msys2/setup-msys2@v2
with:
msystem: ${{matrix.sys}}
update: true
install: git python
pacboy: gcc:p cmake:p ninja:p
- name: Fetch Boost.CI
uses: actions/checkout@v3
with:
repository: boostorg/boost-ci
ref: master
path: boost-ci-cloned
- name: Get CI scripts folder
run: |
cd ../boost-root
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker
# Copy ci folder if not testing Boost.CI
[[ "$GITHUB_REPOSITORY" =~ "boost-ci" ]] || cp -r boost-ci-cloned/ci .
rm -rf boost-ci-cloned
- name: Setup Boost
env:
B2_COMPILER: ${{matrix.compiler}}
B2_CXXSTD: ${{matrix.cxxstd}}
B2_SANITIZE: ${{matrix.sanitize}}
B2_STDLIB: ${{matrix.stdlib}}
run: ci/github/install.sh
- name: Run tests
run: ci/build.sh
# Run also the CMake tests to avoid having to setup another matrix for CMake on MSYS
- name: Run CMake tests
run: |
cd "$BOOST_ROOT"
mkdir __build_cmake_test__ && cd __build_cmake_test__
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DBOOST_INCLUDE_LIBRARIES=$SELF -DBUILD_SHARED_LIBS=ON -DBUILD_TESTING=ON -DBoost_VERBOSE=ON ..
cmake --build . --target tests --config Debug -j$B2_JOBS
ctest --output-on-failure --build-config Debug
CMake:
defaults:
run:
shell: bash
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-20.04, build_shared: ON, build_type: Debug, generator: 'Unix Makefiles' }
- { os: windows-2019, build_shared: ON, build_type: Debug, generator: 'Visual Studio 16 2019' }
timeout-minutes: 120
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- name: Fetch Boost.CI
uses: actions/checkout@v3
with:
repository: boostorg/boost-ci
ref: master
path: boost-ci-cloned
- name: Get CI scripts folder
run: |
# Copy ci folder if not testing Boost.CI
[[ "$GITHUB_REPOSITORY" =~ "boost-ci" ]] || cp -r boost-ci-cloned/ci .
rm -rf boost-ci-cloned
- name: Setup Boost
env: {B2_DONT_BOOTSTRAP: 1}
run: source ci/github/install.sh
- name: Run CMake tests
run: |
cd "$BOOST_ROOT"
mkdir __build_cmake_test__ && cd __build_cmake_test__
cmake -G "${{matrix.generator}}" -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBOOST_INCLUDE_LIBRARIES=$SELF -DBUILD_SHARED_LIBS=${{matrix.build_shared}} -DBUILD_TESTING=ON -DBoost_VERBOSE=ON ..
cmake --build . --target tests --config ${{matrix.build_type}} -j$B2_JOBS
ctest --output-on-failure --build-config ${{matrix.build_type}}
- name: Run CMake subdir tests
run: |
cmake_test_folder="$BOOST_ROOT/libs/$SELF/test/cmake_test" # New unified folder
[ -d "$cmake_test_folder" ] || cmake_test_folder="$BOOST_ROOT/libs/$SELF/test/cmake_subdir_test"
cd "$cmake_test_folder"
mkdir __build_cmake_subdir_test__ && cd __build_cmake_subdir_test__
cmake -G "${{matrix.generator}}" -DBOOST_CI_INSTALL_TEST=OFF -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBUILD_SHARED_LIBS=${{matrix.build_shared}} ..
cmake --build . --config ${{matrix.build_type}} -j$B2_JOBS
ctest --output-on-failure --build-config ${{matrix.build_type}}
- name: Install Library
run: |
cd "$BOOST_ROOT"
mkdir __build_cmake_install_test__ && cd __build_cmake_install_test__
cmake -G "${{matrix.generator}}" -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBOOST_INCLUDE_LIBRARIES=$SELF -DBUILD_SHARED_LIBS=${{matrix.build_shared}} -DCMAKE_INSTALL_PREFIX=~/.local -DBoost_VERBOSE=ON -DBoost_DEBUG=ON ..
cmake --build . --target install --config ${{matrix.build_type}} -j$B2_JOBS
- name: Run CMake install tests
run: |
cmake_test_folder="$BOOST_ROOT/libs/$SELF/test/cmake_test" # New unified folder
[ -d "$cmake_test_folder" ] || cmake_test_folder="$BOOST_ROOT/libs/$SELF/test/cmake_install_test"
cd "$cmake_test_folder"
mkdir __build_cmake_install_test__ && cd __build_cmake_install_test__
cmake -G "${{matrix.generator}}" -DBOOST_CI_INSTALL_TEST=ON -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBUILD_SHARED_LIBS=${{matrix.build_shared}} -DCMAKE_PREFIX_PATH=~/.local ..
cmake --build . --config ${{matrix.build_type}} -j$B2_JOBS
ctest --output-on-failure --build-config ${{matrix.build_type}}
+3 -6
View File
@@ -1,9 +1,9 @@
# Generated by `boostdep --cmake unordered`
# Copyright 2020 Peter Dimov
# 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.16)
cmake_minimum_required(VERSION 3.5...3.20)
project(boost_unordered VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
@@ -16,14 +16,12 @@ target_link_libraries(boost_unordered
INTERFACE
Boost::assert
Boost::config
Boost::container
Boost::container_hash
Boost::core
Boost::detail
Boost::move
Boost::mp11
Boost::predef
Boost::preprocessor
Boost::smart_ptr
Boost::throw_exception
Boost::tuple
Boost::type_traits
@@ -34,4 +32,3 @@ if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)
endif()
+23
View File
@@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
+49
View File
@@ -0,0 +1,49 @@
# Boost.Unordered
Part of collection of the [Boost C++ Libraries](http://github.com/boostorg).
For accessing data based on key lookup, the C++ standard library offers `std::set`, `std::map`, `std::multiset` and `std::multimap`.
These are generally implemented using balanced binary trees so that lookup time has logarithmic complexity.
That is generally okay, but in many cases a hash table can perform better, as accessing data has constant complexity, on average.
The worst case complexity is linear, but that occurs rarely and with some care, can be avoided.
Also, the existing containers require a 'less than' comparison object to order their elements.
For some data types this is impossible to implement or isnt practical.
In contrast, a hash table only needs an equality function and a hash function for the key.
With this in mind, unordered associative containers were added to the C++ standard.
This is an implementation of the containers described in C++11, with some deviations from the standard in order to work with non-C++11 compilers and libraries.
### License
Distributed under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt).
### Properties
* C++03
* Header-Only
### Build Status
Branch | GH Actions | Appveyor | codecov.io | Deps | Docs | Tests |
:-------------: | ---------- | -------- | ---------- | ---- | ---- | ----- |
[`master`](https://github.com/boostorg/unordered/tree/master) | [![CI](https://github.com/boostorg/unordered/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/unordered/actions/workflows/ci.yml) | [![Build status](https://ci.appveyor.com/api/projects/status/github/boostorg/unordered?branch=master&svg=true)](https://ci.appveyor.com/project/danieljames/unordered-qtwe6/branch/master) | [![codecov](https://codecov.io/gh/boostorg/unordered/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/unordered/branch/master) | [![Deps](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/unordered.html) | [![Documentation](https://img.shields.io/badge/docs-master-brightgreen.svg)](https://www.boost.org/doc/libs/master/libs/unordered/doc/html/unordered.html) | [![Enter the Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/unordered.html)
[`develop`](https://github.com/boostorg/unordered/tree/develop) | [![CI](https://github.com/boostorg/unordered/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/unordered/actions/workflows/ci.yml) | [![Build status](https://ci.appveyor.com/api/projects/status/github/boostorg/unordered?branch=develop&svg=true)](https://ci.appveyor.com/project/danieljames/unordered-qtwe6/branch/develop) | [![codecov](https://codecov.io/gh/boostorg/unordered/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/unordered/branch/develop) | [![Deps](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/unordered.html) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](https://www.boost.org/doc/libs/develop/libs/unordered/doc/html/unordered.html) | [![Enter the Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/unordered.html)
### Directories
| Name | Purpose |
| ----------- | ------------------------------ |
| `doc` | documentation |
| `example` | examples |
| `include` | headers |
| `test` | unit tests |
### More information
* [Ask questions](http://stackoverflow.com/questions/ask?tags=c%2B%2B,boost,boost-unordered)
* [Report bugs](https://github.com/boostorg/unordered/issues): Be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well.
* Submit your patches as pull requests against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt).
* Discussions about the library are held on the [Boost developers mailing list](http://www.boost.org/community/groups.html#main). Be sure to read the [discussion policy](http://www.boost.org/community/policy.html) before posting and add the `[unordered]` tag at the beginning of the subject line.
+85 -8
View File
@@ -14,6 +14,12 @@
# include "absl/container/node_hash_map.h"
# include "absl/container/flat_hash_map.h"
#endif
#ifdef HAVE_TSL_HOPSCOTCH
# include "tsl/hopscotch_map.h"
#endif
#ifdef HAVE_TSL_ROBIN
# include "tsl/robin_map.h"
#endif
#include <unordered_map>
#include <vector>
#include <memory>
@@ -137,7 +143,14 @@ template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::s
{
if( it->second & 1 )
{
map.erase( it++ );
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
{
map.erase( it++ );
}
else
{
it = map.erase( it );
}
}
else
{
@@ -159,13 +172,9 @@ template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::stead
print_time( t1, "Consecutive erase", 0, map.size() );
for( unsigned i = 1; i <= N; ++i )
{
boost::detail::splitmix64 rng;
for( unsigned i = 1; i <= N; ++i )
{
map.erase( indices2[ i ] );
}
map.erase( indices2[ i ] );
}
print_time( t1, "Random erase", 0, map.size() );
@@ -295,6 +304,26 @@ template<class K, class V> using absl_flat_hash_map =
#endif
#ifdef HAVE_TSL_HOPSCOTCH
template<class K, class V> using tsl_hopscotch_map =
tsl::hopscotch_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
template<class K, class V> using tsl_hopscotch_pg_map =
tsl::hopscotch_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
#endif
#ifdef HAVE_TSL_ROBIN
template<class K, class V> using tsl_robin_map =
tsl::robin_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
template<class K, class V> using tsl_robin_pg_map =
tsl::robin_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
#endif
// fnv1a_hash
template<int Bits> struct fnv1a_hash_impl;
@@ -363,6 +392,26 @@ template<class K, class V> using absl_flat_hash_map_fnv1a =
#endif
#ifdef HAVE_TSL_HOPSCOTCH
template<class K, class V> using tsl_hopscotch_map_fnv1a =
tsl::hopscotch_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
template<class K, class V> using tsl_hopscotch_pg_map_fnv1a =
tsl::hopscotch_pg_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
#endif
#ifdef HAVE_TSL_ROBIN
template<class K, class V> using tsl_robin_map_fnv1a =
tsl::robin_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
template<class K, class V> using tsl_robin_pg_map_fnv1a =
tsl::robin_pg_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
#endif
//
int main()
@@ -382,6 +431,20 @@ int main()
#endif
#ifdef HAVE_TSL_HOPSCOTCH
test<tsl_hopscotch_map>( "tsl::hopscotch_map" );
test<tsl_hopscotch_pg_map>( "tsl::hopscotch_pg_map" );
#endif
#ifdef HAVE_TSL_ROBIN
test<tsl_robin_map>( "tsl::robin_map" );
test<tsl_robin_pg_map>( "tsl::robin_pg_map" );
#endif
#endif
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
@@ -393,13 +456,27 @@ int main()
test<absl_node_hash_map_fnv1a>( "absl::node_hash_map, FNV-1a" );
test<absl_flat_hash_map_fnv1a>( "absl::flat_hash_map, FNV-1a" );
#endif
#ifdef HAVE_TSL_HOPSCOTCH
test<tsl_hopscotch_map_fnv1a>( "tsl::hopscotch_map, FNV-1a" );
test<tsl_hopscotch_pg_map_fnv1a>( "tsl::hopscotch_pg_map, FNV-1a" );
#endif
#ifdef HAVE_TSL_ROBIN
test<tsl_robin_map_fnv1a>( "tsl::robin_map, FNV-1a" );
test<tsl_robin_pg_map_fnv1a>( "tsl::robin_pg_map, FNV-1a" );
#endif
std::cout << "---\n\n";
for( auto const& x: times )
{
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
std::cout << std::setw( 31 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
}
}
+85 -8
View File
@@ -14,6 +14,12 @@
# include "absl/container/node_hash_map.h"
# include "absl/container/flat_hash_map.h"
#endif
#ifdef HAVE_TSL_HOPSCOTCH
# include "tsl/hopscotch_map.h"
#endif
#ifdef HAVE_TSL_ROBIN
# include "tsl/robin_map.h"
#endif
#include <unordered_map>
#include <string_view>
#include <vector>
@@ -138,7 +144,14 @@ template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::s
{
if( it->second & 1 )
{
map.erase( it++ );
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
{
map.erase( it++ );
}
else
{
it = map.erase( it );
}
}
else
{
@@ -160,13 +173,9 @@ template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::stead
print_time( t1, "Consecutive erase", 0, map.size() );
for( unsigned i = 1; i <= N; ++i )
{
boost::detail::splitmix64 rng;
for( unsigned i = 1; i <= N; ++i )
{
map.erase( indices2[ i ] );
}
map.erase( indices2[ i ] );
}
print_time( t1, "Random erase", 0, map.size() );
@@ -296,6 +305,26 @@ template<class K, class V> using absl_flat_hash_map =
#endif
#ifdef HAVE_TSL_HOPSCOTCH
template<class K, class V> using tsl_hopscotch_map =
tsl::hopscotch_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
template<class K, class V> using tsl_hopscotch_pg_map =
tsl::hopscotch_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
#endif
#ifdef HAVE_TSL_ROBIN
template<class K, class V> using tsl_robin_map =
tsl::robin_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
template<class K, class V> using tsl_robin_pg_map =
tsl::robin_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
#endif
// fnv1a_hash
template<int Bits> struct fnv1a_hash_impl;
@@ -364,6 +393,26 @@ template<class K, class V> using absl_flat_hash_map_fnv1a =
#endif
#ifdef HAVE_TSL_HOPSCOTCH
template<class K, class V> using tsl_hopscotch_map_fnv1a =
tsl::hopscotch_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
template<class K, class V> using tsl_hopscotch_pg_map_fnv1a =
tsl::hopscotch_pg_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
#endif
#ifdef HAVE_TSL_ROBIN
template<class K, class V> using tsl_robin_map_fnv1a =
tsl::robin_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
template<class K, class V> using tsl_robin_pg_map_fnv1a =
tsl::robin_pg_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
#endif
//
int main()
@@ -383,6 +432,20 @@ int main()
#endif
#ifdef HAVE_TSL_HOPSCOTCH
test<tsl_hopscotch_map>( "tsl::hopscotch_map" );
test<tsl_hopscotch_pg_map>( "tsl::hopscotch_pg_map" );
#endif
#ifdef HAVE_TSL_ROBIN
test<tsl_robin_map>( "tsl::robin_map" );
test<tsl_robin_pg_map>( "tsl::robin_pg_map" );
#endif
#endif
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
@@ -394,13 +457,27 @@ int main()
test<absl_node_hash_map_fnv1a>( "absl::node_hash_map, FNV-1a" );
test<absl_flat_hash_map_fnv1a>( "absl::flat_hash_map, FNV-1a" );
#endif
#ifdef HAVE_TSL_HOPSCOTCH
test<tsl_hopscotch_map_fnv1a>( "tsl::hopscotch_map, FNV-1a" );
test<tsl_hopscotch_pg_map_fnv1a>( "tsl::hopscotch_pg_map, FNV-1a" );
#endif
#ifdef HAVE_TSL_ROBIN
test<tsl_robin_map_fnv1a>( "tsl::robin_map, FNV-1a" );
test<tsl_robin_pg_map_fnv1a>( "tsl::robin_pg_map, FNV-1a" );
#endif
std::cout << "---\n\n";
for( auto const& x: times )
{
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
std::cout << std::setw( 31 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
}
}
+55 -11
View File
@@ -8,12 +8,19 @@
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/endian/conversion.hpp>
#include <boost/core/detail/splitmix64.hpp>
#include <boost/config.hpp>
#ifdef HAVE_ABSEIL
# include "absl/container/node_hash_map.h"
# include "absl/container/flat_hash_map.h"
#endif
#ifdef HAVE_TSL_HOPSCOTCH
# include "tsl/hopscotch_map.h"
#endif
#ifdef HAVE_TSL_ROBIN
# include "tsl/robin_map.h"
#endif
#include <unordered_map>
#include <vector>
#include <memory>
@@ -62,7 +69,7 @@ static void init_indices()
for( unsigned i = 1; i <= N*2; ++i )
{
indices3.push_back( (std::uint32_t)i << 11 );
indices3.push_back( boost::endian::endian_reverse( static_cast<std::uint32_t>( i ) ) );
}
}
@@ -87,7 +94,7 @@ template<class Map> BOOST_NOINLINE void test_insert( Map& map, std::chrono::stea
map.insert( { indices3[ i ], i } );
}
print_time( t1, "Consecutive shifted insert", 0, map.size() );
print_time( t1, "Consecutive reversed insert", 0, map.size() );
std::cout << std::endl;
}
@@ -133,7 +140,7 @@ template<class Map> BOOST_NOINLINE void test_lookup( Map& map, std::chrono::stea
}
}
print_time( t1, "Consecutive shifted lookup", s, map.size() );
print_time( t1, "Consecutive reversed lookup", s, map.size() );
std::cout << std::endl;
}
@@ -146,7 +153,14 @@ template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::s
{
if( it->second & 1 )
{
map.erase( it++ );
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
{
map.erase( it++ );
}
else
{
it = map.erase( it );
}
}
else
{
@@ -168,13 +182,9 @@ template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::stead
print_time( t1, "Consecutive erase", 0, map.size() );
for( unsigned i = 1; i <= N; ++i )
{
boost::detail::splitmix64 rng;
for( unsigned i = 1; i <= N; ++i )
{
map.erase( indices2[ i ] );
}
map.erase( indices2[ i ] );
}
print_time( t1, "Random erase", 0, map.size() );
@@ -184,7 +194,7 @@ template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::stead
map.erase( indices3[ i ] );
}
print_time( t1, "Consecutive shifted erase", 0, map.size() );
print_time( t1, "Consecutive reversed erase", 0, map.size() );
std::cout << std::endl;
}
@@ -311,6 +321,26 @@ template<class K, class V> using absl_flat_hash_map =
#endif
#ifdef HAVE_TSL_HOPSCOTCH
template<class K, class V> using tsl_hopscotch_map =
tsl::hopscotch_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
template<class K, class V> using tsl_hopscotch_pg_map =
tsl::hopscotch_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
#endif
#ifdef HAVE_TSL_ROBIN
template<class K, class V> using tsl_robin_map =
tsl::robin_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
template<class K, class V> using tsl_robin_pg_map =
tsl::robin_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
#endif
int main()
{
init_indices();
@@ -324,6 +354,20 @@ int main()
test<absl_node_hash_map>( "absl::node_hash_map" );
test<absl_flat_hash_map>( "absl::flat_hash_map" );
#endif
#ifdef HAVE_TSL_HOPSCOTCH
test<tsl_hopscotch_map>( "tsl::hopscotch_map" );
test<tsl_hopscotch_pg_map>( "tsl::hopscotch_pg_map" );
#endif
#ifdef HAVE_TSL_ROBIN
test<tsl_robin_map>( "tsl::robin_map" );
test<tsl_robin_pg_map>( "tsl::robin_pg_map" );
#endif
std::cout << "---\n\n";
+55 -11
View File
@@ -8,12 +8,19 @@
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/endian/conversion.hpp>
#include <boost/core/detail/splitmix64.hpp>
#include <boost/config.hpp>
#ifdef HAVE_ABSEIL
# include "absl/container/node_hash_map.h"
# include "absl/container/flat_hash_map.h"
#endif
#ifdef HAVE_TSL_HOPSCOTCH
# include "tsl/hopscotch_map.h"
#endif
#ifdef HAVE_TSL_ROBIN
# include "tsl/robin_map.h"
#endif
#include <unordered_map>
#include <vector>
#include <memory>
@@ -62,7 +69,7 @@ static void init_indices()
for( unsigned i = 1; i <= N*2; ++i )
{
indices3.push_back( (std::uint64_t)i << 40 );
indices3.push_back( boost::endian::endian_reverse( static_cast<std::uint64_t>( i ) ) );
}
}
@@ -87,7 +94,7 @@ template<class Map> BOOST_NOINLINE void test_insert( Map& map, std::chrono::stea
map.insert( { indices3[ i ], i } );
}
print_time( t1, "Consecutive shifted insert", 0, map.size() );
print_time( t1, "Consecutive reversed insert", 0, map.size() );
std::cout << std::endl;
}
@@ -133,7 +140,7 @@ template<class Map> BOOST_NOINLINE void test_lookup( Map& map, std::chrono::stea
}
}
print_time( t1, "Consecutive shifted lookup", s, map.size() );
print_time( t1, "Consecutive reversed lookup", s, map.size() );
std::cout << std::endl;
}
@@ -146,7 +153,14 @@ template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::s
{
if( it->second & 1 )
{
map.erase( it++ );
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
{
map.erase( it++ );
}
else
{
it = map.erase( it );
}
}
else
{
@@ -168,13 +182,9 @@ template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::stead
print_time( t1, "Consecutive erase", 0, map.size() );
for( unsigned i = 1; i <= N; ++i )
{
boost::detail::splitmix64 rng;
for( unsigned i = 1; i <= N; ++i )
{
map.erase( indices2[ i ] );
}
map.erase( indices2[ i ] );
}
print_time( t1, "Random erase", 0, map.size() );
@@ -184,7 +194,7 @@ template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::stead
map.erase( indices3[ i ] );
}
print_time( t1, "Consecutive shifted erase", 0, map.size() );
print_time( t1, "Consecutive reversed erase", 0, map.size() );
std::cout << std::endl;
}
@@ -311,6 +321,26 @@ template<class K, class V> using absl_flat_hash_map =
#endif
#ifdef HAVE_TSL_HOPSCOTCH
template<class K, class V> using tsl_hopscotch_map =
tsl::hopscotch_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
template<class K, class V> using tsl_hopscotch_pg_map =
tsl::hopscotch_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
#endif
#ifdef HAVE_TSL_ROBIN
template<class K, class V> using tsl_robin_map =
tsl::robin_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
template<class K, class V> using tsl_robin_pg_map =
tsl::robin_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
#endif
int main()
{
init_indices();
@@ -324,6 +354,20 @@ int main()
test<absl_node_hash_map>( "absl::node_hash_map" );
test<absl_flat_hash_map>( "absl::flat_hash_map" );
#endif
#ifdef HAVE_TSL_HOPSCOTCH
test<tsl_hopscotch_map>( "tsl::hopscotch_map" );
test<tsl_hopscotch_pg_map>( "tsl::hopscotch_pg_map" );
#endif
#ifdef HAVE_TSL_ROBIN
test<tsl_robin_map>( "tsl::robin_map" );
test<tsl_robin_pg_map>( "tsl::robin_pg_map" );
#endif
std::cout << "---\n\n";
-66
View File
@@ -1,66 +0,0 @@
#!/usr/bin/env python
import urllib, os, os.path, sys, json, tarfile, zipfile, tempfile
def download(snapshot):
if snapshot == 'stable':
# TODO: Default version/filename if not available?
downloads = [
"https://sourceforge.net/projects/boost/files/boost/%s/%s.tar.bz2/download" %
(os.environ['BOOST_VERSION'], os.environ['BOOST_FILENAME'])]
else:
json_response = urllib.urlopen('https://api.bintray.com/packages/boostorg/%s/snapshot/files' % (snapshot))
x = json.load(json_response)
extension_priorities = { '.bz2': 2, '.gz': 1, '.zip': 0 }
file_list = []
version_dates = {}
for file in x:
file_extension = os.path.splitext(file['path'])[1]
if (file_extension in extension_priorities):
file['priority'] = extension_priorities[file_extension]
file_list.append(file)
if not file['version'] in version_dates or file['created'] < version_dates[file['version']]:
version_dates[file['version']] = file['created']
file_list.sort(key=lambda x: (version_dates[x['version']], x['priority']), reverse=True)
downloads = ['http://dl.bintray.com/boostorg/%s/%s' % (snapshot, file['path']) for file in file_list]
filename = ''
for download_url in downloads:
try:
print "Downloading: " + download_url
(filename, headers) = urllib.urlretrieve(download_url)
print "Extracting: " + filename
dir = tempfile.mkdtemp()
extract(filename, dir)
os.remove(filename)
files = os.listdir(dir)
assert(len(files) == 1)
os.rename(os.path.join(dir, files[0]), 'boost')
return
except IOError:
print "Error opening URL: " + download_url
def extract(filename, path = '.'):
if (filename.endswith(".gz")):
tar = tarfile.open(filename, "r:gz")
tar.extractall(path)
tar.close
elif (filename.endswith(".bz2")):
tar = tarfile.open(filename, "r:bz2")
tar.extractall(path)
tar.close
elif (filename.endswith(".zip")):
zip = zipfile.ZipFile(filename, "r")
zip.extractall(path)
zip.close
else:
assert False
if len(sys.argv) == 1:
download('stable')
elif len(sys.argv) == 2:
download(sys.argv[1])
else:
print "Usage: %s [stable|branch-name]" % (sys.argv[0])
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

+47
View File
@@ -0,0 +1,47 @@
# Building Boost from the Tip of Develop
To build Boost from the tip of the develop branch without cloning the entire
history, use the command below:
Linux:
```bash
cwd=$(pwd) \
&& cd ~ \
&& git clone -b develop --depth 1 --recurse-submodules --shallow-submodules --jobs 8 https://github.com/boostorg/boost.git boost-develop-beta \
&& cd boost-develop-beta \
&& ./bootstrap.sh \
&& ./b2 install --prefix=boost-install cxxstd=17 \
&& echo "Boost successfully installed into $(realpath boost-install)!
Add this to your CMake toolchain file.
list(APPEND CMAKE_PREFIX_PATH $(realpath boost-install))
" \
&& cd $cwd
```
Windows (using plain Command Prompt):
```bat
cmd /v
set cwd=%cd% ^
&& cd %homepath% ^
&& git clone -b develop --depth 1 --recurse-submodules --shallow-submodules --jobs 8 https://github.com/boostorg/boost.git boost-develop-beta ^
&& cd boost-develop-beta ^
&& bootstrap.bat ^
&& b2 install --prefix=boost-install cxxstd=17 address-model=64 ^
&& echo Boost successfully installed into !cd!\boost-install! ^
&& echo Add this to your CMake toolchain file. ^
&& echo list(APPEND CMAKE_PREFIX_PATH !cd:\=/!/boost-install) ^
&& cd !cwd! ^
&& exit
```
Note: you can build Boost with a specific compiler by setting the toolset in
the `./b2` command above. To build with clang, specify `toolset=clang`; to build
with a specific version of gcc, clang or msvc, specify e.g. `toolset=gcc-12` for GCC
12, `clang-14` for Clang 14, `msvc-14.3` for MSVC 14.3. The value of `cxxstd`
can also be set to other values such as 11 for C++11, 14 for C++14, etc.
For more info on what's possible, check out this link on b2:
https://www.boost.org/doc/libs/develop/tools/build/doc/html/index.html#bbv2.overview.builtins.features
This should hopefully cover the two most common cases of building a dependency,
setting the compiler and C++ standard used.
+188
View File
@@ -0,0 +1,188 @@
# Refactoring Roadmap
[Proof of concept](https://github.com/joaquintides/fca_unordered) implementation for a fast closed-addressing implementation.
## Plan of Refactoring
* remove `ptr_node` and `ptr_bucket`
* see if the code can survive a lack of the `extra_node` or maybe we hard-code it in
* implement bucket groups as they are in `fca` but don't use them directly yet, add alongside the `buckets_` data member in `struct table`
* try to remove `bucket_info_` from the node structure (breaks all call-sites that use `get_bucket()` and dependents)
* make sure `fca` can successfully handle multi-variants at this stage + supports mutable iterators for `map`/`multimap`
* do a hard-break:
* update code to no longer use one single linked list across all buckets (each bucket contains its own unique list)
* integrate the `bucket_group<Node>` structure into the `table` (update iterator call-sites to include `bucket_iterator`s)
Blockers:
* how to handle `multi` variants with new `fca` prototype
## Implementation Differences
### Unordered
### Node Type
Bullet Points:
* reify node type into a single one
* come up with implementation for multi- variants
* code that touches `get_bucket()` and `*_in_group()` member functions may need updating
There are two node types in Unordered, `struct node` and `struct ptr_node`, and the node type is selected conditionally based on the Allocator's pointer type:
```c++
template <typename A, typename T, typename NodePtr, typename BucketPtr>
struct pick_node2
{
typedef boost::unordered::detail::node<A, T> node;
// ...
};
template <typename A, typename T>
struct pick_node2<A, T, boost::unordered::detail::ptr_node<T>*,
boost::unordered::detail::ptr_bucket*>
{
typedef boost::unordered::detail::ptr_node<T> node;
// ...
};
template <typename A, typename T> struct pick_node
{
typedef typename boost::remove_const<T>::type nonconst;
typedef boost::unordered::detail::allocator_traits<
typename boost::unordered::detail::rebind_wrap<A,
boost::unordered::detail::ptr_node<nonconst> >::type>
tentative_node_traits;
typedef boost::unordered::detail::allocator_traits<
typename boost::unordered::detail::rebind_wrap<A,
boost::unordered::detail::ptr_bucket>::type>
tentative_bucket_traits;
typedef pick_node2<A, nonconst, typename tentative_node_traits::pointer,
typename tentative_bucket_traits::pointer>
pick;
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
};
```
The node types are identical in terms of interface and the only difference is that `node` is chosen when the Allocator uses fancy pointers and `ptr_node` is chosen when the Allocator's pointer type is `T*`.
Nodes in Unorderd store `bucket_info_`:
```cpp
template <typename A, typename T>
struct node : boost::unordered::detail::value_base<T>
{
link_pointer next_;
std::size_t bucket_info_;
node() : next_(), bucket_info_(0) {}
// ...
};
```
`bucket_info_` maps each node back to its corresponding bucket via the member function:
```cpp
std::size_t get_bucket() const
{
return bucket_info_ & ((std::size_t)-1 >> 1);
}
```
`bucket_info_` is also used to demarcate the start of equivalent nodes in the containers via:
```cpp
// Note that nodes start out as the first in their group, as `bucket_info_` defaults to 0.
std::size_t is_first_in_group() const
{ return !(bucket_info_ & ~((std::size_t)-1 >> 1)); }
void set_first_in_group()
{ bucket_info_ = bucket_info_ & ((std::size_t)-1 >> 1); }
void reset_first_in_group()
{ bucket_info_ = bucket_info_ | ~((std::size_t)-1 >> 1); }
```
A goal of refactoring is to simply have one node type:
```cpp
template<class T>
struct node {
node *next;
T value;
};
```
that is used unconditionally. This also requires updating the code that touches the `bucket_info_` along with the code that that touches the `*_in_group()` member functions.
### Bucket Type
Bullet points:
* reify bucket structure into a single one
* figure out how to add `bucket_group`s to the table struct
Buckets are similar to nodes in that there are two variations: `template<class NodePointer> struct bucket` and `struct ptr_bucket`.
The buckets exist to contain a pointer to a node, however they contain an `enum { extra_node = true };` or `enum { extra_node = false }` to determine whether or not the code should explicitly allocate a default constructed node whose address assigned as the dummy node at the end of the bucket array.
`extra_node` is used in the creation and deletion of the bucket array but it is not inherently clear what its intended purpose is.
### Iterators
Iterators are currently templated on the type of Node they store. Because `fca` constructs iterators with two arguments, all the call-sites that instantiate iterators will need to be updated but this a straight-forward mechanical change.
Iterators are selected, as of now, via the `detail::map` and `detail::set` class templates.
For example, for `unordered_map`, `iterator` is defined as:
```cpp
typedef boost::unordered::detail::map<A, K, T, H, P> types;
typedef typename types::table table;
typedef typename table::iterator iterator;
```
The iterator is a member typedef of the `table` which is `types::table`. Examining `types` (aka `detail::map<...>`), we see:
```cpp
template <typename A, typename K, typename M, typename H, typename P>
struct map {
// ...
typedef boost::unordered::detail::table<types> table;
// ...
};
```
Examining the `detail::table<types>` struct, we see:
```cpp
template <typename Types>
struct table {
// ...
typedef typename Types::iterator iterator;
// ...
}
```
Collapsing all of this, we see that our iterator types are defined here:
```cpp
template <typename A, typename K, typename M, typename H, typename P>
struct map
{
// ...
typedef boost::unordered::detail::pick_node<A, value_type> pick;
typedef typename pick::node node;
typedef boost::unordered::iterator_detail::iterator<node> iterator;
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
typedef boost::unordered::iterator_detail::l_iterator<node> l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node>
cl_iterator;
// ...
};
```
This is similarly designed for `detail::set`:
```cpp
typedef boost::unordered::iterator_detail::c_iterator<node> iterator;
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node> l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node>
cl_iterator;
```
The only difference here is that `set::iterator` is always a `c_iterator`, a `const_iterator` type.
+1
View File
@@ -12,6 +12,7 @@
include::unordered/intro.adoc[]
include::unordered/buckets.adoc[]
include::unordered/benchmarks.adoc[]
include::unordered/hash_equality.adoc[]
include::unordered/comparison.adoc[]
include::unordered/compliance.adoc[]
+277
View File
@@ -0,0 +1,277 @@
[#benchmarks]
:idprefix: benchmarks_
:imagesdir: ../diagrams
= Benchmarks
All benchmarks were created using `unordered_set<unsigned int>` (non-duplicate) and `unordered_multiset<unsigned int>` (duplicate). The source code can be https://github.com/joaquintides/boost_unordered_benchmark[found here].
The insertion benchmarks insert `n` random values, where `n` is between 10,000 and 3 million. For the duplicated benchmarks, the same random values are repeated an average of 5 times.
The erasure benchmarks erase all `n` elements randomly until the container is empty.
The successful lookup benchmarks are done by looking up all `n` values, in the their original insertion order.
The unsuccessful lookup benchmarks use `n` randomly generated integers but using a different seed value.
== GCC 11 + libstdc++-v3
=== Insertion
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/gcc/running insertion.xlsx.practice.png[width=250,link=../diagrams/benchmarks/gcc/running insertion.xlsx.practice.png,window=_blank]
|image::benchmarks/gcc/running%20insertion.xlsx.practice non-unique.png[width=250,link=../diagrams/benchmarks/gcc/running%20insertion.xlsx.practice non-unique.png,window=_blank]
|image::benchmarks/gcc/running%20insertion.xlsx.practice non-unique 5.png[width=250,link=../diagrams/benchmarks/gcc/running%20insertion.xlsx.practice non-unique 5.png,window=_blank]
h|non-duplicate elements
h|duplicate elements
h|duplicate elements +
max load factor 5
|===
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/gcc/running%20insertion.xlsx.practice norehash.png[width=250,link=../diagrams/benchmarks/gcc/running%20insertion.xlsx.practice norehash.png,window=_blank]
|image::benchmarks/gcc/running%20insertion.xlsx.practice norehash non-unique.png[width=250,link=../diagrams/benchmarks/gcc/running%20insertion.xlsx.practice norehash non-unique.png,window=_blank]
|image::benchmarks/gcc/running%20insertion.xlsx.practice norehash non-unique 5.png[width=250,link=../diagrams/benchmarks/gcc/running%20insertion.xlsx.practice norehash non-unique 5.png,window=_blank]
h|non-duplicate elements, +
prior `reserve`
h|duplicate elements, +
prior `reserve`
h|duplicate elements, +
max load factor 5, +
prior `reserve`
|===
=== Erasure
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/gcc/scattered%20erasure.xlsx.practice.png[width=250,link=../diagrams/benchmarks/gcc/scattered%20erasure.xlsx.practice.png,window=_blank]
|image::benchmarks/gcc/scattered%20erasure.xlsx.practice non-unique.png[width=250,link=../diagrams/benchmarks/gcc/scattered%20erasure.xlsx.practice non-unique.png,window=_blank]
|image::benchmarks/gcc/scattered%20erasure.xlsx.practice non-unique 5.png[width=250,link=../diagrams/benchmarks/gcc/scattered%20erasure.xlsx.practice non-unique 5.png,window=_blank]
h|non-duplicate elements
h|duplicate elements
h|duplicate elements +
max load factor 5
|===
=== Successful Lookup
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/gcc/scattered%20successful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/gcc/scattered%20successful%20looukp.xlsx.practice.png]
|image::benchmarks/gcc/scattered%20successful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/gcc/scattered%20successful%20looukp.xlsx.practice non-unique.png]
|image::benchmarks/gcc/scattered%20successful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/gcc/scattered%20successful%20looukp.xlsx.practice non-unique 5.png]
h|non-duplicate elements
h|duplicate elements
h|duplicate elements, +
max load factor 5
|===
=== Unsuccessful lookup
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/gcc/scattered%20unsuccessful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/gcc/scattered%20unsuccessful%20looukp.xlsx.practice.png]
|image::benchmarks/gcc/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/gcc/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png]
|image::benchmarks/gcc/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/gcc/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png]
h|non-duplicate elements
h|duplicate elements
h|duplicate elements, +
max load factor 5
|===
== Clang 12 + libc++
=== Insertion
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/clang_libcpp/running%20insertion.xlsx.practice.png[width=250, window=_blank,link=../diagrams/benchmarks/clang_libcpp/running%20insertion.xlsx.practice.png]
|image::benchmarks/clang_libcpp/running%20insertion.xlsx.practice non-unique.png[width=250, window=_blank,link=../diagrams/benchmarks/clang_libcpp/running%20insertion.xlsx.practice non-unique.png]
|image::benchmarks/clang_libcpp/running%20insertion.xlsx.practice non-unique 5.png[width=250, window=_blank,link=../diagrams/benchmarks/clang_libcpp/running%20insertion.xlsx.practice non-unique 5.png]
h|non-duplicate elements
h|duplicate elements
h|duplicate elements, +
max load factor 5
|===
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/clang_libcpp/running%20insertion.xlsx.practice norehash.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/running%20insertion.xlsx.practice norehash.png]
|image::benchmarks/clang_libcpp/running%20insertion.xlsx.practice norehash non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/running%20insertion.xlsx.practice norehash non-unique.png]
|image::benchmarks/clang_libcpp/running%20insertion.xlsx.practice norehash non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/running%20insertion.xlsx.practice norehash non-unique 5.png]
h|non-duplicate elements, +
prior `reserve`
h|duplicate elements, +
prior `reserve`
h|duplicate elements, +
max load factor 5, +
prior `reserve`
|===
=== Erasure
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/clang_libcpp/scattered%20erasure.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20erasure.xlsx.practice.png]
|image::benchmarks/clang_libcpp/scattered%20erasure.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20erasure.xlsx.practice non-unique.png]
|image::benchmarks/clang_libcpp/scattered%20erasure.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20erasure.xlsx.practice non-unique 5.png]
h|non-duplicate elements
h|duplicate elements
h|duplicate elements, +
max load factor 5
|===
=== Successful lookup
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/clang_libcpp/scattered%20successful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20successful%20looukp.xlsx.practice.png]
|image::benchmarks/clang_libcpp/scattered%20successful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20successful%20looukp.xlsx.practice non-unique.png]
|image::benchmarks/clang_libcpp/scattered%20successful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20successful%20looukp.xlsx.practice non-unique 5.png]
h|non-duplicate elements
h|duplicate elements
h|duplicate elements, +
max load factor 5
|===
=== Unsuccessful lookup
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice.png]
|image::benchmarks/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png]
|image::benchmarks/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png]
h|non-duplicate elements
h|duplicate elements
h|duplicate elements, +
max load factor 5
|===
== Visual Studio 2019 + Dinkumware
=== Insertion
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/vs/running%20insertion.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/running%20insertion.xlsx.practice.png]
|image::benchmarks/vs/running%20insertion.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/running%20insertion.xlsx.practice non-unique.png]
|image::benchmarks/vs/running%20insertion.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/running%20insertion.xlsx.practice non-unique 5.png]
h|non-duplicate elements
h|duplicate elements
h|duplicate elements, +
max load factor 5
|===
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/vs/running%20insertion.xlsx.practice norehash.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/running%20insertion.xlsx.practice norehash.png]
|image::benchmarks/vs/running%20insertion.xlsx.practice norehash non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/running%20insertion.xlsx.practice norehash non-unique.png]
|image::benchmarks/vs/running%20insertion.xlsx.practice norehash non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/running%20insertion.xlsx.practice norehash non-unique 5.png]
h|non-duplicate elements, +
prior `reserve`
h|duplicate elements, +
prior `reserve`
h|duplicate elements, +
max load factor 5, +
prior `reserve`
|===
=== Erasure
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/vs/scattered%20erasure.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20erasure.xlsx.practice.png]
|image::benchmarks/vs/scattered%20erasure.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20erasure.xlsx.practice non-unique.png]
|image::benchmarks/vs/scattered%20erasure.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20erasure.xlsx.practice non-unique 5.png]
h|non-duplicate elements
h|duplicate elements
h|duplicate elements, +
max load factor 5
|===
=== Successful lookup
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/vs/scattered%20successful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20successful%20looukp.xlsx.practice.png]
|image::benchmarks/vs/scattered%20successful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20successful%20looukp.xlsx.practice non-unique.png]
|image::benchmarks/vs/scattered%20successful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20successful%20looukp.xlsx.practice non-unique 5.png]
h|non-duplicate elements
h|duplicate elements
h|duplicate elements, +
max load factor 5
|===
=== Unsuccessful lookup
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks/vs/scattered%20unsuccessful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20unsuccessful%20looukp.xlsx.practice.png]
|image::benchmarks/vs/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png]
|image::benchmarks/vs/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png]
h|non-duplicate elements
h|duplicate elements
h|duplicate elements, +
max load factor 5
|===
+59 -1
View File
@@ -1,5 +1,6 @@
[#buckets]
:idprefix: buckets_
:imagesdir: ../diagrams
= The Data Structure
@@ -8,7 +9,7 @@ any number of elements. For example, the following diagram shows an <<unordered_
`B`, `C`, `D` and `E` (this is just for illustration, containers will typically
have more buckets).
image::../diagrams/buckets.png[]
image::buckets.png[]
In order to decide which bucket to place an element in, the container applies
the hash function, `Hash`, to the element's key (for `unordered_set` and
@@ -150,3 +151,60 @@ x.rehash(std::ceil(n / x.max_load_factor()))
+
See the <<unordered_map_rehash,reference for more details>> on the `rehash` function.
== Fast Closed Addressing Implementation
++++
<style>
.imageblock > .title {
text-align: inherit;
}
</style>
++++
Boost.Unordered sports one of the fastest implementations of closed addressing, also commonly known as https://en.wikipedia.org/wiki/Hash_table#Separate_chaining[separate chaining]. An example figure representing the data structure is below:
[#img-bucket-groups,.text-center]
.A simple bucket group approach
image::bucket-groups.png[align=center]
An array of "buckets" is allocated and each bucket in turn points to its own individual linked list. This makes meeting the standard requirements of bucket iteration straight-forward. Unfortunately, iteration of the entire container is often times slow using this layout as each bucket must be examined for occupancy, yielding a time complexity of `O(bucket_count() + size())` when the standard requires complexity to be `O(size())`.
Canonical standard implementations will wind up looking like the diagram below:
[.text-center]
.The canonical standard approach
image::singly-linked.png[align=center,link=../diagrams/singly-linked.png,window=_blank]
It's worth noting that this approach is only used by pass:[libc++] and pass:[libstdc++]; the MSVC Dinkumware implementation uses a different one. A more detailed analysis of the standard containers can be found http://bannalia.blogspot.com/2013/10/implementation-of-c-unordered.html[here].
This unusually laid out data structure is chosen to make iteration of the entire container efficient by inter-connecting all of the nodes into a singly-linked list. One might also notice that buckets point to the node _before_ the start of the bucket's elements. This is done so that removing elements from the list can be done efficiently without introducing the need for a doubly-linked list. Unfortunately, this data structure introduces a guaranteed extra indirection. For example, to access the first element of a bucket, something like this must be done:
```c++
auto const idx = get_bucket_idx(hash_function(key));
node* p = buckets[idx]; // first load
node* n = p->next; // second load
if (n && is_in_bucket(n, idx)) {
value_type const& v = *n; // third load
// ...
}
```
With a simple bucket group layout, this is all that must be done:
```c++
auto const idx = get_bucket_idx(hash_function(key));
node* n = buckets[idx]; // first load
if (n) {
value_type const& v = *n; // second load
// ...
}
```
In practice, the extra indirection can have a dramatic performance impact to common operations such as `insert`, `find` and `erase`. But to keep iteration of the container fast, Boost.Unordered introduces a novel data structure, a "bucket group". A bucket group is a fixed-width view of a subsection of the buckets array. It contains a bitmask (a `std::size_t`) which it uses to track occupancy of buckets and contains two pointers so that it can form a doubly-linked list with non-empty groups. An example diagram is below:
[#img-fca-layout]
.The new layout used by Boost
image::fca.png[align=center]
Thus container-wide iteration is turned into traversing the non-empty bucket groups (an operation with constant time complexity) which reduces the time complexity back to `O(size())`. In total, a bucket group is only 4 words in size and it views `sizeof(std::size_t) * CHAR_BIT` buckets meaning that for all common implementations, there's only 4 bits of space overhead per bucket introduced by the bucket groups.
For more information on implementation rationale, read the <<Implementation Rationale, corresponding section>>.
+7
View File
@@ -6,6 +6,13 @@
:github-pr-url: https://github.com/boostorg/unordered/pull
:cpp: C++
== Release 1.80.0 - Major update
* Refactor internal implementation to be dramatically faster
* Allow `final` Hasher and KeyEqual objects
* Update documentation, adding benchmark graphs and notes on the new internal
data structures
== Release 1.79.0
* Improved {cpp}20 support:
+2
View File
@@ -9,4 +9,6 @@ Copyright (C) 2003, 2004 Jeremy B. Maitin-Shepard
Copyright (C) 2005-2008 Daniel James
Copyright (C) 2022 Christian Mazakas
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)
+4
View File
@@ -66,3 +66,7 @@ by using `(h * m) >> (w - k)`, where `h` is the hash value, `m` is the golden
ratio multiplied by `2^w`, `w` is the word size (32 or 64), and `2^k` is the
number of buckets. This provides a good compromise between speed and
distribution.
Since release 1.80.0, prime numbers are chosen for the number of buckets in
tandem with sophisticated modulo arithmetic. This removes the need for "mixing"
the result of the user's hash function as was used for release 1.79.0.
+7 -1
View File
@@ -1566,7 +1566,9 @@ Effects:;; Changes the container's maximum load factor, using `z` as a hint.
void rehash(size_type n);
```
Changes the number of buckets so that there at least `n` buckets, and so that the load factor is less than the maximum load factor.
Changes the number of buckets so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container.
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array.
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
@@ -1580,6 +1582,10 @@ Throws:;; The function has no effect if an exception is thrown, unless it is thr
void reserve(size_type n);
```
Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`, or `a.rehash(1)` if `n > 0` and `a.max_load_factor() == std::numeric_limits<float>::infinity()`.
Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container.
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
[horizontal]
+7 -1
View File
@@ -1345,7 +1345,9 @@ Effects:;; Changes the container's maximum load factor, using `z` as a hint.
void rehash(size_type n);
```
Changes the number of buckets so that there at least `n` buckets, and so that the load factor is less than the maximum load factor.
Changes the number of buckets so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container.
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array.
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
@@ -1359,6 +1361,10 @@ Throws:;; The function has no effect if an exception is thrown, unless it is thr
void reserve(size_type n);
```
Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`, or `a.rehash(1)` if `n > 0` and `a.max_load_factor() == std::numeric_limits<float>::infinity()`.
Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container.
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
[horizontal]
+8 -1
View File
@@ -1306,7 +1306,9 @@ Effects:;; Changes the container's maximum load factor, using `z` as a hint.
void rehash(size_type n);
```
Changes the number of buckets so that there at least `n` buckets, and so that the load factor is less than the maximum load factor.
Changes the number of buckets so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container.
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array.
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
@@ -1320,11 +1322,16 @@ Throws:;; The function has no effect if an exception is thrown, unless it is thr
void reserve(size_type n);
```
Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`, or `a.rehash(1)` if `n > 0` and `a.max_load_factor() == std::numeric_limits<float>::infinity()`.
Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container.
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
[horizontal]
Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.
---
=== Equality Comparisons
+8 -1
View File
@@ -1329,7 +1329,9 @@ Effects:;; Changes the container's maximum load factor, using `z` as a hint.
void rehash(size_type n);
```
Changes the number of buckets so that there at least `n` buckets, and so that the load factor is less than the maximum load factor.
Changes the number of buckets so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container.
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array.
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
@@ -1343,11 +1345,16 @@ Throws:;; The function has no effect if an exception is thrown, unless it is thr
void reserve(size_type n);
```
Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`, or `a.rehash(1)` if `n > 0` and `a.max_load_factor() == std::numeric_limits<float>::infinity()`.
Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container.
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
[horizontal]
Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.
=== Equality Comparisons
==== operator==
+849
View File
@@ -0,0 +1,849 @@
// Copyright (C) 2022 Joaquin M Lopez Munoz.
// Copyright (C) 2022 Christian Mazakas
//
// 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_UNORDERED_DETAIL_FCA_HPP
#define BOOST_UNORDERED_DETAIL_FCA_HPP
/*
The general structure of the fast closed addressing implementation is that we
use straight-forward separate chaining (i.e. each bucket contains its own linked
list) and then improve iteration time by adding an array of "bucket groups".
A bucket group is a constant-width view into a subsection of the buckets array,
containing a bitmask that indicates which one of the buckets in the subsection
contains a list of nodes. This allows the code to test N buckets for occupancy
in a single operation. Additional speed can be found by inter-linking occupied
bucket groups with one another in a doubly-linked list. To this end, large
swathes of the bucket groups array no longer need to be iterated and have their
bitmasks examined for occupancy.
A bucket group iterator contains a pointer to a bucket group along with a
pointer into the buckets array. The iterator's bucket pointer is guaranteed to
point to a bucket within the bucket group's view of the array. To advance the
iterator, we need to determine if we need to skip to the next bucket group or
simply move to the next occupied bucket as denoted by the bitmask.
To accomplish this, we perform something roughly equivalent to this:
```
bucket_iterator itb = ...
bucket_pointer p = itb.p
bucket_group_pointer pbg = itb.pbg
offset = p - pbg->buckets
// because we wish to see if the _next_ bit in the mask is occupied, we'll
// generate a testing mask from the current offset + 1
//
testing_mask = reset_first_bits(offset + 1)
n = ctz(pbg->bitmask & testing_mask)
if (n < N) {
p = pbg->buckets + n
} else {
pbg = pbg->next
p = pbg->buckets + ctz(pbg->bitmask)
}
```
`reset_first_bits` yields an unsigned integral with the first n bits set to 0
and then by counting the number of trailing zeroes when AND'd against the bucket
group's bitmask, we can derive the offset into the buckets array. When the
calculated offset is equal to N, we know we've reached the end of a bucket group
and we can advance to the next one.
This is a rough explanation for how iterator incrementation should work for a
fixed width size of N as 3 for the bucket groups
```
N = 3
p = buckets
pbg->bitmask = 0b101
pbg->buckets = buckets
offset = p - pbg->buckets // => 0
testing_mask = reset_first_bits(offset + 1) // reset_first_bits(1) => 0b110
x = bitmask & testing_mask // => 0b101 & 0b110 => 0b100
ctz(x) // ctz(0b100) => 2
// 2 < 3
=> p = pbg->buckets + 2
// increment again...
offset = p - pbg->buckets // => 2
testing_mask = reset_first_bits(offset + 1) // reset_first_bits(3) => 0b000
bitmask & testing_mask // 0b101 & 0b000 => 0b000
ctz(0b000) => 3
// 3 < 3 is false now
pbg = pbg->next
initial_offset = ctz(pbg->bitmask)
p = pbg->buckets + initial_offset
```
For `size_` number of buckets, there are `1 + (size_ / N)` bucket groups where
`N` is the width of a bucket group, determined at compile-time.
We allocate space for `size_ + 1` buckets, using the last one as a dummy bucket
which is kept permanently empty so it can act as a sentinel value in the
implementation of `iterator end();`. We set the last bucket group to act as a
sentinel.
```
num_groups = size_ / N + 1
groups = allocate(num_groups)
pbg = groups + (num_groups - 1)
// not guaranteed to point to exactly N buckets
pbg->buckets = buckets + N * (size_ / N)
// this marks the true end of the bucket array
buckets pbg->bitmask = set_bit(size_ % N)
// links in on itself
pbg->next = pbg->prev = pbg
```
To this end, we can devise a safe iteration scheme while also creating a useful
sentinel to use as the end iterator.
Otherwise, usage of the data structure is relatively straight-forward compared
to normal separate chaining implementations.
*/
#include <boost/unordered/detail/prime_fmod.hpp>
#include <boost/core/addressof.hpp>
#include <boost/core/allocator_access.hpp>
#include <boost/core/bit.hpp>
#include <boost/core/empty_value.hpp>
#include <boost/core/no_exceptions_support.hpp>
#include <boost/cstdint.hpp>
#include <boost/move/core.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/swap.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/config.hpp>
#include <iterator>
namespace boost {
namespace unordered {
namespace detail {
template <class ValueType, class VoidPtr> struct node
{
typedef ValueType value_type;
typedef typename boost::pointer_traits<VoidPtr>::template rebind_to<
node>::type node_pointer;
node_pointer next;
typename boost::aligned_storage<sizeof(value_type),
boost::alignment_of<value_type>::value>::type buf;
node() BOOST_NOEXCEPT : next(), buf() {}
value_type* value_ptr() BOOST_NOEXCEPT
{
return reinterpret_cast<value_type*>(buf.address());
}
value_type& value() BOOST_NOEXCEPT
{
return *reinterpret_cast<value_type*>(buf.address());
}
};
template <class Node, class VoidPtr> struct bucket
{
typedef typename boost::pointer_traits<VoidPtr>::template rebind_to<
Node>::type node_pointer;
typedef typename boost::pointer_traits<VoidPtr>::template rebind_to<
bucket>::type bucket_pointer;
node_pointer next;
bucket() BOOST_NOEXCEPT : next() {}
};
template <class Bucket> struct bucket_group
{
typedef typename Bucket::bucket_pointer bucket_pointer;
typedef
typename boost::pointer_traits<bucket_pointer>::template rebind_to<
bucket_group>::type bucket_group_pointer;
BOOST_STATIC_CONSTANT(std::size_t, N = sizeof(std::size_t) * CHAR_BIT);
bucket_pointer buckets;
std::size_t bitmask;
bucket_group_pointer next, prev;
bucket_group() BOOST_NOEXCEPT : buckets(), bitmask(0), next(), prev() {}
~bucket_group() {}
};
inline std::size_t set_bit(std::size_t n) { return std::size_t(1) << n; }
inline std::size_t reset_bit(std::size_t n)
{
return ~(std::size_t(1) << n);
}
inline std::size_t reset_first_bits(std::size_t n) // n>0
{
return ~(~(std::size_t(0)) >> (sizeof(std::size_t) * 8 - n));
}
template <class Bucket> struct grouped_bucket_iterator
{
public:
typedef typename Bucket::bucket_pointer bucket_pointer;
typedef
typename boost::pointer_traits<bucket_pointer>::template rebind_to<
bucket_group<Bucket> >::type bucket_group_pointer;
typedef Bucket value_type;
typedef typename boost::pointer_traits<bucket_pointer>::difference_type
difference_type;
typedef Bucket& reference;
typedef Bucket* pointer;
typedef std::forward_iterator_tag iterator_category;
private:
bucket_pointer p;
bucket_group_pointer pbg;
public:
grouped_bucket_iterator() : p(), pbg() {}
reference operator*() const BOOST_NOEXCEPT { return dereference(); }
pointer operator->() const BOOST_NOEXCEPT
{
return boost::to_address(p);
}
grouped_bucket_iterator& operator++() BOOST_NOEXCEPT
{
increment();
return *this;
}
grouped_bucket_iterator operator++(int) BOOST_NOEXCEPT
{
grouped_bucket_iterator old = *this;
increment();
return old;
}
bool operator==(
grouped_bucket_iterator const& other) const BOOST_NOEXCEPT
{
return equal(other);
}
bool operator!=(
grouped_bucket_iterator const& other) const BOOST_NOEXCEPT
{
return !equal(other);
}
private:
template <typename, typename, typename>
friend class grouped_bucket_array;
BOOST_STATIC_CONSTANT(std::size_t, N = bucket_group<Bucket>::N);
grouped_bucket_iterator(bucket_pointer p_, bucket_group_pointer pbg_)
: p(p_), pbg(pbg_)
{
}
Bucket& dereference() const BOOST_NOEXCEPT { return *p; }
bool equal(const grouped_bucket_iterator& x) const BOOST_NOEXCEPT
{
return p == x.p;
}
void increment() BOOST_NOEXCEPT
{
std::size_t const offset = static_cast<std::size_t>(p - pbg->buckets);
std::size_t n = std::size_t(boost::core::countr_zero(
pbg->bitmask & reset_first_bits(offset + 1)));
if (n < N) {
p = pbg->buckets + static_cast<difference_type>(n);
} else {
pbg = pbg->next;
std::ptrdiff_t x = boost::core::countr_zero(pbg->bitmask);
p = pbg->buckets + x;
}
}
};
template <class Node> struct const_grouped_local_bucket_iterator;
template <class Node> struct grouped_local_bucket_iterator
{
typedef typename Node::node_pointer node_pointer;
public:
typedef typename Node::value_type value_type;
typedef value_type element_type;
typedef value_type* pointer;
typedef value_type& reference;
typedef std::ptrdiff_t difference_type;
typedef std::forward_iterator_tag iterator_category;
grouped_local_bucket_iterator() : p() {}
reference operator*() const BOOST_NOEXCEPT { return dereference(); }
pointer operator->() const BOOST_NOEXCEPT
{
return boost::to_address(p);
}
grouped_local_bucket_iterator& operator++() BOOST_NOEXCEPT
{
increment();
return *this;
}
grouped_local_bucket_iterator operator++(int) BOOST_NOEXCEPT
{
grouped_local_bucket_iterator old = *this;
increment();
return old;
}
bool operator==(
grouped_local_bucket_iterator const& other) const BOOST_NOEXCEPT
{
return equal(other);
}
bool operator!=(
grouped_local_bucket_iterator const& other) const BOOST_NOEXCEPT
{
return !equal(other);
}
private:
template <typename, typename, typename>
friend class grouped_bucket_array;
template <class> friend struct const_grouped_local_bucket_iterator;
grouped_local_bucket_iterator(node_pointer p_) : p(p_) {}
value_type& dereference() const BOOST_NOEXCEPT { return p->value(); }
bool equal(const grouped_local_bucket_iterator& x) const BOOST_NOEXCEPT
{
return p == x.p;
}
void increment() BOOST_NOEXCEPT { p = p->next; }
node_pointer p;
};
template <class Node> struct const_grouped_local_bucket_iterator
{
typedef typename Node::node_pointer node_pointer;
public:
typedef typename Node::value_type const value_type;
typedef value_type const element_type;
typedef value_type const* pointer;
typedef value_type const& reference;
typedef std::ptrdiff_t difference_type;
typedef std::forward_iterator_tag iterator_category;
const_grouped_local_bucket_iterator() : p() {}
const_grouped_local_bucket_iterator(
grouped_local_bucket_iterator<Node> it)
: p(it.p)
{
}
reference operator*() const BOOST_NOEXCEPT { return dereference(); }
pointer operator->() const BOOST_NOEXCEPT
{
return boost::to_address(p);
}
const_grouped_local_bucket_iterator& operator++() BOOST_NOEXCEPT
{
increment();
return *this;
}
const_grouped_local_bucket_iterator operator++(int) BOOST_NOEXCEPT
{
const_grouped_local_bucket_iterator old = *this;
increment();
return old;
}
bool operator==(
const_grouped_local_bucket_iterator const& other) const BOOST_NOEXCEPT
{
return equal(other);
}
bool operator!=(
const_grouped_local_bucket_iterator const& other) const BOOST_NOEXCEPT
{
return !equal(other);
}
private:
template <typename, typename, typename>
friend class grouped_bucket_array;
const_grouped_local_bucket_iterator(node_pointer p_) : p(p_) {}
value_type& dereference() const BOOST_NOEXCEPT { return p->value(); }
bool equal(
const const_grouped_local_bucket_iterator& x) const BOOST_NOEXCEPT
{
return p == x.p;
}
void increment() BOOST_NOEXCEPT { p = p->next; }
node_pointer p;
};
template <class T> struct span
{
T* begin() const BOOST_NOEXCEPT { return data; }
T* end() const BOOST_NOEXCEPT { return data + size; }
T* data;
std::size_t size;
span(T* data_, std::size_t size_) : data(data_), size(size_) {}
};
template <class Bucket, class Allocator, class SizePolicy>
class grouped_bucket_array
: boost::empty_value<typename boost::allocator_rebind<Allocator,
node<typename boost::allocator_value_type<Allocator>::type,
typename boost::allocator_void_pointer<Allocator>::type> >::
type>
{
BOOST_MOVABLE_BUT_NOT_COPYABLE(grouped_bucket_array)
typedef typename boost::allocator_value_type<Allocator>::type
allocator_value_type;
typedef
typename boost::allocator_void_pointer<Allocator>::type void_pointer;
typedef typename boost::allocator_difference_type<Allocator>::type
difference_type;
public:
typedef typename boost::allocator_rebind<Allocator,
node<allocator_value_type, void_pointer> >::type node_allocator_type;
typedef node<allocator_value_type, void_pointer> node_type;
typedef typename boost::allocator_pointer<node_allocator_type>::type
node_pointer;
typedef SizePolicy size_policy;
private:
typedef typename boost::allocator_rebind<Allocator, Bucket>::type
bucket_allocator_type;
typedef typename boost::allocator_pointer<bucket_allocator_type>::type
bucket_pointer;
typedef boost::pointer_traits<bucket_pointer> bucket_pointer_traits;
typedef bucket_group<Bucket> group;
typedef typename boost::allocator_rebind<Allocator, group>::type
group_allocator_type;
typedef typename boost::allocator_pointer<group_allocator_type>::type
group_pointer;
typedef typename boost::pointer_traits<group_pointer>
group_pointer_traits;
public:
typedef Bucket value_type;
typedef Bucket bucket_type;
typedef std::size_t size_type;
typedef Allocator allocator_type;
typedef grouped_bucket_iterator<Bucket> iterator;
typedef grouped_local_bucket_iterator<node_type> local_iterator;
typedef const_grouped_local_bucket_iterator<node_type>
const_local_iterator;
private:
std::size_t size_index_, size_;
bucket_pointer buckets;
group_pointer groups;
public:
static std::size_t bucket_count_for(std::size_t num_buckets)
{
if (num_buckets == 0) {
return 0;
}
return size_policy::size(size_policy::size_index(num_buckets));
}
grouped_bucket_array()
: empty_value<node_allocator_type>(
empty_init_t(), node_allocator_type()),
size_index_(0), size_(0), buckets(), groups()
{
}
grouped_bucket_array(size_type n, const Allocator& al)
: empty_value<node_allocator_type>(empty_init_t(), al),
size_index_(0),
size_(0), buckets(), groups()
{
if (n == 0) {
return;
}
size_index_ = size_policy::size_index(n);
size_ = size_policy::size(size_index_);
bucket_allocator_type bucket_alloc = this->get_bucket_allocator();
group_allocator_type group_alloc = this->get_group_allocator();
size_type const num_buckets = buckets_len();
size_type const num_groups = groups_len();
buckets = boost::allocator_allocate(bucket_alloc, num_buckets);
BOOST_TRY
{
groups = boost::allocator_allocate(group_alloc, num_groups);
bucket_type* pb = boost::to_address(buckets);
for (size_type i = 0; i < num_buckets; ++i) {
new (pb + i) bucket_type();
}
group* pg = boost::to_address(groups);
for (size_type i = 0; i < num_groups; ++i) {
new (pg + i) group();
}
}
BOOST_CATCH(...)
{
boost::allocator_deallocate(bucket_alloc, buckets, num_buckets);
BOOST_RETHROW
}
BOOST_CATCH_END
size_type const N = group::N;
group_pointer pbg =
groups + static_cast<difference_type>(num_groups - 1);
pbg->buckets =
buckets + static_cast<difference_type>(N * (size_ / N));
pbg->bitmask = set_bit(size_ % N);
pbg->next = pbg->prev = pbg;
}
~grouped_bucket_array() { this->deallocate(); }
grouped_bucket_array(
BOOST_RV_REF(grouped_bucket_array) other) BOOST_NOEXCEPT
: empty_value<node_allocator_type>(
empty_init_t(), other.get_node_allocator()),
size_index_(other.size_index_),
size_(other.size_),
buckets(other.buckets),
groups(other.groups)
{
other.size_ = 0;
other.size_index_ = 0;
other.buckets = bucket_pointer();
other.groups = group_pointer();
}
grouped_bucket_array& operator=(
BOOST_RV_REF(grouped_bucket_array) other) BOOST_NOEXCEPT
{
BOOST_ASSERT(
this->get_node_allocator() == other.get_node_allocator());
if (this == boost::addressof(other)) {
return *this;
}
this->deallocate();
size_index_ = other.size_index_;
size_ = other.size_;
buckets = other.buckets;
groups = other.groups;
other.size_index_ = 0;
other.size_ = 0;
other.buckets = bucket_pointer();
other.groups = group_pointer();
return *this;
}
void deallocate() BOOST_NOEXCEPT
{
if (buckets) {
bucket_allocator_type bucket_alloc = this->get_bucket_allocator();
boost::allocator_deallocate(
bucket_alloc, buckets, this->buckets_len());
buckets = bucket_pointer();
}
if (groups) {
group_allocator_type group_alloc = this->get_group_allocator();
boost::allocator_deallocate(
group_alloc, groups, this->groups_len());
groups = group_pointer();
}
}
void swap(grouped_bucket_array& other)
{
std::swap(size_index_, other.size_index_);
std::swap(size_, other.size_);
std::swap(buckets, other.buckets);
std::swap(groups, other.groups);
bool b = boost::allocator_propagate_on_container_swap<
allocator_type>::type::value;
if (b) {
boost::swap(get_node_allocator(), other.get_node_allocator());
}
}
node_allocator_type const& get_node_allocator() const
{
return empty_value<node_allocator_type>::get();
}
node_allocator_type& get_node_allocator()
{
return empty_value<node_allocator_type>::get();
}
bucket_allocator_type get_bucket_allocator() const
{
return this->get_node_allocator();
}
group_allocator_type get_group_allocator() const
{
return this->get_node_allocator();
}
size_type buckets_len() const BOOST_NOEXCEPT { return size_ + 1; }
size_type groups_len() const BOOST_NOEXCEPT
{
return size_ / group::N + 1;
}
void reset_allocator(Allocator const& allocator_)
{
this->get_node_allocator() = node_allocator_type(allocator_);
}
size_type bucket_count() const { return size_; }
iterator begin() const { return size_ == 0 ? end() : ++at(size_); }
iterator end() const
{
// micro optimization: no need to return the bucket group
// as end() is not incrementable
iterator pbg;
pbg.p =
buckets + static_cast<difference_type>(this->buckets_len() - 1);
return pbg;
}
local_iterator begin(size_type n) const
{
if (size_ == 0) {
return this->end(n);
}
return local_iterator(
(buckets + static_cast<difference_type>(n))->next);
}
local_iterator end(size_type) const { return local_iterator(); }
size_type capacity() const BOOST_NOEXCEPT { return size_; }
iterator at(size_type n) const
{
if (size_ > 0) {
std::size_t const N = group::N;
iterator pbg(buckets + static_cast<difference_type>(n),
groups + static_cast<difference_type>(n / N));
return pbg;
} else {
return this->end();
}
}
span<Bucket> raw()
{
BOOST_ASSERT(size_ == 0 || size_ < this->buckets_len());
return span<Bucket>(boost::to_address(buckets), size_);
}
size_type position(std::size_t hash) const
{
return size_policy::position(hash, size_index_);
}
void clear()
{
this->deallocate();
size_index_ = 0;
size_ = 0;
}
void append_bucket_group(iterator itb) BOOST_NOEXCEPT
{
std::size_t const N = group::N;
bool const is_empty_bucket = (!itb->next);
if (is_empty_bucket) {
bucket_pointer pb = itb.p;
group_pointer pbg = itb.pbg;
std::size_t n =
static_cast<std::size_t>(boost::to_address(pb) - &buckets[0]);
bool const is_empty_group = (!pbg->bitmask);
if (is_empty_group) {
size_type const num_groups = this->groups_len();
group_pointer last_group =
groups + static_cast<difference_type>(num_groups - 1);
pbg->buckets =
buckets + static_cast<difference_type>(N * (n / N));
pbg->next = last_group->next;
pbg->next->prev = pbg;
pbg->prev = last_group;
pbg->prev->next = pbg;
}
pbg->bitmask |= set_bit(n % N);
}
}
void insert_node(iterator itb, node_pointer p) BOOST_NOEXCEPT
{
this->append_bucket_group(itb);
p->next = itb->next;
itb->next = p;
}
void insert_node_hint(
iterator itb, node_pointer p, node_pointer hint) BOOST_NOEXCEPT
{
this->append_bucket_group(itb);
if (hint) {
p->next = hint->next;
hint->next = p;
} else {
p->next = itb->next;
itb->next = p;
}
}
void extract_node(iterator itb, node_pointer p) BOOST_NOEXCEPT
{
node_pointer* pp = boost::addressof(itb->next);
while ((*pp) != p)
pp = boost::addressof((*pp)->next);
*pp = p->next;
if (!itb->next)
unlink_bucket(itb);
}
void extract_node_after(iterator itb, node_pointer* pp) BOOST_NOEXCEPT
{
*pp = (*pp)->next;
if (!itb->next)
unlink_bucket(itb);
}
void unlink_empty_buckets() BOOST_NOEXCEPT
{
std::size_t const N = group::N;
group_pointer pbg = groups,
last = groups + static_cast<difference_type>(
this->groups_len() - 1);
for (; pbg != last; ++pbg) {
if (!pbg->buckets) {
continue;
}
for (std::size_t n = 0; n < N; ++n) {
bucket_pointer bs = pbg->buckets;
bucket_type& b = bs[static_cast<std::ptrdiff_t>(n)];
if (!b.next)
pbg->bitmask &= reset_bit(n);
}
if (!pbg->bitmask && pbg->next)
unlink_group(pbg);
}
// do not check end bucket
for (std::size_t n = 0; n < size_ % N; ++n) {
if (!pbg->buckets[static_cast<std::ptrdiff_t>(n)].next)
pbg->bitmask &= reset_bit(n);
}
}
void unlink_bucket(iterator itb)
{
typename iterator::bucket_pointer p = itb.p;
typename iterator::bucket_group_pointer pbg = itb.pbg;
if (!(pbg->bitmask &=
reset_bit(static_cast<std::size_t>(p - pbg->buckets))))
unlink_group(pbg);
}
private:
void unlink_group(group_pointer pbg)
{
pbg->next->prev = pbg->prev;
pbg->prev->next = pbg->next;
pbg->prev = pbg->next = group_pointer();
}
};
} // namespace detail
} // namespace unordered
} // namespace boost
#endif // BOOST_UNORDERED_DETAIL_FCA_HPP
+2 -1
View File
@@ -1,5 +1,6 @@
// Copyright (C) 2008-2016 Daniel James.
// Copyright (C) 2022 Christian Mazakas
// 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)
@@ -31,7 +32,7 @@
// 2012 = VC+11 = BOOST_MSVC 1700 Hopefully!
// I have no idea when Dinkumware added it, probably a lot
// earlier than this check.
#if BOOST_LIB_STD_DINKUMWARE >= BOOST_VERSION_NUMBER(6, 50, 0) || \
#if BOOST_LIB_STD_DINKUMWARE >= BOOST_VERSION_NUMBER(6, 10, 0) || \
BOOST_COMP_MSVC >= BOOST_VERSION_NUMBER(17, 0, 0)
#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
#endif
File diff suppressed because it is too large Load Diff
+8 -14
View File
@@ -1,5 +1,6 @@
// Copyright (C) 2005-2016 Daniel James
// Copyright (C) 2022 Christian Mazakas
// 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)
@@ -25,25 +26,18 @@ namespace boost {
typedef boost::unordered::detail::allocator_traits<value_allocator>
value_allocator_traits;
typedef boost::unordered::detail::pick_node<A, value_type> pick;
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef boost::unordered::detail::table<types> table;
typedef boost::unordered::detail::map_extractor<value_type> extractor;
typedef typename boost::unordered::detail::pick_policy<K>::type policy;
typedef typename boost::allocator_void_pointer<value_allocator>::type
void_pointer;
typedef boost::unordered::iterator_detail::iterator<node> iterator;
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
typedef boost::unordered::iterator_detail::l_iterator<node> l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node>
cl_iterator;
typedef boost::unordered::node_handle_map<
node<value_type, void_pointer>, K, M, A>
node_type;
typedef boost::unordered::node_handle_map<node, K, M, A> node_type;
typedef boost::unordered::insert_return_type_map<node, K, M, A>
insert_return_type;
typedef typename table::iterator iterator;
typedef boost::unordered::insert_return_type_map<iterator, node_type> insert_return_type;
};
template <typename K, typename M, typename H, typename P, typename A>
@@ -0,0 +1,262 @@
// Copyright (C) 2022 Joaquin M Lopez Munoz.
// Copyright (C) 2022 Christian Mazakas
//
// 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_UNORDERED_DETAIL_PRIME_FMOD_HPP
#define BOOST_UNORDERED_DETAIL_PRIME_FMOD_HPP
#include <boost/cstdint.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/config.hpp>
#include <climits>
#include <cstddef>
#if defined(SIZE_MAX)
#if ((((SIZE_MAX >> 16) >> 16) >> 16) >> 15) != 0
#define BOOST_UNORDERED_FCA_HAS_64B_SIZE_T
#endif
#elif defined(UINTPTR_MAX) /* used as proxy for std::size_t */
#if ((((UINTPTR_MAX >> 16) >> 16) >> 16) >> 15) != 0
#define BOOST_UNORDERED_FCA_HAS_64B_SIZE_T
#endif
#endif
#if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) && defined(_MSC_VER)
#include <intrin.h>
#endif
namespace boost {
namespace unordered {
namespace detail {
template <class = void> struct prime_fmod_size
{
// Because we compile for C++03, we don't have access to any inline
// initialization for array data members so the definitions must exist
// out-of-line. To keep the library header-only, we introduce a dummy
// template parameter which permits the definition to be included in
// multiple TUs without conflict.
//
static std::size_t sizes[];
static std::size_t const sizes_len;
static std::size_t (*positions[])(std::size_t);
#if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
static boost::uint64_t inv_sizes32[];
static std::size_t const inv_sizes32_len;
#endif /* defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) */
static inline std::size_t size_index(std::size_t n)
{
std::size_t i = 0;
for (; i < (sizes_len - 1); ++i) {
if (sizes[i] >= n) {
break;
}
}
return i;
}
static inline std::size_t size(std::size_t size_index)
{
return sizes[size_index];
}
template <std::size_t Size> static std::size_t modulo(std::size_t hash)
{
return hash % Size;
}
#if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
// We emulate the techniques taken from:
// Faster Remainder by Direct Computation: Applications to Compilers and
// Software Libraries
// https://arxiv.org/abs/1902.01961
//
// In essence, use fancy math to directly calculate the remainder (aka
// modulo) exploiting how compilers transform division
//
static inline boost::uint64_t get_remainder(
boost::uint64_t fractional, boost::uint32_t d)
{
#if defined(_MSC_VER)
// use MSVC intrinsics when available to avoid promotion to 128 bits
return __umulh(fractional, d);
#elif defined(BOOST_HAS_INT128)
return static_cast<boost::uint64_t>(
((boost::uint128_type)fractional * d) >> 64);
#else
// portable implementation in the absence of boost::uint128_type on 64
// bits, which happens at least in GCC 4.5 and prior
boost::uint64_t r1 = (fractional & UINT32_MAX) * d;
boost::uint64_t r2 = (fractional >> 32) * d;
r2 += r1 >> 32;
return r2 >> 32;
#endif /* defined(_MSC_VER) */
}
static inline boost::uint32_t fast_modulo(
boost::uint32_t a, boost::uint64_t M, boost::uint32_t d)
{
boost::uint64_t fractional = M * a;
return (boost::uint32_t)(get_remainder(fractional, d));
}
#endif /* defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) */
static inline std::size_t position(
std::size_t hash, std::size_t size_index)
{
#if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
std::size_t sizes_under_32bit = inv_sizes32_len;
if (BOOST_LIKELY(size_index < sizes_under_32bit)) {
return fast_modulo(
boost::uint32_t(hash) + boost::uint32_t(hash >> 32),
inv_sizes32[size_index], boost::uint32_t(sizes[size_index]));
} else {
return positions[size_index - sizes_under_32bit](hash);
}
#else
return positions[size_index](hash);
#endif /* defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) */
}
}; // prime_fmod_size
#define BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT_INCOMPLETE \
(13ul)(29ul)(53ul)(97ul)(193ul)(389ul)(769ul)(1543ul)(3079ul)(6151ul)( \
12289ul)(24593ul)(49157ul)(98317ul)(196613ul)(393241ul)(786433ul)( \
1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul)(50331653ul)( \
100663319ul)(201326611ul)(402653189ul)(805306457ul)(1610612741ul)( \
3221225473ul)
#if !defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
#define BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT \
BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT_INCOMPLETE(4294967291ul)
#define BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT
#else
#define BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT \
BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT_INCOMPLETE
// The original sequence here is this:
// (6442450939ul)
// (12884901893ul)
// (25769803751ul)
// (51539607551ul)
// (103079215111ul)
// (206158430209ul)
// (412316860441ul)
// (824633720831ul)
// (1649267441651ul)
//
// but this causes problems on versions of mingw where the `long` type is 32
// bits, even for 64-bit targets. We work around this by replacing the literals
// with compile-time arithmetic, using bitshifts to reconstruct the number.
//
// clang-format off
#define BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT \
((boost::ulong_long_type(1ul) << 32) + boost::ulong_long_type(2147483643ul)) \
((boost::ulong_long_type(3ul) << 32) + boost::ulong_long_type(5ul)) \
((boost::ulong_long_type(5ul) << 32) + boost::ulong_long_type(4294967271ul)) \
((boost::ulong_long_type(11ul) << 32) + boost::ulong_long_type(4294967295ul)) \
((boost::ulong_long_type(24ul) << 32) + boost::ulong_long_type(7ul)) \
((boost::ulong_long_type(48ul) << 32) + boost::ulong_long_type(1ul)) \
((boost::ulong_long_type(96ul) << 32) + boost::ulong_long_type(25ul)) \
((boost::ulong_long_type(191ul) << 32) + boost::ulong_long_type(4294967295ul)) \
((boost::ulong_long_type(383ul) << 32) + boost::ulong_long_type(4294967283ul))
// clang-format on
#endif /* BOOST_UNORDERED_FCA_HAS_64B_SIZE_T */
#define BOOST_UNORDERED_PRIME_FMOD_SIZES \
BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT
template <class T>
std::size_t prime_fmod_size<T>::sizes[] = {
BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIME_FMOD_SIZES)};
template <class T>
std::size_t const prime_fmod_size<T>::sizes_len = BOOST_PP_SEQ_SIZE(
BOOST_UNORDERED_PRIME_FMOD_SIZES);
// Similarly here, we have to re-express the integer initialization using
// arithmetic such that each literal can fit in a 32-bit value.
//
#if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
// clang-format off
template <class T>
boost::uint64_t prime_fmod_size<T>::inv_sizes32[] = {
(boost::ulong_long_type(330382099ul) << 32) + boost::ulong_long_type(2973438898ul) /* = 1418980313362273202 */,
(boost::ulong_long_type(148102320ul) << 32) + boost::ulong_long_type(2369637129ul) /* = 636094623231363849 */,
(boost::ulong_long_type(81037118ul) << 32) + boost::ulong_long_type(3403558990ul) /* = 348051774975651918 */,
(boost::ulong_long_type(44278013ul) << 32) + boost::ulong_long_type(1549730468ul) /* = 190172619316593316 */,
(boost::ulong_long_type(22253716ul) << 32) + boost::ulong_long_type(2403401389ul) /* = 95578984837873325 */,
(boost::ulong_long_type(11041047ul) << 32) + boost::ulong_long_type(143533612ul) /* = 47420935922132524 */,
(boost::ulong_long_type(5585133ul) << 32) + boost::ulong_long_type(106117528ul) /* = 23987963684927896 */,
(boost::ulong_long_type(2783517ul) << 32) + boost::ulong_long_type(1572687312ul) /* = 11955116055547344 */,
(boost::ulong_long_type(1394922ul) << 32) + boost::ulong_long_type(3428720239ul) /* = 5991147799191151 */,
(boost::ulong_long_type(698255ul) << 32) + boost::ulong_long_type(552319807ul) /* = 2998982941588287 */,
(boost::ulong_long_type(349496ul) << 32) + boost::ulong_long_type(3827689953ul) /* = 1501077717772769 */,
(boost::ulong_long_type(174641ul) << 32) + boost::ulong_long_type(3699438549ul) /* = 750081082979285 */,
(boost::ulong_long_type(87372ul) << 32) + boost::ulong_long_type(1912757574ul) /* = 375261795343686 */,
(boost::ulong_long_type(43684ul) << 32) + boost::ulong_long_type(3821029929ul) /* = 187625172388393 */,
(boost::ulong_long_type(21844ul) << 32) + boost::ulong_long_type(3340590800ul) /* = 93822606204624 */,
(boost::ulong_long_type(10921ul) << 32) + boost::ulong_long_type(4175852267ul) /* = 46909513691883 */,
(boost::ulong_long_type(5461ul) << 32) + boost::ulong_long_type(1401829642ul) /* = 23456218233098 */,
(boost::ulong_long_type(2730ul) << 32) + boost::ulong_long_type(2826028947ul) /* = 11728086747027 */,
(boost::ulong_long_type(1365ul) << 32) + boost::ulong_long_type(1411150351ul) /* = 5864041509391 */,
(boost::ulong_long_type(682ul) << 32) + boost::ulong_long_type(2857253105ul) /* = 2932024948977 */,
(boost::ulong_long_type(341ul) << 32) + boost::ulong_long_type(1431073224ul) /* = 1466014921160 */,
(boost::ulong_long_type(170ul) << 32) + boost::ulong_long_type(2862758116ul) /* = 733007198436 */,
(boost::ulong_long_type(85ul) << 32) + boost::ulong_long_type(1431619357ul) /* = 366503839517 */,
(boost::ulong_long_type(42ul) << 32) + boost::ulong_long_type(2863269661ul) /* = 183251896093 */,
(boost::ulong_long_type(21ul) << 32) + boost::ulong_long_type(1431647119ul) /* = 91625960335 */,
(boost::ulong_long_type(10ul) << 32) + boost::ulong_long_type(2863310962ul) /* = 45812983922 */,
(boost::ulong_long_type(5ul) << 32) + boost::ulong_long_type(1431653234ul) /* = 22906489714 */,
(boost::ulong_long_type(2ul) << 32) + boost::ulong_long_type(2863311496ul) /* = 11453246088 */,
(boost::ulong_long_type(1ul) << 32) + boost::ulong_long_type(1431655764ul) /* = 5726623060 */,
};
// clang-format on
template <class T>
std::size_t const
prime_fmod_size<T>::inv_sizes32_len = sizeof(inv_sizes32) /
sizeof(inv_sizes32[0]);
#endif /* defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) */
#define BOOST_UNORDERED_PRIME_FMOD_POSITIONS_ELEMENT(z, _, n) \
prime_fmod_size<T>::template modulo<n>,
template <class T>
std::size_t (*prime_fmod_size<T>::positions[])(std::size_t) = {
#if !defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
BOOST_PP_SEQ_FOR_EACH(BOOST_UNORDERED_PRIME_FMOD_POSITIONS_ELEMENT, ~,
BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT)
#else
BOOST_PP_SEQ_FOR_EACH(BOOST_UNORDERED_PRIME_FMOD_POSITIONS_ELEMENT, ~,
BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT)
#endif
};
#undef BOOST_UNORDERED_PRIME_FMOD_POSITIONS_ELEMENT
#undef BOOST_UNORDERED_PRIME_FMOD_SIZES
#undef BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT
#undef BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT
#undef BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT_INCOMPLETE
} // namespace detail
} // namespace unordered
} // namespace boost
#endif // BOOST_UNORDERED_DETAIL_PRIME_FMOD_HPP
+8 -13
View File
@@ -1,5 +1,6 @@
// Copyright (C) 2005-2016 Daniel James
// Copyright (C) 2022 Christian Mazakas
// 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)
@@ -24,24 +25,18 @@ namespace boost {
typedef boost::unordered::detail::allocator_traits<value_allocator>
value_allocator_traits;
typedef boost::unordered::detail::pick_node<A, value_type> pick;
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef boost::unordered::detail::table<types> table;
typedef boost::unordered::detail::set_extractor<value_type> extractor;
typedef typename boost::unordered::detail::pick_policy<T>::type policy;
typedef typename boost::allocator_void_pointer<value_allocator>::type
void_pointer;
typedef boost::unordered::iterator_detail::c_iterator<node> iterator;
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node> l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node>
cl_iterator;
typedef boost::unordered::node_handle_set<
node<value_type, void_pointer>, T, A>
node_type;
typedef boost::unordered::node_handle_set<node, T, A> node_type;
typedef boost::unordered::insert_return_type_set<node, T, A>
typedef typename table::c_iterator iterator;
typedef boost::unordered::insert_return_type_set<iterator, node_type>
insert_return_type;
};
+136 -187
View File
@@ -1,6 +1,7 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2011 Daniel James.
// Copyright (C) 2022 Christian Mazakas
// 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)
@@ -57,8 +58,6 @@ namespace boost {
typedef boost::unordered::detail::map<A, K, T, H, P> types;
typedef typename types::value_allocator_traits value_allocator_traits;
typedef typename types::table table;
typedef typename table::node_pointer node_pointer;
typedef typename table::link_pointer link_pointer;
public:
typedef typename value_allocator_traits::pointer pointer;
@@ -97,7 +96,7 @@ namespace boost {
unordered_map(unordered_map const&);
#if defined(BOOST_UNORDERED_USE_MOVE) || \
#if defined(BOOST_UNORDERED_USE_MOVE) || \
!defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_map(BOOST_RV_REF(unordered_map) other)
BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
@@ -188,9 +187,9 @@ namespace boost {
return table_.node_alloc();
}
// iterators
// // iterators
iterator begin() BOOST_NOEXCEPT { return iterator(table_.begin()); }
iterator begin() BOOST_NOEXCEPT { return table_.begin(); }
const_iterator begin() const BOOST_NOEXCEPT
{
@@ -445,7 +444,7 @@ namespace boost {
insert_return_type insert(BOOST_RV_REF(node_type) np)
{
insert_return_type result;
table_.move_insert_node_type_unique(np, result);
table_.move_insert_node_type_unique((node_type&)np, result);
return boost::move(result);
}
@@ -728,8 +727,7 @@ namespace boost {
size_type>::type
erase(BOOST_FWD_REF(Key) k)
{
return table_.erase_key_unique_impl(
this->key_eq(), boost::forward<Key>(k));
return table_.erase_key_unique_impl(boost::forward<Key>(k));
}
BOOST_UNORDERED_DEPRECATED("Use erase instead")
@@ -774,9 +772,7 @@ namespace boost {
iterator>::type
find(const Key& key)
{
return iterator(table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), key), key,
this->key_eq()));
return table_.find(key);
}
template <class Key>
@@ -784,9 +780,7 @@ namespace boost {
const_iterator>::type
find(const Key& key) const
{
return const_iterator(table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), key), key,
this->key_eq()));
return const_iterator(table_.find(key));
}
template <class CompatibleKey, class CompatibleHash,
@@ -801,9 +795,7 @@ namespace boost {
bool contains(const key_type& k) const
{
return 0 != table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq());
return table_.find(k) != this->end();
}
template <class Key>
@@ -811,9 +803,7 @@ namespace boost {
bool>::type
contains(const Key& k) const
{
return 0 != table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq());
return table_.find(k) != this->end();
}
size_type count(const key_type&) const;
@@ -823,14 +813,7 @@ namespace boost {
size_type>::type
count(const Key& k) const
{
std::size_t const key_hash =
table::policy::apply_hash(this->hash_function(), k);
P const& eq = this->key_eq();
node_pointer p = table_.find_node_impl(key_hash, k, eq);
return (p ? 1 : 0);
return (table_.find(k) != this->end() ? 1 : 0);
}
std::pair<iterator, iterator> equal_range(const key_type&);
@@ -842,12 +825,13 @@ namespace boost {
std::pair<iterator, iterator> >::type
equal_range(const Key& key)
{
node_pointer p = table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), key), key,
this->key_eq());
iterator first = table_.find(key);
iterator last = first;
if (last != this->end()) {
++last;
}
return std::make_pair(
iterator(p), iterator(p ? table::next_node(p) : p));
return std::make_pair(first, last);
}
template <class Key>
@@ -855,12 +839,13 @@ namespace boost {
std::pair<const_iterator, const_iterator> >::type
equal_range(const Key& key) const
{
node_pointer p = table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), key), key,
this->key_eq());
iterator first = table_.find(key);
iterator last = first;
if (last != this->end()) {
++last;
}
return std::make_pair(
const_iterator(p), const_iterator(p ? table::next_node(p) : p));
return std::make_pair(first, last);
}
mapped_type& operator[](const key_type&);
@@ -872,7 +857,7 @@ namespace boost {
size_type bucket_count() const BOOST_NOEXCEPT
{
return table_.bucket_count_;
return table_.bucket_count();
}
size_type max_bucket_count() const BOOST_NOEXCEPT
@@ -889,16 +874,15 @@ namespace boost {
local_iterator begin(size_type n)
{
return local_iterator(table_.begin(n), n, table_.bucket_count_);
return table_.begin(n);
}
const_local_iterator begin(size_type n) const
{
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
return const_local_iterator(table_.begin(n));
}
local_iterator end(size_type) { return local_iterator(); }
const_local_iterator end(size_type) const
{
return const_local_iterator();
@@ -906,7 +890,7 @@ namespace boost {
const_local_iterator cbegin(size_type n) const
{
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
return const_local_iterator(table_.begin(n));
}
const_local_iterator cend(size_type) const
@@ -1026,8 +1010,6 @@ namespace boost {
typedef boost::unordered::detail::map<A, K, T, H, P> types;
typedef typename types::value_allocator_traits value_allocator_traits;
typedef typename types::table table;
typedef typename table::node_pointer node_pointer;
typedef typename table::link_pointer link_pointer;
public:
typedef typename value_allocator_traits::pointer pointer;
@@ -1394,7 +1376,7 @@ namespace boost {
node_type extract(const key_type& k)
{
return node_type(table_.extract_by_key(k), table_.node_alloc());
return node_type(table_.extract_by_key_impl(k), table_.node_alloc());
}
template <class Key>
@@ -1437,8 +1419,7 @@ namespace boost {
size_type>::type
erase(BOOST_FWD_REF(Key) k)
{
return table_.erase_key_equiv_impl(
this->key_eq(), boost::forward<Key>(k));
return table_.erase_key_equiv_impl(boost::forward<Key>(k));
}
BOOST_UNORDERED_DEPRECATED("Use erase instead")
@@ -1483,9 +1464,7 @@ namespace boost {
iterator>::type
find(const Key& key)
{
return iterator(table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), key), key,
this->key_eq()));
return table_.find(key);
}
template <class Key>
@@ -1493,9 +1472,7 @@ namespace boost {
const_iterator>::type
find(const Key& key) const
{
return const_iterator(table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), key), key,
this->key_eq()));
return const_iterator(table_.find(key));
}
template <class CompatibleKey, class CompatibleHash,
@@ -1510,9 +1487,7 @@ namespace boost {
bool contains(key_type const& k) const
{
return 0 != table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq());
return table_.find(k) != this->end();
}
template <class Key>
@@ -1520,9 +1495,7 @@ namespace boost {
bool>::type
contains(const Key& k) const
{
return 0 != table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq());
return table_.find(k) != this->end();
}
size_type count(const key_type&) const;
@@ -1532,11 +1505,7 @@ namespace boost {
size_type>::type
count(const Key& k) const
{
node_pointer n = table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq());
return n ? table_.group_count(n) : 0;
return table_.group_count(k);
}
std::pair<iterator, iterator> equal_range(const key_type&);
@@ -1548,12 +1517,8 @@ namespace boost {
std::pair<iterator, iterator> >::type
equal_range(const Key& key)
{
node_pointer p = table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), key), key,
this->key_eq());
return std::make_pair(
iterator(p), iterator(p ? table_.next_group(p) : p));
iterator p = table_.find(key);
return std::make_pair(p, table_.next_group(key, p));
}
template <class Key>
@@ -1561,19 +1526,16 @@ namespace boost {
std::pair<const_iterator, const_iterator> >::type
equal_range(const Key& key) const
{
node_pointer p = table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), key), key,
this->key_eq());
iterator p = table_.find(key);
return std::make_pair(
const_iterator(p), const_iterator(p ? table_.next_group(p) : p));
const_iterator(p), const_iterator(table_.next_group(key, p)));
}
// bucket interface
size_type bucket_count() const BOOST_NOEXCEPT
{
return table_.bucket_count_;
return table_.bucket_count();
}
size_type max_bucket_count() const BOOST_NOEXCEPT
@@ -1590,12 +1552,12 @@ namespace boost {
local_iterator begin(size_type n)
{
return local_iterator(table_.begin(n), n, table_.bucket_count_);
return local_iterator(table_.begin(n));
}
const_local_iterator begin(size_type n) const
{
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
return const_local_iterator(table_.begin(n));
}
local_iterator end(size_type) { return local_iterator(); }
@@ -1607,7 +1569,7 @@ namespace boost {
const_local_iterator cbegin(size_type n) const
{
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
return const_local_iterator(table_.begin(n));
}
const_local_iterator cend(size_type) const
@@ -1702,8 +1664,6 @@ namespace boost {
template <class K, class T, class H, class P, class A>
unordered_map<K, T, H, P, A>::unordered_map()
: table_(boost::unordered::detail::default_bucket_count, hasher(),
key_equal(), allocator_type())
{
}
@@ -1730,7 +1690,7 @@ namespace boost {
unordered_map::value_allocator_traits::
select_on_container_copy_construction(other.get_allocator()))
{
if (other.table_.size_) {
if (other.size()) {
table_.copy_buckets(
other.table_, boost::unordered::detail::true_type());
}
@@ -1894,29 +1854,21 @@ namespace boost {
typename unordered_map<K, T, H, P, A>::iterator
unordered_map<K, T, H, P, A>::erase(iterator position)
{
node_pointer node = table::get_node(position);
BOOST_ASSERT(node);
node_pointer next = table::next_node(node);
table_.erase_nodes_unique(node, next);
return iterator(next);
return table_.erase_node(position);
}
template <class K, class T, class H, class P, class A>
typename unordered_map<K, T, H, P, A>::iterator
unordered_map<K, T, H, P, A>::erase(const_iterator position)
{
node_pointer node = table::get_node(position);
BOOST_ASSERT(node);
node_pointer next = table::next_node(node);
table_.erase_nodes_unique(node, next);
return iterator(next);
return table_.erase_node(position);
}
template <class K, class T, class H, class P, class A>
typename unordered_map<K, T, H, P, A>::size_type
unordered_map<K, T, H, P, A>::erase(const key_type& k)
{
return table_.erase_key_unique_impl(this->key_eq(), k);
return table_.erase_key_unique_impl(k);
}
template <class K, class T, class H, class P, class A>
@@ -1924,11 +1876,7 @@ namespace boost {
unordered_map<K, T, H, P, A>::erase(
const_iterator first, const_iterator last)
{
node_pointer last_node = table::get_node(last);
if (first == last)
return iterator(last_node);
table_.erase_nodes_unique(table::get_node(first), last_node);
return iterator(last_node);
return table_.erase_nodes_range(first, last);
}
template <class K, class T, class H, class P, class A>
@@ -1998,14 +1946,14 @@ namespace boost {
typename unordered_map<K, T, H, P, A>::iterator
unordered_map<K, T, H, P, A>::find(const key_type& k)
{
return iterator(table_.find_node(k));
return iterator(table_.find(k));
}
template <class K, class T, class H, class P, class A>
typename unordered_map<K, T, H, P, A>::const_iterator
unordered_map<K, T, H, P, A>::find(const key_type& k) const
{
return const_iterator(table_.find_node(k));
return const_iterator(table_.find(k));
}
template <class K, class T, class H, class P, class A>
@@ -2015,8 +1963,7 @@ namespace boost {
unordered_map<K, T, H, P, A>::find(CompatibleKey const& k,
CompatibleHash const& hash, CompatiblePredicate const& eq)
{
return iterator(
table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq));
return table_.transparent_find(k, hash, eq);
}
template <class K, class T, class H, class P, class A>
@@ -2026,8 +1973,7 @@ namespace boost {
unordered_map<K, T, H, P, A>::find(CompatibleKey const& k,
CompatibleHash const& hash, CompatiblePredicate const& eq) const
{
return const_iterator(
table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq));
return table_.transparent_find(k, hash, eq);
}
template <class K, class T, class H, class P, class A>
@@ -2042,8 +1988,12 @@ namespace boost {
typename unordered_map<K, T, H, P, A>::iterator>
unordered_map<K, T, H, P, A>::equal_range(const key_type& k)
{
node_pointer n = table_.find_node(k);
return std::make_pair(iterator(n), iterator(n ? table::next_node(n) : n));
iterator first = table_.find(k);
iterator second = first;
if (second != this->end()) {
++second;
}
return std::make_pair(first, second);
}
template <class K, class T, class H, class P, class A>
@@ -2051,9 +2001,12 @@ namespace boost {
typename unordered_map<K, T, H, P, A>::const_iterator>
unordered_map<K, T, H, P, A>::equal_range(const key_type& k) const
{
node_pointer n = table_.find_node(k);
return std::make_pair(
const_iterator(n), const_iterator(n ? table::next_node(n) : n));
iterator first = table_.find(k);
iterator second = first;
if (second != this->end()) {
++second;
}
return std::make_pair(const_iterator(first), const_iterator(second));
}
template <class K, class T, class H, class P, class A>
@@ -2074,10 +2027,12 @@ namespace boost {
typename unordered_map<K, T, H, P, A>::mapped_type&
unordered_map<K, T, H, P, A>::at(const key_type& k)
{
typedef typename table::node_pointer node_pointer;
if (table_.size_) {
node_pointer n = table_.find_node(k);
if (n)
return n->value().second;
node_pointer p = table_.find_node(k);
if (p)
return p->value().second;
}
boost::throw_exception(
@@ -2088,10 +2043,12 @@ namespace boost {
typename unordered_map<K, T, H, P, A>::mapped_type const&
unordered_map<K, T, H, P, A>::at(const key_type& k) const
{
typedef typename table::node_pointer node_pointer;
if (table_.size_) {
node_pointer n = table_.find_node(k);
if (n)
return n->value().second;
node_pointer p = table_.find_node(k);
if (p)
return p->value().second;
}
boost::throw_exception(
@@ -2110,9 +2067,13 @@ namespace boost {
template <class K, class T, class H, class P, class A>
float unordered_map<K, T, H, P, A>::load_factor() const BOOST_NOEXCEPT
{
BOOST_ASSERT(table_.bucket_count_ != 0);
if (table_.size_ == 0) {
return 0.0f;
}
BOOST_ASSERT(table_.bucket_count() != 0);
return static_cast<float>(table_.size_) /
static_cast<float>(table_.bucket_count_);
static_cast<float>(table_.bucket_count());
}
template <class K, class T, class H, class P, class A>
@@ -2130,8 +2091,7 @@ namespace boost {
template <class K, class T, class H, class P, class A>
void unordered_map<K, T, H, P, A>::reserve(size_type n)
{
table_.rehash(static_cast<std::size_t>(
std::ceil(static_cast<double>(n) / table_.mlf_)));
table_.reserve(n);
}
template <class K, class T, class H, class P, class A>
@@ -2185,8 +2145,6 @@ namespace boost {
template <class K, class T, class H, class P, class A>
unordered_multimap<K, T, H, P, A>::unordered_multimap()
: table_(boost::unordered::detail::default_bucket_count, hasher(),
key_equal(), allocator_type())
{
}
@@ -2377,22 +2335,16 @@ namespace boost {
typename unordered_multimap<K, T, H, P, A>::iterator
unordered_multimap<K, T, H, P, A>::erase(iterator position)
{
node_pointer node = table::get_node(position);
BOOST_ASSERT(node);
node_pointer next = table::next_node(node);
table_.erase_nodes_equiv(node, next);
return iterator(next);
BOOST_ASSERT(position != this->end());
return table_.erase_node(position);
}
template <class K, class T, class H, class P, class A>
typename unordered_multimap<K, T, H, P, A>::iterator
unordered_multimap<K, T, H, P, A>::erase(const_iterator position)
{
node_pointer node = table::get_node(position);
BOOST_ASSERT(node);
node_pointer next = table::next_node(node);
table_.erase_nodes_equiv(node, next);
return iterator(next);
BOOST_ASSERT(position != this->end());
return table_.erase_node(position);
}
template <class K, class T, class H, class P, class A>
@@ -2407,11 +2359,7 @@ namespace boost {
unordered_multimap<K, T, H, P, A>::erase(
const_iterator first, const_iterator last)
{
node_pointer last_node = table::get_node(last);
if (first == last)
return iterator(last_node);
table_.erase_nodes_equiv(table::get_node(first), last_node);
return iterator(last_node);
return table_.erase_nodes_range(first, last);
}
template <class K, class T, class H, class P, class A>
@@ -2489,14 +2437,14 @@ namespace boost {
typename unordered_multimap<K, T, H, P, A>::iterator
unordered_multimap<K, T, H, P, A>::find(const key_type& k)
{
return iterator(table_.find_node(k));
return iterator(table_.find(k));
}
template <class K, class T, class H, class P, class A>
typename unordered_multimap<K, T, H, P, A>::const_iterator
unordered_multimap<K, T, H, P, A>::find(const key_type& k) const
{
return const_iterator(table_.find_node(k));
return const_iterator(table_.find(k));
}
template <class K, class T, class H, class P, class A>
@@ -2506,8 +2454,7 @@ namespace boost {
unordered_multimap<K, T, H, P, A>::find(CompatibleKey const& k,
CompatibleHash const& hash, CompatiblePredicate const& eq)
{
return iterator(
table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq));
return table_.transparent_find(k, hash, eq);
}
template <class K, class T, class H, class P, class A>
@@ -2525,8 +2472,7 @@ namespace boost {
typename unordered_multimap<K, T, H, P, A>::size_type
unordered_multimap<K, T, H, P, A>::count(const key_type& k) const
{
node_pointer n = table_.find_node(k);
return n ? table_.group_count(n) : 0;
return table_.group_count(k);
}
template <class K, class T, class H, class P, class A>
@@ -2534,9 +2480,8 @@ namespace boost {
typename unordered_multimap<K, T, H, P, A>::iterator>
unordered_multimap<K, T, H, P, A>::equal_range(const key_type& k)
{
node_pointer n = table_.find_node(k);
return std::make_pair(
iterator(n), iterator(n ? table_.next_group(n) : n));
iterator n = table_.find(k);
return std::make_pair(n, (n == end() ? n : table_.next_group(k, n)));
}
template <class K, class T, class H, class P, class A>
@@ -2544,9 +2489,9 @@ namespace boost {
typename unordered_multimap<K, T, H, P, A>::const_iterator>
unordered_multimap<K, T, H, P, A>::equal_range(const key_type& k) const
{
node_pointer n = table_.find_node(k);
return std::make_pair(
const_iterator(n), const_iterator(n ? table_.next_group(n) : n));
iterator n = table_.find(k);
return std::make_pair(const_iterator(n),
const_iterator(n == end() ? n : table_.next_group(k, n)));
}
template <class K, class T, class H, class P, class A>
@@ -2561,9 +2506,13 @@ namespace boost {
template <class K, class T, class H, class P, class A>
float unordered_multimap<K, T, H, P, A>::load_factor() const BOOST_NOEXCEPT
{
BOOST_ASSERT(table_.bucket_count_ != 0);
if (table_.size_ == 0) {
return 0.0f;
}
BOOST_ASSERT(table_.bucket_count() != 0);
return static_cast<float>(table_.size_) /
static_cast<float>(table_.bucket_count_);
static_cast<float>(table_.bucket_count());
}
template <class K, class T, class H, class P, class A>
@@ -2582,8 +2531,7 @@ namespace boost {
template <class K, class T, class H, class P, class A>
void unordered_multimap<K, T, H, P, A>::reserve(size_type n)
{
table_.rehash(static_cast<std::size_t>(
std::ceil(static_cast<double>(n) / table_.mlf_)));
table_.reserve(n);
}
template <class K, class T, class H, class P, class A>
@@ -2643,16 +2591,14 @@ namespace boost {
template <class K2, class T2, class H2, class P2, class A2>
friend class boost::unordered::unordered_multimap;
typedef typename boost::unordered::detail::rebind_wrap<A,
std::pair<K const, T> >::type value_allocator;
typedef boost::unordered::detail::allocator_traits<value_allocator>
value_allocator_traits;
typedef typename boost::allocator_rebind<A, std::pair<K const, T> >::type
value_allocator;
typedef N node;
typedef typename boost::unordered::detail::rebind_wrap<A, node>::type
node_allocator;
typedef boost::unordered::detail::allocator_traits<node_allocator>
node_allocator_traits;
typedef typename node_allocator_traits::pointer node_pointer;
typedef typename boost::allocator_rebind<A, node>::type node_allocator;
typedef
typename boost::allocator_pointer<node_allocator>::type node_pointer;
public:
typedef K key_type;
@@ -2681,8 +2627,8 @@ namespace boost {
}
node_handle_map(BOOST_RV_REF(node_handle_map) n) BOOST_NOEXCEPT
: ptr_(n.ptr_),
alloc_(boost::move(n.alloc_))
: ptr_(n.ptr_),
alloc_(boost::move(n.alloc_))
{
n.ptr_ = node_pointer();
}
@@ -2690,8 +2636,8 @@ namespace boost {
node_handle_map& operator=(BOOST_RV_REF(node_handle_map) n)
{
BOOST_ASSERT(!alloc_.has_value() ||
value_allocator_traits::
propagate_on_container_move_assignment::value ||
boost::allocator_propagate_on_container_move_assignment<
value_allocator>::type::value ||
(n.alloc_.has_value() && alloc_ == n.alloc_));
if (ptr_) {
@@ -2702,8 +2648,8 @@ namespace boost {
}
if (!alloc_.has_value() ||
value_allocator_traits::propagate_on_container_move_assignment::
value) {
boost::allocator_propagate_on_container_move_assignment<
value_allocator>::type::value) {
alloc_ = boost::move(n.alloc_);
}
ptr_ = n.ptr_;
@@ -2731,14 +2677,17 @@ namespace boost {
}
void swap(node_handle_map& n) BOOST_NOEXCEPT_IF(
value_allocator_traits::propagate_on_container_swap::value ||
value_allocator_traits::is_always_equal::value)
boost::allocator_propagate_on_container_swap<
value_allocator>::type::value ||
boost::allocator_is_always_equal<value_allocator>::type::value)
{
BOOST_ASSERT(
!alloc_.has_value() || !n.alloc_.has_value() ||
value_allocator_traits::propagate_on_container_swap::value ||
alloc_ == n.alloc_);
if (value_allocator_traits::propagate_on_container_swap::value ||
BOOST_ASSERT(!alloc_.has_value() || !n.alloc_.has_value() ||
boost::allocator_propagate_on_container_swap<
value_allocator>::type::value ||
alloc_ == n.alloc_);
if (boost::allocator_propagate_on_container_swap<
value_allocator>::type::value ||
!alloc_.has_value() || !n.alloc_.has_value()) {
boost::swap(alloc_, n.alloc_);
}
@@ -2753,25 +2702,25 @@ namespace boost {
x.swap(y);
}
template <class N, class K, class T, class A> struct insert_return_type_map
template <class Iter, class NodeType> struct insert_return_type_map
{
private:
BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type_map)
typedef typename boost::unordered::detail::rebind_wrap<A,
std::pair<K const, T> >::type value_allocator;
typedef N node_;
// typedef typename boost::allocator_rebind<A,
// std::pair<K const, T> >::type value_allocator;
// typedef N node_;
public:
Iter position;
bool inserted;
boost::unordered::iterator_detail::iterator<node_> position;
boost::unordered::node_handle_map<N, K, T, A> node;
NodeType node;
insert_return_type_map() : inserted(false), position(), node() {}
insert_return_type_map() : position(), inserted(false), node() {}
insert_return_type_map(BOOST_RV_REF(insert_return_type_map)
x) BOOST_NOEXCEPT : inserted(x.inserted),
position(x.position),
x) BOOST_NOEXCEPT : position(x.position),
inserted(x.inserted),
node(boost::move(x.node))
{
}
@@ -2785,9 +2734,9 @@ namespace boost {
}
};
template <class N, class K, class T, class A>
void swap(insert_return_type_map<N, K, T, A>& x,
insert_return_type_map<N, K, T, A>& y)
template <class Iter, class NodeType>
void swap(insert_return_type_map<Iter, NodeType>& x,
insert_return_type_map<Iter, NodeType>& y)
{
boost::swap(x.node, y.node);
boost::swap(x.inserted, y.inserted);
@@ -1,5 +1,6 @@
// Copyright (C) 2008-2011 Daniel James.
// Copyright (C) 2022 Christian Mazakas
// 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)
@@ -59,7 +60,7 @@ namespace boost {
unordered_multimap<K, T, H, P, A>& c, Predicate pred);
template <class N, class K, class T, class A> class node_handle_map;
template <class N, class K, class T, class A> struct insert_return_type_map;
template <class Iter, class NodeType> struct insert_return_type_map;
}
using boost::unordered::unordered_map;
+80 -119
View File
@@ -1,6 +1,7 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2011 Daniel James.
// Copyright (C) 2022 Christian Mazakas
// 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)
@@ -55,8 +56,6 @@ namespace boost {
typedef boost::unordered::detail::set<A, T, H, P> types;
typedef typename types::value_allocator_traits value_allocator_traits;
typedef typename types::table table;
typedef typename table::node_pointer node_pointer;
typedef typename table::link_pointer link_pointer;
public:
typedef typename value_allocator_traits::pointer pointer;
@@ -68,9 +67,9 @@ namespace boost {
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef typename table::iterator iterator;
typedef typename table::c_iterator iterator;
typedef typename table::c_iterator const_iterator;
typedef typename table::l_iterator local_iterator;
typedef typename table::cl_iterator local_iterator;
typedef typename table::cl_iterator const_local_iterator;
typedef typename types::node_type node_type;
typedef typename types::insert_return_type insert_return_type;
@@ -411,7 +410,7 @@ namespace boost {
node_type extract(const key_type& k)
{
return node_type(table_.extract_by_key(k), table_.node_alloc());
return node_type(table_.extract_by_key_impl(k), table_.node_alloc());
}
template <class Key>
@@ -455,8 +454,7 @@ namespace boost {
size_type>::type
erase(BOOST_FWD_REF(Key) k)
{
return table_.erase_key_unique_impl(
this->key_eq(), boost::forward<Key>(k));
return table_.erase_key_unique_impl(boost::forward<Key>(k));
}
BOOST_UNORDERED_DEPRECATED("Use erase instead")
@@ -500,9 +498,7 @@ namespace boost {
const_iterator>::type
find(const Key& k) const
{
return const_iterator(table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq()));
return const_iterator(table_.find(k));
}
template <class CompatibleKey, class CompatibleHash,
@@ -512,9 +508,7 @@ namespace boost {
bool contains(key_type const& k) const
{
return 0 != table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq());
return table_.find(k) != this->end();
}
template <class Key>
@@ -522,9 +516,7 @@ namespace boost {
bool>::type
contains(const Key& k) const
{
return 0 != table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq());
return table_.find(k) != this->end();
}
size_type count(const key_type&) const;
@@ -534,11 +526,7 @@ namespace boost {
size_type>::type
count(const Key& k) const
{
node_pointer n = table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq());
return n ? 1 : 0;
return table_.find(k) != this->end() ? 1 : 0;
}
std::pair<const_iterator, const_iterator> equal_range(
@@ -549,19 +537,20 @@ namespace boost {
std::pair<const_iterator, const_iterator> >::type
equal_range(Key const& k) const
{
node_pointer n = table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq());
iterator n = table_.find(k);
iterator m = n;
if (m != this->end()) {
++m;
}
return std::make_pair(
const_iterator(n), const_iterator(n ? table::next_node(n) : n));
return std::make_pair(const_iterator(n), const_iterator(m));
}
// bucket interface
size_type bucket_count() const BOOST_NOEXCEPT
{
return table_.bucket_count_;
return table_.bucket_count();
}
size_type max_bucket_count() const BOOST_NOEXCEPT
@@ -578,12 +567,12 @@ namespace boost {
local_iterator begin(size_type n)
{
return local_iterator(table_.begin(n), n, table_.bucket_count_);
return local_iterator(table_.begin(n));
}
const_local_iterator begin(size_type n) const
{
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
return const_local_iterator(table_.begin(n));
}
local_iterator end(size_type) { return local_iterator(); }
@@ -595,7 +584,7 @@ namespace boost {
const_local_iterator cbegin(size_type n) const
{
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
return const_local_iterator(table_.begin(n));
}
const_local_iterator cend(size_type) const
@@ -684,8 +673,6 @@ namespace boost {
typedef boost::unordered::detail::set<A, T, H, P> types;
typedef typename types::value_allocator_traits value_allocator_traits;
typedef typename types::table table;
typedef typename table::node_pointer node_pointer;
typedef typename table::link_pointer link_pointer;
public:
typedef typename value_allocator_traits::pointer pointer;
@@ -697,9 +684,9 @@ namespace boost {
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef typename table::iterator iterator;
typedef typename table::c_iterator iterator;
typedef typename table::c_iterator const_iterator;
typedef typename table::l_iterator local_iterator;
typedef typename table::cl_iterator local_iterator;
typedef typename table::cl_iterator const_local_iterator;
typedef typename types::node_type node_type;
@@ -1035,7 +1022,7 @@ namespace boost {
node_type extract(const key_type& k)
{
return node_type(table_.extract_by_key(k), table_.node_alloc());
return node_type(table_.extract_by_key_impl(k), table_.node_alloc());
}
template <class Key>
@@ -1076,7 +1063,7 @@ namespace boost {
size_type>::type
erase(const Key& k)
{
return table_.erase_key_equiv_impl(this->key_eq(), k);
return table_.erase_key_equiv_impl(k);
}
iterator erase(const_iterator, const_iterator);
@@ -1121,9 +1108,7 @@ namespace boost {
const_iterator>::type
find(const Key& k) const
{
return const_iterator(table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq()));
return table_.find(k);
}
template <class CompatibleKey, class CompatibleHash,
@@ -1133,9 +1118,7 @@ namespace boost {
bool contains(const key_type& k) const
{
return 0 != table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq());
return table_.find(k) != this->end();
}
template <class Key>
@@ -1143,9 +1126,7 @@ namespace boost {
bool>::type
contains(const Key& k) const
{
return 0 != table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq());
return table_.find(k) != this->end();
}
size_type count(const key_type&) const;
@@ -1155,11 +1136,7 @@ namespace boost {
size_type>::type
count(const Key& k) const
{
node_pointer n = table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq());
return n ? table_.group_count(n) : 0;
return table_.group_count(k);
}
std::pair<const_iterator, const_iterator> equal_range(
@@ -1170,19 +1147,16 @@ namespace boost {
std::pair<const_iterator, const_iterator> >::type
equal_range(const Key& k) const
{
node_pointer n = table_.find_node_impl(
table::policy::apply_hash(this->hash_function(), k), k,
this->key_eq());
return std::make_pair(
const_iterator(n), const_iterator(n ? table_.next_group(n) : n));
iterator first = table_.find(k);
iterator last = table_.next_group(k, first);
return std::make_pair(const_iterator(first), const_iterator(last));
}
// bucket interface
size_type bucket_count() const BOOST_NOEXCEPT
{
return table_.bucket_count_;
return table_.bucket_count();
}
size_type max_bucket_count() const BOOST_NOEXCEPT
@@ -1199,12 +1173,12 @@ namespace boost {
local_iterator begin(size_type n)
{
return local_iterator(table_.begin(n), n, table_.bucket_count_);
return local_iterator(table_.begin(n));
}
const_local_iterator begin(size_type n) const
{
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
return const_local_iterator(table_.begin(n));
}
local_iterator end(size_type) { return local_iterator(); }
@@ -1216,7 +1190,7 @@ namespace boost {
const_local_iterator cbegin(size_type n) const
{
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
return const_local_iterator(table_.begin(n));
}
const_local_iterator cend(size_type) const
@@ -1292,8 +1266,6 @@ namespace boost {
////////////////////////////////////////////////////////////////////////////
template <class T, class H, class P, class A>
unordered_set<T, H, P, A>::unordered_set()
: table_(boost::unordered::detail::default_bucket_count, hasher(),
key_equal(), allocator_type())
{
}
@@ -1319,7 +1291,7 @@ namespace boost {
unordered_set::value_allocator_traits::
select_on_container_copy_construction(other.get_allocator()))
{
if (other.table_.size_) {
if (other.size()) {
table_.copy_buckets(
other.table_, boost::unordered::detail::true_type());
}
@@ -1483,29 +1455,21 @@ namespace boost {
typename unordered_set<T, H, P, A>::iterator
unordered_set<T, H, P, A>::erase(const_iterator position)
{
node_pointer node = table::get_node(position);
BOOST_ASSERT(node);
node_pointer next = table::next_node(node);
table_.erase_nodes_unique(node, next);
return iterator(next);
return table_.erase_node(position);
}
template <class T, class H, class P, class A>
typename unordered_set<T, H, P, A>::size_type
unordered_set<T, H, P, A>::erase(const key_type& k)
{
return table_.erase_key_unique_impl(this->key_eq(), k);
return table_.erase_key_unique_impl(k);
}
template <class T, class H, class P, class A>
typename unordered_set<T, H, P, A>::iterator
unordered_set<T, H, P, A>::erase(const_iterator first, const_iterator last)
{
node_pointer last_node = table::get_node(last);
if (first == last)
return iterator(last_node);
table_.erase_nodes_unique(table::get_node(first), last_node);
return iterator(last_node);
return table_.erase_nodes_range(first, last);
}
template <class T, class H, class P, class A>
@@ -1575,7 +1539,7 @@ namespace boost {
typename unordered_set<T, H, P, A>::const_iterator
unordered_set<T, H, P, A>::find(const key_type& k) const
{
return const_iterator(table_.find_node(k));
return const_iterator(table_.find(k));
}
template <class T, class H, class P, class A>
@@ -1585,8 +1549,7 @@ namespace boost {
unordered_set<T, H, P, A>::find(CompatibleKey const& k,
CompatibleHash const& hash, CompatiblePredicate const& eq) const
{
return const_iterator(
table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq));
return table_.transparent_find(k, hash, eq);
}
template <class T, class H, class P, class A>
@@ -1601,9 +1564,12 @@ namespace boost {
typename unordered_set<T, H, P, A>::const_iterator>
unordered_set<T, H, P, A>::equal_range(const key_type& k) const
{
node_pointer n = table_.find_node(k);
return std::make_pair(
const_iterator(n), const_iterator(n ? table::next_node(n) : n));
iterator first = table_.find(k);
iterator second = first;
if (second != this->end()) {
++second;
}
return std::make_pair(first, second);
}
template <class T, class H, class P, class A>
@@ -1618,9 +1584,13 @@ namespace boost {
template <class T, class H, class P, class A>
float unordered_set<T, H, P, A>::load_factor() const BOOST_NOEXCEPT
{
BOOST_ASSERT(table_.bucket_count_ != 0);
if (table_.size_ == 0) {
return 0.0f;
}
BOOST_ASSERT(table_.bucket_count() != 0);
return static_cast<float>(table_.size_) /
static_cast<float>(table_.bucket_count_);
static_cast<float>(table_.bucket_count());
}
template <class T, class H, class P, class A>
@@ -1638,8 +1608,7 @@ namespace boost {
template <class T, class H, class P, class A>
void unordered_set<T, H, P, A>::reserve(size_type n)
{
table_.rehash(static_cast<std::size_t>(
std::ceil(static_cast<double>(n) / table_.mlf_)));
table_.reserve(n);
}
template <class T, class H, class P, class A>
@@ -1693,8 +1662,6 @@ namespace boost {
template <class T, class H, class P, class A>
unordered_multiset<T, H, P, A>::unordered_multiset()
: table_(boost::unordered::detail::default_bucket_count, hasher(),
key_equal(), allocator_type())
{
}
@@ -1883,11 +1850,8 @@ namespace boost {
typename unordered_multiset<T, H, P, A>::iterator
unordered_multiset<T, H, P, A>::erase(const_iterator position)
{
node_pointer node = table::get_node(position);
BOOST_ASSERT(node);
node_pointer next = table::next_node(node);
table_.erase_nodes_equiv(node, next);
return iterator(next);
BOOST_ASSERT(position != this->end());
return table_.erase_node(position);
}
template <class T, class H, class P, class A>
@@ -1902,11 +1866,7 @@ namespace boost {
unordered_multiset<T, H, P, A>::erase(
const_iterator first, const_iterator last)
{
node_pointer last_node = table::get_node(last);
if (first == last)
return iterator(last_node);
table_.erase_nodes_equiv(table::get_node(first), last_node);
return iterator(last_node);
return table_.erase_nodes_range(first, last);
}
template <class T, class H, class P, class A>
@@ -1984,7 +1944,7 @@ namespace boost {
typename unordered_multiset<T, H, P, A>::const_iterator
unordered_multiset<T, H, P, A>::find(const key_type& k) const
{
return const_iterator(table_.find_node(k));
return const_iterator(table_.find(k));
}
template <class T, class H, class P, class A>
@@ -1994,16 +1954,14 @@ namespace boost {
unordered_multiset<T, H, P, A>::find(CompatibleKey const& k,
CompatibleHash const& hash, CompatiblePredicate const& eq) const
{
return const_iterator(
table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq));
return table_.transparent_find(k, hash, eq);
}
template <class T, class H, class P, class A>
typename unordered_multiset<T, H, P, A>::size_type
unordered_multiset<T, H, P, A>::count(const key_type& k) const
{
node_pointer n = table_.find_node(k);
return n ? table_.group_count(n) : 0;
return table_.group_count(k);
}
template <class T, class H, class P, class A>
@@ -2011,9 +1969,9 @@ namespace boost {
typename unordered_multiset<T, H, P, A>::const_iterator>
unordered_multiset<T, H, P, A>::equal_range(const key_type& k) const
{
node_pointer n = table_.find_node(k);
return std::make_pair(
const_iterator(n), const_iterator(n ? table_.next_group(n) : n));
iterator n = table_.find(k);
return std::make_pair(const_iterator(n),
const_iterator(n == end() ? n : table_.next_group(k, n)));
}
template <class T, class H, class P, class A>
@@ -2028,9 +1986,13 @@ namespace boost {
template <class T, class H, class P, class A>
float unordered_multiset<T, H, P, A>::load_factor() const BOOST_NOEXCEPT
{
BOOST_ASSERT(table_.bucket_count_ != 0);
if (table_.size_ == 0) {
return 0.0f;
}
BOOST_ASSERT(table_.bucket_count() != 0);
return static_cast<float>(table_.size_) /
static_cast<float>(table_.bucket_count_);
static_cast<float>(table_.bucket_count());
}
template <class T, class H, class P, class A>
@@ -2048,8 +2010,7 @@ namespace boost {
template <class T, class H, class P, class A>
void unordered_multiset<T, H, P, A>::reserve(size_type n)
{
table_.rehash(static_cast<std::size_t>(
std::ceil(static_cast<double>(n) / table_.mlf_)));
table_.reserve(n);
}
template <class T, class H, class P, class A>
@@ -2217,25 +2178,25 @@ namespace boost {
x.swap(y);
}
template <typename N, typename T, typename A> struct insert_return_type_set
template <class Iter, class NodeType> struct insert_return_type_set
{
private:
BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type_set)
typedef typename boost::unordered::detail::rebind_wrap<A, T>::type
value_allocator;
typedef N node_;
// typedef typename boost::unordered::detail::rebind_wrap<A, T>::type
// value_allocator;
// typedef N node_;
public:
Iter position;
bool inserted;
boost::unordered::iterator_detail::c_iterator<node_> position;
boost::unordered::node_handle_set<N, T, A> node;
NodeType node;
insert_return_type_set() : inserted(false), position(), node() {}
insert_return_type_set() : position(), inserted(false), node() {}
insert_return_type_set(BOOST_RV_REF(insert_return_type_set)
x) BOOST_NOEXCEPT : inserted(x.inserted),
position(x.position),
x) BOOST_NOEXCEPT : position(x.position),
inserted(x.inserted),
node(boost::move(x.node))
{
}
@@ -2249,9 +2210,9 @@ namespace boost {
}
};
template <typename N, typename T, typename A>
template <class Iter, class NodeType>
void swap(
insert_return_type_set<N, T, A>& x, insert_return_type_set<N, T, A>& y)
insert_return_type_set<Iter, NodeType>& x, insert_return_type_set<Iter, NodeType>& y)
{
boost::swap(x.node, y.node);
boost::swap(x.inserted, y.inserted);
@@ -1,5 +1,6 @@
// Copyright (C) 2008-2011 Daniel James.
// Copyright (C) 2022 Christian Mazakas
// 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)
@@ -57,7 +58,7 @@ namespace boost {
unordered_multiset<K, H, P, A>& c, Predicate pred);
template <class N, class T, class A> class node_handle_set;
template <class N, class T, class A> struct insert_return_type_set;
template <class Iter, class NodeType> struct insert_return_type_set;
}
using boost::unordered::unordered_set;
+17
View File
@@ -0,0 +1,17 @@
# Copyright 2018, 2019 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::unordered
Boost::core
Boost::concept_check
)
endif()
+64 -77
View File
@@ -1,5 +1,6 @@
# Copyright 2006-2008 Daniel James.
# Copyright 2022 Christian Mazakas
# 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)
@@ -23,88 +24,74 @@ project
<toolset>clang:<cxxflags>$(clang-flags)
<toolset>msvc:<cxxflags>$(msvc-flags)
<toolset>gcc-4.4:<cxxflags>-Wno-strict-aliasing
<toolset>gcc-4.4:<cxxflags>-fno-deduce-init-list
<toolset>gcc:<warnings-as-errors>on
<toolset>clang:<warnings-as-errors>on
<toolset>msvc:<warnings-as-errors>on
;
#alias framework : /boost/test//boost_unit_test_framework ;
alias framework : ;
run unordered/prime_fmod_tests.cpp ;
run unordered/fwd_set_test.cpp ;
run unordered/fwd_map_test.cpp ;
run unordered/allocator_traits.cpp ;
run unordered/minimal_allocator.cpp ;
run unordered/compile_set.cpp ;
run unordered/compile_map.cpp ;
run unordered/noexcept_tests.cpp ;
run unordered/link_test_1.cpp unordered/link_test_2.cpp ;
run unordered/incomplete_test.cpp ;
run unordered/simple_tests.cpp ;
run unordered/equivalent_keys_tests.cpp ;
run unordered/constructor_tests.cpp ;
run unordered/copy_tests.cpp ;
run unordered/move_tests.cpp ;
run unordered/assign_tests.cpp ;
run unordered/insert_tests.cpp ;
run unordered/insert_stable_tests.cpp ;
run unordered/insert_hint_tests.cpp ;
run unordered/emplace_tests.cpp ;
run unordered/unnecessary_copy_tests.cpp ;
run unordered/erase_tests.cpp : : : <define>BOOST_UNORDERED_SUPPRESS_DEPRECATED ;
run unordered/erase_equiv_tests.cpp ;
run unordered/extract_tests.cpp ;
run unordered/node_handle_tests.cpp ;
run unordered/merge_tests.cpp ;
compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MAP : insert_node_type_fail_map ;
compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MULTIMAP : insert_node_type_fail_multimap ;
compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_SET : insert_node_type_fail_set ;
compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MULTISET : insert_node_type_fail_multiset ;
run unordered/find_tests.cpp ;
run unordered/at_tests.cpp ;
run unordered/bucket_tests.cpp ;
run unordered/load_factor_tests.cpp ;
run unordered/rehash_tests.cpp ;
run unordered/equality_tests.cpp ;
run unordered/swap_tests.cpp ;
run unordered/deduction_tests.cpp ;
run unordered/scoped_allocator.cpp : : : <toolset>msvc-14.0:<build>no ;
run unordered/transparent_tests.cpp ;
run unordered/reserve_tests.cpp ;
run unordered/contains_tests.cpp ;
run unordered/erase_if.cpp ;
run unordered/scary_tests.cpp ;
test-suite unordered
:
[ run unordered/fwd_set_test.cpp ]
[ run unordered/fwd_map_test.cpp ]
[ run unordered/allocator_traits.cpp ]
[ run unordered/minimal_allocator.cpp ]
[ run unordered/compile_set.cpp ]
[ run unordered/compile_map.cpp ]
[ run unordered/noexcept_tests.cpp ]
[ run unordered/link_test_1.cpp unordered/link_test_2.cpp ]
[ run unordered/incomplete_test.cpp ]
[ run unordered/simple_tests.cpp ]
[ run unordered/equivalent_keys_tests.cpp ]
[ run unordered/constructor_tests.cpp ]
[ run unordered/copy_tests.cpp ]
[ run unordered/move_tests.cpp ]
[ run unordered/assign_tests.cpp ]
[ run unordered/insert_tests.cpp ]
[ run unordered/insert_stable_tests.cpp ]
[ run unordered/insert_hint_tests.cpp ]
[ run unordered/emplace_tests.cpp ]
[ run unordered/unnecessary_copy_tests.cpp ]
[ run unordered/erase_tests.cpp : : : <define>BOOST_UNORDERED_SUPPRESS_DEPRECATED ]
[ run unordered/erase_equiv_tests.cpp ]
[ run unordered/extract_tests.cpp ]
[ run unordered/node_handle_tests.cpp ]
[ run unordered/merge_tests.cpp ]
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MAP : insert_node_type_fail_map ]
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MULTIMAP : insert_node_type_fail_multimap ]
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_SET : insert_node_type_fail_set ]
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MULTISET : insert_node_type_fail_multiset ]
[ run unordered/find_tests.cpp ]
[ run unordered/at_tests.cpp ]
[ run unordered/bucket_tests.cpp ]
[ run unordered/load_factor_tests.cpp ]
[ run unordered/rehash_tests.cpp ]
[ run unordered/equality_tests.cpp ]
[ run unordered/swap_tests.cpp ]
[ run unordered/detail_tests.cpp ]
[ run unordered/deduction_tests.cpp ]
[ run unordered/scoped_allocator.cpp : : : <toolset>msvc-14.0:<build>no ]
[ run unordered/transparent_tests.cpp ]
[ run unordered/reserve_tests.cpp ]
[ run unordered/contains_tests.cpp ]
[ run unordered/mix_policy.cpp ]
[ run unordered/erase_if.cpp ]
run unordered/compile_set.cpp : : : <define>BOOST_UNORDERED_USE_MOVE : bmove_compile_set ;
run unordered/compile_map.cpp : : : <define>BOOST_UNORDERED_USE_MOVE : bmove_compile_map ;
run unordered/copy_tests.cpp : : : <define>BOOST_UNORDERED_USE_MOVE : bmove_copy ;
run unordered/move_tests.cpp : : : <define>BOOST_UNORDERED_USE_MOVE : bmove_move ;
run unordered/assign_tests.cpp : : : <define>BOOST_UNORDERED_USE_MOVE : bmove_assign ;
[ run unordered/compile_set.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_compile_set ]
[ run unordered/compile_map.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_compile_map ]
[ run unordered/copy_tests.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_copy ]
[ run unordered/move_tests.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_move ]
[ run unordered/assign_tests.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_assign ]
;
test-suite unordered-exception
:
[ run exception/constructor_exception_tests.cpp framework ]
[ run exception/copy_exception_tests.cpp framework ]
[ run exception/assign_exception_tests.cpp framework ]
[ run exception/move_assign_exception_tests.cpp framework ]
[ run exception/insert_exception_tests.cpp framework ]
[ run exception/erase_exception_tests.cpp framework ]
[ run exception/rehash_exception_tests.cpp framework ]
[ run exception/swap_exception_tests.cpp framework : : :
<define>BOOST_UNORDERED_SWAP_METHOD=2 ]
[ run exception/merge_exception_tests.cpp framework ]
;
run exception/constructor_exception_tests.cpp ;
run exception/copy_exception_tests.cpp ;
run exception/assign_exception_tests.cpp ;
run exception/move_assign_exception_tests.cpp ;
run exception/insert_exception_tests.cpp ;
run exception/erase_exception_tests.cpp ;
run exception/rehash_exception_tests.cpp ;
run exception/swap_exception_tests.cpp : : : <define>BOOST_UNORDERED_SWAP_METHOD=2 ;
run exception/merge_exception_tests.cpp ;
run quick.cpp ;
+17
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_unordered REQUIRED)
add_executable(quick ../quick.cpp)
target_link_libraries(quick Boost::unordered)
enable_testing()
add_test(quick quick)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)
+49
View File
@@ -0,0 +1,49 @@
# 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/unordered)
# `boostdep --brief unordered`
set(deps
# Primary dependencies
assert
config
container_hash
core
move
mp11
predef
preprocessor
throw_exception
tuple
type_traits
# Secondary dependencies
detail
integer
static_assert
winapi
)
foreach(dep IN LISTS deps)
add_subdirectory(../../../${dep} boostorg/${dep})
endforeach()
add_executable(quick ../quick.cpp)
target_link_libraries(quick Boost::unordered Boost::core)
enable_testing()
add_test(quick quick)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)
+2 -2
View File
@@ -95,7 +95,7 @@ void insert_rehash_exception_test(
T*, Inserter insert, test::random_generator gen)
{
for (int i = 0; i < 5; ++i) {
T x;
T x(1);
rehash_prep(x);
test::random_values<T> v2(5, gen);
@@ -393,7 +393,7 @@ template <typename T>
void insert_range_rehash_exception_test(T*, test::random_generator gen)
{
for (int i = 0; i < 5; ++i) {
T x;
T x(1);
rehash_prep(x);
test::random_values<T> v2(5, gen);
+3 -4
View File
@@ -9,8 +9,8 @@
#include "./generators.hpp"
#include "./list.hpp"
#include "./metafunctions.hpp"
#include <boost/type_traits/conditional.hpp>
#include <algorithm>
#include <boost/detail/select_type.hpp>
namespace test {
template <class X> struct unordered_generator_set
@@ -69,9 +69,8 @@ namespace test {
template <class X>
struct unordered_generator_base
: public boost::detail::if_true<test::is_set<X>::value>::
BOOST_NESTED_TEMPLATE then<test::unordered_generator_set<X>,
test::unordered_generator_map<X> >
: public boost::conditional<test::is_set<X>::value,
test::unordered_generator_set<X>, test::unordered_generator_map<X> >
{
};
+15 -12
View File
@@ -1,5 +1,6 @@
// Copyright 2006-2011 Daniel James.
// Copyright 2022 Christian Mazakas
// 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)
@@ -213,25 +214,27 @@ namespace test
::operator delete((void*)p);
}
void construct(T* p, T const& t)
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class U, class V>
void construct(U* p, V const& v)
{
detail::tracker.track_construct((void*)p, sizeof(T), tag_);
new (p) T(t);
detail::tracker.track_construct((void*)p, sizeof(U), tag_);
new (p) U(v);
}
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <typename... Args>
void construct(T* p, BOOST_FWD_REF(Args)... args)
#else
template <class U, typename... Args>
void construct(U* p, BOOST_FWD_REF(Args)... args)
{
detail::tracker.track_construct((void*)p, sizeof(T), tag_);
new (p) T(boost::forward<Args>(args)...);
detail::tracker.track_construct((void*)p, sizeof(U), tag_);
new (p) U(boost::forward<Args>(args)...);
}
#endif
void destroy(T* p)
template <class U>
void destroy(U* p)
{
detail::tracker.track_destroy((void*)p, sizeof(T), tag_);
p->~T();
detail::tracker.track_destroy((void*)p, sizeof(U), tag_);
p->~U();
}
size_type max_size() const
+32 -26
View File
@@ -1,5 +1,6 @@
// Copyright 2006-2009 Daniel James.
// Copyright 2022 Christian Mazakas
// 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)
@@ -475,32 +476,34 @@ namespace test {
}
}
void construct(pointer p, T const& t)
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class U, class Arg>
void construct(U* p, Arg const& t)
{
UNORDERED_SCOPE(allocator::construct(T*, T))
UNORDERED_SCOPE(allocator::construct(U*, Arg))
{
UNORDERED_EPOINT("Mock allocator construct function.");
new (p) T(t);
new (p) U(t);
}
test::detail::tracker.track_construct((void*)p, sizeof(T), tag_);
test::detail::tracker.track_construct((void*)p, sizeof(U), tag_);
}
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args)
#else
template <class U, class... Args> void construct(U* p, BOOST_FWD_REF(Args)... args)
{
UNORDERED_SCOPE(allocator::construct(pointer, BOOST_FWD_REF(Args)...))
UNORDERED_SCOPE(allocator::construct(U*, BOOST_FWD_REF(Args)...))
{
UNORDERED_EPOINT("Mock allocator construct function.");
new (p) T(boost::forward<Args>(args)...);
new (p) U(boost::forward<Args>(args)...);
}
test::detail::tracker.track_construct((void*)p, sizeof(T), tag_);
test::detail::tracker.track_construct((void*)p, sizeof(U), tag_);
}
#endif
void destroy(T* p)
template <class U>
void destroy(U* p)
{
test::detail::tracker.track_destroy((void*)p, sizeof(T), tag_);
p->~T();
test::detail::tracker.track_destroy((void*)p, sizeof(U), tag_);
p->~U();
}
size_type max_size() const
@@ -654,32 +657,35 @@ namespace test {
}
}
void construct(pointer p, T const& t)
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class U, class V>
void construct(U* p, V const& v)
{
UNORDERED_SCOPE(allocator2::construct(T*, T))
UNORDERED_SCOPE(allocator2::construct(U*, V))
{
UNORDERED_EPOINT("Mock allocator2 construct function.");
new (p) T(t);
new (p) U(v);
}
test::detail::tracker.track_construct((void*)p, sizeof(T), tag_);
test::detail::tracker.track_construct((void*)p, sizeof(U), tag_);
}
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args)
#else
template <class U, class... Args>
void construct(U* p, BOOST_FWD_REF(Args)... args)
{
UNORDERED_SCOPE(allocator2::construct(pointer, BOOST_FWD_REF(Args)...))
UNORDERED_SCOPE(allocator2::construct(U*, BOOST_FWD_REF(Args)...))
{
UNORDERED_EPOINT("Mock allocator2 construct function.");
new (p) T(boost::forward<Args>(args)...);
new (p) U(boost::forward<Args>(args)...);
}
test::detail::tracker.track_construct((void*)p, sizeof(T), tag_);
test::detail::tracker.track_construct((void*)p, sizeof(U), tag_);
}
#endif
void destroy(T* p)
template <class U>
void destroy(U* p)
{
test::detail::tracker.track_destroy((void*)p, sizeof(T), tag_);
p->~T();
test::detail::tracker.track_destroy((void*)p, sizeof(U), tag_);
p->~U();
}
size_type max_size() const
+51 -23
View File
@@ -1,5 +1,6 @@
// Copyright 2006-2009 Daniel James.
// Copyright 2022 Christian Mazakas
// 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)
@@ -10,6 +11,8 @@
#if !defined(BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER)
#define BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER
#include <boost/core/lightweight_test.hpp>
#include <boost/core/pointer_traits.hpp>
#include <boost/move/move.hpp>
#include <cstddef>
#include <utility>
@@ -309,13 +312,17 @@ namespace test {
return tmp;
}
ptr operator+(std::ptrdiff_t s) const { return ptr<T>(ptr_ + s); }
friend ptr operator+(std::ptrdiff_t s, ptr p)
{
return ptr<T>(s + p.ptr_);
}
friend ptr operator+(std::ptrdiff_t s, ptr p) { return ptr<T>(s + p.ptr_); }
std::ptrdiff_t operator-(ptr p) const { return ptr_ - p.ptr_; }
ptr operator-(std::ptrdiff_t s) const { return ptr(ptr_ - s); }
T& operator[](std::ptrdiff_t s) const { return ptr_[s]; }
bool operator!() const { return !ptr_; }
static ptr pointer_to(T& p) {
return ptr(&p);
}
// I'm not using the safe bool idiom because the containers should be
// able to cope with bool conversions.
operator bool() const { return !!ptr_; }
@@ -428,16 +435,20 @@ namespace test {
::operator delete((void*)p.ptr_);
}
void construct(T* p, T const& t) { new ((void*)p) T(t); }
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args)
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class U, class V> void construct(U* p, V const& v)
{
new ((void*)p) T(boost::forward<Args>(args)...);
new ((void*)p) U(v);
}
#else
template <class U, class... Args>
void construct(U* p, BOOST_FWD_REF(Args)... args)
{
new ((void*)p) U(boost::forward<Args>(args)...);
}
#endif
void destroy(T* p) { p->~T(); }
template <class U> void destroy(U* p) { p->~U(); }
size_type max_size() const { return 1000; }
@@ -498,17 +509,20 @@ namespace test {
::operator delete((void*)p.ptr_);
}
void construct(T const* p, T const& t) { new ((void*)p) T(t); }
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class... Args>
void construct(T const* p, BOOST_FWD_REF(Args)... args)
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class U> void construct(U* p, U const& t)
{
new ((void*)p) T(boost::forward<Args>(args)...);
new (p) U(t);
}
#else
template <class U, class... Args>
void construct(U* p, BOOST_FWD_REF(Args)... args)
{
new (p) U(boost::forward<Args>(args)...);
}
#endif
void destroy(T const* p) { p->~T(); }
template <class U> void destroy(U* p) { p->~U(); }
size_type max_size() const { return 1000; }
@@ -573,16 +587,20 @@ namespace test {
void deallocate(T* p, std::size_t) { ::operator delete((void*)p); }
void construct(T* p, T const& t) { new ((void*)p) T(t); }
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args)
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class U, class V> void construct(U* p, V const& v)
{
new ((void*)p) T(boost::forward<Args>(args)...);
new ((void*)p) U(v);
}
#else
template <class U, class... Args>
void construct(U* p, BOOST_FWD_REF(Args)... args)
{
new ((void*)p) U(boost::forward<Args>(args)...);
}
#endif
void destroy(T* p) { p->~T(); }
template <class U> void destroy(U* p) { p->~U(); }
std::size_t max_size() const { return 1000u; }
};
@@ -624,4 +642,14 @@ namespace test {
#pragma warning(pop)
#endif
namespace boost {
template <> struct pointer_traits< ::test::minimal::void_ptr>
{
template <class U> struct rebind_to
{
typedef ::test::minimal::ptr<U> type;
};
};
}
#endif
+40 -19
View File
@@ -1,5 +1,6 @@
// Copyright 2006-2009 Daniel James.
// Copyright 2022 Christian Mazakas
// 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)
@@ -184,7 +185,7 @@ namespace test {
};
// Note: This is a deliberately bad hash function.
class hash
class hash BOOST_FINAL
{
int type_;
@@ -289,7 +290,7 @@ namespace test {
}
}
std::size_t operator()(int x1, int x2) const { return x1 < x2; }
bool operator()(int x1, int x2) const { return x1 < x2; }
friend bool operator==(less const& x1, less const& x2)
{
@@ -297,7 +298,7 @@ namespace test {
}
};
class equal_to
class equal_to BOOST_FINAL
{
int type_;
@@ -330,7 +331,7 @@ namespace test {
}
}
std::size_t operator()(int x1, int x2) const { return x1 == x2; }
bool operator()(int x1, int x2) const { return x1 == x2; }
friend bool operator==(equal_to const& x1, equal_to const& x2)
{
@@ -499,11 +500,9 @@ namespace test {
friend class const_ptr<T>;
friend struct void_ptr;
T* ptr_;
ptr(T* x) : ptr_(x) {}
public:
T* ptr_;
ptr(T* x) : ptr_(x) {}
ptr() : ptr_(0) {}
explicit ptr(void_ptr const& x) : ptr_((T*)x.ptr_) {}
@@ -520,11 +519,22 @@ namespace test {
++ptr_;
return tmp;
}
ptr operator+(std::ptrdiff_t s) const { return ptr<T>(ptr_ + s); }
friend ptr operator+(std::ptrdiff_t s, ptr p) { return ptr<T>(s + p.ptr_); }
std::ptrdiff_t operator-(ptr p) const { return ptr_ - p.ptr_; }
ptr operator-(std::ptrdiff_t s) const { return ptr(ptr_ - s); }
ptr& operator+=(std::ptrdiff_t s) { ptr_ += s; return *this; }
T& operator[](std::ptrdiff_t s) const { return ptr_[s]; }
bool operator!() const { return !ptr_; }
static ptr pointer_to(T& p) {
return ptr(&p);
}
// I'm not using the safe bool idiom because the containers should be
// able to cope with bool conversions.
operator bool() const { return !!ptr_; }
@@ -646,24 +656,25 @@ namespace test {
::operator delete((void*)p.ptr_);
}
void construct(T* p, T const& t)
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class U, class V> void construct(U* p, V const& v)
{
detail::tracker.track_construct((void*)p, sizeof(T), tag_);
new (p) T(t);
detail::tracker.track_construct((void*)p, sizeof(U), tag_);
new (p) U(v);
}
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args)
#else
template <class U, class... Args>
void construct(U* p, BOOST_FWD_REF(Args)... args)
{
detail::tracker.track_construct((void*)p, sizeof(T), tag_);
new (p) T(boost::forward<Args>(args)...);
detail::tracker.track_construct((void*)p, sizeof(U), tag_);
new (p) U(boost::forward<Args>(args)...);
}
#endif
void destroy(T* p)
template <class U> void destroy(U* p)
{
detail::tracker.track_destroy((void*)p, sizeof(T), tag_);
p->~T();
detail::tracker.track_destroy((void*)p, sizeof(U), tag_);
p->~U();
}
size_type max_size() const
@@ -699,4 +710,14 @@ namespace test {
}
}
namespace boost {
template <> struct pointer_traits< ::test::void_ptr>
{
template <class U> struct rebind_to
{
typedef ::test::ptr<U> type;
};
};
} // namespace boost
#endif
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2022 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/unordered_map.hpp>
#include <boost/core/lightweight_test.hpp>
#include <string>
int main()
{
boost::unordered_map<std::string, int> map;
map[ "2" ] = 2;
BOOST_TEST_EQ( map[ "1" ], 0 );
BOOST_TEST_EQ( map[ "2" ], 2 );
return boost::report_errors();
}
+2
View File
@@ -45,6 +45,7 @@ namespace assign_tests {
BOOST_TEST(x.empty());
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::detail::tracker.count_allocations == 0);
}
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests1.2\n";
@@ -94,6 +95,7 @@ namespace assign_tests {
BOOST_TEST(test::equivalent(x1.key_eq(), eq1));
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
BOOST_TEST(test::detail::tracker.count_allocations == 0);
test::check_container(x1, x2);
}
+107
View File
@@ -35,6 +35,7 @@ namespace constructor_tests {
T x(0, hf, eq);
BOOST_TEST(x.empty());
BOOST_TEST_EQ(x.bucket_count(), 0u);
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
@@ -73,6 +74,7 @@ namespace constructor_tests {
T x;
BOOST_TEST(x.empty());
BOOST_TEST_EQ(x.bucket_count(), 0u);
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
@@ -140,6 +142,7 @@ namespace constructor_tests {
T x(0, hf, eq, al);
BOOST_TEST(x.empty());
BOOST_TEST_EQ(x.bucket_count(), 0u);
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
@@ -166,6 +169,7 @@ namespace constructor_tests {
T x(al);
BOOST_TEST(x.empty());
BOOST_TEST_EQ(x.bucket_count(), 0u);
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
@@ -325,6 +329,7 @@ namespace constructor_tests {
T x(list);
BOOST_TEST(x.empty());
BOOST_TEST_EQ(x.bucket_count(), 0u);
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
@@ -380,6 +385,104 @@ namespace constructor_tests {
#endif
}
template <class T>
void no_alloc_default_construct_test(T*, test::random_generator)
{
UNORDERED_SUB_TEST("Construct 1")
{
T x;
BOOST_TEST_EQ(x.bucket_count(), 0u);
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
}
UNORDERED_SUB_TEST("Construct 2")
{
{
T x(0);
BOOST_TEST_EQ(x.bucket_count(), 0u);
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
}
{
T x(1);
BOOST_TEST_GT(x.bucket_count(), 0u);
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
}
}
UNORDERED_SUB_TEST("Construct 3")
{
test::random_values<T> v;
T x(v.begin(), v.end());
BOOST_TEST_EQ(x.bucket_count(), 0u);
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
}
UNORDERED_SUB_TEST("Construct 4")
{
{
test::random_values<T> v;
T x(v.begin(), v.end(), 0);
BOOST_TEST_EQ(x.bucket_count(), 0u);
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
}
{
test::random_values<T> v;
T x(v.begin(), v.end(), 1);
BOOST_TEST_GT(x.bucket_count(), 0u);
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
}
}
UNORDERED_SUB_TEST("Construct 5")
{
typename T::allocator_type al;
{
T x(al);
BOOST_TEST_EQ(x.bucket_count(), 0u);
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
}
}
UNORDERED_SUB_TEST("Construct 6")
{
typename T::allocator_type al;
T x(0, al);
BOOST_TEST_EQ(x.bucket_count(), 0u);
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
}
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
UNORDERED_SUB_TEST("Initializer list 1")
{
std::initializer_list<typename T::value_type> list;
T x(list);
BOOST_TEST_EQ(x.bucket_count(), 0u);
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
}
UNORDERED_SUB_TEST("Initializer list 2")
{
{
std::initializer_list<typename T::value_type> list;
T x(list, 0);
BOOST_TEST_EQ(x.bucket_count(), 0u);
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
}
{
std::initializer_list<typename T::value_type> list;
T x(list, 1);
BOOST_TEST_GT(x.bucket_count(), 0u);
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
}
}
#endif
}
template <class T>
void map_constructor_test(T*, test::random_generator const& generator)
{
@@ -422,6 +525,10 @@ namespace constructor_tests {
((test_map_std_alloc)(test_map)(test_multimap))(
(default_generator)(generate_collisions)(limited_range)))
UNORDERED_TEST(no_alloc_default_construct_test,
((test_set)(test_multiset)(test_map)(test_multimap))(
(default_generator)(generate_collisions)(limited_range)))
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
UNORDERED_AUTO_TEST (test_default_initializer_list) {
+79
View File
@@ -43,6 +43,23 @@ namespace copy_tests {
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
BOOST_TEST(test::selected_count(y.get_allocator()) ==
(allocator_type::is_select_on_copy));
BOOST_TEST(test::detail::tracker.count_allocations == 0);
test::check_equivalent_keys(y);
}
{
test::check_instances check_;
T x(0);
T y(x);
BOOST_TEST(y.empty());
BOOST_TEST(test::equivalent(y.hash_function(), hf));
BOOST_TEST(test::equivalent(y.key_eq(), eq));
BOOST_TEST(test::equivalent(y.get_allocator(), al));
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
BOOST_TEST(test::selected_count(y.get_allocator()) ==
(allocator_type::is_select_on_copy));
BOOST_TEST(test::detail::tracker.count_allocations == 0);
test::check_equivalent_keys(y);
}
@@ -91,6 +108,22 @@ namespace copy_tests {
typedef typename T::allocator_type allocator_type;
{
test::check_instances check_;
T x(0, hf, eq, al);
T y(x);
BOOST_TEST(y.empty());
BOOST_TEST(test::equivalent(y.hash_function(), hf));
BOOST_TEST(test::equivalent(y.key_eq(), eq));
BOOST_TEST(test::equivalent(y.get_allocator(), al));
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
BOOST_TEST(test::selected_count(y.get_allocator()) ==
(allocator_type::is_select_on_copy));
BOOST_TEST(test::detail::tracker.count_allocations == 0);
test::check_equivalent_keys(y);
}
{
test::check_instances check_;
@@ -106,6 +139,21 @@ namespace copy_tests {
test::check_equivalent_keys(y);
}
{
test::check_instances check_;
T x(0, hf, eq, al);
T y(x, al2);
BOOST_TEST(y.empty());
BOOST_TEST(test::equivalent(y.hash_function(), hf));
BOOST_TEST(test::equivalent(y.key_eq(), eq));
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
BOOST_TEST(test::detail::tracker.count_allocations == 0);
test::check_equivalent_keys(y);
}
{
test::check_instances check_;
@@ -120,6 +168,22 @@ namespace copy_tests {
test::check_equivalent_keys(y);
}
{
test::check_instances check_;
test::random_values<T> v;
T x(v.begin(), v.end(), 0, hf, eq, al);
T y(x);
test::unordered_equivalence_tester<T> equivalent(x);
BOOST_TEST(equivalent(y));
test::check_equivalent_keys(y);
BOOST_TEST(test::selected_count(y.get_allocator()) ==
(allocator_type::is_select_on_copy));
BOOST_TEST(test::equivalent(y.get_allocator(), al));
BOOST_TEST(test::detail::tracker.count_allocations == 0);
}
{
test::check_instances check_;
@@ -135,6 +199,21 @@ namespace copy_tests {
BOOST_TEST(test::equivalent(y.get_allocator(), al));
}
{
test::check_instances check_;
test::random_values<T> v;
T x(v.begin(), v.end(), 0, hf, eq, al);
T y(x, al2);
test::unordered_equivalence_tester<T> equivalent(x);
BOOST_TEST(equivalent(y));
test::check_equivalent_keys(y);
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
BOOST_TEST(test::detail::tracker.count_allocations == 0);
}
{
test::check_instances check_;
-101
View File
@@ -1,101 +0,0 @@
// 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)
// clang-format off
#include "../helpers/prefix.hpp"
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include "../helpers/postfix.hpp"
// clang-format on
#include "../helpers/test.hpp"
#include <map>
// Pretty inefficient, but the test is fast enough.
// Might be too slow if we had larger primes?
bool is_prime(std::size_t x)
{
if (x == 2) {
return true;
} else if (x == 1 || x % 2 == 0) {
return false;
} else {
// y*y <= x had rounding errors, so instead use y <= (x/y).
for (std::size_t y = 3; y <= (x / y); y += 2) {
if (x % y == 0) {
return false;
break;
}
}
return true;
}
}
void test_next_prime(std::size_t value)
{
std::size_t x = boost::unordered::detail::next_prime(value);
BOOST_TEST(is_prime(x));
BOOST_TEST(x >= value);
}
void test_prev_prime(std::size_t value)
{
std::size_t x = boost::unordered::detail::prev_prime(value);
BOOST_TEST(is_prime(x));
BOOST_TEST(x <= value);
if (x > value) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM << x << "," << value << std::endl;
}
}
UNORDERED_AUTO_TEST (next_prime_test) {
BOOST_TEST(!is_prime(0));
BOOST_TEST(!is_prime(1));
BOOST_TEST(is_prime(2));
BOOST_TEST(is_prime(3));
BOOST_TEST(is_prime(13));
BOOST_TEST(!is_prime(4));
BOOST_TEST(!is_prime(100));
BOOST_TEST(boost::unordered::detail::next_prime(0) > 0);
// test_prev_prime doesn't work for values less than 17.
// Which should be okay, unless an allocator has a really tiny
// max_size?
const std::size_t min_prime = 17;
// test_next_prime doesn't work for values greater than this,
// which might be a problem if you've got terrabytes of memory?
// I seriously doubt the container would work well at such sizes
// regardless.
const std::size_t max_prime = 4294967291ul;
std::size_t i;
BOOST_TEST(is_prime(min_prime));
BOOST_TEST(is_prime(max_prime));
for (i = 0; i < 10000; ++i) {
if (i < min_prime) {
BOOST_TEST(boost::unordered::detail::prev_prime(i) == min_prime);
} else {
test_prev_prime(i);
}
test_next_prime(i);
}
std::size_t last = i - 1;
for (; i > last; last = i, i += i / 5) {
if (i > max_prime) {
BOOST_TEST(boost::unordered::detail::next_prime(i) == max_prime);
} else {
test_next_prime(i);
}
test_prev_prime(i);
}
}
RUN_TESTS()
+3 -2
View File
@@ -1,4 +1,4 @@
// Copyright 2021 Christian Mazakas.
// Copyright 2021-2022 Christian Mazakas.
// 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)
@@ -11,9 +11,10 @@
#include "../helpers/test.hpp"
#include <boost/config.hpp>
#include <string>
#if BOOST_CXX_VERSION >= 201103L
#if !defined(BOOST_NO_CXX11_REF_QUALIFIERS)
#define UNORDERED_LVALUE_QUAL &
#else
#define UNORDERED_LVALUE_QUAL

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