Compare commits

...
39 Commits
Author SHA1 Message Date
joaquintides 636164f135 updated release notes 2026-06-17 17:00:28 +02:00
joaquintidesandGitHub 88f984e890 added interoperability with C++20 ranges (#355)
* added from_range ctors and insert_range
* worked around GCC 10-11 bug when piping a temporary range
* added insert_range_(or|and)_[c]visit
* typo
* tried to avoid MinGW32 compilation OOM in cfoa/insert_tests.cpp
* s/<debug-symbols>off/<cxxflags>-g0
* tested CTAD deduction guides
* typo
* updated docs
* Justified std::from_range_t detection trick
* reduced parallel build jobs in MINGW32 to try to avoid OOM during compilation
* tried to avoid compilation OOM by tweaking GC
* relaxed GCC parameters somewhat
* applied same changes to test/CMakeLists.txt
* fixed CMake syntax error
* fixed GCC commandline syntax error
2026-06-17 09:00:00 +02:00
joaquintidesandGitHub b785bb5501 fixed Clang 3.8 codegen issue with double_to_size (#354)
* isolated and instrumented test_gh348_2
* fixed Jamfile.v2
* fixed Jamfile.v2
* added more instrumentation
* added more instrumentation
* added more instrumentation
* Clang 3.8 now passes --> codegen issue, retired instrumentation
* tried replacing ternary operator with if/else
* fixed fix
* tried another workaround
* tried another workaround
* tried another workaround
* conditionally applied workaround to Clang < 3.9
* added link to GitHub PR, reverted research traces
2026-05-30 00:46:12 +02:00
02c0fc5faa Fix float bugs in reserve_for_insert and min_buckets (#348)
* Add fix
* regression-tested previous fix, plus regression-tested and fixed adjacent UB bug related to double-to-integer conversion

---------

Co-authored-by: Daniel Kral <daniel.kral@recombee.com>
Co-authored-by: joaquintides <joaquin@tid.es>
2026-05-29 08:57:52 +02:00
joaquintidesandGitHub cebefdede7 avoided OOM during test compilation with GCC/MinGW32 (#353)
* added options to reduce GCC/MinGW32's memory consumption at compilation
* tried something stronger
* tried something stronger
2026-05-26 08:59:32 +02:00
joaquintidesandGitHub 9006dc737f simplified "Setup environment" installation in ci.yml (#352)
* removed installation of git
* install git at "Setup environment" (some OSs don't have it preinstalled)
* installed g++ as well (pre GCC toolchain)
2026-05-24 23:43:54 +02:00
joaquintidesandGitHub a67213fbf6 reformulated SFINAE clauses checking key_type completeness (#351)
* added GCC 16 to CI
* replaced usage of apt-key (not present in Ubuntu 26.04)
* created GPG home directory if it doesn't exit (Ubuntu 26.04)
* s/is_complete_and_move_constructible/std::is_move_constructible, made SFINAE invocations of the latter dependent
* split gcc-16 jobs
2026-05-24 12:18:46 +02:00
joaquintides 7a595971a1 provided a better reference description of size() and (somewhat fastidiously) stated its complexity (closes #350) 2026-05-22 20:55:59 +02:00
joaquintidesandGitHub 846ea5a38c typos (closes #349) 2026-05-22 20:31:55 +02:00
joaquintidesandGitHub 669918498c run npm audit fix (#346) 2026-04-08 16:54:24 +02:00
Braden GanetskyandGitHub f1e2fa38b0 Fix issue with constructing an FOA container from a class with a template conversion operator (#334)
* Add missing compile-only tests in CMake

* Rewrite the FOA containers' CFOA constructors so that a class with a template conversion operator does not instantiate the CFOA container

* Rewrite the CFOA containers' FOA constructors so that a class with a template conversion operator does not instantiate the FOA container
2026-03-12 16:29:30 +01:00
joaquintidesandGitHub 4fd90dc706 fixed https://nvd.nist.gov/vuln/detail/CVE-2026-27903 (#345) 2026-03-06 10:35:06 +01:00
joaquintidesandGitHub b00e7c4624 fixed cfoa range insert functions to return the number of elements inserted instead of the size of the input range (#344)
* fixed cfoa range insert functions to return the number of elements inserted instead of the size of the input range

* avoided variable shadowing

* fixed calculation error in test

* updated release notes
2026-02-14 18:08:20 +01:00
Braden GanetskyandGitHub df2dfe6140 Fix GDB pretty-printers to work with GCC and C++26 (#342) 2026-01-27 20:47:24 +01:00
Peter Dimov 08aa7fe1c3 Update test/cmake_subdir_test 2026-01-23 17:12:01 +02:00
Peter DimovandGitHub 33169aaf41 Merge pull request #341 from Lastique/feature/remove_static_assert
Remove dependencies on Boost.StaticAssert
2026-01-23 17:08:41 +02:00
Andrey Semashev ba00d17236 Remove dependencies on Boost.StaticAssert.
Boost.StaticAssert has been merged into Boost.Config, so remove
the dependency.
2026-01-22 19:38:52 +03:00
joaquintidesandGitHub 83395442ab fixed some issues with doc building (#339)
* added cleanup_node_modules_ to target boostrelease

* removed antora_docs.sh
2026-01-08 13:17:05 +01:00
joaquintidesandGitHub d60d9069f0 improved cleanup-node-modules (#337) 2026-01-05 13:15:31 +01:00
Peter Dimov 597276dd9a Fix -Wundef warning in transparent_tests.cpp 2026-01-05 05:26:25 +02:00
Peter Dimov 86521cc4a4 Enable -Wundef in test/Jamfile.v2 2026-01-05 05:26:25 +02:00
Sam DarwinandGitHub c09d52fe84 Docs: download extension (#332) 2026-01-04 11:18:49 +01:00
joaquintidesandGitHub af47772876 simplified doc/Jamfile.v2 (#336) 2026-01-03 16:50:37 +01:00
Peter DimovandGitHub 719e77f113 Merge pull request #317 from boostorg/cmake
Mark natvis file as PUBLIC in CMakeLists.txt
2026-01-01 22:00:48 +02:00
Peter Dimov 8d68f6d22b Merge branch 'feature/gha' into develop 2026-01-01 21:59:24 +02:00
joaquintidesandGitHub c5cd88e2a8 solved https://www.cve.org/CVERecord?id=CVE-2025-64718 (#335) 2026-01-01 19:50:07 +01:00
Peter Dimov 665371e6da Check __cpp_aligned_new in test/helpers/pmr.hpp before using std::align_val_t 2026-01-01 19:25:00 +02:00
Peter Dimov c70208609e Add clang-19, clang-20, macos-26 to ci.yml. Replace macos-13 with macos-latest. 2026-01-01 15:20:55 +02:00
Braden Ganetsky 009bd32c3d Mark natvis file as PUBLIC in CMakeLists.txt, mirroring the CMake in Boost.Assert 2025-12-31 17:46:15 -06:00
joaquintidesandGitHub 11e05a3c4c updated package-lock.json (#328) 2025-10-21 20:47:01 +02:00
joaquintidesandGitHub e9ca2a2def added /doc/html/unordered.html redirect (#327)
* added /doc/html/unordered.html redirect
* added trailing newline
2025-10-20 09:04:57 +02:00
joaquintidesandGitHub 9c8da06481 raised Antora version requirements (#326) 2025-10-19 17:02:32 +02:00
Peter Dimov e01b7b52a6 BOOST_TEST_THROWS requires a semicolon after https://github.com/boostorg/core/pull/205 2025-10-18 17:53:23 +03:00
Sam DarwinandGitHub 4ec5cb59cd Drone: llvm apt installation (#323) 2025-10-15 09:40:04 +02:00
joaquintidesandGitHub 09d6416755 made boost::unordered_[multi](map|set)::[const_][local_]iterator instantiable with incomplete value_type (#321)
* made boost::unordered_[multi](map|set)::[const_][local_]iterator instantiable with incomplete value_type
* qualified name to avoid self-definition
2025-10-12 13:14:16 +02:00
joaquintidesandGitHub 4b76ac84ec removed ccache for macos-13 (#320) 2025-10-11 17:49:06 +02:00
Alexander GrundandGitHub dcc485bcb5 Update Link to regression test matrix in README (#316)
* Update Link to regression test matrix in README

* Use boost.org instead of boost.io
2025-09-19 09:07:03 +02:00
joaquintidesandGitHub cc9a787f14 microoptimized unchecked_countr_zero for GCC/Clang 2025-08-26 17:08:01 +02:00
Braden GanetskyandGitHub 6fd63ab727 Fix pretty-printers not working when constexpr variables are optimized away (#315)
* Move unordered_printers.hpp into 'detail', where it should have been from the beginning

This is not a public header. It is only meant to be consumed as a transitive include.

* Store self.table instead of self.val

* Fix pretty-printers not working when constexpr variables are optimized away

Also do a few other things.
* `groups` and `elements` are now stored inside `self`
* `mask`, `n0`, and `n` aren't declared ahead of their first assignment
* Remove trailing whitespace

* Update the generated pretty-printer header
2025-08-22 10:15:49 +02:00
68 changed files with 7683 additions and 1882 deletions
+4 -1
View File
@@ -34,8 +34,9 @@ local linux_pipeline(name, image, environment, packages = "", sources = [], arch
commands: commands:
[ [
'set -e', 'set -e',
'echo $DRONE_STAGE_MACHINE',
'uname -a', 'uname -a',
'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -', 'curl -sSL --retry 5 https://apt.llvm.org/llvm-snapshot.gpg.key | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/llvm-snapshot.gpg',
] + ] +
(if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) + (if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) +
(if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) + (if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) +
@@ -66,6 +67,8 @@ local macos_pipeline(name, environment, xcode_version = "12.2", osx_version = "c
environment: environment + { "DEVELOPER_DIR": "/Applications/Xcode-" + xcode_version + ".app/Contents/Developer" }, environment: environment + { "DEVELOPER_DIR": "/Applications/Xcode-" + xcode_version + ".app/Contents/Developer" },
commands: commands:
[ [
'echo $DRONE_STAGE_MACHINE',
'sw_vers',
'uname -a', 'uname -a',
'export LIBRARY=' + library, 'export LIBRARY=' + library,
'./.drone/drone.sh', './.drone/drone.sh',
+15 -11
View File
@@ -60,6 +60,9 @@ jobs:
- { compiler: gcc-12, cxxstd: '11,14,17,20', os: 'ubuntu-22.04', install: 'g++-12' } - { compiler: gcc-12, cxxstd: '11,14,17,20', os: 'ubuntu-22.04', install: 'g++-12' }
- { compiler: gcc-13, cxxstd: '11,14,17,20', os: 'ubuntu-24.04', install: 'g++-13' } - { compiler: gcc-13, cxxstd: '11,14,17,20', os: 'ubuntu-24.04', install: 'g++-13' }
- { compiler: gcc-14, cxxstd: '11,14,17,20', os: 'ubuntu-24.04', install: 'g++-14' } - { compiler: gcc-14, cxxstd: '11,14,17,20', os: 'ubuntu-24.04', install: 'g++-14' }
- { compiler: gcc-16, cxxstd: '11,14,17', container: 'ubuntu:26.04', os: 'ubuntu-latest', install: 'g++-16-multilib' }
- { compiler: gcc-16, cxxstd: '20,23,2c', container: 'ubuntu:26.04', os: 'ubuntu-latest', install: 'g++-16-multilib' }
- { name: "gcc-14 w/ sanitizers (11)", sanitize: yes, - { name: "gcc-14 w/ sanitizers (11)", sanitize: yes,
compiler: gcc-14, cxxstd: '11', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san1" } compiler: gcc-14, cxxstd: '11', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san1" }
- { name: "gcc-14 w/ sanitizers (14)", sanitize: yes, - { name: "gcc-14 w/ sanitizers (14)", sanitize: yes,
@@ -72,7 +75,6 @@ jobs:
compiler: gcc-14, cxxstd: '2b', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san2" } compiler: gcc-14, cxxstd: '2b', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san2" }
- { name: Collect coverage, coverage: yes, - { name: Collect coverage, coverage: yes,
compiler: gcc-14, cxxstd: '20', os: 'ubuntu-24.04', install: 'g++-14 g++-14-multilib', address-model: '32,64', ccache_key: "cov" } compiler: gcc-14, cxxstd: '20', os: 'ubuntu-24.04', install: 'g++-14 g++-14-multilib', address-model: '32,64', ccache_key: "cov" }
- { name: "cfoa tsan (gcc-14)", cxxstd: '11,14,17,20,2b', os: 'ubuntu-24.04', install: 'g++-14', compiler: gcc-14, - { name: "cfoa tsan (gcc-14)", cxxstd: '11,14,17,20,2b', os: 'ubuntu-24.04', install: 'g++-14', compiler: gcc-14,
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes, ccache_key: "tsan" } targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes, ccache_key: "tsan" }
@@ -101,6 +103,10 @@ jobs:
- { compiler: 'clang-17', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-17 libc++-17-dev libc++abi-17-dev' } - { compiler: 'clang-17', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-17 libc++-17-dev libc++abi-17-dev' }
- { compiler: 'clang-18', cxxstd: '11,14', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev' } - { compiler: 'clang-18', cxxstd: '11,14', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev' }
- { compiler: 'clang-18', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev' } - { compiler: 'clang-18', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev' }
- { compiler: 'clang-19', cxxstd: '11,14', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-19 libc++-19-dev libc++abi-19-dev' }
- { compiler: 'clang-19', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-19 libc++-19-dev libc++abi-19-dev' }
- { compiler: 'clang-20', cxxstd: '11,14,17', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-20 libc++-20-dev libc++abi-20-dev' }
- { compiler: 'clang-20', cxxstd: '20,23,2c', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-20 libc++-20-dev libc++abi-20-dev' }
# not using libc++ because of https://github.com/llvm/llvm-project/issues/52771 # not using libc++ because of https://github.com/llvm/llvm-project/issues/52771
- { name: "clang-18 w/ sanitizers (11,14)", sanitize: yes, - { name: "clang-18 w/ sanitizers (11,14)", sanitize: yes,
@@ -117,10 +123,12 @@ jobs:
stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev', ccache_key: "tsan" } stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev', ccache_key: "tsan" }
# OSX, clang # OSX, clang
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-13', sanitize: yes, ccache_key: "san1" } - { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-latest', sanitize: yes, ccache: no, ccache_key: "san1" }
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-13', thread-sanitize: yes, targets: 'libs/unordered/test//cfoa_tests', ccache_key: "tsan" } - { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-latest', thread-sanitize: yes, targets: 'libs/unordered/test//cfoa_tests', ccache: no, ccache_key: "tsan" }
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-14' } - { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-14' }
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-15' } - { compiler: clang, cxxstd: '11,14,17,20,23,2c', os: 'macos-15' }
- { compiler: clang, cxxstd: '11,14,17,20,23,2c', os: 'macos-26' }
timeout-minutes: 360 timeout-minutes: 360
# posix (gcc-12 w/ sanitizers is taking longer than 210 minutes # posix (gcc-12 w/ sanitizers is taking longer than 210 minutes
@@ -139,12 +147,7 @@ jobs:
fi fi
if [ -n "${{matrix.container}}" ] && [ -f "/etc/debian_version" ]; then 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 update
apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common git g++
# 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-is-python3 git
fi fi
# For jobs not compatible with ccache, use "ccache: no" in the matrix # For jobs not compatible with ccache, use "ccache: no" in the matrix
if [[ "${{ matrix.ccache }}" == "no" ]]; then if [[ "${{ matrix.ccache }}" == "no" ]]; then
@@ -344,7 +347,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- { sys: MINGW32, compiler: gcc, cxxstd: '11,17,20', variant: 'release' } - { sys: MINGW32, compiler: gcc, cxxstd: '11,17,20', variant: 'release', cxxflags: '--param ggc-min-expand=10 --param ggc-min-heapsize=16384' }
- { sys: MINGW64, compiler: gcc, cxxstd: '11,17,20', variant: 'debug,release' } - { sys: MINGW64, compiler: gcc, cxxstd: '11,17,20', variant: 'debug,release' }
needs: [runner-selection] needs: [runner-selection]
@@ -380,6 +383,7 @@ jobs:
B2_SANITIZE: ${{matrix.sanitize}} B2_SANITIZE: ${{matrix.sanitize}}
B2_STDLIB: ${{matrix.stdlib}} B2_STDLIB: ${{matrix.stdlib}}
B2_VARIANT: ${{matrix.variant}} B2_VARIANT: ${{matrix.variant}}
B2_CXXFLAGS: ${{ matrix.cxxflags }}
run: ci/github/install.sh run: ci/github/install.sh
- name: Run tests - name: Run tests
+21 -5
View File
@@ -23,12 +23,28 @@ target_link_libraries(boost_unordered
Boost::throw_exception Boost::throw_exception
) )
if(CMAKE_VERSION VERSION_GREATER 3.18 AND CMAKE_GENERATOR MATCHES "Visual Studio") # Add headers and .natvis to project, for better IDE integration
file(GLOB_RECURSE boost_unordered_IDEFILES CONFIGURE_DEPENDS include/*.hpp) if(NOT CMAKE_VERSION VERSION_LESS 3.19)
source_group(TREE ${PROJECT_SOURCE_DIR}/include FILES ${boost_unordered_IDEFILES} PREFIX "Header Files")
list(APPEND boost_unordered_IDEFILES extra/boost_unordered.natvis) # Using target_sources with PRIVATE or PUBLIC on INTERFACE targets requires 3.19
target_sources(boost_unordered PRIVATE ${boost_unordered_IDEFILES})
file(GLOB_RECURSE headers CONFIGURE_DEPENDS include/*.hpp)
target_sources(boost_unordered PRIVATE ${headers})
unset(headers)
if(MSVC)
# Only Visual Studio needs this, but the generator may also be Ninja
target_sources(boost_unordered PUBLIC extra/boost_unordered.natvis)
endif()
# Make IDE project folders match directory structure
get_target_property(sources boost_unordered SOURCES)
source_group(TREE ${PROJECT_SOURCE_DIR} FILES ${sources})
unset(sources)
endif() endif()
+2 -2
View File
@@ -1,7 +1,7 @@
# Boost.Unordered # Boost.Unordered
[![Branch](https://img.shields.io/badge/branch-master-brightgreen.svg)](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) [![Drone status](https://img.shields.io/drone/build/boostorg/unordered/master?server=https%3A%2F%2Fdrone.cpp.al&logo=drone&logoColor=%23CCCCCC&label=CI)](https://drone.cpp.al/boostorg/unordered) [![Build status](https://img.shields.io/appveyor/build/cppalliance/unordered/master?logo=appveyor&label=CI)](https://ci.appveyor.com/project/cppalliance/unordered/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/index.html) [![Enter the Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/unordered.html)<br/> [![Branch](https://img.shields.io/badge/branch-master-brightgreen.svg)](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) [![Drone status](https://img.shields.io/drone/build/boostorg/unordered/master?server=https%3A%2F%2Fdrone.cpp.al&logo=drone&logoColor=%23CCCCCC&label=CI)](https://drone.cpp.al/boostorg/unordered) [![Build status](https://img.shields.io/appveyor/build/cppalliance/unordered/master?logo=appveyor&label=CI)](https://ci.appveyor.com/project/cppalliance/unordered/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/index.html) [![Enter the Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](https://regression.boost.org/master/developer/unordered.html)<br/>
[![Branch](https://img.shields.io/badge/branch-develop-brightgreen.svg)](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) [![Drone status](https://img.shields.io/drone/build/boostorg/unordered/develop?server=https%3A%2F%2Fdrone.cpp.al&logo=drone&logoColor=%23CCCCCC&label=CI)](https://drone.cpp.al/boostorg/unordered) [![Build status](https://img.shields.io/appveyor/build/cppalliance/unordered/develop?logo=appveyor&label=CI)](https://ci.appveyor.com/project/cppalliance/unordered/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/index.html) [![Enter the Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/unordered.html)<br/> [![Branch](https://img.shields.io/badge/branch-develop-brightgreen.svg)](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) [![Drone status](https://img.shields.io/drone/build/boostorg/unordered/develop?server=https%3A%2F%2Fdrone.cpp.al&logo=drone&logoColor=%23CCCCCC&label=CI)](https://drone.cpp.al/boostorg/unordered) [![Build status](https://img.shields.io/appveyor/build/cppalliance/unordered/develop?logo=appveyor&label=CI)](https://ci.appveyor.com/project/cppalliance/unordered/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/index.html) [![Enter the Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](https://regression.boost.org/develop/developer/unordered.html)<br/>
[![BSL 1.0](https://img.shields.io/badge/license-BSL_1.0-blue.svg)](https://www.boost.org/users/license.html) <img alt="C++11 required" src="https://img.shields.io/badge/standard-C%2b%2b11-blue.svg"> <img alt="Header-only library" src="https://img.shields.io/badge/build-header--only-blue.svg"> [![BSL 1.0](https://img.shields.io/badge/license-BSL_1.0-blue.svg)](https://www.boost.org/users/license.html) <img alt="C++11 required" src="https://img.shields.io/badge/standard-C%2b%2b11-blue.svg"> <img alt="Header-only library" src="https://img.shields.io/badge/build-header--only-blue.svg">
Boost.Unordered offers a catalog of hash containers with different standards compliance levels, performances and intented usage scenarios: Boost.Unordered offers a catalog of hash containers with different standards compliance levels, performances and intented usage scenarios:
+13 -42
View File
@@ -1,57 +1,28 @@
import generate ; # Copyright 2026 Joaquin M Lopez Munoz
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
import path ; import path ;
import property-set ;
import virtual-target ;
path-constant HERE : . ; make html_ : build_antora.sh : @run-script ;
make html/index.html : build_antora.sh : @run-script ;
generate files-to-install : html/index.html : <generating-rule>@delayed-glob ;
install install
: files-to-install
: <location>html
<install-source-root>html/unordered
;
explicit html/index.html files-to-install ;
# this runs the antora script
actions run-script actions run-script
{ {
bash $(>) bash $(>)
} }
# this globs after its sources are created path-constant DOC_DIR : . ;
rule delayed-glob ( project name : property-set : sources * ) .node_modules = [ path.join $(DOC_DIR) node_modules ] ;
make cleanup_node_modules_ : html_ : @cleanup-node-modules ;
actions cleanup-node-modules
{ {
for local src in $(sources) rm -rf $(.node_modules)
{
# the next line causes the source to be generated immediately
# and not later (which it normally would)
UPDATE_NOW [ $(src).actualize ] ;
}
# we need to construct the path to the globbed directory;
# this path would be <current-project>/antora
local root = [ path.root html [ $(project).location ] ] ;
local files ;
# actual globbing happens here
for local file in [ path.glob-tree $(root) : * ]
{
# we have to skip directories, because our match expression accepts anything
if [ CHECK_IF_FILE $(file) ]
{
# we construct a list of targets to copy
files += [ virtual-target.from-file $(file:D=) : $(file:D) : $(project) ] ;
}
}
# we prepend empty usage requirements to the result
return [ property-set.empty ] $(files) ;
} }
############################################################################### ###############################################################################
alias boostdoc ; alias boostdoc ;
explicit boostdoc ; explicit boostdoc ;
alias boostrelease : install ; alias boostrelease : html_ cleanup_node_modules_ ;
explicit boostrelease ; explicit boostrelease ;
-9
View File
@@ -1,9 +0,0 @@
#!/bin/bash
set -ex
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cd "$SCRIPT_DIR"
npm ci
npx antora unordered-playbook.yml
+1
View File
@@ -7,3 +7,4 @@ cd "$SCRIPT_DIR"
npm ci npm ci
npx antora unordered-playbook.yml npx antora unordered-playbook.yml
cp -f html/index.html html/unordered.html
+15
View File
@@ -6,6 +6,21 @@
:github-pr-url: https://github.com/boostorg/unordered/pull :github-pr-url: https://github.com/boostorg/unordered/pull
:cpp: C++ :cpp: C++
== Release 1.92.0
* Added interoperability with pass:[C++20] ranges to all the containers in the library:
`insert_range` (plus `insert_range_(or|and)_[c]visit` for concurrent containers),
`std::from_range` construction and associated CTAD deduction guides.
The `boost::unordered::from_range` construction tag is provided
as an alternative to pass:[C++23] `std::from_range` or when this is not available.
* Fixed a performance issue with closed-addressing containers when rehashing at very
large container sizes ({github-pr-url}/348[PR#348^]). Contributed by Daniel Kr&aacute;l.
== Release 1.91.0
* Fixed the returned value of range insertion in concurrent containers
({github-pr-url}/344[PR#344^]).
== Release 1.89.0 == Release 1.89.0
* Deprecated `boost::unordered::hash_is_avalanching` is now a using-declaration of * Deprecated `boost::unordered::hash_is_avalanching` is now a using-declaration of
+1 -1
View File
@@ -11,7 +11,7 @@ Copyright (C) 2005-2008 Daniel James
Copyright (C) 2022-2025 Christian Mazakas Copyright (C) 2022-2025 Christian Mazakas
Copyright (C) 2022-2025 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz Copyright (C) 2022-2026 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz
Copyright (C) 2022-2023 Peter Dimov Copyright (C) 2022-2023 Peter Dimov
@@ -77,6 +77,12 @@ namespace unordered {
xref:#concurrent_flat_map_copy_constructor_with_allocator[concurrent_flat_map](const concurrent_flat_map& other, const Allocator& a); xref:#concurrent_flat_map_copy_constructor_with_allocator[concurrent_flat_map](const concurrent_flat_map& other, const Allocator& a);
xref:#concurrent_flat_map_move_constructor_with_allocator[concurrent_flat_map](concurrent_flat_map&& other, const Allocator& a); xref:#concurrent_flat_map_move_constructor_with_allocator[concurrent_flat_map](concurrent_flat_map&& other, const Allocator& a);
xref:#concurrent_flat_map_move_constructor_from_unordered_flat_map[concurrent_flat_map](unordered_flat_map<Key, T, Hash, Pred, Allocator>&& other); xref:#concurrent_flat_map_move_constructor_from_unordered_flat_map[concurrent_flat_map](unordered_flat_map<Key, T, Hash, Pred, Allocator>&& other);
template<class FromRangeT, xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_flat_map_range_constructor[concurrent_flat_map](FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
xref:#concurrent_flat_map_initializer_list_constructor[concurrent_flat_map](std::initializer_list<value_type> il, xref:#concurrent_flat_map_initializer_list_constructor[concurrent_flat_map](std::initializer_list<value_type> il,
size_type n = _implementation-defined_ size_type n = _implementation-defined_
const hasher& hf = hasher(), const hasher& hf = hasher(),
@@ -90,6 +96,13 @@ namespace unordered {
template<class InputIterator> template<class InputIterator>
xref:#concurrent_flat_map_iterator_range_constructor_with_bucket_count_and_hasher[concurrent_flat_map](InputIterator f, InputIterator l, size_type n, const hasher& hf, xref:#concurrent_flat_map_iterator_range_constructor_with_bucket_count_and_hasher[concurrent_flat_map](InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a); const allocator_type& a);
template<class FromRangeT, xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_flat_map_range_constructor_with_allocator[concurrent_flat_map](FromRangeT&&, R&& rg, const allocator_type& a);
template<class FromRangeT, xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_flat_map_range_constructor_with_bucket_count_and_allocator[concurrent_flat_map](FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
template<class FromRangeT, xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_flat_map_range_constructor_with_bucket_count_and_hasher_and_allocator[concurrent_flat_map](FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
xref:#concurrent_flat_map_initializer_list_constructor_with_allocator[concurrent_flat_map](std::initializer_list<value_type> il, const allocator_type& a); xref:#concurrent_flat_map_initializer_list_constructor_with_allocator[concurrent_flat_map](std::initializer_list<value_type> il, const allocator_type& a);
xref:#concurrent_flat_map_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_flat_map](std::initializer_list<value_type> il, size_type n, xref:#concurrent_flat_map_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_flat_map](std::initializer_list<value_type> il, size_type n,
const allocator_type& a); const allocator_type& a);
@@ -152,6 +165,8 @@ namespace unordered {
bool xref:#concurrent_flat_map_move_insert[insert](value_type&& obj); bool xref:#concurrent_flat_map_move_insert[insert](value_type&& obj);
bool xref:#concurrent_flat_map_move_insert[insert](init_type&& obj); bool xref:#concurrent_flat_map_move_insert[insert](init_type&& obj);
template<class InputIterator> size_type xref:#concurrent_flat_map_insert_iterator_range[insert](InputIterator first, InputIterator last); template<class InputIterator> size_type xref:#concurrent_flat_map_insert_iterator_range[insert](InputIterator first, InputIterator last);
template<xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
size_type xref:#concurrent_flat_map_insert_range[insert_range](R&& rg);
size_type xref:#concurrent_flat_map_insert_initializer_list[insert](std::initializer_list<value_type> il); size_type xref:#concurrent_flat_map_insert_initializer_list[insert](std::initializer_list<value_type> il);
template<class... Args, class F> bool xref:#concurrent_flat_map_emplace_or_cvisit[emplace_or_visit](Args&&... args, F&& f); template<class... Args, class F> bool xref:#concurrent_flat_map_emplace_or_cvisit[emplace_or_visit](Args&&... args, F&& f);
@@ -168,6 +183,10 @@ namespace unordered {
size_type xref:#concurrent_flat_map_insert_iterator_range_or_visit[insert_or_visit](InputIterator first, InputIterator last, F f); size_type xref:#concurrent_flat_map_insert_iterator_range_or_visit[insert_or_visit](InputIterator first, InputIterator last, F f);
template<class InputIterator,class F> template<class InputIterator,class F>
size_type xref:#concurrent_flat_map_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f); size_type xref:#concurrent_flat_map_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f);
template<xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type xref:#concurrent_flat_map_insert_range_or_visit[insert_range_or_visit](R&& rg, F f);
template<xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type xref:#concurrent_flat_map_insert_range_or_visit[insert_range_or_cvisit](R&& rg, F f);
template<class F> size_type xref:#concurrent_flat_map_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list<value_type> il, F f); template<class F> size_type xref:#concurrent_flat_map_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list<value_type> il, F f);
template<class F> size_type xref:#concurrent_flat_map_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list<value_type> il, F f); template<class F> size_type xref:#concurrent_flat_map_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list<value_type> il, F f);
@@ -187,6 +206,10 @@ namespace unordered {
size_type xref:#concurrent_flat_map_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2); size_type xref:#concurrent_flat_map_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2);
template<class InputIterator,class F1, class F2> template<class InputIterator,class F1, class F2>
size_type xref:#concurrent_flat_map_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2); size_type xref:#concurrent_flat_map_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2);
template<xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type xref:#concurrent_flat_map_insert_range_and_visit[insert_range_and_visit](R&& rg, F1 f1, F2 f2);
template<xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type xref:#concurrent_flat_map_insert_range_and_visit[insert_range_and_cvisit](R&& rg, F1 f1, F2 f2);
template<class F1, class F2> template<class F1, class F2>
size_type xref:#concurrent_flat_map_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list<value_type> il, F1 f1, F2 f2); size_type xref:#concurrent_flat_map_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list<value_type> il, F1 f1, F2 f2);
template<class F1, class F2> template<class F1, class F2>
@@ -282,6 +305,17 @@ namespace unordered {
-> concurrent_flat_map<xref:#concurrent_flat_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#concurrent_flat_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash, -> concurrent_flat_map<xref:#concurrent_flat_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#concurrent_flat_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
Pred, Allocator>; Pred, Allocator>;
template<xref:#concurrent_flat_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R,
class Hash = boost::hash<xref:#concurrent_flat_map_range_key_type[__range-key-type__]<R>>,
class Pred = std::equal_to<xref:#concurrent_flat_map_range_key_type[__range-key-type__]<R>>,
class Allocator = std::allocator<xref:#concurrent_flat_map_range_to_alloc_type[__range-to-alloc-type__]<R>>>
concurrent_flat_map(FromRangeT&&, R&&,
typename xref:#concurrent_flat_map_deduction_guides[__see below__]::size_type = xref:#concurrent_flat_map_deduction_guides[__see below__], Hash = Hash(),
Pred = Pred(), Allocator = Allocator())
-> concurrent_flat_map<xref:#concurrent_flat_map_range_key_type[__range-key-type__]<R>, xref:#concurrent_flat_map_range_mapped_type[__range-mapped-type__]<R>,
Hash, Pred,Allocator>;
template<class Key, class T, class Hash = boost::hash<Key>, template<class Key, class T, class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>, class Pred = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<const Key, T>>> class Allocator = std::allocator<std::pair<const Key, T>>>
@@ -308,6 +342,27 @@ namespace unordered {
-> concurrent_flat_map<xref:#concurrent_flat_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#concurrent_flat_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash, -> concurrent_flat_map<xref:#concurrent_flat_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#concurrent_flat_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
std::equal_to<xref:#concurrent_flat_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>; std::equal_to<xref:#concurrent_flat_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
template<xref:#concurrent_flat_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
concurrent_flat_map(FromRangeT&&, R&&, typename xref:#concurrent_flat_map_deduction_guides[__see below__]::size_type, Allocator)
-> concurrent_flat_map<xref:#concurrent_flat_map_range_key_type[__range-key-type__]<R>, xref:#concurrent_flat_map_range_mapped_type[__range-mapped-type__]<R>,
boost::hash<xref:#concurrent_flat_map_range_key_type[__range-key-type__]<R>>,
std::equal_to<xref:#concurrent_flat_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<xref:#concurrent_flat_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
concurrent_flat_map(FromRangeT&&, R&&, Allocator)
-> concurrent_flat_map<xref:#concurrent_flat_map_range_key_type[__range-key-type__]<R>, xref:#concurrent_flat_map_range_mapped_type[__range-mapped-type__]<R>,
boost::hash<xref:#concurrent_flat_map_range_key_type[__range-key-type__]<R>>,
std::equal_to<xref:#concurrent_flat_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<xref:#concurrent_flat_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Hash, class Allocator>
concurrent_flat_map(FromRangeT&&, R&&, typename xref:#concurrent_flat_map_deduction_guides[__see below__]::size_type, Hash,
Allocator)
-> concurrent_flat_map<xref:#concurrent_flat_map_range_key_type[__range-key-type__]<R>, xref:#concurrent_flat_map_range_mapped_type[__range-mapped-type__]<R>,
Hash, std::equal_to<xref:#concurrent_flat_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<class Key, class T, class Allocator> template<class Key, class T, class Allocator>
concurrent_flat_map(std::initializer_list<std::pair<Key, T>>, typename xref:#concurrent_flat_map_deduction_guides[__see below__]::size_type, concurrent_flat_map(std::initializer_list<std::pair<Key, T>>, typename xref:#concurrent_flat_map_deduction_guides[__see below__]::size_type,
Allocator) Allocator)
@@ -444,6 +499,15 @@ Chunk size internally used in xref:concurrent_flat_map_bulk_visit[bulk visit] op
=== Constructors === Constructors
==== __container-compatible-range__
[listings,subs="+macros,+quotes"]
-----
template<class R, class T>
concept container_compatible_range =
std::ranges::input_range<R> &&
std::convertible_to<std::ranges::range_reference_t<R>, T>; // exposition only
-----
==== Default Constructor ==== Default Constructor
```c++ ```c++
concurrent_flat_map(); concurrent_flat_map();
@@ -591,6 +655,27 @@ Complexity:;; O(`bucket_count()`)
--- ---
==== Range Constructor
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_flat_map(FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
----
Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Initializer List Constructor ==== Initializer List Constructor
[source,c++,subs="+quotes"] [source,c++,subs="+quotes"]
---- ----
@@ -663,6 +748,58 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/
--- ---
==== Range Constructor with Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_flat_map(FromRangeT&&, R&& rg, const allocator_type& a);
----
Constructs an empty table using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_flat_map(FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
----
Constructs an empty table with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Hasher and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_flat_map(FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
----
Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== initializer_list Constructor with Allocator ==== initializer_list Constructor with Allocator
```c++ ```c++
@@ -696,7 +833,7 @@ concurrent_flat_map(std::initializer_list<value_type> il, size_type n, const has
const allocator_type& a); const allocator_type& a);
``` ```
Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate,and inserts the elements from `il` into it. Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate, and inserts the elements from `il` into it.
[horizontal] [horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
@@ -925,8 +1062,7 @@ size_type size() const noexcept;
[horizontal] [horizontal]
Returns:;; The number of elements in the table. Returns:;; The number of elements in the table.
Complexity:;; Constant time.
[horizontal]
Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect
the true size of the table right after execution. the true size of the table right after execution.
@@ -1014,6 +1150,24 @@ Returns:;; The number of elements inserted.
--- ---
==== Insert Range
[source,c++,subs="+macros,+quotes"]
----
template<xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
void insert_range(R&& rg);
----
Equivalent to
[listing,subs="+macros,+quotes"]
-----
for(auto&& x: rg) this->xref:#concurrent_flat_map_emplace[emplace](std::forward<decltype(x)>(x));
-----
[horizontal]
Returns:;; The number of elements inserted.
---
==== Insert Initializer List ==== Insert Initializer List
```c++ ```c++
size_type insert(std::initializer_list<value_type> il); size_type insert(std::initializer_list<value_type> il);
@@ -1096,9 +1250,9 @@ only if `std::remove_reference<decltype(obj)>::type` is `value_type`.
==== Insert Iterator Range or Visit ==== Insert Iterator Range or Visit
```c++ ```c++
template<class InputIterator,class F> template<class InputIterator,class F>
size_type insert_or_visit(InputIterator first, InputIterator last, F f); size_type insert_or_visit(InputIterator first, InputIterator last, F f);
template<class InputIterator,class F> template<class InputIterator,class F>
size_type insert_or_cvisit(InputIterator first, InputIterator last, F f); size_type insert_or_cvisit(InputIterator first, InputIterator last, F f);
``` ```
Equivalent to Equivalent to
@@ -1112,6 +1266,27 @@ Returns:;; The number of elements inserted.
--- ---
==== Insert Range or Visit
[source,c++,subs="+macros,+quotes"]
----
template<xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type insert_range_or_visit(R&& rg, F f);
template<xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type insert_range_or_visit(R&& rg, F f);
----
Equivalent to
[listing,subs="+macros,+quotes"]
-----
for(auto&& x: rg)
this->xref:#concurrent_flat_map_emplace_or_cvisit[emplace_or_[c\]visit](std::forward<decltype(x)>(x), std::ref(f));
-----
[horizontal]
Returns:;; The number of elements inserted.
---
==== Insert Initializer List or Visit ==== Insert Initializer List or Visit
```c++ ```c++
template<class F> size_type insert_or_visit(std::initializer_list<value_type> il, F f); template<class F> size_type insert_or_visit(std::initializer_list<value_type> il, F f);
@@ -1216,6 +1391,28 @@ Returns:;; The number of elements inserted.
--- ---
==== Insert Range and Visit
[source,c++,subs="+macros,+quotes"]
----
template<xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type insert_range_and_visit(R&& rg, F1 f1, F2 f2);
template<xref:#concurrent_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type insert_range_and_cvisit(R&& rg, F1 f1, F2 f2);
----
Equivalent to
[listing,subs="+macros,+quotes"]
-----
for(auto&& x: rg)
this->xref:#concurrent_flat_map_emplace_and_cvisit[emplace_and_[c\]visit](
std::forward<decltype(x)>(x), std::ref(f1), std::ref(f2));
-----
[horizontal]
Returns:;; The number of elements inserted.
---
==== Insert Initializer List and Visit ==== Insert Initializer List and Visit
```c++ ```c++
template<class F1, class F2> template<class F1, class F2>
@@ -1743,6 +1940,42 @@ template<class InputIterator>
std::tuple_element_t<1, xref:#concurrent_flat_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only std::tuple_element_t<1, xref:#concurrent_flat_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only
----- -----
==== __convertible-to-from-range_t__
[listings,subs="+macros,+quotes"]
-----
template<typename FromRangeT>
concept __convertible-to-from_range_t__ =
// first clause not present if std::from_range_t does not exist
std::is_convertible_v<FromRangeT, std::from_range_t> ||
std::is_convertible_v<FromRangeT, boost::unordered::from_range_t>; // exposition only
-----
==== __range-key-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-key-type__ =
std::remove_cvref_t<
std::tuple_element_t<0, std::ranges::range_value_t<R>>>; // exposition only
-----
==== __range-mapped-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-mapped-type__ =
std::remove_cvref_t<
std::tuple_element_t<1, std::ranges::range_value_t<R>>>; // exposition only
-----
==== __range-to-alloc-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-to-alloc-type__ =
std::pair<const xref:#concurrent_flat_map_range_key_type[__range-key-type__]<R>, xref:#concurrent_flat_map_range_mapped_type[__range-mapped-type__]<R>>; // exposition only
-----
=== Equality Comparisons === Equality Comparisons
==== operator== ==== operator==
@@ -72,6 +72,12 @@ namespace unordered {
xref:#concurrent_flat_set_copy_constructor_with_allocator[concurrent_flat_set](const concurrent_flat_set& other, const Allocator& a); xref:#concurrent_flat_set_copy_constructor_with_allocator[concurrent_flat_set](const concurrent_flat_set& other, const Allocator& a);
xref:#concurrent_flat_set_move_constructor_with_allocator[concurrent_flat_set](concurrent_flat_set&& other, const Allocator& a); xref:#concurrent_flat_set_move_constructor_with_allocator[concurrent_flat_set](concurrent_flat_set&& other, const Allocator& a);
xref:#concurrent_flat_set_move_constructor_from_unordered_flat_set[concurrent_flat_set](unordered_flat_set<Key, Hash, Pred, Allocator>&& other); xref:#concurrent_flat_set_move_constructor_from_unordered_flat_set[concurrent_flat_set](unordered_flat_set<Key, Hash, Pred, Allocator>&& other);
template<class FromRangeT, xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_flat_set_range_constructor[concurrent_flat_set](FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
xref:#concurrent_flat_set_initializer_list_constructor[concurrent_flat_set](std::initializer_list<value_type> il, xref:#concurrent_flat_set_initializer_list_constructor[concurrent_flat_set](std::initializer_list<value_type> il,
size_type n = _implementation-defined_ size_type n = _implementation-defined_
const hasher& hf = hasher(), const hasher& hf = hasher(),
@@ -85,6 +91,13 @@ namespace unordered {
template<class InputIterator> template<class InputIterator>
xref:#concurrent_flat_set_iterator_range_constructor_with_bucket_count_and_hasher[concurrent_flat_set](InputIterator f, InputIterator l, size_type n, const hasher& hf, xref:#concurrent_flat_set_iterator_range_constructor_with_bucket_count_and_hasher[concurrent_flat_set](InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a); const allocator_type& a);
template<class FromRangeT, xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_flat_set_range_constructor_with_allocator[concurrent_flat_set](FromRangeT&&, R&& rg, const allocator_type& a);
template<class FromRangeT, xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_flat_set_range_constructor_with_bucket_count_and_allocator[concurrent_flat_set](FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
template<class FromRangeT, xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_flat_set_range_constructor_with_bucket_count_and_hasher_and_allocator[concurrent_flat_set](FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
xref:#concurrent_flat_set_initializer_list_constructor_with_allocator[concurrent_flat_set](std::initializer_list<value_type> il, const allocator_type& a); xref:#concurrent_flat_set_initializer_list_constructor_with_allocator[concurrent_flat_set](std::initializer_list<value_type> il, const allocator_type& a);
xref:#concurrent_flat_set_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_flat_set](std::initializer_list<value_type> il, size_type n, xref:#concurrent_flat_set_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_flat_set](std::initializer_list<value_type> il, size_type n,
const allocator_type& a); const allocator_type& a);
@@ -145,6 +158,8 @@ namespace unordered {
bool xref:#concurrent_flat_set_move_insert[insert](value_type&& obj); bool xref:#concurrent_flat_set_move_insert[insert](value_type&& obj);
template<class K> bool xref:#concurrent_flat_set_transparent_insert[insert](K&& k); template<class K> bool xref:#concurrent_flat_set_transparent_insert[insert](K&& k);
template<class InputIterator> size_type xref:#concurrent_flat_set_insert_iterator_range[insert](InputIterator first, InputIterator last); template<class InputIterator> size_type xref:#concurrent_flat_set_insert_iterator_range[insert](InputIterator first, InputIterator last);
template<xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
size_type xref:#concurrent_flat_set_insert_range[insert_range](R&& rg);
size_type xref:#concurrent_flat_set_insert_initializer_list[insert](std::initializer_list<value_type> il); size_type xref:#concurrent_flat_set_insert_initializer_list[insert](std::initializer_list<value_type> il);
template<class... Args, class F> bool xref:#concurrent_flat_set_emplace_or_cvisit[emplace_or_visit](Args&&... args, F&& f); template<class... Args, class F> bool xref:#concurrent_flat_set_emplace_or_cvisit[emplace_or_visit](Args&&... args, F&& f);
@@ -159,6 +174,10 @@ namespace unordered {
size_type xref:#concurrent_flat_set_insert_iterator_range_or_visit[insert_or_visit](InputIterator first, InputIterator last, F f); size_type xref:#concurrent_flat_set_insert_iterator_range_or_visit[insert_or_visit](InputIterator first, InputIterator last, F f);
template<class InputIterator,class F> template<class InputIterator,class F>
size_type xref:#concurrent_flat_set_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f); size_type xref:#concurrent_flat_set_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f);
template<xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type xref:#concurrent_flat_set_insert_range_or_visit[insert_range_or_visit](R&& rg, F f);
template<xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type xref:#concurrent_flat_set_insert_range_or_visit[insert_range_or_cvisit](R&& rg, F f);
template<class F> size_type xref:#concurrent_flat_set_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list<value_type> il, F f); template<class F> size_type xref:#concurrent_flat_set_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list<value_type> il, F f);
template<class F> size_type xref:#concurrent_flat_set_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list<value_type> il, F f); template<class F> size_type xref:#concurrent_flat_set_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list<value_type> il, F f);
@@ -176,6 +195,10 @@ namespace unordered {
size_type xref:#concurrent_flat_set_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2); size_type xref:#concurrent_flat_set_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2);
template<class InputIterator,class F1, class F2> template<class InputIterator,class F1, class F2>
size_type xref:#concurrent_flat_set_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2); size_type xref:#concurrent_flat_set_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2);
template<xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type xref:#concurrent_flat_set_insert_range_and_visit[insert_range_and_visit](R&& rg, F1 f1, F2 f2);
template<xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type xref:#concurrent_flat_set_insert_range_and_visit[insert_range_and_cvisit](R&& rg, F1 f1, F2 f2);
template<class F1, class F2> template<class F1, class F2>
size_type xref:#concurrent_flat_set_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list<value_type> il, F1 f1, F2 f2); size_type xref:#concurrent_flat_set_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list<value_type> il, F1 f1, F2 f2);
template<class F1, class F2> template<class F1, class F2>
@@ -236,6 +259,16 @@ namespace unordered {
Hash = Hash(), Pred = Pred(), Allocator = Allocator()) Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> concurrent_flat_set<xref:#concurrent_flat_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>; -> concurrent_flat_set<xref:#concurrent_flat_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>;
template<xref:#concurrent_flat_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R,
class Hash = boost::hash<std::ranges::range_value_t<R>>,
class Pred = std::equal_to<std::ranges::range_value_t<R>>,
class Allocator = std::allocator<std::ranges::range_value_t<R>>
concurrent_flat_set(FromRangeT&&, R&&,
typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type = xref:#concurrent_flat_set_deduction_guides[__see below__], Hash = Hash(),
Pred = Pred(), Allocator = Allocator())
-> concurrent_flat_set<std::ranges::range_value_t<R>, Hash, Pred,Allocator>;
template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>, template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>,
class Allocator = std::allocator<T>> class Allocator = std::allocator<T>>
concurrent_flat_set(std::initializer_list<T>, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type = xref:#concurrent_flat_set_deduction_guides[__see below__], concurrent_flat_set(std::initializer_list<T>, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type = xref:#concurrent_flat_set_deduction_guides[__see below__],
@@ -260,6 +293,27 @@ namespace unordered {
-> concurrent_flat_set<xref:#concurrent_flat_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, -> concurrent_flat_set<xref:#concurrent_flat_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash,
std::equal_to<xref:#concurrent_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>; std::equal_to<xref:#concurrent_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
template<xref:#concurrent_flat_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
concurrent_flat_set(FromRangeT&&, R&&, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type, Allocator)
-> concurrent_flat_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R>>,
std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<xref:#concurrent_flat_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
concurrent_flat_set(FromRangeT&&, R&&, Allocator)
-> concurrent_flat_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R>>,
std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<xref:#concurrent_flat_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Hash, class Allocator>
concurrent_flat_set(FromRangeT&&, R&&, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type, Hash,
Allocator)
-> concurrent_flat_set<std::ranges::range_value_t<R>,
Hash, std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<class T, class Allocator> template<class T, class Allocator>
concurrent_flat_set(std::initializer_list<T>, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type, Allocator) concurrent_flat_set(std::initializer_list<T>, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type, Allocator)
-> concurrent_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>; -> concurrent_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
@@ -391,6 +445,15 @@ Chunk size internally used in xref:concurrent_flat_set_bulk_visit[bulk visit] op
=== Constructors === Constructors
==== __container-compatible-range__
[listings,subs="+macros,+quotes"]
-----
template<class R, class T>
concept container_compatible_range =
std::ranges::input_range<R> &&
std::convertible_to<std::ranges::range_reference_t<R>, T>; // exposition only
-----
==== Default Constructor ==== Default Constructor
```c++ ```c++
concurrent_flat_set(); concurrent_flat_set();
@@ -538,6 +601,27 @@ Complexity:;; O(`bucket_count()`)
--- ---
==== Range Constructor
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_flat_set(FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
----
Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Initializer List Constructor ==== Initializer List Constructor
[source,c++,subs="+quotes"] [source,c++,subs="+quotes"]
---- ----
@@ -610,6 +694,58 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/
--- ---
==== Range Constructor with Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_flat_set(FromRangeT&&, R&& rg, const allocator_type& a);
----
Constructs an empty table using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_flat_set(FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
----
Constructs an empty table with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Hasher and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_flat_set(FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
----
Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== initializer_list Constructor with Allocator ==== initializer_list Constructor with Allocator
```c++ ```c++
@@ -643,7 +779,7 @@ concurrent_flat_set(std::initializer_list<value_type> il, size_type n, const has
const allocator_type& a); const allocator_type& a);
``` ```
Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate,and inserts the elements from `il` into it. Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate, and inserts the elements from `il` into it.
[horizontal] [horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
@@ -866,8 +1002,7 @@ size_type size() const noexcept;
[horizontal] [horizontal]
Returns:;; The number of elements in the table. Returns:;; The number of elements in the table.
Complexity:;; Constant time.
[horizontal]
Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect
the true size of the table right after execution. the true size of the table right after execution.
@@ -964,6 +1099,24 @@ Returns:;; The number of elements inserted.
--- ---
==== Insert Range
[source,c++,subs="+macros,+quotes"]
----
template<xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
void insert_range(R&& rg);
----
Equivalent to
[listing,subs="+macros,+quotes"]
-----
for(auto&& x: rg) this->xref:#concurrent_flat_set_emplace[emplace](std::forward<decltype(x)>(x));
-----
[horizontal]
Returns:;; The number of elements inserted.
---
==== Insert Initializer List ==== Insert Initializer List
```c++ ```c++
size_type insert(std::initializer_list<value_type> il); size_type insert(std::initializer_list<value_type> il);
@@ -1071,6 +1224,27 @@ Returns:;; The number of elements inserted.
--- ---
==== Insert Range or Visit
[source,c++,subs="+macros,+quotes"]
----
template<xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type insert_range_or_visit(R&& rg, F f);
template<xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type insert_range_or_visit(R&& rg, F f);
----
Equivalent to
[listing,subs="+macros,+quotes"]
-----
for(auto&& x: rg)
this->xref:#concurrent_flat_set_emplace_or_cvisit[emplace_or_[c\]visit](std::forward<decltype(x)>(x), std::ref(f));
-----
[horizontal]
Returns:;; The number of elements inserted.
---
==== Insert Initializer List or Visit ==== Insert Initializer List or Visit
```c++ ```c++
template<class F> size_type insert_or_visit(std::initializer_list<value_type> il, F f); template<class F> size_type insert_or_visit(std::initializer_list<value_type> il, F f);
@@ -1185,6 +1359,28 @@ Returns:;; The number of elements inserted.
--- ---
==== Insert Range and Visit
[source,c++,subs="+macros,+quotes"]
----
template<xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type insert_range_and_visit(R&& rg, F1 f1, F2 f2);
template<xref:#concurrent_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type insert_range_and_cvisit(R&& rg, F1 f1, F2 f2);
----
Equivalent to
[listing,subs="+macros,+quotes"]
-----
for(auto&& x: rg)
this->xref:#concurrent_flat_set_emplace_and_cvisit[emplace_and_[c\]visit](
std::forward<decltype(x)>(x), std::ref(f1), std::ref(f2));
-----
[horizontal]
Returns:;; The number of elements inserted.
---
==== Insert Initializer List and Visit ==== Insert Initializer List and Visit
```c++ ```c++
template<class F1, class F2> template<class F1, class F2>
@@ -1517,6 +1713,16 @@ template<class InputIterator>
typename std::iterator_traits<InputIterator>::value_type; // exposition only typename std::iterator_traits<InputIterator>::value_type; // exposition only
----- -----
==== __convertible-to-from-range_t__
[listings,subs="+macros,+quotes"]
-----
template<typename FromRangeT>
concept __convertible-to-from_range_t__ =
// first clause not present if std::from_range_t does not exist
std::is_convertible_v<FromRangeT, std::from_range_t> ||
std::is_convertible_v<FromRangeT, boost::unordered::from_range_t>; // exposition only
-----
=== Equality Comparisons === Equality Comparisons
==== operator== ==== operator==
@@ -80,6 +80,12 @@ namespace unordered {
xref:#concurrent_node_map_copy_constructor_with_allocator[concurrent_node_map](const concurrent_node_map& other, const Allocator& a); xref:#concurrent_node_map_copy_constructor_with_allocator[concurrent_node_map](const concurrent_node_map& other, const Allocator& a);
xref:#concurrent_node_map_move_constructor_with_allocator[concurrent_node_map](concurrent_node_map&& other, const Allocator& a); xref:#concurrent_node_map_move_constructor_with_allocator[concurrent_node_map](concurrent_node_map&& other, const Allocator& a);
xref:#concurrent_node_map_move_constructor_from_unordered_node_map[concurrent_node_map](unordered_node_map<Key, T, Hash, Pred, Allocator>&& other); xref:#concurrent_node_map_move_constructor_from_unordered_node_map[concurrent_node_map](unordered_node_map<Key, T, Hash, Pred, Allocator>&& other);
template<class FromRangeT, xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_node_map_range_constructor[concurrent_node_map](FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
xref:#concurrent_node_map_initializer_list_constructor[concurrent_node_map](std::initializer_list<value_type> il, xref:#concurrent_node_map_initializer_list_constructor[concurrent_node_map](std::initializer_list<value_type> il,
size_type n = _implementation-defined_ size_type n = _implementation-defined_
const hasher& hf = hasher(), const hasher& hf = hasher(),
@@ -93,6 +99,13 @@ namespace unordered {
template<class InputIterator> template<class InputIterator>
xref:#concurrent_node_map_iterator_range_constructor_with_bucket_count_and_hasher[concurrent_node_map](InputIterator f, InputIterator l, size_type n, const hasher& hf, xref:#concurrent_node_map_iterator_range_constructor_with_bucket_count_and_hasher[concurrent_node_map](InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a); const allocator_type& a);
template<class FromRangeT, xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_node_map_range_constructor_with_allocator[concurrent_node_map](FromRangeT&&, R&& rg, const allocator_type& a);
template<class FromRangeT, xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_node_map_range_constructor_with_bucket_count_and_allocator[concurrent_node_map](FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
template<class FromRangeT, xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_node_map_range_constructor_with_bucket_count_and_hasher_and_allocator[concurrent_node_map](FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
xref:#concurrent_node_map_initializer_list_constructor_with_allocator[concurrent_node_map](std::initializer_list<value_type> il, const allocator_type& a); xref:#concurrent_node_map_initializer_list_constructor_with_allocator[concurrent_node_map](std::initializer_list<value_type> il, const allocator_type& a);
xref:#concurrent_node_map_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_node_map](std::initializer_list<value_type> il, size_type n, xref:#concurrent_node_map_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_node_map](std::initializer_list<value_type> il, size_type n,
const allocator_type& a); const allocator_type& a);
@@ -155,6 +168,8 @@ namespace unordered {
bool xref:#concurrent_node_map_move_insert[insert](value_type&& obj); bool xref:#concurrent_node_map_move_insert[insert](value_type&& obj);
bool xref:#concurrent_node_map_move_insert[insert](init_type&& obj); bool xref:#concurrent_node_map_move_insert[insert](init_type&& obj);
template<class InputIterator> size_type xref:#concurrent_node_map_insert_iterator_range[insert](InputIterator first, InputIterator last); template<class InputIterator> size_type xref:#concurrent_node_map_insert_iterator_range[insert](InputIterator first, InputIterator last);
template<xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
size_type xref:#concurrent_node_map_insert_range[insert_range](R&& rg);
size_type xref:#concurrent_node_map_insert_initializer_list[insert](std::initializer_list<value_type> il); size_type xref:#concurrent_node_map_insert_initializer_list[insert](std::initializer_list<value_type> il);
insert_return_type xref:#concurrent_node_map_insert_node[insert](node_type&& nh); insert_return_type xref:#concurrent_node_map_insert_node[insert](node_type&& nh);
@@ -172,6 +187,10 @@ namespace unordered {
size_type xref:#concurrent_node_map_insert_iterator_range_or_visit[insert_or_visit](InputIterator first, InputIterator last, F f); size_type xref:#concurrent_node_map_insert_iterator_range_or_visit[insert_or_visit](InputIterator first, InputIterator last, F f);
template<class InputIterator,class F> template<class InputIterator,class F>
size_type xref:#concurrent_node_map_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f); size_type xref:#concurrent_node_map_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f);
template<xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type xref:#concurrent_node_map_insert_range_or_visit[insert_range_or_visit](R&& rg, F f);
template<xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type xref:#concurrent_node_map_insert_range_or_visit[insert_range_or_cvisit](R&& rg, F f);
template<class F> size_type xref:#concurrent_node_map_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list<value_type> il, F f); template<class F> size_type xref:#concurrent_node_map_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list<value_type> il, F f);
template<class F> size_type xref:#concurrent_node_map_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list<value_type> il, F f); template<class F> size_type xref:#concurrent_node_map_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list<value_type> il, F f);
template<class F> insert_return_type xref:#concurrent_node_map_insert_node_or_visit[insert_or_visit](node_type&& nh, F f); template<class F> insert_return_type xref:#concurrent_node_map_insert_node_or_visit[insert_or_visit](node_type&& nh, F f);
@@ -193,6 +212,10 @@ namespace unordered {
size_type xref:#concurrent_node_map_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2); size_type xref:#concurrent_node_map_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2);
template<class InputIterator,class F1, class F2> template<class InputIterator,class F1, class F2>
size_type xref:#concurrent_node_map_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2); size_type xref:#concurrent_node_map_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2);
template<xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type xref:#concurrent_node_map_insert_range_and_visit[insert_range_and_visit](R&& rg, F1 f1, F2 f2);
template<xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type xref:#concurrent_node_map_insert_range_and_visit[insert_range_and_cvisit](R&& rg, F1 f1, F2 f2);
template<class F1, class F2> template<class F1, class F2>
size_type xref:#concurrent_node_map_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list<value_type> il, F1 f1, F2 f2); size_type xref:#concurrent_node_map_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list<value_type> il, F1 f1, F2 f2);
template<class F1, class F2> template<class F1, class F2>
@@ -300,6 +323,17 @@ namespace unordered {
-> concurrent_node_map<xref:#concurrent_node_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#concurrent_node_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash, -> concurrent_node_map<xref:#concurrent_node_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#concurrent_node_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
Pred, Allocator>; Pred, Allocator>;
template<xref:#concurrent_node_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R,
class Hash = boost::hash<xref:#concurrent_node_map_range_key_type[__range-key-type__]<R>>,
class Pred = std::equal_to<xref:#concurrent_node_map_range_key_type[__range-key-type__]<R>>,
class Allocator = std::allocator<xref:#concurrent_node_map_range_to_alloc_type[__range-to-alloc-type__]<R>>>
concurrent_node_map(FromRangeT&&, R&&,
typename xref:#concurrent_node_map_deduction_guides[__see below__]::size_type = xref:#concurrent_node_map_deduction_guides[__see below__], Hash = Hash(),
Pred = Pred(), Allocator = Allocator())
-> concurrent_node_map<xref:#concurrent_node_map_range_key_type[__range-key-type__]<R>, xref:#concurrent_node_map_range_mapped_type[__range-mapped-type__]<R>,
Hash, Pred,Allocator>;
template<class Key, class T, class Hash = boost::hash<Key>, template<class Key, class T, class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>, class Pred = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<const Key, T>>> class Allocator = std::allocator<std::pair<const Key, T>>>
@@ -326,6 +360,27 @@ namespace unordered {
-> concurrent_node_map<xref:#concurrent_node_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#concurrent_node_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash, -> concurrent_node_map<xref:#concurrent_node_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#concurrent_node_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
std::equal_to<xref:#concurrent_node_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>; std::equal_to<xref:#concurrent_node_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
template<xref:#concurrent_node_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
concurrent_node_map(FromRangeT&&, R&&, typename xref:#concurrent_node_map_deduction_guides[__see below__]::size_type, Allocator)
-> concurrent_node_map<xref:#concurrent_node_map_range_key_type[__range-key-type__]<R>, xref:#concurrent_node_map_range_mapped_type[__range-mapped-type__]<R>,
boost::hash<xref:#concurrent_node_map_range_key_type[__range-key-type__]<R>>,
std::equal_to<xref:#concurrent_node_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<xref:#concurrent_node_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
concurrent_node_map(FromRangeT&&, R&&, Allocator)
-> concurrent_node_map<xref:#concurrent_node_map_range_key_type[__range-key-type__]<R>, xref:#concurrent_node_map_range_mapped_type[__range-mapped-type__]<R>,
boost::hash<xref:#concurrent_node_map_range_key_type[__range-key-type__]<R>>,
std::equal_to<xref:#concurrent_node_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<xref:#concurrent_node_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Hash, class Allocator>
concurrent_node_map(FromRangeT&&, R&&, typename xref:#concurrent_node_map_deduction_guides[__see below__]::size_type, Hash,
Allocator)
-> concurrent_node_map<xref:#concurrent_node_map_range_key_type[__range-key-type__]<R>, xref:#concurrent_node_map_range_mapped_type[__range-mapped-type__]<R>,
Hash, std::equal_to<xref:#concurrent_node_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<class Key, class T, class Allocator> template<class Key, class T, class Allocator>
concurrent_node_map(std::initializer_list<std::pair<Key, T>>, typename xref:#concurrent_node_map_deduction_guides[__see below__]::size_type, concurrent_node_map(std::initializer_list<std::pair<Key, T>>, typename xref:#concurrent_node_map_deduction_guides[__see below__]::size_type,
Allocator) Allocator)
@@ -496,6 +551,15 @@ Chunk size internally used in xref:concurrent_node_map_bulk_visit[bulk visit] op
=== Constructors === Constructors
==== __container-compatible-range__
[listings,subs="+macros,+quotes"]
-----
template<class R, class T>
concept container_compatible_range =
std::ranges::input_range<R> &&
std::convertible_to<std::ranges::range_reference_t<R>, T>; // exposition only
-----
==== Default Constructor ==== Default Constructor
```c++ ```c++
concurrent_node_map(); concurrent_node_map();
@@ -643,6 +707,27 @@ Complexity:;; O(`bucket_count()`)
--- ---
==== Range Constructor
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_node_map(FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
----
Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Initializer List Constructor ==== Initializer List Constructor
[source,c++,subs="+quotes"] [source,c++,subs="+quotes"]
---- ----
@@ -715,6 +800,58 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/
--- ---
==== Range Constructor with Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_node_map(FromRangeT&&, R&& rg, const allocator_type& a);
----
Constructs an empty table using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_node_map(FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
----
Constructs an empty table with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Hasher and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_node_map(FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
----
Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== initializer_list Constructor with Allocator ==== initializer_list Constructor with Allocator
```c++ ```c++
@@ -977,8 +1114,7 @@ size_type size() const noexcept;
[horizontal] [horizontal]
Returns:;; The number of elements in the table. Returns:;; The number of elements in the table.
Complexity:;; Constant time.
[horizontal]
Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect
the true size of the table right after execution. the true size of the table right after execution.
@@ -1060,6 +1196,24 @@ Returns:;; The number of elements inserted.
--- ---
==== Insert Range
[source,c++,subs="+macros,+quotes"]
----
template<xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
void insert_range(R&& rg);
----
Equivalent to
[listing,subs="+macros,+quotes"]
-----
for(auto&& x: rg) this->xref:#concurrent_node_map_emplace[emplace](std::forward<decltype(x)>(x));
-----
[horizontal]
Returns:;; The number of elements inserted.
---
==== Insert Initializer List ==== Insert Initializer List
```c++ ```c++
size_type insert(std::initializer_list<value_type> il); size_type insert(std::initializer_list<value_type> il);
@@ -1171,6 +1325,27 @@ Returns:;; The number of elements inserted.
--- ---
==== Insert Range or Visit
[source,c++,subs="+macros,+quotes"]
----
template<xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type insert_range_or_visit(R&& rg, F f);
template<xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type insert_range_or_visit(R&& rg, F f);
----
Equivalent to
[listing,subs="+macros,+quotes"]
-----
for(auto&& x: rg)
this->xref:#concurrent_node_map_emplace_or_cvisit[emplace_or_[c\]visit](std::forward<decltype(x)>(x), std::ref(f));
-----
[horizontal]
Returns:;; The number of elements inserted.
---
==== Insert Initializer List or Visit ==== Insert Initializer List or Visit
```c++ ```c++
template<class F> size_type insert_or_visit(std::initializer_list<value_type> il, F f); template<class F> size_type insert_or_visit(std::initializer_list<value_type> il, F f);
@@ -1290,6 +1465,28 @@ Returns:;; The number of elements inserted.
--- ---
==== Insert Range and Visit
[source,c++,subs="+macros,+quotes"]
----
template<xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type insert_range_and_visit(R&& rg, F1 f1, F2 f2);
template<xref:#concurrent_node_map_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type insert_range_and_cvisit(R&& rg, F1 f1, F2 f2);
----
Equivalent to
[listing,subs="+macros,+quotes"]
-----
for(auto&& x: rg)
this->xref:#concurrent_node_map_emplace_and_cvisit[emplace_and_[c\]visit](
std::forward<decltype(x)>(x), std::ref(f1), std::ref(f2));
-----
[horizontal]
Returns:;; The number of elements inserted.
---
==== Insert Initializer List and Visit ==== Insert Initializer List and Visit
```c++ ```c++
template<class F1, class F2> template<class F1, class F2>
@@ -1859,6 +2056,42 @@ template<class InputIterator>
std::tuple_element_t<1, xref:#concurrent_node_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only std::tuple_element_t<1, xref:#concurrent_node_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only
----- -----
==== __convertible-to-from-range_t__
[listings,subs="+macros,+quotes"]
-----
template<typename FromRangeT>
concept __convertible-to-from_range_t__ =
// first clause not present if std::from_range_t does not exist
std::is_convertible_v<FromRangeT, std::from_range_t> ||
std::is_convertible_v<FromRangeT, boost::unordered::from_range_t>; // exposition only
-----
==== __range-key-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-key-type__ =
std::remove_cvref_t<
std::tuple_element_t<0, std::ranges::range_value_t<R>>>; // exposition only
-----
==== __range-mapped-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-mapped-type__ =
std::remove_cvref_t<
std::tuple_element_t<1, std::ranges::range_value_t<R>>>; // exposition only
-----
==== __range-to-alloc-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-to-alloc-type__ =
std::pair<const xref:#concurrent_node_map_range_key_type[__range-key-type__]<R>, xref:#concurrent_node_map_range_mapped_type[__range-mapped-type__]<R>>; // exposition only
-----
=== Equality Comparisons === Equality Comparisons
==== operator== ==== operator==
@@ -75,6 +75,12 @@ namespace unordered {
xref:#concurrent_node_set_copy_constructor_with_allocator[concurrent_node_set](const concurrent_node_set& other, const Allocator& a); xref:#concurrent_node_set_copy_constructor_with_allocator[concurrent_node_set](const concurrent_node_set& other, const Allocator& a);
xref:#concurrent_node_set_move_constructor_with_allocator[concurrent_node_set](concurrent_node_set&& other, const Allocator& a); xref:#concurrent_node_set_move_constructor_with_allocator[concurrent_node_set](concurrent_node_set&& other, const Allocator& a);
xref:#concurrent_node_set_move_constructor_from_unordered_node_set[concurrent_node_set](unordered_node_set<Key, Hash, Pred, Allocator>&& other); xref:#concurrent_node_set_move_constructor_from_unordered_node_set[concurrent_node_set](unordered_node_set<Key, Hash, Pred, Allocator>&& other);
template<class FromRangeT, xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_node_set_range_constructor[concurrent_node_set](FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
xref:#concurrent_node_set_initializer_list_constructor[concurrent_node_set](std::initializer_list<value_type> il, xref:#concurrent_node_set_initializer_list_constructor[concurrent_node_set](std::initializer_list<value_type> il,
size_type n = _implementation-defined_ size_type n = _implementation-defined_
const hasher& hf = hasher(), const hasher& hf = hasher(),
@@ -88,6 +94,13 @@ namespace unordered {
template<class InputIterator> template<class InputIterator>
xref:#concurrent_node_set_iterator_range_constructor_with_bucket_count_and_hasher[concurrent_node_set](InputIterator f, InputIterator l, size_type n, const hasher& hf, xref:#concurrent_node_set_iterator_range_constructor_with_bucket_count_and_hasher[concurrent_node_set](InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a); const allocator_type& a);
template<class FromRangeT, xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_node_set_range_constructor_with_allocator[concurrent_node_set](FromRangeT&&, R&& rg, const allocator_type& a);
template<class FromRangeT, xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_node_set_range_constructor_with_bucket_count_and_allocator[concurrent_node_set](FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
template<class FromRangeT, xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#concurrent_node_set_range_constructor_with_bucket_count_and_hasher_and_allocator[concurrent_node_set](FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
xref:#concurrent_node_set_initializer_list_constructor_with_allocator[concurrent_node_set](std::initializer_list<value_type> il, const allocator_type& a); xref:#concurrent_node_set_initializer_list_constructor_with_allocator[concurrent_node_set](std::initializer_list<value_type> il, const allocator_type& a);
xref:#concurrent_node_set_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_node_set](std::initializer_list<value_type> il, size_type n, xref:#concurrent_node_set_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_node_set](std::initializer_list<value_type> il, size_type n,
const allocator_type& a); const allocator_type& a);
@@ -148,6 +161,8 @@ namespace unordered {
bool xref:#concurrent_node_set_move_insert[insert](value_type&& obj); bool xref:#concurrent_node_set_move_insert[insert](value_type&& obj);
template<class K> bool xref:#concurrent_node_set_transparent_insert[insert](K&& k); template<class K> bool xref:#concurrent_node_set_transparent_insert[insert](K&& k);
template<class InputIterator> size_type xref:#concurrent_node_set_insert_iterator_range[insert](InputIterator first, InputIterator last); template<class InputIterator> size_type xref:#concurrent_node_set_insert_iterator_range[insert](InputIterator first, InputIterator last);
template<xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
size_type xref:#concurrent_node_set_insert_range[insert_range](R&& rg);
size_type xref:#concurrent_node_set_insert_initializer_list[insert](std::initializer_list<value_type> il); size_type xref:#concurrent_node_set_insert_initializer_list[insert](std::initializer_list<value_type> il);
insert_return_type xref:#concurrent_node_set_insert_node[insert](node_type&& nh); insert_return_type xref:#concurrent_node_set_insert_node[insert](node_type&& nh);
@@ -163,6 +178,10 @@ namespace unordered {
size_type xref:#concurrent_node_set_insert_iterator_range_or_visit[insert_or_visit](InputIterator first, InputIterator last, F f); size_type xref:#concurrent_node_set_insert_iterator_range_or_visit[insert_or_visit](InputIterator first, InputIterator last, F f);
template<class InputIterator,class F> template<class InputIterator,class F>
size_type xref:#concurrent_node_set_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f); size_type xref:#concurrent_node_set_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f);
template<xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type xref:#concurrent_node_set_insert_range_or_visit[insert_range_or_visit](R&& rg, F f);
template<xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type xref:#concurrent_node_set_insert_range_or_visit[insert_range_or_cvisit](R&& rg, F f);
template<class F> size_type xref:#concurrent_node_set_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list<value_type> il, F f); template<class F> size_type xref:#concurrent_node_set_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list<value_type> il, F f);
template<class F> size_type xref:#concurrent_node_set_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list<value_type> il, F f); template<class F> size_type xref:#concurrent_node_set_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list<value_type> il, F f);
template<class F> insert_return_type xref:#concurrent_node_set_insert_node_or_visit[insert_or_visit](node_type&& nh, F f); template<class F> insert_return_type xref:#concurrent_node_set_insert_node_or_visit[insert_or_visit](node_type&& nh, F f);
@@ -182,6 +201,10 @@ namespace unordered {
size_type xref:#concurrent_node_set_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2); size_type xref:#concurrent_node_set_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2);
template<class InputIterator,class F1, class F2> template<class InputIterator,class F1, class F2>
size_type xref:#concurrent_node_set_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2); size_type xref:#concurrent_node_set_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2);
template<xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type xref:#concurrent_node_set_insert_range_and_visit[insert_range_and_visit](R&& rg, F1 f1, F2 f2);
template<xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type xref:#concurrent_node_set_insert_range_and_visit[insert_range_and_cvisit](R&& rg, F1 f1, F2 f2);
template<class F1, class F2> template<class F1, class F2>
size_type xref:#concurrent_node_set_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list<value_type> il, F1 f1, F2 f2); size_type xref:#concurrent_node_set_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list<value_type> il, F1 f1, F2 f2);
template<class F1, class F2> template<class F1, class F2>
@@ -253,6 +276,16 @@ namespace unordered {
Hash = Hash(), Pred = Pred(), Allocator = Allocator()) Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> concurrent_node_set<xref:#concurrent_node_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>; -> concurrent_node_set<xref:#concurrent_node_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>;
template<xref:#concurrent_node_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R,
class Hash = boost::hash<std::ranges::range_value_t<R>>,
class Pred = std::equal_to<std::ranges::range_value_t<R>>,
class Allocator = std::allocator<std::ranges::range_value_t<R>>
concurrent_node_set(FromRangeT&&, R&&,
typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type = xref:#concurrent_node_set_deduction_guides[__see below__], Hash = Hash(),
Pred = Pred(), Allocator = Allocator())
-> concurrent_node_set<std::ranges::range_value_t<R>, Hash, Pred,Allocator>;
template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>, template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>,
class Allocator = std::allocator<T>> class Allocator = std::allocator<T>>
concurrent_node_set(std::initializer_list<T>, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type = xref:#concurrent_node_set_deduction_guides[__see below__], concurrent_node_set(std::initializer_list<T>, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type = xref:#concurrent_node_set_deduction_guides[__see below__],
@@ -277,6 +310,26 @@ namespace unordered {
-> concurrent_node_set<xref:#concurrent_node_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, -> concurrent_node_set<xref:#concurrent_node_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash,
std::equal_to<xref:#concurrent_node_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>; std::equal_to<xref:#concurrent_node_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
template<xref:#concurrent_node_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
concurrent_node_set(FromRangeT&&, R&&, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type, Allocator)
-> concurrent_node_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R>>,
std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<xref:#concurrent_node_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
concurrent_node_set(FromRangeT&&, R&&, Allocator)
-> concurrent_node_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R>>,
std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<xref:#concurrent_node_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Hash, class Allocator>
concurrent_node_set(FromRangeT&&, R&&, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type, Hash,
Allocator)
-> concurrent_node_set<std::ranges::range_value_t<R>,
Hash, std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<class T, class Allocator> template<class T, class Allocator>
concurrent_node_set(std::initializer_list<T>, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type, Allocator) concurrent_node_set(std::initializer_list<T>, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type, Allocator)
-> concurrent_node_set<T, boost::hash<T>, std::equal_to<T>, Allocator>; -> concurrent_node_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
@@ -441,6 +494,15 @@ Chunk size internally used in xref:concurrent_node_set_bulk_visit[bulk visit] op
=== Constructors === Constructors
==== __container-compatible-range__
[listings,subs="+macros,+quotes"]
-----
template<class R, class T>
concept container_compatible_range =
std::ranges::input_range<R> &&
std::convertible_to<std::ranges::range_reference_t<R>, T>; // exposition only
-----
==== Default Constructor ==== Default Constructor
```c++ ```c++
concurrent_node_set(); concurrent_node_set();
@@ -588,6 +650,27 @@ Complexity:;; O(`bucket_count()`)
--- ---
==== Range Constructor
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_node_set(FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
----
Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Initializer List Constructor ==== Initializer List Constructor
[source,c++,subs="+quotes"] [source,c++,subs="+quotes"]
---- ----
@@ -660,6 +743,58 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/
--- ---
==== Range Constructor with Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_node_set(FromRangeT&&, R&& rg, const allocator_type& a);
----
Constructs an empty table using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_node_set(FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
----
Constructs an empty table with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Hasher and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
concurrent_node_set(FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
----
Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::concurrent::from_range_t`.
[horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== initializer_list Constructor with Allocator ==== initializer_list Constructor with Allocator
```c++ ```c++
@@ -916,8 +1051,7 @@ size_type size() const noexcept;
[horizontal] [horizontal]
Returns:;; The number of elements in the table. Returns:;; The number of elements in the table.
Complexity:;; Constant time.
[horizontal]
Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect
the true size of the table right after execution. the true size of the table right after execution.
@@ -1009,6 +1143,25 @@ Returns:;; The number of elements inserted.
--- ---
==== Insert Range
[source,c++,subs="+macros,+quotes"]
----
template<xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
void insert_range(R&& rg);
----
Equivalent to
[listing,subs="+macros,+quotes"]
-----
for(auto&& x: rg) this->xref:#concurrent_node_set_emplace[emplace](std::forward<decltype(x)>(x));
-----
[horizontal]
Returns:;; The number of elements inserted.
---
==== Insert Initializer List ==== Insert Initializer List
```c++ ```c++
size_type insert(std::initializer_list<value_type> il); size_type insert(std::initializer_list<value_type> il);
@@ -1129,6 +1282,27 @@ Returns:;; The number of elements inserted.
--- ---
==== Insert Range or Visit
[source,c++,subs="+macros,+quotes"]
----
template<xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type insert_range_or_visit(R&& rg, F f);
template<xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F>
size_type insert_range_or_visit(R&& rg, F f);
----
Equivalent to
[listing,subs="+macros,+quotes"]
-----
for(auto&& x: rg)
this->xref:#concurrent_node_set_emplace_or_cvisit[emplace_or_[c\]visit](std::forward<decltype(x)>(x), std::ref(f));
-----
[horizontal]
Returns:;; The number of elements inserted.
---
==== Insert Initializer List or Visit ==== Insert Initializer List or Visit
```c++ ```c++
template<class F> size_type insert_or_visit(std::initializer_list<value_type> il, F f); template<class F> size_type insert_or_visit(std::initializer_list<value_type> il, F f);
@@ -1258,6 +1432,28 @@ Returns:;; The number of elements inserted.
--- ---
==== Insert Range and Visit
[source,c++,subs="+macros,+quotes"]
----
template<xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type insert_range_and_visit(R&& rg, F1 f1, F2 f2);
template<xref:#concurrent_node_set_container_compatible_range[__container-compatible-range__]<value_type> R, class F1, class F2>
size_type insert_range_and_cvisit(R&& rg, F1 f1, F2 f2);
----
Equivalent to
[listing,subs="+macros,+quotes"]
-----
for(auto&& x: rg)
this->xref:#concurrent_node_set_emplace_and_cvisit[emplace_and_[c\]visit](
std::forward<decltype(x)>(x), std::ref(f1), std::ref(f2));
-----
[horizontal]
Returns:;; The number of elements inserted.
---
==== Insert Initializer List and Visit ==== Insert Initializer List and Visit
```c++ ```c++
template<class F1, class F2> template<class F1, class F2>
@@ -1640,6 +1836,16 @@ template<class InputIterator>
typename std::iterator_traits<InputIterator>::value_type; // exposition only typename std::iterator_traits<InputIterator>::value_type; // exposition only
----- -----
==== __convertible-to-from-range_t__
[listings,subs="+macros,+quotes"]
-----
template<typename FromRangeT>
concept __convertible-to-from_range_t__ =
// first clause not present if std::from_range_t does not exist
std::is_convertible_v<FromRangeT, std::from_range_t> ||
std::is_convertible_v<FromRangeT, boost::unordered::from_range_t>; // exposition only
-----
=== Equality Comparisons === Equality Comparisons
==== operator== ==== operator==
@@ -19,6 +19,10 @@ namespace unordered {
class Allocator = std::allocator<std::pair<const Key, T>>> class Allocator = std::allocator<std::pair<const Key, T>>>
class xref:reference/concurrent_flat_map.adoc#concurrent_flat_map[concurrent_flat_map]; class xref:reference/concurrent_flat_map.adoc#concurrent_flat_map[concurrent_flat_map];
// Tag for construction from ranges (pass:[C++20] and up)
struct from_range_t { explicit from_range_t() = default; };
inline constexpr from_range_t from_range{};
// Equality Comparisons // Equality Comparisons
template<class Key, class T, class Hash, class Pred, class Alloc> template<class Key, class T, class Hash, class Pred, class Alloc>
bool xref:reference/concurrent_flat_map.adoc#concurrent_flat_map_operator[operator++==++](const concurrent_flat_map<Key, T, Hash, Pred, Alloc>& x, bool xref:reference/concurrent_flat_map.adoc#concurrent_flat_map_operator[operator++==++](const concurrent_flat_map<Key, T, Hash, Pred, Alloc>& x,
@@ -39,7 +43,7 @@ namespace unordered {
typename concurrent_flat_map<K, T, H, P, A>::size_type typename concurrent_flat_map<K, T, H, P, A>::size_type
xref:reference/concurrent_flat_map.adoc#concurrent_flat_map_erase_if[erase_if](concurrent_flat_map<K, T, H, P, A>& c, Predicate pred); xref:reference/concurrent_flat_map.adoc#concurrent_flat_map_erase_if[erase_if](concurrent_flat_map<K, T, H, P, A>& c, Predicate pred);
// Pmr aliases (C++17 and up) // Pmr aliases (pass:[C++17] and up)
namespace pmr { namespace pmr {
template<class Key, template<class Key,
class T, class T,
@@ -18,6 +18,10 @@ namespace unordered {
class Allocator = std::allocator<Key>> class Allocator = std::allocator<Key>>
class xref:reference/concurrent_flat_set.adoc#concurrent_flat_set[concurrent_flat_set]; class xref:reference/concurrent_flat_set.adoc#concurrent_flat_set[concurrent_flat_set];
// Tag for construction from ranges (pass:[C++20] and up)
struct from_range_t { explicit from_range_t() = default; };
inline constexpr from_range_t from_range{};
// Equality Comparisons // Equality Comparisons
template<class Key, class Hash, class Pred, class Alloc> template<class Key, class Hash, class Pred, class Alloc>
bool xref:reference/concurrent_flat_set.adoc#concurrent_flat_set_operator[operator++==++](const concurrent_flat_set<Key, Hash, Pred, Alloc>& x, bool xref:reference/concurrent_flat_set.adoc#concurrent_flat_set_operator[operator++==++](const concurrent_flat_set<Key, Hash, Pred, Alloc>& x,
@@ -38,7 +42,7 @@ namespace unordered {
typename concurrent_flat_set<K, H, P, A>::size_type typename concurrent_flat_set<K, H, P, A>::size_type
xref:reference/concurrent_flat_set.adoc#concurrent_flat_set_erase_if[erase_if](concurrent_flat_set<K, H, P, A>& c, Predicate pred); xref:reference/concurrent_flat_set.adoc#concurrent_flat_set_erase_if[erase_if](concurrent_flat_set<K, H, P, A>& c, Predicate pred);
// Pmr aliases (C++17 and up) // Pmr aliases (pass:[C++17] and up)
namespace pmr { namespace pmr {
template<class Key, template<class Key,
class Hash = boost::hash<Key>, class Hash = boost::hash<Key>,
@@ -19,6 +19,10 @@ namespace unordered {
class Allocator = std::allocator<std::pair<const Key, T>>> class Allocator = std::allocator<std::pair<const Key, T>>>
class xref:reference/concurrent_node_map.adoc#concurrent_node_map[concurrent_node_map]; class xref:reference/concurrent_node_map.adoc#concurrent_node_map[concurrent_node_map];
// Tag for construction from ranges (pass:[C++20] and up)
struct from_range_t { explicit from_range_t() = default; };
inline constexpr from_range_t from_range{};
// Equality Comparisons // Equality Comparisons
template<class Key, class T, class Hash, class Pred, class Alloc> template<class Key, class T, class Hash, class Pred, class Alloc>
bool xref:reference/concurrent_node_map.adoc#concurrent_node_map_operator[operator++==++](const concurrent_node_map<Key, T, Hash, Pred, Alloc>& x, bool xref:reference/concurrent_node_map.adoc#concurrent_node_map_operator[operator++==++](const concurrent_node_map<Key, T, Hash, Pred, Alloc>& x,
@@ -39,7 +43,7 @@ namespace unordered {
typename concurrent_node_map<K, T, H, P, A>::size_type typename concurrent_node_map<K, T, H, P, A>::size_type
xref:reference/concurrent_node_map.adoc#concurrent_node_map_erase_if[erase_if](concurrent_node_map<K, T, H, P, A>& c, Predicate pred); xref:reference/concurrent_node_map.adoc#concurrent_node_map_erase_if[erase_if](concurrent_node_map<K, T, H, P, A>& c, Predicate pred);
// Pmr aliases (C++17 and up) // Pmr aliases (pass:[C++17] and up)
namespace pmr { namespace pmr {
template<class Key, template<class Key,
class T, class T,
@@ -18,6 +18,10 @@ namespace unordered {
class Allocator = std::allocator<Key>> class Allocator = std::allocator<Key>>
class xref:reference/concurrent_node_set.adoc#concurrent_node_set[concurrent_node_set]; class xref:reference/concurrent_node_set.adoc#concurrent_node_set[concurrent_node_set];
// Tag for construction from ranges (pass:[C++20] and up)
struct from_range_t { explicit from_range_t() = default; };
inline constexpr from_range_t from_range{};
// Equality Comparisons // Equality Comparisons
template<class Key, class Hash, class Pred, class Alloc> template<class Key, class Hash, class Pred, class Alloc>
bool xref:reference/concurrent_node_set.adoc#concurrent_node_set_operator[operator++==++](const concurrent_node_set<Key, Hash, Pred, Alloc>& x, bool xref:reference/concurrent_node_set.adoc#concurrent_node_set_operator[operator++==++](const concurrent_node_set<Key, Hash, Pred, Alloc>& x,
@@ -38,7 +42,7 @@ namespace unordered {
typename concurrent_node_set<K, H, P, A>::size_type typename concurrent_node_set<K, H, P, A>::size_type
xref:reference/concurrent_node_set.adoc#concurrent_node_set_erase_if[erase_if](concurrent_node_set<K, H, P, A>& c, Predicate pred); xref:reference/concurrent_node_set.adoc#concurrent_node_set_erase_if[erase_if](concurrent_node_set<K, H, P, A>& c, Predicate pred);
// Pmr aliases (C++17 and up) // Pmr aliases (pass:[C++17] and up)
namespace pmr { namespace pmr {
template<class Key, template<class Key,
class Hash = boost::hash<Key>, class Hash = boost::hash<Key>,
@@ -19,6 +19,10 @@ namespace unordered {
class Allocator = std::allocator<std::pair<const Key, T>>> class Allocator = std::allocator<std::pair<const Key, T>>>
class xref:reference/unordered_flat_map.adoc#unordered_flat_map[unordered_flat_map]; class xref:reference/unordered_flat_map.adoc#unordered_flat_map[unordered_flat_map];
// Tag for construction from ranges (pass:[C++20] and up)
struct from_range_t { explicit from_range_t() = default; };
inline constexpr from_range_t from_range{};
// Equality Comparisons // Equality Comparisons
template<class Key, class T, class Hash, class Pred, class Alloc> template<class Key, class T, class Hash, class Pred, class Alloc>
bool xref:reference/unordered_flat_map.adoc#unordered_flat_map_operator_2[operator++==++](const unordered_flat_map<Key, T, Hash, Pred, Alloc>& x, bool xref:reference/unordered_flat_map.adoc#unordered_flat_map_operator_2[operator++==++](const unordered_flat_map<Key, T, Hash, Pred, Alloc>& x,
@@ -39,7 +43,7 @@ namespace unordered {
typename unordered_flat_map<K, T, H, P, A>::size_type typename unordered_flat_map<K, T, H, P, A>::size_type
xref:reference/unordered_flat_map.adoc#unordered_flat_map_erase_if[erase_if](unordered_flat_map<K, T, H, P, A>& c, Predicate pred); xref:reference/unordered_flat_map.adoc#unordered_flat_map_erase_if[erase_if](unordered_flat_map<K, T, H, P, A>& c, Predicate pred);
// Pmr aliases (C++17 and up) // Pmr aliases (pass:[C++17] and up)
namespace pmr { namespace pmr {
template<class Key, template<class Key,
class T, class T,
@@ -18,6 +18,10 @@ namespace unordered {
class Allocator = std::allocator<Key>> class Allocator = std::allocator<Key>>
class xref:reference/unordered_flat_set.adoc#unordered_flat_set[unordered_flat_set]; class xref:reference/unordered_flat_set.adoc#unordered_flat_set[unordered_flat_set];
// Tag for construction from ranges (pass:[C++20] and up)
struct from_range_t { explicit from_range_t() = default; };
inline constexpr from_range_t from_range{};
// Equality Comparisons // Equality Comparisons
template<class Key, class Hash, class Pred, class Alloc> template<class Key, class Hash, class Pred, class Alloc>
bool xref:reference/unordered_flat_set.adoc#unordered_flat_set_operator[operator++==++](const unordered_flat_set<Key, Hash, Pred, Alloc>& x, bool xref:reference/unordered_flat_set.adoc#unordered_flat_set_operator[operator++==++](const unordered_flat_set<Key, Hash, Pred, Alloc>& x,
@@ -38,7 +42,7 @@ namespace unordered {
typename unordered_flat_set<K, H, P, A>::size_type typename unordered_flat_set<K, H, P, A>::size_type
xref:reference/unordered_flat_set.adoc#unordered_flat_set_erase_if[erase_if](unordered_flat_set<K, H, P, A>& c, Predicate pred); xref:reference/unordered_flat_set.adoc#unordered_flat_set_erase_if[erase_if](unordered_flat_set<K, H, P, A>& c, Predicate pred);
// Pmr aliases (C++17 and up) // Pmr aliases (pass:[C++17] and up)
namespace pmr { namespace pmr {
template<class Key, template<class Key,
class Hash = boost::hash<Key>, class Hash = boost::hash<Key>,
@@ -20,6 +20,10 @@ namespace unordered {
class Allocator = std::allocator<std::pair<const Key, T>>> class Allocator = std::allocator<std::pair<const Key, T>>>
class xref:reference/unordered_map.adoc#unordered_map[unordered_map]; class xref:reference/unordered_map.adoc#unordered_map[unordered_map];
// Tag for construction from ranges (pass:[C++20] and up)
struct from_range_t { explicit from_range_t() = default; };
inline constexpr from_range_t from_range{};
// Equality Comparisons // Equality Comparisons
template<class Key, class T, class Hash, class Pred, class Alloc> template<class Key, class T, class Hash, class Pred, class Alloc>
bool xref:reference/unordered_map.adoc#unordered_map_operator_2[operator++==++](const unordered_map<Key, T, Hash, Pred, Alloc>& x, bool xref:reference/unordered_map.adoc#unordered_map_operator_2[operator++==++](const unordered_map<Key, T, Hash, Pred, Alloc>& x,
@@ -67,7 +71,7 @@ namespace unordered {
typename unordered_multimap<K, T, H, P, A>::size_type typename unordered_multimap<K, T, H, P, A>::size_type
xref:reference/unordered_multimap.adoc#unordered_multimap_erase_if[erase_if](unordered_multimap<K, T, H, P, A>& c, Predicate pred); xref:reference/unordered_multimap.adoc#unordered_multimap_erase_if[erase_if](unordered_multimap<K, T, H, P, A>& c, Predicate pred);
// Pmr aliases (C++17 and up) // Pmr aliases (pass:[C++17] and up)
namespace pmr { namespace pmr {
template<class Key, template<class Key,
class T, class T,
@@ -19,6 +19,10 @@ namespace unordered {
class Allocator = std::allocator<std::pair<const Key, T>>> class Allocator = std::allocator<std::pair<const Key, T>>>
class xref:reference/unordered_node_map.adoc#unordered_node_map[unordered_node_map]; class xref:reference/unordered_node_map.adoc#unordered_node_map[unordered_node_map];
// Tag for construction from ranges (pass:[C++20] and up)
struct from_range_t { explicit from_range_t() = default; };
inline constexpr from_range_t from_range{};
// Equality Comparisons // Equality Comparisons
template<class Key, class T, class Hash, class Pred, class Alloc> template<class Key, class T, class Hash, class Pred, class Alloc>
bool xref:reference/unordered_node_map.adoc#unordered_node_map_operator_2[operator++==++](const unordered_node_map<Key, T, Hash, Pred, Alloc>& x, bool xref:reference/unordered_node_map.adoc#unordered_node_map_operator_2[operator++==++](const unordered_node_map<Key, T, Hash, Pred, Alloc>& x,
@@ -39,7 +43,7 @@ namespace unordered {
typename unordered_node_map<K, T, H, P, A>::size_type typename unordered_node_map<K, T, H, P, A>::size_type
xref:reference/unordered_node_map.adoc#unordered_node_map_erase_if[erase_if](unordered_node_map<K, T, H, P, A>& c, Predicate pred); xref:reference/unordered_node_map.adoc#unordered_node_map_erase_if[erase_if](unordered_node_map<K, T, H, P, A>& c, Predicate pred);
// Pmr aliases (C++17 and up) // Pmr aliases (pass:[C++17] and up)
namespace pmr { namespace pmr {
template<class Key, template<class Key,
class T, class T,
@@ -18,6 +18,10 @@ namespace unordered {
class Allocator = std::allocator<Key>> class Allocator = std::allocator<Key>>
class xref:reference/unordered_node_set.adoc#unordered_node_set[unordered_node_set]; class xref:reference/unordered_node_set.adoc#unordered_node_set[unordered_node_set];
// Tag for construction from ranges (pass:[C++20] and up)
struct from_range_t { explicit from_range_t() = default; };
inline constexpr from_range_t from_range{};
// Equality Comparisons // Equality Comparisons
template<class Key, class Hash, class Pred, class Alloc> template<class Key, class Hash, class Pred, class Alloc>
bool xref:reference/unordered_node_set.adoc#unordered_node_set_operator[operator++==++](const unordered_node_set<Key, Hash, Pred, Alloc>& x, bool xref:reference/unordered_node_set.adoc#unordered_node_set_operator[operator++==++](const unordered_node_set<Key, Hash, Pred, Alloc>& x,
@@ -38,7 +42,7 @@ namespace unordered {
typename unordered_node_set<K, H, P, A>::size_type typename unordered_node_set<K, H, P, A>::size_type
xref:reference/unordered_node_set.adoc#unordered_node_set_erase_if[erase_if](unordered_node_set<K, H, P, A>& c, Predicate pred); xref:reference/unordered_node_set.adoc#unordered_node_set_erase_if[erase_if](unordered_node_set<K, H, P, A>& c, Predicate pred);
// Pmr aliases (C++17 and up) // Pmr aliases (pass:[C++17] and up)
namespace pmr { namespace pmr {
template<class Key, template<class Key,
class Hash = boost::hash<Key>, class Hash = boost::hash<Key>,
@@ -19,6 +19,10 @@ namespace unordered {
class Allocator = std::allocator<Key>> class Allocator = std::allocator<Key>>
class xref:reference/unordered_set.adoc#unordered_set[unordered_set]; class xref:reference/unordered_set.adoc#unordered_set[unordered_set];
// Tag for construction from ranges (pass:[C++20] and up)
struct from_range_t { explicit from_range_t() = default; };
inline constexpr from_range_t from_range{};
// Equality Comparisons // Equality Comparisons
template<class Key, class Hash, class Pred, class Alloc> template<class Key, class Hash, class Pred, class Alloc>
bool xref:reference/unordered_set.adoc#unordered_set_operator[operator++==++](const unordered_set<Key, Hash, Pred, Alloc>& x, bool xref:reference/unordered_set.adoc#unordered_set_operator[operator++==++](const unordered_set<Key, Hash, Pred, Alloc>& x,
@@ -65,7 +69,7 @@ namespace unordered {
typename unordered_multiset<K, H, P, A>::size_type typename unordered_multiset<K, H, P, A>::size_type
xref:reference/unordered_multiset.adoc#unordered_multiset_erase_if[erase_if](unordered_multiset<K, H, P, A>& c, Predicate pred); xref:reference/unordered_multiset.adoc#unordered_multiset_erase_if[erase_if](unordered_multiset<K, H, P, A>& c, Predicate pred);
// Pmr aliases (C++17 and up) // Pmr aliases (pass:[C++17] and up)
namespace pmr { namespace pmr {
template<class Key, template<class Key,
class Hash = boost::hash<Key>, class Hash = boost::hash<Key>,
@@ -82,6 +82,12 @@ namespace unordered {
xref:#unordered_flat_map_copy_constructor_with_allocator[unordered_flat_map](const unordered_flat_map& other, const Allocator& a); xref:#unordered_flat_map_copy_constructor_with_allocator[unordered_flat_map](const unordered_flat_map& other, const Allocator& a);
xref:#unordered_flat_map_move_constructor_with_allocator[unordered_flat_map](unordered_flat_map&& other, const Allocator& a); xref:#unordered_flat_map_move_constructor_with_allocator[unordered_flat_map](unordered_flat_map&& other, const Allocator& a);
xref:#unordered_flat_map_move_constructor_from_concurrent_flat_map[unordered_flat_map](concurrent_flat_map<Key, T, Hash, Pred, Allocator>&& other); xref:#unordered_flat_map_move_constructor_from_concurrent_flat_map[unordered_flat_map](concurrent_flat_map<Key, T, Hash, Pred, Allocator>&& other);
template<class FromRangeT, xref:#unordered_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_flat_map_range_constructor[unordered_flat_map](FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
xref:#unordered_flat_map_initializer_list_constructor[unordered_flat_map](std::initializer_list<value_type> il, xref:#unordered_flat_map_initializer_list_constructor[unordered_flat_map](std::initializer_list<value_type> il,
size_type n = _implementation-defined_ size_type n = _implementation-defined_
const hasher& hf = hasher(), const hasher& hf = hasher(),
@@ -94,6 +100,13 @@ namespace unordered {
template<class InputIterator> template<class InputIterator>
xref:#unordered_flat_map_iterator_range_constructor_with_bucket_count_and_hasher[unordered_flat_map](InputIterator f, InputIterator l, size_type n, const hasher& hf, xref:#unordered_flat_map_iterator_range_constructor_with_bucket_count_and_hasher[unordered_flat_map](InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a); const allocator_type& a);
template<class FromRangeT, xref:#unordered_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_flat_map_range_constructor_with_allocator[unordered_flat_map](FromRangeT&&, R&& rg, const allocator_type& a);
template<class FromRangeT, xref:#unordered_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_flat_map_range_constructor_with_bucket_count_and_allocator[unordered_flat_map](FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
template<class FromRangeT, xref:#unordered_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_flat_map_range_constructor_with_bucket_count_and_hasher_and_allocator[unordered_flat_map](FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
xref:#unordered_flat_map_initializer_list_constructor_with_allocator[unordered_flat_map](std::initializer_list<value_type> il, const allocator_type& a); xref:#unordered_flat_map_initializer_list_constructor_with_allocator[unordered_flat_map](std::initializer_list<value_type> il, const allocator_type& a);
xref:#unordered_flat_map_initializer_list_constructor_with_bucket_count_and_allocator[unordered_flat_map](std::initializer_list<value_type> il, size_type n, xref:#unordered_flat_map_initializer_list_constructor_with_bucket_count_and_allocator[unordered_flat_map](std::initializer_list<value_type> il, size_type n,
const allocator_type& a); const allocator_type& a);
@@ -133,6 +146,8 @@ namespace unordered {
iterator xref:#unordered_flat_map_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); iterator xref:#unordered_flat_map_move_insert_with_hint[insert](const_iterator hint, value_type&& obj);
iterator xref:#unordered_flat_map_copy_insert_with_hint[insert](const_iterator hint, init_type&& obj); iterator xref:#unordered_flat_map_copy_insert_with_hint[insert](const_iterator hint, init_type&& obj);
template<class InputIterator> void xref:#unordered_flat_map_insert_iterator_range[insert](InputIterator first, InputIterator last); template<class InputIterator> void xref:#unordered_flat_map_insert_iterator_range[insert](InputIterator first, InputIterator last);
template<xref:#unordered_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
void xref:#unordered_flat_map_insert_range[insert_range](R&& rg);
void xref:#unordered_flat_map_insert_initializer_list[insert](std::initializer_list<value_type>); void xref:#unordered_flat_map_insert_initializer_list[insert](std::initializer_list<value_type>);
template<class... Args> template<class... Args>
@@ -235,6 +250,17 @@ namespace unordered {
-> unordered_flat_map<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_flat_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash, -> unordered_flat_map<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_flat_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
Pred, Allocator>; Pred, Allocator>;
template<xref:#unordered_flat_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R,
class Hash = boost::hash<xref:#unordered_flat_map_range_key_type[__range-key-type__]<R>>,
class Pred = std::equal_to<xref:#unordered_flat_map_range_key_type[__range-key-type__]<R>>,
class Allocator = std::allocator<xref:#unordered_flat_map_range_to_alloc_type[__range-to-alloc-type__]<R>>>
unordered_flat_map(FromRangeT&&, R&&,
typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type = xref:#unordered_flat_map_deduction_guides[__see below__], Hash = Hash(),
Pred = Pred(), Allocator = Allocator())
-> unordered_flat_map<xref:#unordered_flat_map_range_key_type[__range-key-type__]<R>, xref:#unordered_flat_map_range_mapped_type[__range-mapped-type__]<R>,
Hash, Pred,Allocator>;
template<class Key, class T, class Hash = boost::hash<Key>, template<class Key, class T, class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>, class Pred = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<const Key, T>>> class Allocator = std::allocator<std::pair<const Key, T>>>
@@ -261,6 +287,27 @@ namespace unordered {
-> unordered_flat_map<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_flat_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash, -> unordered_flat_map<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_flat_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
std::equal_to<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>; std::equal_to<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
template<xref:#unordered_flat_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_flat_map(FromRangeT&&, R&&, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type, Allocator)
-> unordered_flat_map<xref:#unordered_flat_map_range_key_type[__range-key-type__]<R>, xref:#unordered_flat_map_range_mapped_type[__range-mapped-type__]<R>,
boost::hash<xref:#unordered_flat_map_range_key_type[__range-key-type__]<R>>,
std::equal_to<xref:#unordered_flat_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<xref:#unordered_flat_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_flat_map(FromRangeT&&, R&&, Allocator)
-> unordered_flat_map<xref:#unordered_flat_map_range_key_type[__range-key-type__]<R>, xref:#unordered_flat_map_range_mapped_type[__range-mapped-type__]<R>,
boost::hash<xref:#unordered_flat_map_range_key_type[__range-key-type__]<R>>,
std::equal_to<xref:#unordered_flat_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<xref:#unordered_flat_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Hash, class Allocator>
unordered_flat_map(FromRangeT&&, R&&, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type, Hash,
Allocator)
-> unordered_flat_map<xref:#unordered_flat_map_range_key_type[__range-key-type__]<R>, xref:#unordered_flat_map_range_mapped_type[__range-mapped-type__]<R>,
Hash, std::equal_to<xref:#unordered_flat_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<class Key, class T, class Allocator> template<class Key, class T, class Allocator>
unordered_flat_map(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type, unordered_flat_map(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type,
Allocator) Allocator)
@@ -358,6 +405,15 @@ The iterator category is at least a forward iterator.
=== Constructors === Constructors
==== __container-compatible-range__
[listings,subs="+macros,+quotes"]
-----
template<class R, class T>
concept container_compatible_range =
std::ranges::input_range<R> &&
std::convertible_to<std::ranges::range_reference_t<R>, T>; // exposition only
-----
==== Default Constructor ==== Default Constructor
```c++ ```c++
unordered_flat_map(); unordered_flat_map();
@@ -496,6 +552,27 @@ Concurrency:;; Blocking on `other`.
--- ---
==== Range Constructor
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_flat_map(FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Initializer List Constructor ==== Initializer List Constructor
[source,c++,subs="+quotes"] [source,c++,subs="+quotes"]
---- ----
@@ -506,7 +583,7 @@ unordered_flat_map(std::initializer_list<value_type> il,
const allocator_type& a = allocator_type()); const allocator_type& a = allocator_type());
---- ----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a`, and inserts the elements from `il` into it. Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `il` into it.
[horizontal] [horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
@@ -568,6 +645,58 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/
--- ---
==== Range Constructor with Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_flat_map(FromRangeT&&, R&& rg, const allocator_type& a);
----
Constructs an empty container using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_flat_map(FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Hasher and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_flat_map(FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== initializer_list Constructor with Allocator ==== initializer_list Constructor with Allocator
```c++ ```c++
@@ -729,7 +858,8 @@ size_type size() const noexcept;
``` ```
[horizontal] [horizontal]
Returns:;; `std::distance(begin(), end())` Returns:;; The number of elements in the container.
Complexity:;; Constant time.
--- ---
@@ -883,6 +1013,22 @@ Notes:;; Can invalidate iterators, pointers and references, but only if the inse
--- ---
==== Insert Range
[source,c++,subs="+macros,+quotes"]
----
template<xref:#unordered_flat_map_container_compatible_range[__container-compatible-range__]<value_type> R>
void insert_range(R&& rg);
----
Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key.
[horizontal]
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into the container from `*std::ranges::begin(rg)`.
Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect.
Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load.
---
==== Insert Initializer List ==== Insert Initializer List
```c++ ```c++
void insert(std::initializer_list<value_type>); void insert(std::initializer_list<value_type>);
@@ -1444,6 +1590,42 @@ template<class InputIterator>
std::tuple_element_t<1, xref:#unordered_flat_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only std::tuple_element_t<1, xref:#unordered_flat_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only
----- -----
==== __convertible-to-from-range_t__
[listings,subs="+macros,+quotes"]
-----
template<typename FromRangeT>
concept __convertible-to-from_range_t__ =
// first clause not present if std::from_range_t does not exist
std::is_convertible_v<FromRangeT, std::from_range_t> ||
std::is_convertible_v<FromRangeT, boost::unordered::from_range_t>; // exposition only
-----
==== __range-key-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-key-type__ =
std::remove_cvref_t<
std::tuple_element_t<0, std::ranges::range_value_t<R>>>; // exposition only
-----
==== __range-mapped-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-mapped-type__ =
std::remove_cvref_t<
std::tuple_element_t<1, std::ranges::range_value_t<R>>>; // exposition only
-----
==== __range-to-alloc-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-to-alloc-type__ =
std::pair<const xref:#unordered_flat_map_range_key_type[__range-key-type__]<R>, xref:#unordered_flat_map_range_mapped_type[__range-mapped-type__]<R>>; // exposition only
-----
=== Equality Comparisons === Equality Comparisons
==== operator== ==== operator==
@@ -12,7 +12,7 @@ array, and insertions into an already occupied bucket are diverted to available
vicinity of the original position. This type of data layout is known as _open addressing_. vicinity of the original position. This type of data layout is known as _open addressing_.
As a result of its using open addressing, the interface of `boost::unordered_flat_set` deviates in As a result of its using open addressing, the interface of `boost::unordered_flat_set` deviates in
a number of aspects from that of `boost::unordered_flat_set`/`std::unordered_flat_set`: a number of aspects from that of `boost::unordered_set`/`std::unordered_set`:
- `value_type` must be move-constructible. - `value_type` must be move-constructible.
- Pointer stability is not kept under rehashing. - Pointer stability is not kept under rehashing.
@@ -76,6 +76,12 @@ namespace unordered {
explicit xref:#unordered_flat_set_allocator_constructor[unordered_flat_set](const Allocator& a); explicit xref:#unordered_flat_set_allocator_constructor[unordered_flat_set](const Allocator& a);
xref:#unordered_flat_set_copy_constructor_with_allocator[unordered_flat_set](const unordered_flat_set& other, const Allocator& a); xref:#unordered_flat_set_copy_constructor_with_allocator[unordered_flat_set](const unordered_flat_set& other, const Allocator& a);
xref:#unordered_flat_set_move_constructor_from_concurrent_flat_set[unordered_flat_set](concurrent_flat_set<Key, Hash, Pred, Allocator>&& other); xref:#unordered_flat_set_move_constructor_from_concurrent_flat_set[unordered_flat_set](concurrent_flat_set<Key, Hash, Pred, Allocator>&& other);
template<class FromRangeT, xref:#unordered_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_flat_set_range_constructor[unordered_flat_set](FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
xref:#unordered_flat_set_initializer_list_constructor[unordered_flat_set](std::initializer_list<value_type> il, xref:#unordered_flat_set_initializer_list_constructor[unordered_flat_set](std::initializer_list<value_type> il,
size_type n = _implementation-defined_ size_type n = _implementation-defined_
const hasher& hf = hasher(), const hasher& hf = hasher(),
@@ -88,6 +94,13 @@ namespace unordered {
template<class InputIterator> template<class InputIterator>
xref:#unordered_flat_set_iterator_range_constructor_with_bucket_count_and_hasher[unordered_flat_set](InputIterator f, InputIterator l, size_type n, const hasher& hf, xref:#unordered_flat_set_iterator_range_constructor_with_bucket_count_and_hasher[unordered_flat_set](InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a); const allocator_type& a);
template<class FromRangeT, xref:#unordered_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_flat_set_range_constructor_with_allocator[unordered_flat_set](FromRangeT&&, R&& rg, const allocator_type& a);
template<class FromRangeT, xref:#unordered_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_flat_set_range_constructor_with_bucket_count_and_allocator[unordered_flat_set](FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
template<class FromRangeT, xref:#unordered_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_flat_set_range_constructor_with_bucket_count_and_hasher_and_allocator[unordered_flat_set](FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
xref:#unordered_flat_set_initializer_list_constructor_with_allocator[unordered_flat_set](std::initializer_list<value_type> il, const allocator_type& a); xref:#unordered_flat_set_initializer_list_constructor_with_allocator[unordered_flat_set](std::initializer_list<value_type> il, const allocator_type& a);
xref:#unordered_flat_set_initializer_list_constructor_with_bucket_count_and_allocator[unordered_flat_set](std::initializer_list<value_type> il, size_type n, xref:#unordered_flat_set_initializer_list_constructor_with_bucket_count_and_allocator[unordered_flat_set](std::initializer_list<value_type> il, size_type n,
const allocator_type& a); const allocator_type& a);
@@ -125,6 +138,8 @@ namespace unordered {
iterator xref:#unordered_flat_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); iterator xref:#unordered_flat_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj);
template<class K> iterator xref:#unordered_flat_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k); template<class K> iterator xref:#unordered_flat_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k);
template<class InputIterator> void xref:#unordered_flat_set_insert_iterator_range[insert](InputIterator first, InputIterator last); template<class InputIterator> void xref:#unordered_flat_set_insert_iterator_range[insert](InputIterator first, InputIterator last);
template<xref:#unordered_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
void xref:#unordered_flat_set_insert_range[insert_range](R&& rg);
void xref:#unordered_flat_set_insert_initializer_list[insert](std::initializer_list<value_type>); void xref:#unordered_flat_set_insert_initializer_list[insert](std::initializer_list<value_type>);
_convertible-to-iterator_ xref:#unordered_flat_set_erase_by_position[erase](iterator position); _convertible-to-iterator_ xref:#unordered_flat_set_erase_by_position[erase](iterator position);
@@ -192,6 +207,16 @@ namespace unordered {
Hash = Hash(), Pred = Pred(), Allocator = Allocator()) Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_flat_set<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>; -> unordered_flat_set<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>;
template<xref:#unordered_flat_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R,
class Hash = boost::hash<std::ranges::range_value_t<R>>,
class Pred = std::equal_to<std::ranges::range_value_t<R>>,
class Allocator = std::allocator<std::ranges::range_value_t<R>>
unordered_flat_set(FromRangeT&&, R&&,
typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type = xref:#unordered_flat_set_deduction_guides[__see below__], Hash = Hash(),
Pred = Pred(), Allocator = Allocator())
-> unordered_flat_set<std::ranges::range_value_t<R>, Hash, Pred,Allocator>;
template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>, template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>,
class Allocator = std::allocator<T>> class Allocator = std::allocator<T>>
unordered_flat_set(std::initializer_list<T>, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type = xref:#unordered_flat_set_deduction_guides[__see below__], unordered_flat_set(std::initializer_list<T>, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type = xref:#unordered_flat_set_deduction_guides[__see below__],
@@ -216,6 +241,27 @@ namespace unordered {
-> unordered_flat_set<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, -> unordered_flat_set<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash,
std::equal_to<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>; std::equal_to<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
template<xref:#unordered_flat_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_flat_set(FromRangeT&&, R&&, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Allocator)
-> unordered_flat_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R>>,
std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<xref:#unordered_flat_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_flat_set(FromRangeT&&, R&&, Allocator)
-> unordered_flat_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R>>,
std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<xref:#unordered_flat_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Hash, class Allocator>
unordered_flat_set(FromRangeT&&, R&&, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Hash,
Allocator)
-> unordered_flat_set<std::ranges::range_value_t<R>,
Hash, std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<class T, class Allocator> template<class T, class Allocator>
unordered_flat_set(std::initializer_list<T>, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Allocator) unordered_flat_set(std::initializer_list<T>, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Allocator)
-> unordered_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>; -> unordered_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
@@ -307,6 +353,15 @@ The iterator category is at least a forward iterator.
=== Constructors === Constructors
==== __container-compatible-range__
[listings,subs="+macros,+quotes"]
-----
template<class R, class T>
concept container_compatible_range =
std::ranges::input_range<R> &&
std::convertible_to<std::ranges::range_reference_t<R>, T>; // exposition only
-----
==== Default Constructor ==== Default Constructor
```c++ ```c++
unordered_flat_set(); unordered_flat_set();
@@ -445,6 +500,27 @@ Concurrency:;; Blocking on `other`.
--- ---
==== Range Constructor
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_flat_set(FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Initializer List Constructor ==== Initializer List Constructor
[source,c++,subs="+quotes"] [source,c++,subs="+quotes"]
---- ----
@@ -455,7 +531,7 @@ unordered_flat_set(std::initializer_list<value_type> il,
const allocator_type& a = allocator_type()); const allocator_type& a = allocator_type());
---- ----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a`, and inserts the elements from `il` into it. Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `il` into it.
[horizontal] [horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
@@ -517,6 +593,58 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/
--- ---
==== Range Constructor with Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_flat_set(FromRangeT&&, R&& rg, const allocator_type& a);
----
Constructs an empty container using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_flat_set(FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Hasher and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_flat_set(FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== initializer_list Constructor with Allocator ==== initializer_list Constructor with Allocator
```c++ ```c++
@@ -550,7 +678,7 @@ unordered_flat_set(std::initializer_list<value_type> il, size_type n, const hash
const allocator_type& a); const allocator_type& a);
``` ```
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate,and inserts the elements from `il` into it. Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate, and inserts the elements from `il` into it.
[horizontal] [horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
@@ -678,7 +806,8 @@ size_type size() const noexcept;
``` ```
[horizontal] [horizontal]
Returns:;; `std::distance(begin(), end())` Returns:;; The number of elements in the container.
Complexity:;; Constant time.
--- ---
@@ -856,6 +985,22 @@ Notes:;; Can invalidate iterators, pointers and references, but only if the inse
--- ---
==== Insert Range
[source,c++,subs="+macros,+quotes"]
----
template<xref:#unordered_flat_set_container_compatible_range[__container-compatible-range__]<value_type> R>
void insert_range(R&& rg);
----
Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key.
[horizontal]
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into the container from `*std::ranges::begin(rg)`.
Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect.
Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load.
---
==== Insert Initializer List ==== Insert Initializer List
```c++ ```c++
void insert(std::initializer_list<value_type>); void insert(std::initializer_list<value_type>);
@@ -1193,6 +1338,16 @@ template<class InputIterator>
typename std::iterator_traits<InputIterator>::value_type; // exposition only typename std::iterator_traits<InputIterator>::value_type; // exposition only
----- -----
==== __convertible-to-from-range_t__
[listings,subs="+macros,+quotes"]
-----
template<typename FromRangeT>
concept __convertible-to-from_range_t__ =
// first clause not present if std::from_range_t does not exist
std::is_convertible_v<FromRangeT, std::from_range_t> ||
std::is_convertible_v<FromRangeT, boost::unordered::from_range_t>; // exposition only
-----
=== Equality Comparisons === Equality Comparisons
==== operator== ==== operator==
@@ -61,8 +61,14 @@ namespace unordered {
explicit xref:#unordered_map_allocator_constructor[unordered_map](const Allocator& a); explicit xref:#unordered_map_allocator_constructor[unordered_map](const Allocator& a);
xref:#unordered_map_copy_constructor_with_allocator[unordered_map](const unordered_map& other, const Allocator& a); xref:#unordered_map_copy_constructor_with_allocator[unordered_map](const unordered_map& other, const Allocator& a);
xref:#unordered_map_move_constructor_with_allocator[unordered_map](unordered_map&& other, const Allocator& a); xref:#unordered_map_move_constructor_with_allocator[unordered_map](unordered_map&& other, const Allocator& a);
template<class FromRangeT, xref:#unordered_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_map_range_constructor[unordered_map](FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
xref:#unordered_map_initializer_list_constructor[unordered_map](std::initializer_list<value_type> il, xref:#unordered_map_initializer_list_constructor[unordered_map](std::initializer_list<value_type> il,
size_type n = _implementation-defined_ size_type n = _implementation-defined_,
const hasher& hf = hasher(), const hasher& hf = hasher(),
const key_equal& eql = key_equal(), const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type()); const allocator_type& a = allocator_type());
@@ -73,6 +79,13 @@ namespace unordered {
template<class InputIterator> template<class InputIterator>
xref:#unordered_map_iterator_range_constructor_with_bucket_count_and_hasher[unordered_map](InputIterator f, InputIterator l, size_type n, const hasher& hf, xref:#unordered_map_iterator_range_constructor_with_bucket_count_and_hasher[unordered_map](InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a); const allocator_type& a);
template<class FromRangeT, xref:#unordered_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_map_range_constructor_with_allocator[unordered_map](FromRangeT&&, R&& rg, const allocator_type& a);
template<class FromRangeT, xref:#unordered_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_map_range_constructor_with_bucket_count_and_allocator[unordered_map](FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
template<class FromRangeT, xref:#unordered_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_map_range_constructor_with_bucket_count_and_hasher_and_allocator[unordered_map](FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
xref:#unordered_map_initializer_list_constructor_with_allocator[unordered_map](std::initializer_list<value_type> il, const allocator_type& a); xref:#unordered_map_initializer_list_constructor_with_allocator[unordered_map](std::initializer_list<value_type> il, const allocator_type& a);
xref:#unordered_map_initializer_list_constructor_with_bucket_count_and_allocator[unordered_map](std::initializer_list<value_type> il, size_type n, const allocator_type& a); xref:#unordered_map_initializer_list_constructor_with_bucket_count_and_allocator[unordered_map](std::initializer_list<value_type> il, size_type n, const allocator_type& a);
xref:#unordered_map_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[unordered_map](std::initializer_list<value_type> il, size_type n, const hasher& hf, xref:#unordered_map_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[unordered_map](std::initializer_list<value_type> il, size_type n, const hasher& hf,
@@ -109,6 +122,8 @@ namespace unordered {
iterator xref:#unordered_map_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); iterator xref:#unordered_map_move_insert_with_hint[insert](const_iterator hint, value_type&& obj);
template<class P> iterator xref:#unordered_map_emplace_insert_with_hint[insert](const_iterator hint, P&& obj); template<class P> iterator xref:#unordered_map_emplace_insert_with_hint[insert](const_iterator hint, P&& obj);
template<class InputIterator> void xref:#unordered_map_insert_iterator_range[insert](InputIterator first, InputIterator last); template<class InputIterator> void xref:#unordered_map_insert_iterator_range[insert](InputIterator first, InputIterator last);
template<xref:#unordered_map_container_compatible_range[__container-compatible-range__]<value_type> R>
void xref:#unordered_map_insert_range[insert_range](R&& rg);
void xref:#unordered_map_insert_initializer_list[insert](std::initializer_list<value_type>); void xref:#unordered_map_insert_initializer_list[insert](std::initializer_list<value_type>);
template<class... Args> template<class... Args>
@@ -231,8 +246,19 @@ namespace unordered {
class Allocator = std::allocator<xref:#unordered_map_iter_to_alloc_type[__iter-to-alloc-type__]<InputIterator>>> class Allocator = std::allocator<xref:#unordered_map_iter_to_alloc_type[__iter-to-alloc-type__]<InputIterator>>>
unordered_map(InputIterator, InputIterator, typename xref:#unordered_map_deduction_guides[__see below__]::size_type = xref:#unordered_map_deduction_guides[__see below__], unordered_map(InputIterator, InputIterator, typename xref:#unordered_map_deduction_guides[__see below__]::size_type = xref:#unordered_map_deduction_guides[__see below__],
Hash = Hash(), Pred = Pred(), Allocator = Allocator()) Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_map<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash, Pred, -> unordered_map<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>,
Allocator>; Hash, Pred, Allocator>;
template<xref:#unordered_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R,
class Hash = boost::hash<xref:#unordered_map_range_key_type[__range-key-type__]<R>>,
class Pred = std::equal_to<xref:#unordered_map_range_key_type[__range-key-type__]<R>>,
class Allocator = std::allocator<xref:#unordered_map_range_to_alloc_type[__range-to-alloc-type__]<R>>>
unordered_map(FromRangeT&&, R&&,
typename xref:#unordered_map_deduction_guides[__see below__]::size_type = xref:#unordered_map_deduction_guides[__see below__], Hash = Hash(),
Pred = Pred(), Allocator = Allocator())
-> unordered_map<xref:#unordered_map_range_key_type[__range-key-type__]<R>, xref:#unordered_map_range_mapped_type[__range-mapped-type__]<R>,
Hash, Pred,Allocator>;
template<class Key, class T, class Hash = boost::hash<Key>, template<class Key, class T, class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>, class Pred = std::equal_to<Key>,
@@ -259,6 +285,27 @@ namespace unordered {
-> unordered_map<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash, -> unordered_map<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
std::equal_to<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>; std::equal_to<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
template<xref:#unordered_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_map(FromRangeT&&, R&&, typename xref:#unordered_map_deduction_guides[__see below__]::size_type, Allocator)
-> unordered_map<xref:#unordered_map_range_key_type[__range-key-type__]<R>, xref:#unordered_map_range_mapped_type[__range-mapped-type__]<R>,
boost::hash<xref:#unordered_map_range_key_type[__range-key-type__]<R>>,
std::equal_to<xref:#unordered_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<xref:#unordered_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_map(FromRangeT&&, R&&, Allocator)
-> unordered_map<xref:#unordered_map_range_key_type[__range-key-type__]<R>, xref:#unordered_map_range_mapped_type[__range-mapped-type__]<R>,
boost::hash<xref:#unordered_map_range_key_type[__range-key-type__]<R>>,
std::equal_to<xref:#unordered_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<xref:#unordered_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Hash, class Allocator>
unordered_map(FromRangeT&&, R&&, typename xref:#unordered_map_deduction_guides[__see below__]::size_type, Hash,
Allocator)
-> unordered_map<xref:#unordered_map_range_key_type[__range-key-type__]<R>, xref:#unordered_map_range_mapped_type[__range-mapped-type__]<R>,
Hash, std::equal_to<xref:#unordered_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<class Key, class T, class Allocator> template<class Key, class T, class Allocator>
unordered_map(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_map_deduction_guides[__see below__]::size_type, unordered_map(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_map_deduction_guides[__see below__]::size_type,
Allocator) Allocator)
@@ -397,6 +444,15 @@ with `Iterator` = `iterator` and `NodeType` = `node_type`.
=== Constructors === Constructors
==== __container-compatible-range__
[listings,subs="+macros,+quotes"]
-----
template<class R, class T>
concept container_compatible_range =
std::ranges::input_range<R> &&
std::convertible_to<std::ranges::range_reference_t<R>, T>; // exposition only
-----
==== Default Constructor ==== Default Constructor
```c++ ```c++
unordered_map(); unordered_map();
@@ -519,11 +575,32 @@ Requires:;; `value_type` is move insertable.
--- ---
==== Range Constructor
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_map_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_map(FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate, `a` as the allocator and a maximum load factor of `1.0` and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Initializer List Constructor ==== Initializer List Constructor
[source,c++,subs="+quotes"] [source,c++,subs="+quotes"]
---- ----
unordered_map(std::initializer_list<value_type> il, unordered_map(std::initializer_list<value_type> il,
size_type n = _implementation-defined_ size_type n = _implementation-defined_,
const hasher& hf = hasher(), const hasher& hf = hasher(),
const key_equal& eql = key_equal(), const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type()); const allocator_type& a = allocator_type());
@@ -591,6 +668,58 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/
--- ---
==== Range Constructor with Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_map_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_map(FromRangeT&&, R&& rg, const allocator_type& a);
----
Constructs an empty container using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_map_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_map(FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Hasher and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_map_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_map(FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== initializer_list Constructor with Allocator ==== initializer_list Constructor with Allocator
```c++ ```c++
@@ -749,7 +878,8 @@ size_type size() const noexcept;
``` ```
[horizontal] [horizontal]
Returns:;; `std::distance(begin(), end())` Returns:;; The number of elements in the container.
Complexity:;; Constant time.
--- ---
@@ -943,6 +1073,24 @@ Pointers and references to elements are never invalidated.
--- ---
==== Insert Range
[source,c++,subs="+macros,+quotes"]
----
template<xref:#unordered_map_container_compatible_range[__container-compatible-range__]<value_type> R>
void insert_range(R&& rg);
----
Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key.
[horizontal]
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into the container from `*std::ranges::begin(rg)`.
Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect.
Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. +
+
Pointers and references to elements are never invalidated.
---
==== Insert Initializer List ==== Insert Initializer List
```c++ ```c++
void insert(std::initializer_list<value_type>); void insert(std::initializer_list<value_type>);
@@ -1696,6 +1844,42 @@ template<class InputIterator>
std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only
----- -----
==== __convertible-to-from-range_t__
[listings,subs="+macros,+quotes"]
-----
template<typename FromRangeT>
concept __convertible-to-from_range_t__ =
// first clause not present if std::from_range_t does not exist
std::is_convertible_v<FromRangeT, std::from_range_t> ||
std::is_convertible_v<FromRangeT, boost::unordered::from_range_t>; // exposition only
-----
==== __range-key-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-key-type__ =
std::remove_cvref_t<
std::tuple_element_t<0, std::ranges::range_value_t<R>>>; // exposition only
-----
==== __range-mapped-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-mapped-type__ =
std::remove_cvref_t<
std::tuple_element_t<1, std::ranges::range_value_t<R>>>; // exposition only
-----
==== __range-to-alloc-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-to-alloc-type__ =
std::pair<const xref:#unordered_map_range_key_type[__range-key-type__]<R>, xref:#unordered_map_range_mapped_type[__range-mapped-type__]<R>>; // exposition only
-----
=== Equality Comparisons === Equality Comparisons
==== operator== ==== operator==
@@ -60,6 +60,12 @@ namespace unordered {
explicit xref:#unordered_multimap_allocator_constructor[unordered_multimap](const Allocator& a); explicit xref:#unordered_multimap_allocator_constructor[unordered_multimap](const Allocator& a);
xref:#unordered_multimap_copy_constructor_with_allocator[unordered_multimap](const unordered_multimap& other, const Allocator& a); xref:#unordered_multimap_copy_constructor_with_allocator[unordered_multimap](const unordered_multimap& other, const Allocator& a);
xref:#unordered_multimap_move_constructor_with_allocator[unordered_multimap](unordered_multimap&& other, const Allocator& a); xref:#unordered_multimap_move_constructor_with_allocator[unordered_multimap](unordered_multimap&& other, const Allocator& a);
template<class FromRangeT, xref:#unordered_multimap_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_multimap_range_constructor[unordered_multimap](FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
xref:#unordered_multimap_initializer_list_constructor[unordered_multimap](std::initializer_list<value_type> il, xref:#unordered_multimap_initializer_list_constructor[unordered_multimap](std::initializer_list<value_type> il,
size_type n = _implementation-defined_, size_type n = _implementation-defined_,
const hasher& hf = hasher(), const hasher& hf = hasher(),
@@ -72,6 +78,13 @@ namespace unordered {
template<class InputIterator> template<class InputIterator>
xref:#unordered_multimap_iterator_range_constructor_with_bucket_count_and_hasher[unordered_multimap](InputIterator f, InputIterator l, size_type n, const hasher& hf, xref:#unordered_multimap_iterator_range_constructor_with_bucket_count_and_hasher[unordered_multimap](InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a); const allocator_type& a);
template<class FromRangeT, xref:#unordered_multimap_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_multimap_range_constructor_with_allocator[unordered_multimap](FromRangeT&&, R&& rg, const allocator_type& a);
template<class FromRangeT, xref:#unordered_multimap_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_multimap_range_constructor_with_bucket_count_and_allocator[unordered_multimap](FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
template<class FromRangeT, xref:#unordered_multimap_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_multimap_range_constructor_with_bucket_count_and_hasher_and_allocator[unordered_multimap](FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
xref:#unordered_multimap_initializer_list_constructor_with_allocator[unordered_multimap](std::initializer_list<value_type> il, const allocator_type& a); xref:#unordered_multimap_initializer_list_constructor_with_allocator[unordered_multimap](std::initializer_list<value_type> il, const allocator_type& a);
xref:#unordered_multimap_initializer_list_constructor_with_bucket_count_and_allocator[unordered_multimap](std::initializer_list<value_type> il, size_type n, xref:#unordered_multimap_initializer_list_constructor_with_bucket_count_and_allocator[unordered_multimap](std::initializer_list<value_type> il, size_type n,
const allocator_type& a); const allocator_type& a);
@@ -109,6 +122,8 @@ namespace unordered {
iterator xref:#unordered_multimap_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); iterator xref:#unordered_multimap_move_insert_with_hint[insert](const_iterator hint, value_type&& obj);
template<class P> iterator xref:#unordered_multimap_emplace_insert_with_hint[insert](const_iterator hint, P&& obj); template<class P> iterator xref:#unordered_multimap_emplace_insert_with_hint[insert](const_iterator hint, P&& obj);
template<class InputIterator> void xref:#unordered_multimap_insert_iterator_range[insert](InputIterator first, InputIterator last); template<class InputIterator> void xref:#unordered_multimap_insert_iterator_range[insert](InputIterator first, InputIterator last);
template<xref:#unordered_multimap_container_compatible_range[__container-compatible-range__]<value_type> R>
void xref:#unordered_multimap_insert_range[insert_range](R&& rg);
void xref:#unordered_multimap_insert_initializer_list[insert](std::initializer_list<value_type> il); void xref:#unordered_multimap_insert_initializer_list[insert](std::initializer_list<value_type> il);
node_type xref:#unordered_multimap_extract_by_iterator[extract](const_iterator position); node_type xref:#unordered_multimap_extract_by_iterator[extract](const_iterator position);
@@ -200,6 +215,17 @@ namespace unordered {
-> unordered_multimap<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_multimap_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash, -> unordered_multimap<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_multimap_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
Pred, Allocator>; Pred, Allocator>;
template<xref:#unordered_multimap_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R,
class Hash = boost::hash<xref:#unordered_multimap_range_key_type[__range-key-type__]<R>>,
class Pred = std::equal_to<xref:#unordered_multimap_range_key_type[__range-key-type__]<R>>,
class Allocator = std::allocator<xref:#unordered_multimap_range_to_alloc_type[__range-to-alloc-type__]<R>>>
unordered_multimap(FromRangeT&&, R&&,
typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type = xref:#unordered_multimap_deduction_guides[__see below__], Hash = Hash(),
Pred = Pred(), Allocator = Allocator())
-> unordered_multimap<xref:#unordered_multimap_range_key_type[__range-key-type__]<R>, xref:#unordered_multimap_range_mapped_type[__range-mapped-type__]<R>,
Hash, Pred,Allocator>;
template<class Key, class T, class Hash = boost::hash<Key>, template<class Key, class T, class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>, class Pred = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<const Key, T>>> class Allocator = std::allocator<std::pair<const Key, T>>>
@@ -226,6 +252,27 @@ namespace unordered {
-> unordered_multimap<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_multimap_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash, -> unordered_multimap<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_multimap_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
std::equal_to<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>; std::equal_to<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
template<xref:#unordered_multimap_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_multimap(FromRangeT&&, R&&, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type, Allocator)
-> unordered_multimap<xref:#unordered_multimap_range_key_type[__range-key-type__]<R>, xref:#unordered_multimap_range_mapped_type[__range-mapped-type__]<R>,
boost::hash<xref:#unordered_multimap_range_key_type[__range-key-type__]<R>>,
std::equal_to<xref:#unordered_multimap_range_key_type[__range-key-type__]<R>>, Allocator>;
template<xref:#unordered_multimap_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_multimap(FromRangeT&&, R&&, Allocator)
-> unordered_multimap<xref:#unordered_multimap_range_key_type[__range-key-type__]<R>, xref:#unordered_multimap_range_mapped_type[__range-mapped-type__]<R>,
boost::hash<xref:#unordered_multimap_range_key_type[__range-key-type__]<R>>,
std::equal_to<xref:#unordered_multimap_range_key_type[__range-key-type__]<R>>, Allocator>;
template<xref:#unordered_multimap_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Hash, class Allocator>
unordered_multimap(FromRangeT&&, R&&, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type, Hash,
Allocator)
-> unordered_multimap<xref:#unordered_multimap_range_key_type[__range-key-type__]<R>, xref:#unordered_multimap_range_mapped_type[__range-mapped-type__]<R>,
Hash, std::equal_to<xref:#unordered_multimap_range_key_type[__range-key-type__]<R>>, Allocator>;
template<class Key, class T, class Allocator> template<class Key, class T, class Allocator>
unordered_multimap(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type, unordered_multimap(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type,
Allocator) Allocator)
@@ -341,6 +388,15 @@ See node_handle_map for details.
=== Constructors === Constructors
==== __container-compatible-range__
[listings,subs="+macros,+quotes"]
-----
template<class R, class T>
concept container_compatible_range =
std::ranges::input_range<R> &&
std::convertible_to<std::ranges::range_reference_t<R>, T>; // exposition only
-----
==== Default Constructor ==== Default Constructor
```c++ ```c++
unordered_multimap(); unordered_multimap();
@@ -463,6 +519,27 @@ Requires:;; `value_type` is move insertable.
--- ---
==== Range Constructor
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_multimap_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_multimap(FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate, `a` as the allocator and a maximum load factor of `1.0` and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Initializer List Constructor ==== Initializer List Constructor
[source,c++,subs="+quotes"] [source,c++,subs="+quotes"]
---- ----
@@ -534,6 +611,58 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/
--- ---
==== Range Constructor with Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_multimap_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_multimap(FromRangeT&&, R&& rg, const allocator_type& a);
----
Constructs an empty container using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_multimap_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_multimap(FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Hasher and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_multimap_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_multimap(FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== initializer_list Constructor with Allocator ==== initializer_list Constructor with Allocator
```c++ ```c++
@@ -692,7 +821,8 @@ size_type size() const noexcept;
``` ```
[horizontal] [horizontal]
Returns:;; `std::distance(begin(), end())` Returns:;; The number of elements in the container.
Complexity:;; Constant time.
--- ---
@@ -873,6 +1003,25 @@ Pointers and references to elements are never invalidated.
--- ---
==== Insert Range
[source,c++,subs="+macros,+quotes"]
----
template<xref:#unordered_multimap_container_compatible_range[__container-compatible-range__]<value_type> R>
void insert_range(R&& rg);
----
Inserts a range of elements into the container.
[horizontal]
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into the container from `*std::ranges::begin(rg)`.
Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect.
Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. +
+
Pointers and references to elements are never invalidated.
---
==== Insert Initializer List ==== Insert Initializer List
```c++ ```c++
void insert(std::initializer_list<value_type> il); void insert(std::initializer_list<value_type> il);
@@ -1413,6 +1562,42 @@ template<class InputIterator>
std::tuple_element_t<1, xref:#unordered_multimap_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only std::tuple_element_t<1, xref:#unordered_multimap_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only
----- -----
==== __convertible-to-from-range_t__
[listings,subs="+macros,+quotes"]
-----
template<typename FromRangeT>
concept __convertible-to-from_range_t__ =
// first clause not present if std::from_range_t does not exist
std::is_convertible_v<FromRangeT, std::from_range_t> ||
std::is_convertible_v<FromRangeT, boost::unordered::from_range_t>; // exposition only
-----
==== __range-key-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-key-type__ =
std::remove_cvref_t<
std::tuple_element_t<0, std::ranges::range_value_t<R>>>; // exposition only
-----
==== __range-mapped-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-mapped-type__ =
std::remove_cvref_t<
std::tuple_element_t<1, std::ranges::range_value_t<R>>>; // exposition only
-----
==== __range-to-alloc-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-to-alloc-type__ =
std::pair<const xref:#unordered_multimap_range_key_type[__range-key-type__]<R>, xref:#unordered_multimap_range_mapped_type[__range-mapped-type__]<R>>; // exposition only
-----
=== Equality Comparisons === Equality Comparisons
==== operator== ==== operator==
@@ -58,6 +58,12 @@ namespace unordered {
explicit xref:#unordered_multiset_allocator_constructor[unordered_multiset](const Allocator& a); explicit xref:#unordered_multiset_allocator_constructor[unordered_multiset](const Allocator& a);
xref:#unordered_multiset_copy_constructor_with_allocator[unordered_multiset](const unordered_multiset& other, const Allocator& a); xref:#unordered_multiset_copy_constructor_with_allocator[unordered_multiset](const unordered_multiset& other, const Allocator& a);
xref:#unordered_multiset_move_constructor_with_allocator[unordered_multiset](unordered_multiset&& other, const Allocator& a); xref:#unordered_multiset_move_constructor_with_allocator[unordered_multiset](unordered_multiset&& other, const Allocator& a);
template<class FromRangeT, xref:#unordered_multiset_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_multiset_range_constructor[unordered_multiset](FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
xref:#unordered_multiset_initializer_list_constructor[unordered_multiset](std::initializer_list<value_type> il, xref:#unordered_multiset_initializer_list_constructor[unordered_multiset](std::initializer_list<value_type> il,
size_type n = _implementation-defined_, size_type n = _implementation-defined_,
const hasher& hf = hasher(), const hasher& hf = hasher(),
@@ -70,6 +76,13 @@ namespace unordered {
template<class InputIterator> template<class InputIterator>
xref:#unordered_multiset_iterator_range_constructor_with_bucket_count_and_hasher[unordered_multiset](InputIterator f, InputIterator l, size_type n, const hasher& hf, xref:#unordered_multiset_iterator_range_constructor_with_bucket_count_and_hasher[unordered_multiset](InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a); const allocator_type& a);
template<class FromRangeT, xref:#unordered_multiset_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_multiset_range_constructor_with_allocator[unordered_multiset](FromRangeT&&, R&& rg, const allocator_type& a);
template<class FromRangeT, xref:#unordered_multiset_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_multiset_range_constructor_with_bucket_count_and_allocator[unordered_multiset](FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
template<class FromRangeT, xref:#unordered_multiset_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_multiset_range_constructor_with_bucket_count_and_hasher_and_allocator[unordered_multiset](FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
xref:#unordered_multiset_initializer_list_constructor_with_allocator[unordered_multiset](std::initializer_list<value_type> il, const allocator_type& a); xref:#unordered_multiset_initializer_list_constructor_with_allocator[unordered_multiset](std::initializer_list<value_type> il, const allocator_type& a);
xref:#unordered_multiset_initializer_list_constructor_with_bucket_count_and_allocator[unordered_multiset](std::initializer_list<value_type> il, size_type n, xref:#unordered_multiset_initializer_list_constructor_with_bucket_count_and_allocator[unordered_multiset](std::initializer_list<value_type> il, size_type n,
const allocator_type& a) const allocator_type& a)
@@ -105,6 +118,8 @@ namespace unordered {
iterator xref:#unordered_multiset_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); iterator xref:#unordered_multiset_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj);
iterator xref:#unordered_multiset_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); iterator xref:#unordered_multiset_move_insert_with_hint[insert](const_iterator hint, value_type&& obj);
template<class InputIterator> void xref:#unordered_multiset_insert_iterator_range[insert](InputIterator first, InputIterator last); template<class InputIterator> void xref:#unordered_multiset_insert_iterator_range[insert](InputIterator first, InputIterator last);
template<xref:#unordered_multiset_container_compatible_range[__container-compatible-range__]<value_type> R>
void xref:#unordered_multiset_insert_range[insert_range](R&& rg);
void xref:#unordered_multiset_insert_initializer_list[insert](std::initializer_list<value_type> il); void xref:#unordered_multiset_insert_initializer_list[insert](std::initializer_list<value_type> il);
node_type xref:#unordered_multiset_extract_by_iterator[extract](const_iterator position); node_type xref:#unordered_multiset_extract_by_iterator[extract](const_iterator position);
@@ -195,6 +210,16 @@ namespace unordered {
Hash = Hash(), Pred = Pred(), Allocator = Allocator()) Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_multiset<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>; -> unordered_multiset<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>;
template<xref:#unordered_multiset_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R,
class Hash = boost::hash<std::ranges::range_value_t<R>>,
class Pred = std::equal_to<std::ranges::range_value_t<R>>,
class Allocator = std::allocator<std::ranges::range_value_t<R>>
unordered_multiset(FromRangeT&&, R&&,
typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type = xref:#unordered_multiset_deduction_guides[__see below__], Hash = Hash(),
Pred = Pred(), Allocator = Allocator())
-> unordered_multiset<std::ranges::range_value_t<R>, Hash, Pred,Allocator>;
template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>, template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>,
class Allocator = std::allocator<T>> class Allocator = std::allocator<T>>
unordered_multiset(std::initializer_list<T>, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type = xref:#unordered_multiset_deduction_guides[__see below__], unordered_multiset(std::initializer_list<T>, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type = xref:#unordered_multiset_deduction_guides[__see below__],
@@ -219,6 +244,27 @@ namespace unordered {
-> unordered_multiset<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>, Hash, -> unordered_multiset<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>, Hash,
std::equal_to<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>; std::equal_to<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
template<xref:#unordered_multiset_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_multiset(FromRangeT&&, R&&, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Allocator)
-> unordered_multiset<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R>>,
std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<xref:#unordered_multiset_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_multiset(FromRangeT&&, R&&, Allocator)
-> unordered_multiset<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R>>,
std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<xref:#unordered_multiset_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Hash, class Allocator>
unordered_multiset(FromRangeT&&, R&&, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Hash,
Allocator)
-> unordered_multiset<std::ranges::range_value_t<R>,
Hash, std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<class T, class Allocator> template<class T, class Allocator>
unordered_multiset(std::initializer_list<T>, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Allocator) unordered_multiset(std::initializer_list<T>, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Allocator)
-> unordered_multiset<T, boost::hash<T>, std::equal_to<T>, Allocator>; -> unordered_multiset<T, boost::hash<T>, std::equal_to<T>, Allocator>;
@@ -329,6 +375,15 @@ See node_handle_set for details.
=== Constructors === Constructors
==== __container-compatible-range__
[listings,subs="+macros,+quotes"]
-----
template<class R, class T>
concept container_compatible_range =
std::ranges::input_range<R> &&
std::convertible_to<std::ranges::range_reference_t<R>, T>; // exposition only
-----
==== Default Constructor ==== Default Constructor
```c++ ```c++
unordered_multiset(); unordered_multiset();
@@ -451,6 +506,27 @@ Requires:;; `value_type` is move insertable.
--- ---
==== Range Constructor
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_multiset_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_multiset(FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate, `a` as the allocator and a maximum load factor of `1.0` and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Initializer List Constructor ==== Initializer List Constructor
[source,c++,subs="+quotes"] [source,c++,subs="+quotes"]
---- ----
@@ -523,6 +599,58 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/
--- ---
==== Range Constructor with Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_multiset_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_multiset(FromRangeT&&, R&& rg, const allocator_type& a);
----
Constructs an empty container using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_multiset_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_multiset(FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Hasher and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_multiset_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_multiset(FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== initializer_list Constructor with Allocator ==== initializer_list Constructor with Allocator
```c++ ```c++
@@ -683,7 +811,8 @@ size_type size() const noexcept;
``` ```
[horizontal] [horizontal]
Returns:;; `std::distance(begin(), end())` Returns:;; The number of elements in the container.
Complexity:;; Constant time.
--- ---
@@ -830,12 +959,30 @@ Pointers and references to elements are never invalidated.
--- ---
==== Insert Range
[source,c++,subs="+macros,+quotes"]
----
template<xref:#unordered_multiset_container_compatible_range[__container-compatible-range__]<value_type> R>
void insert_range(R&& rg);
----
Inserts a range of elements into the container.
[horizontal]
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into the container from `*std::ranges::begin(rg)`.
Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect.
Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. +
+
Pointers and references to elements are never invalidated.
---
==== Insert Initializer List ==== Insert Initializer List
```c++ ```c++
void insert(std::initializer_list<value_type> il); void insert(std::initializer_list<value_type> il);
``` ```
Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. Inserts a range of elements into the container.
[horizontal] [horizontal]
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container. Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container.
@@ -1345,6 +1492,16 @@ template<class InputIterator>
typename std::iterator_traits<InputIterator>::value_type; // exposition only typename std::iterator_traits<InputIterator>::value_type; // exposition only
----- -----
==== __convertible-to-from-range_t__
[listings,subs="+macros,+quotes"]
-----
template<typename FromRangeT>
concept __convertible-to-from_range_t__ =
// first clause not present if std::from_range_t does not exist
std::is_convertible_v<FromRangeT, std::from_range_t> ||
std::is_convertible_v<FromRangeT, boost::unordered::from_range_t>; // exposition only
-----
=== Equality Comparisons === Equality Comparisons
==== operator== ==== operator==
@@ -81,6 +81,12 @@ namespace unordered {
xref:#unordered_node_map_copy_constructor_with_allocator[unordered_node_map](const unordered_node_map& other, const Allocator& a); xref:#unordered_node_map_copy_constructor_with_allocator[unordered_node_map](const unordered_node_map& other, const Allocator& a);
xref:#unordered_node_map_move_constructor_with_allocator[unordered_node_map](unordered_node_map&& other, const Allocator& a); xref:#unordered_node_map_move_constructor_with_allocator[unordered_node_map](unordered_node_map&& other, const Allocator& a);
xref:#unordered_node_map_move_constructor_from_concurrent_node_map[unordered_node_map](concurrent_node_map<Key, T, Hash, Pred, Allocator>&& other); xref:#unordered_node_map_move_constructor_from_concurrent_node_map[unordered_node_map](concurrent_node_map<Key, T, Hash, Pred, Allocator>&& other);
template<class FromRangeT, xref:#unordered_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_node_map_range_constructor[unordered_node_map](FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
xref:#unordered_node_map_initializer_list_constructor[unordered_node_map](std::initializer_list<value_type> il, xref:#unordered_node_map_initializer_list_constructor[unordered_node_map](std::initializer_list<value_type> il,
size_type n = _implementation-defined_ size_type n = _implementation-defined_
const hasher& hf = hasher(), const hasher& hf = hasher(),
@@ -93,6 +99,13 @@ namespace unordered {
template<class InputIterator> template<class InputIterator>
xref:#unordered_node_map_iterator_range_constructor_with_bucket_count_and_hasher[unordered_node_map](InputIterator f, InputIterator l, size_type n, const hasher& hf, xref:#unordered_node_map_iterator_range_constructor_with_bucket_count_and_hasher[unordered_node_map](InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a); const allocator_type& a);
template<class FromRangeT, xref:#unordered_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_node_map_range_constructor_with_allocator[unordered_node_map](FromRangeT&&, R&& rg, const allocator_type& a);
template<class FromRangeT, xref:#unordered_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_node_map_range_constructor_with_bucket_count_and_allocator[unordered_node_map](FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
template<class FromRangeT, xref:#unordered_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_node_map_range_constructor_with_bucket_count_and_hasher_and_allocator[unordered_node_map](FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
xref:#unordered_node_map_initializer_list_constructor_with_allocator[unordered_node_map](std::initializer_list<value_type> il, const allocator_type& a); xref:#unordered_node_map_initializer_list_constructor_with_allocator[unordered_node_map](std::initializer_list<value_type> il, const allocator_type& a);
xref:#unordered_node_map_initializer_list_constructor_with_bucket_count_and_allocator[unordered_node_map](std::initializer_list<value_type> il, size_type n, xref:#unordered_node_map_initializer_list_constructor_with_bucket_count_and_allocator[unordered_node_map](std::initializer_list<value_type> il, size_type n,
const allocator_type& a); const allocator_type& a);
@@ -132,6 +145,8 @@ namespace unordered {
iterator xref:#unordered_node_map_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); iterator xref:#unordered_node_map_move_insert_with_hint[insert](const_iterator hint, value_type&& obj);
iterator xref:#unordered_node_map_copy_insert_with_hint[insert](const_iterator hint, init_type&& obj); iterator xref:#unordered_node_map_copy_insert_with_hint[insert](const_iterator hint, init_type&& obj);
template<class InputIterator> void xref:#unordered_node_map_insert_iterator_range[insert](InputIterator first, InputIterator last); template<class InputIterator> void xref:#unordered_node_map_insert_iterator_range[insert](InputIterator first, InputIterator last);
template<xref:#unordered_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
void xref:#unordered_node_map_insert_range[insert_range](R&& rg);
void xref:#unordered_node_map_insert_initializer_list[insert](std::initializer_list<value_type>); void xref:#unordered_node_map_insert_initializer_list[insert](std::initializer_list<value_type>);
insert_return_type xref:#unordered_node_map_insert_node[insert](node_type&& nh); insert_return_type xref:#unordered_node_map_insert_node[insert](node_type&& nh);
iterator xref:#unordered_node_map_insert_node_with_hint[insert](const_iterator hint, node_type&& nh); iterator xref:#unordered_node_map_insert_node_with_hint[insert](const_iterator hint, node_type&& nh);
@@ -239,6 +254,17 @@ namespace unordered {
-> unordered_node_map<xref:#unordered_node_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_node_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash, -> unordered_node_map<xref:#unordered_node_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_node_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
Pred, Allocator>; Pred, Allocator>;
template<xref:#unordered_node_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R,
class Hash = boost::hash<xref:#unordered_node_map_range_key_type[__range-key-type__]<R>>,
class Pred = std::equal_to<xref:#unordered_node_map_range_key_type[__range-key-type__]<R>>,
class Allocator = std::allocator<xref:#unordered_node_map_range_to_alloc_type[__range-to-alloc-type__]<R>>>
unordered_node_map(FromRangeT&&, R&&,
typename xref:#unordered_node_map_deduction_guides[__see below__]::size_type = xref:#unordered_node_map_deduction_guides[__see below__], Hash = Hash(),
Pred = Pred(), Allocator = Allocator())
-> unordered_node_map<xref:#unordered_node_map_range_key_type[__range-key-type__]<R>, xref:#unordered_node_map_range_mapped_type[__range-mapped-type__]<R>,
Hash, Pred,Allocator>;
template<class Key, class T, class Hash = boost::hash<Key>, template<class Key, class T, class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>, class Pred = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<const Key, T>>> class Allocator = std::allocator<std::pair<const Key, T>>>
@@ -265,6 +291,27 @@ namespace unordered {
-> unordered_node_map<xref:#unordered_node_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_node_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash, -> unordered_node_map<xref:#unordered_node_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_node_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
std::equal_to<xref:#unordered_node_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>; std::equal_to<xref:#unordered_node_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
template<xref:#unordered_node_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_node_map(FromRangeT&&, R&&, typename xref:#unordered_node_map_deduction_guides[__see below__]::size_type, Allocator)
-> unordered_node_map<xref:#unordered_node_map_range_key_type[__range-key-type__]<R>, xref:#unordered_node_map_range_mapped_type[__range-mapped-type__]<R>,
boost::hash<xref:#unordered_node_map_range_key_type[__range-key-type__]<R>>,
std::equal_to<xref:#unordered_node_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<xref:#unordered_node_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_node_map(FromRangeT&&, R&&, Allocator)
-> unordered_node_map<xref:#unordered_node_map_range_key_type[__range-key-type__]<R>, xref:#unordered_node_map_range_mapped_type[__range-mapped-type__]<R>,
boost::hash<xref:#unordered_node_map_range_key_type[__range-key-type__]<R>>,
std::equal_to<xref:#unordered_node_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<xref:#unordered_node_map_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Hash, class Allocator>
unordered_node_map(FromRangeT&&, R&&, typename xref:#unordered_node_map_deduction_guides[__see below__]::size_type, Hash,
Allocator)
-> unordered_node_map<xref:#unordered_node_map_range_key_type[__range-key-type__]<R>, xref:#unordered_node_map_range_mapped_type[__range-mapped-type__]<R>,
Hash, std::equal_to<xref:#unordered_node_map_range_key_type[__range-key-type__]<R>>, Allocator>;
template<class Key, class T, class Allocator> template<class Key, class T, class Allocator>
unordered_node_map(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_node_map_deduction_guides[__see below__]::size_type, unordered_node_map(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_node_map_deduction_guides[__see below__]::size_type,
Allocator) Allocator)
@@ -395,6 +442,15 @@ with `Iterator` = `iterator` and `NodeType` = `node_type`.
=== Constructors === Constructors
==== __container-compatible-range__
[listings,subs="+macros,+quotes"]
-----
template<class R, class T>
concept container_compatible_range =
std::ranges::input_range<R> &&
std::convertible_to<std::ranges::range_reference_t<R>, T>; // exposition only
-----
==== Default Constructor ==== Default Constructor
```c++ ```c++
unordered_node_map(); unordered_node_map();
@@ -530,6 +586,27 @@ Concurrency:;; Blocking on `other`.
--- ---
==== Range Constructor
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_node_map(FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Initializer List Constructor ==== Initializer List Constructor
[source,c++,subs="+quotes"] [source,c++,subs="+quotes"]
---- ----
@@ -540,7 +617,7 @@ unordered_node_map(std::initializer_list<value_type> il,
const allocator_type& a = allocator_type()); const allocator_type& a = allocator_type());
---- ----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a`, and inserts the elements from `il` into it. Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `il` into it.
[horizontal] [horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
@@ -602,6 +679,58 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/
--- ---
==== Range Constructor with Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_node_map(FromRangeT&&, R&& rg, const allocator_type& a);
----
Constructs an empty container using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_node_map(FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Hasher and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_node_map(FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== initializer_list Constructor with Allocator ==== initializer_list Constructor with Allocator
```c++ ```c++
@@ -763,7 +892,8 @@ size_type size() const noexcept;
``` ```
[horizontal] [horizontal]
Returns:;; `std::distance(begin(), end())` Returns:;; The number of elements in the container.
Complexity:;; Constant time.
--- ---
@@ -917,6 +1047,22 @@ Notes:;; Can invalidate iterators, but only if the insert causes the load to be
--- ---
==== Insert Range
[source,c++,subs="+macros,+quotes"]
----
template<xref:#unordered_node_map_container_compatible_range[__container-compatible-range__]<value_type> R>
void insert_range(R&& rg);
----
Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key.
[horizontal]
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into the container from `*std::ranges::begin(rg)`.
Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect.
Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load.
---
==== Insert Initializer List ==== Insert Initializer List
```c++ ```c++
void insert(std::initializer_list<value_type>); void insert(std::initializer_list<value_type>);
@@ -1548,6 +1694,42 @@ template<class InputIterator>
std::tuple_element_t<1, xref:#unordered_node_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only std::tuple_element_t<1, xref:#unordered_node_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only
----- -----
==== __convertible-to-from-range_t__
[listings,subs="+macros,+quotes"]
-----
template<typename FromRangeT>
concept __convertible-to-from_range_t__ =
// first clause not present if std::from_range_t does not exist
std::is_convertible_v<FromRangeT, std::from_range_t> ||
std::is_convertible_v<FromRangeT, boost::unordered::from_range_t>; // exposition only
-----
==== __range-key-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-key-type__ =
std::remove_cvref_t<
std::tuple_element_t<0, std::ranges::range_value_t<R>>>; // exposition only
-----
==== __range-mapped-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-mapped-type__ =
std::remove_cvref_t<
std::tuple_element_t<1, std::ranges::range_value_t<R>>>; // exposition only
-----
==== __range-to-alloc-type__
[listings,subs="+macros,+quotes"]
-----
template<std::ranges::input_range R>
using __range-to-alloc-type__ =
std::pair<const xref:#unordered_node_map_range_key_type[__range-key-type__]<R>, xref:#unordered_node_map_range_mapped_type[__range-mapped-type__]<R>>; // exposition only
-----
=== Equality Comparisons === Equality Comparisons
==== operator== ==== operator==
@@ -76,6 +76,12 @@ namespace unordered {
xref:#unordered_node_set_copy_constructor_with_allocator[unordered_node_set](const unordered_node_set& other, const Allocator& a); xref:#unordered_node_set_copy_constructor_with_allocator[unordered_node_set](const unordered_node_set& other, const Allocator& a);
xref:#unordered_node_set_move_constructor_with_allocator[unordered_node_set](unordered_node_set&& other, const Allocator& a); xref:#unordered_node_set_move_constructor_with_allocator[unordered_node_set](unordered_node_set&& other, const Allocator& a);
xref:#unordered_node_set_move_constructor_from_concurrent_node_set[unordered_node_set](concurrent_node_set<Key, Hash, Pred, Allocator>&& other); xref:#unordered_node_set_move_constructor_from_concurrent_node_set[unordered_node_set](concurrent_node_set<Key, Hash, Pred, Allocator>&& other);
template<class FromRangeT, xref:#unordered_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_node_set_range_constructor[unordered_node_set](FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
xref:#unordered_node_set_initializer_list_constructor[unordered_node_set](std::initializer_list<value_type> il, xref:#unordered_node_set_initializer_list_constructor[unordered_node_set](std::initializer_list<value_type> il,
size_type n = _implementation-defined_ size_type n = _implementation-defined_
const hasher& hf = hasher(), const hasher& hf = hasher(),
@@ -88,6 +94,13 @@ namespace unordered {
template<class InputIterator> template<class InputIterator>
xref:#unordered_node_set_iterator_range_constructor_with_bucket_count_and_hasher[unordered_node_set](InputIterator f, InputIterator l, size_type n, const hasher& hf, xref:#unordered_node_set_iterator_range_constructor_with_bucket_count_and_hasher[unordered_node_set](InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a); const allocator_type& a);
template<class FromRangeT, xref:#unordered_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_node_set_range_constructor_with_allocator[unordered_node_set](FromRangeT&&, R&& rg, const allocator_type& a);
template<class FromRangeT, xref:#unordered_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_node_set_range_constructor_with_bucket_count_and_allocator[unordered_node_set](FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
template<class FromRangeT, xref:#unordered_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_node_set_range_constructor_with_bucket_count_and_hasher_and_allocator[unordered_node_set](FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
xref:#unordered_node_set_initializer_list_constructor_with_allocator[unordered_node_set](std::initializer_list<value_type> il, const allocator_type& a); xref:#unordered_node_set_initializer_list_constructor_with_allocator[unordered_node_set](std::initializer_list<value_type> il, const allocator_type& a);
xref:#unordered_node_set_initializer_list_constructor_with_bucket_count_and_allocator[unordered_node_set](std::initializer_list<value_type> il, size_type n, xref:#unordered_node_set_initializer_list_constructor_with_bucket_count_and_allocator[unordered_node_set](std::initializer_list<value_type> il, size_type n,
const allocator_type& a); const allocator_type& a);
@@ -125,6 +138,8 @@ namespace unordered {
iterator xref:#unordered_node_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); iterator xref:#unordered_node_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj);
template<class K> iterator xref:#unordered_node_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k); template<class K> iterator xref:#unordered_node_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k);
template<class InputIterator> void xref:#unordered_node_set_insert_iterator_range[insert](InputIterator first, InputIterator last); template<class InputIterator> void xref:#unordered_node_set_insert_iterator_range[insert](InputIterator first, InputIterator last);
template<xref:#unordered_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
void xref:#unordered_node_set_insert_range[insert_range](R&& rg);
void xref:#unordered_node_set_insert_initializer_list[insert](std::initializer_list<value_type>); void xref:#unordered_node_set_insert_initializer_list[insert](std::initializer_list<value_type>);
insert_return_type xref:#unordered_node_set_insert_node[insert](node_type&& nh); insert_return_type xref:#unordered_node_set_insert_node[insert](node_type&& nh);
iterator xref:#unordered_node_set_insert_node_with_hint[insert](const_iterator hint, node_type&& nh); iterator xref:#unordered_node_set_insert_node_with_hint[insert](const_iterator hint, node_type&& nh);
@@ -197,6 +212,16 @@ namespace unordered {
Hash = Hash(), Pred = Pred(), Allocator = Allocator()) Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_node_set<xref:#unordered_node_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>; -> unordered_node_set<xref:#unordered_node_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>;
template<xref:#unordered_node_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R,
class Hash = boost::hash<std::ranges::range_value_t<R>>,
class Pred = std::equal_to<std::ranges::range_value_t<R>>,
class Allocator = std::allocator<std::ranges::range_value_t<R>>
unordered_node_set(FromRangeT&&, R&&,
typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type = xref:#unordered_node_set_deduction_guides[__see below__], Hash = Hash(),
Pred = Pred(), Allocator = Allocator())
-> unordered_node_set<std::ranges::range_value_t<R>, Hash, Pred,Allocator>;
template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>, template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>,
class Allocator = std::allocator<T>> class Allocator = std::allocator<T>>
unordered_node_set(std::initializer_list<T>, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type = xref:#unordered_node_set_deduction_guides[__see below__], unordered_node_set(std::initializer_list<T>, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type = xref:#unordered_node_set_deduction_guides[__see below__],
@@ -221,6 +246,27 @@ namespace unordered {
-> unordered_node_set<xref:#unordered_node_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, -> unordered_node_set<xref:#unordered_node_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash,
std::equal_to<xref:#unordered_node_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>; std::equal_to<xref:#unordered_node_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
template<xref:#unordered_node_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_node_set(FromRangeT&&, R&&, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type, Allocator)
-> unordered_node_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R>>,
std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<xref:#unordered_node_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_node_set(FromRangeT&&, R&&, Allocator)
-> unordered_node_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R>>,
std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<xref:#unordered_node_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Hash, class Allocator>
unordered_node_set(FromRangeT&&, R&&, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type, Hash,
Allocator)
-> unordered_node_set<std::ranges::range_value_t<R>,
Hash, std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<class T, class Allocator> template<class T, class Allocator>
unordered_node_set(std::initializer_list<T>, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type, Allocator) unordered_node_set(std::initializer_list<T>, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type, Allocator)
-> unordered_node_set<T, boost::hash<T>, std::equal_to<T>, Allocator>; -> unordered_node_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
@@ -345,6 +391,15 @@ with `Iterator` = `iterator` and `NodeType` = `node_type`.
=== Constructors === Constructors
==== __container-compatible-range__
[listings,subs="+macros,+quotes"]
-----
template<class R, class T>
concept container_compatible_range =
std::ranges::input_range<R> &&
std::convertible_to<std::ranges::range_reference_t<R>, T>; // exposition only
-----
==== Default Constructor ==== Default Constructor
```c++ ```c++
unordered_node_set(); unordered_node_set();
@@ -483,6 +538,27 @@ Concurrency:;; Blocking on `other`.
--- ---
==== Range Constructor
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_node_set(FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Initializer List Constructor ==== Initializer List Constructor
[source,c++,subs="+quotes"] [source,c++,subs="+quotes"]
---- ----
@@ -555,6 +631,58 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/
--- ---
==== Range Constructor with Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_node_set(FromRangeT&&, R&& rg, const allocator_type& a);
----
Constructs an empty container using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_node_set(FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Hasher and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_node_set(FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate, and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== initializer_list Constructor with Allocator ==== initializer_list Constructor with Allocator
```c++ ```c++
@@ -588,7 +716,7 @@ unordered_node_set(std::initializer_list<value_type> il, size_type n, const hash
const allocator_type& a); const allocator_type& a);
``` ```
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate,and inserts the elements from `il` into it. Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate, and inserts the elements from `il` into it.
[horizontal] [horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
@@ -716,7 +844,8 @@ size_type size() const noexcept;
``` ```
[horizontal] [horizontal]
Returns:;; `std::distance(begin(), end())` Returns:;; The number of elements in the container.
Complexity:;; Constant time.
--- ---
@@ -894,6 +1023,22 @@ Notes:;; Can invalidate iterators, but only if the insert causes the load to be
--- ---
==== Insert Range
[source,c++,subs="+macros,+quotes"]
----
template<xref:#unordered_node_set_container_compatible_range[__container-compatible-range__]<value_type> R>
void insert_range(R&& rg);
----
Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key.
[horizontal]
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into the container from `*std::ranges::begin(rg)`.
Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect.
Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load.
---
==== Insert Initializer List ==== Insert Initializer List
```c++ ```c++
void insert(std::initializer_list<value_type>); void insert(std::initializer_list<value_type>);
@@ -1301,6 +1446,16 @@ template<class InputIterator>
typename std::iterator_traits<InputIterator>::value_type; // exposition only typename std::iterator_traits<InputIterator>::value_type; // exposition only
----- -----
==== __convertible-to-from-range_t__
[listings,subs="+macros,+quotes"]
-----
template<typename FromRangeT>
concept __convertible-to-from_range_t__ =
// first clause not present if std::from_range_t does not exist
std::is_convertible_v<FromRangeT, std::from_range_t> ||
std::is_convertible_v<FromRangeT, boost::unordered::from_range_t>; // exposition only
-----
=== Equality Comparisons === Equality Comparisons
==== operator== ==== operator==
@@ -59,6 +59,12 @@ namespace unordered {
explicit xref:#unordered_set_allocator_constructor[unordered_set](const Allocator& a); explicit xref:#unordered_set_allocator_constructor[unordered_set](const Allocator& a);
xref:#unordered_set_copy_constructor_with_allocator[unordered_set](const unordered_set& other, const Allocator& a); xref:#unordered_set_copy_constructor_with_allocator[unordered_set](const unordered_set& other, const Allocator& a);
xref:#unordered_set_move_constructor_with_allocator[unordered_set](unordered_set&& other, const Allocator& a); xref:#unordered_set_move_constructor_with_allocator[unordered_set](unordered_set&& other, const Allocator& a);
template<class FromRangeT, xref:#unordered_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_set_range_constructor[unordered_set](FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
xref:#unordered_set_initializer_list_constructor[unordered_set](std::initializer_list<value_type> il, xref:#unordered_set_initializer_list_constructor[unordered_set](std::initializer_list<value_type> il,
size_type n = _implementation-defined_, size_type n = _implementation-defined_,
const hasher& hf = hasher(), const hasher& hf = hasher(),
@@ -71,6 +77,13 @@ namespace unordered {
template<class InputIterator> template<class InputIterator>
xref:#unordered_set_iterator_range_constructor_with_bucket_count_and_hasher[unordered_set](InputIterator f, InputIterator l, size_type n, const hasher& hf, xref:#unordered_set_iterator_range_constructor_with_bucket_count_and_hasher[unordered_set](InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a); const allocator_type& a);
template<class FromRangeT, xref:#unordered_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_set_range_constructor_with_allocator[unordered_set](FromRangeT&&, R&& rg, const allocator_type& a);
template<class FromRangeT, xref:#unordered_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_set_range_constructor_with_bucket_count_and_allocator[unordered_set](FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
template<class FromRangeT, xref:#unordered_set_container_compatible_range[__container-compatible-range__]<value_type> R>
xref:#unordered_set_range_constructor_with_bucket_count_and_hasher_and_allocator[unordered_set](FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
xref:#unordered_set_initializer_list_constructor_with_allocator[unordered_set](std::initializer_list<value_type> il, const allocator_type& a); xref:#unordered_set_initializer_list_constructor_with_allocator[unordered_set](std::initializer_list<value_type> il, const allocator_type& a);
xref:#unordered_set_initializer_list_constructor_with_bucket_count_and_allocator[unordered_set](std::initializer_list<value_type> il, size_type n, const allocator_type& a); xref:#unordered_set_initializer_list_constructor_with_bucket_count_and_allocator[unordered_set](std::initializer_list<value_type> il, size_type n, const allocator_type& a);
xref:#unordered_set_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[unordered_set](std::initializer_list<value_type> il, size_type n, const hasher& hf, xref:#unordered_set_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[unordered_set](std::initializer_list<value_type> il, size_type n, const hasher& hf,
@@ -107,6 +120,8 @@ namespace unordered {
iterator xref:#unordered_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); iterator xref:#unordered_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj);
template<class K> iterator xref:#unordered_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k); template<class K> iterator xref:#unordered_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k);
template<class InputIterator> void xref:#unordered_set_insert_iterator_range[insert](InputIterator first, InputIterator last); template<class InputIterator> void xref:#unordered_set_insert_iterator_range[insert](InputIterator first, InputIterator last);
template<xref:#unordered_set_container_compatible_range[__container-compatible-range__]<value_type> R>
void xref:#unordered_set_insert_range[insert_range](R&& rg);
void xref:#unordered_set_insert_initializer_list[insert](std::initializer_list<value_type>); void xref:#unordered_set_insert_initializer_list[insert](std::initializer_list<value_type>);
node_type xref:#unordered_set_extract_by_iterator[extract](const_iterator position); node_type xref:#unordered_set_extract_by_iterator[extract](const_iterator position);
@@ -197,6 +212,16 @@ namespace unordered {
Hash = Hash(), Pred = Pred(), Allocator = Allocator()) Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_set<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>; -> unordered_set<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>;
template<xref:#unordered_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R,
class Hash = boost::hash<std::ranges::range_value_t<R>>,
class Pred = std::equal_to<std::ranges::range_value_t<R>>,
class Allocator = std::allocator<std::ranges::range_value_t<R>>
unordered_set(FromRangeT&&, R&&,
typename xref:#unordered_set_deduction_guides[__see below__]::size_type = xref:#unordered_set_deduction_guides[__see below__], Hash = Hash(),
Pred = Pred(), Allocator = Allocator())
-> unordered_set<std::ranges::range_value_t<R>, Hash, Pred,Allocator>;
template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>, template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>,
class Allocator = std::allocator<T>> class Allocator = std::allocator<T>>
unordered_set(std::initializer_list<T>, typename xref:#unordered_set_deduction_guides[__see below__]::size_type = xref:#unordered_set_deduction_guides[__see below__], unordered_set(std::initializer_list<T>, typename xref:#unordered_set_deduction_guides[__see below__]::size_type = xref:#unordered_set_deduction_guides[__see below__],
@@ -220,6 +245,27 @@ namespace unordered {
-> unordered_set<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, -> unordered_set<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash,
std::equal_to<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>; std::equal_to<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
template<xref:#unordered_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_set(FromRangeT&&, R&&, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Allocator)
-> unordered_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R>>,
std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<xref:#unordered_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Allocator>
unordered_set(FromRangeT&&, R&&, Allocator)
-> unordered_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R>>,
std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<xref:#unordered_set_convertible_to_from_range_t[__convertible-to-from-range_t__] FromRangeT,
std::ranges::input_range R, class Hash, class Allocator>
unordered_set(FromRangeT&&, R&&, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Hash,
Allocator)
-> unordered_set<std::ranges::range_value_t<R>,
Hash, std::equal_to<std::ranges::range_value_t<R>>, Allocator>;
template<class T, class Allocator> template<class T, class Allocator>
unordered_set(std::initializer_list<T>, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Allocator) unordered_set(std::initializer_list<T>, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Allocator)
-> unordered_set<T, boost::hash<T>, std::equal_to<T>, Allocator>; -> unordered_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
@@ -353,6 +399,16 @@ with `Iterator` = `iterator` and `NodeType` = `node_type`.
=== Constructors === Constructors
==== __container-compatible-range__
[listings,subs="+macros,+quotes"]
-----
template<class R, class T>
concept container_compatible_range =
std::ranges::input_range<R> &&
std::convertible_to<std::ranges::range_reference_t<R>, T>; // exposition only
-----
==== Default Constructor ==== Default Constructor
```c++ ```c++
unordered_set(); unordered_set();
@@ -475,6 +531,27 @@ Requires:;; `value_type` is move insertable.
--- ---
==== Range Constructor
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_set_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_set(FromRangeT&&, R&& rg,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate, `a` as the allocator and a maximum load factor of `1.0` and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Initializer List Constructor ==== Initializer List Constructor
[source,c++,subs="+quotes"] [source,c++,subs="+quotes"]
---- ----
@@ -547,6 +624,58 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/
--- ---
==== Range Constructor with Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_set_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_set(FromRangeT&&, R&& rg, const allocator_type& a);
----
Constructs an empty container using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_set_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_set(FromRangeT&&, R&& rg, size_type n, const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== Range Constructor with Bucket Count and Hasher and Allocator
[source,c++,subs="+macros,+quotes"]
----
template<class FromRangeT, xref:#unordered_set_container_compatible_range[__container-compatible-range__]<value_type> R>
unordered_set(FromRangeT&&, R&& rg, size_type n, const hasher& hf,
const allocator_type& a);
----
Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `rg` into it.
Only participates in overload resolution if `FromRangeT` is convertible to `std::from_range_t` or `boost::unordered::from_range_t`.
[horizontal]
Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^].
---
==== initializer_list Constructor with Allocator ==== initializer_list Constructor with Allocator
```c++ ```c++
@@ -707,7 +836,8 @@ size_type size() const noexcept;
``` ```
[horizontal] [horizontal]
Returns:;; `std::distance(begin(), end())` Returns:;; The number of elements in the container.
Complexity:;; Constant time.
--- ---
@@ -903,6 +1033,24 @@ Pointers and references to elements are never invalidated.
--- ---
==== Insert Range
[source,c++,subs="+macros,+quotes"]
----
template<xref:#unordered_set_container_compatible_range[__container-compatible-range__]<value_type> R>
void insert_range(R&& rg);
----
Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key.
[horizontal]
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into the container from `*std::ranges::begin(rg)`.
Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect.
Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. +
+
Pointers and references to elements are never invalidated.
---
==== Insert Initializer List ==== Insert Initializer List
```c++ ```c++
void insert(std::initializer_list<value_type>); void insert(std::initializer_list<value_type>);
@@ -1423,6 +1571,16 @@ template<class InputIterator>
typename std::iterator_traits<InputIterator>::value_type; // exposition only typename std::iterator_traits<InputIterator>::value_type; // exposition only
----- -----
==== __convertible-to-from-range_t__
[listings,subs="+macros,+quotes"]
-----
template<typename FromRangeT>
concept __convertible-to-from_range_t__ =
// first clause not present if std::from_range_t does not exist
std::is_convertible_v<FromRangeT, std::from_range_t> ||
std::is_convertible_v<FromRangeT, boost::unordered::from_range_t>; // exposition only
-----
=== Equality Comparisons === Equality Comparisons
==== operator== ==== operator==
+1931 -1541
View File
File diff suppressed because it is too large Load Diff
+6 -3
View File
@@ -1,7 +1,10 @@
{ {
"devDependencies": { "devDependencies": {
"@antora/cli": "3.1.10", "@antora/cli": ">=3.1.14",
"@antora/site-generator": "3.1.10", "@antora/site-generator": ">=3.1.14",
"antora": "3.1.10" "antora": ">=3.1.14"
},
"dependencies": {
"@cppalliance/antora-downloads-extension": "^0.0.2"
} }
} }
+4
View File
@@ -12,3 +12,7 @@ ui:
bundle: bundle:
url: https://github.com/boostorg/unordered-ui-bundle/raw/c80db72a7ba804256beb36e3a46d9c7df265d8d7/ui-bundle.zip url: https://github.com/boostorg/unordered-ui-bundle/raw/c80db72a7ba804256beb36e3a46d9c7df265d8d7/ui-bundle.zip
output_dir: unordered/_ output_dir: unordered/_
antora:
extensions:
- require: '@cppalliance/antora-downloads-extension'
+36 -32
View File
@@ -1,4 +1,4 @@
# Copyright 2024 Braden Ganetsky # Copyright 2024-2026 Braden Ganetsky
# Distributed under the Boost Software License, Version 1.0. # Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt # https://www.boost.org/LICENSE_1_0.txt
@@ -16,8 +16,14 @@ class BoostUnorderedHelpers:
return n return n
def maybe_unwrap_foa_element(e): def maybe_unwrap_foa_element(e):
if f"{e.type.strip_typedefs()}".startswith("boost::unordered::detail::foa::element_type<"): # Sometimes the complex typedefs can't be resolved through a pointer
return e["p"] if e.type.strip_typedefs().code == gdb.TYPE_CODE_PTR:
foa_element = e.dereference()
else:
foa_element = e
if f"{foa_element.type.strip_typedefs()}".startswith("boost::unordered::detail::foa::element_type<"):
return foa_element["p"]
else: else:
return e return e
@@ -45,14 +51,15 @@ class BoostUnorderedPointerCustomizationPoint:
class BoostUnorderedFcaPrinter: class BoostUnorderedFcaPrinter:
def __init__(self, val): def __init__(self, val):
self.val = BoostUnorderedHelpers.maybe_unwrap_reference(val) val = BoostUnorderedHelpers.maybe_unwrap_reference(val)
self.name = f"{self.val.type.strip_typedefs()}".split("<")[0] self.table = val["table_"]
self.name = f"{val.type.strip_typedefs()}".split("<")[0]
self.name = self.name.replace("boost::unordered::", "boost::") self.name = self.name.replace("boost::unordered::", "boost::")
self.is_map = self.name.endswith("map") self.is_map = self.name.endswith("map")
self.cpo = BoostUnorderedPointerCustomizationPoint(self.val["table_"]["buckets_"]["buckets"]) self.cpo = BoostUnorderedPointerCustomizationPoint(self.table["buckets_"]["buckets"])
def to_string(self): def to_string(self):
size = self.val["table_"]["size_"] size = self.table["size_"]
return f"{self.name} with {size} elements" return f"{self.name} with {size} elements"
def display_hint(self): def display_hint(self):
@@ -60,7 +67,7 @@ class BoostUnorderedFcaPrinter:
def children(self): def children(self):
def generator(): def generator():
grouped_buckets = self.val["table_"]["buckets_"] grouped_buckets = self.table["buckets_"]
size = grouped_buckets["size_"] size = grouped_buckets["size_"]
buckets = grouped_buckets["buckets"] buckets = grouped_buckets["buckets"]
@@ -154,14 +161,20 @@ class BoostUnorderedFoaCumulativeStatsPrinter:
class BoostUnorderedFoaPrinter: class BoostUnorderedFoaPrinter:
def __init__(self, val): def __init__(self, val):
self.val = BoostUnorderedHelpers.maybe_unwrap_reference(val) val = BoostUnorderedHelpers.maybe_unwrap_reference(val)
self.name = f"{self.val.type.strip_typedefs()}".split("<")[0] self.table = val["table_"]
self.name = f"{val.type.strip_typedefs()}".split("<")[0]
self.name = self.name.replace("boost::unordered::", "boost::") self.name = self.name.replace("boost::unordered::", "boost::")
self.is_map = self.name.endswith("map") self.is_map = self.name.endswith("map")
self.cpo = BoostUnorderedPointerCustomizationPoint(self.val["table_"]["arrays"]["groups_"]) self.cpo = BoostUnorderedPointerCustomizationPoint(self.table["arrays"]["groups_"])
self.groups = self.cpo.to_address(self.table["arrays"]["groups_"])
self.elements = self.cpo.to_address(self.table["arrays"]["elements_"])
self.N = 15 # `self.groups.dereference()["N"]` may be optimized out
self.sentinel_ = 1 # `self.groups.dereference()["sentinel_"]` may be optimized out
def to_string(self): def to_string(self):
size = BoostUnorderedHelpers.maybe_unwrap_atomic(self.val["table_"]["size_ctrl"]["size"]) size = BoostUnorderedHelpers.maybe_unwrap_atomic(self.table["size_ctrl"]["size"])
return f"{self.name} with {size} elements" return f"{self.name} with {size} elements"
def display_hint(self): def display_hint(self):
@@ -191,30 +204,21 @@ class BoostUnorderedFoaPrinter:
m = group["m"] m = group["m"]
at = lambda b: BoostUnorderedHelpers.maybe_unwrap_atomic(m[b]["n"]) at = lambda b: BoostUnorderedHelpers.maybe_unwrap_atomic(m[b]["n"])
N = group["N"]
sentinel_ = group["sentinel_"]
if self.is_regular_layout(group): if self.is_regular_layout(group):
return pos == N-1 and at(N-1) == sentinel_ return pos == self.N-1 and at(self.N-1) == self.sentinel_
else: else:
return pos == N-1 and (at(0) & 0x4000400040004000) == 0x4000 and (at(1) & 0x4000400040004000) == 0 return pos == self.N-1 and (at(0) & 0x4000400040004000) == 0x4000 and (at(1) & 0x4000400040004000) == 0
def children(self): def children(self):
def generator(): def generator():
table = self.val["table_"] pc_ = self.groups.cast(gdb.lookup_type("unsigned char").pointer())
groups = self.cpo.to_address(table["arrays"]["groups_"]) p_ = self.elements
elements = self.cpo.to_address(table["arrays"]["elements_"])
pc_ = groups.cast(gdb.lookup_type("unsigned char").pointer())
p_ = elements
first_time = True first_time = True
mask = 0
n0 = 0
n = 0
count = 0 count = 0
while p_ != 0: while p_ != 0:
# This if block mirrors the condition in the begin() call # This if block mirrors the condition in the begin() call
if (not first_time) or (self.match_occupied(groups.dereference()) & 1): if (not first_time) or (self.match_occupied(self.groups.dereference()) & 1):
pointer = BoostUnorderedHelpers.maybe_unwrap_foa_element(p_) pointer = BoostUnorderedHelpers.maybe_unwrap_foa_element(p_)
value = self.cpo.to_address(pointer).dereference() value = self.cpo.to_address(pointer).dereference()
if self.is_map: if self.is_map:
@@ -228,17 +232,17 @@ class BoostUnorderedFoaPrinter:
count += 1 count += 1
first_time = False first_time = False
n0 = pc_.cast(gdb.lookup_type("uintptr_t")) % groups.dereference().type.sizeof n0 = pc_.cast(gdb.lookup_type("uintptr_t")) % self.groups.dereference().type.sizeof
pc_ = self.cpo.next(pc_, -n0) pc_ = self.cpo.next(pc_, -n0)
mask = (self.match_occupied(pc_.cast(groups.type).dereference()) >> (n0+1)) << (n0+1) mask = (self.match_occupied(pc_.cast(self.groups.type).dereference()) >> (n0+1)) << (n0+1)
while mask == 0: while mask == 0:
pc_ = self.cpo.next(pc_, groups.dereference().type.sizeof) pc_ = self.cpo.next(pc_, self.groups.dereference().type.sizeof)
p_ = self.cpo.next(p_, groups.dereference()["N"]) p_ = self.cpo.next(p_, self.N)
mask = self.match_occupied(pc_.cast(groups.type).dereference()) mask = self.match_occupied(pc_.cast(self.groups.type).dereference())
n = BoostUnorderedHelpers.countr_zero(mask) n = BoostUnorderedHelpers.countr_zero(mask)
if self.is_sentinel(pc_.cast(groups.type).dereference(), n): if self.is_sentinel(pc_.cast(self.groups.type).dereference(), n):
p_ = 0 p_ = 0
else: else:
pc_ = self.cpo.next(pc_, n) pc_ = self.cpo.next(pc_, n)
+196 -6
View File
@@ -1,7 +1,8 @@
/* Fast open-addressing concurrent hashmap. /* Fast open-addressing concurrent hashmap.
* *
* Copyright 2023 Christian Mazakas. * Copyright 2023 Christian Mazakas.
* Copyright 2023-2024 Joaquin M Lopez Munoz. * Copyright 2023-2026 Joaquin M Lopez Munoz.
* Copyright 2026 Braden Ganetsky
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -16,6 +17,7 @@
#include <boost/unordered/detail/concurrent_static_asserts.hpp> #include <boost/unordered/detail/concurrent_static_asserts.hpp>
#include <boost/unordered/detail/foa/concurrent_table.hpp> #include <boost/unordered/detail/foa/concurrent_table.hpp>
#include <boost/unordered/detail/foa/flat_map_types.hpp> #include <boost/unordered/detail/foa/flat_map_types.hpp>
#include <boost/unordered/detail/ranges_support.hpp>
#include <boost/unordered/detail/type_traits.hpp> #include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_flat_map_fwd.hpp> #include <boost/unordered/unordered_flat_map_fwd.hpp>
@@ -101,6 +103,21 @@ namespace boost {
this->insert(f, l); this->insert(f, l);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_flat_map(FromRangeT&&, R&& rg,
size_type n = detail::foa::default_bucket_count,
const hasher& hf = hasher(), const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type())
: table_(n, hf, eql, a)
{
this->insert_range(std::forward<R>(rg));
}
#endif
concurrent_flat_map(concurrent_flat_map const& rhs) concurrent_flat_map(concurrent_flat_map const& rhs)
: table_(rhs.table_, : table_(rhs.table_,
boost::allocator_select_on_container_copy_construction( boost::allocator_select_on_container_copy_construction(
@@ -120,6 +137,19 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_flat_map(
FromRangeT&& fr, R&& rg, allocator_type const& a)
: concurrent_flat_map(
fr, std::forward<R>(rg), 0, hasher(), key_equal(), a)
{
}
#endif
explicit concurrent_flat_map(allocator_type const& a) explicit concurrent_flat_map(allocator_type const& a)
: table_(detail::foa::default_bucket_count, hasher(), key_equal(), a) : table_(detail::foa::default_bucket_count, hasher(), key_equal(), a)
{ {
@@ -170,6 +200,29 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_flat_map(
FromRangeT&& fr, R&& rg, size_type n, const allocator_type& a)
: concurrent_flat_map(
fr, std::forward<R>(rg), n, hasher(), key_equal(), a)
{
}
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_flat_map(FromRangeT&& fr, R&& rg, size_type n,
const hasher& hf, const allocator_type& a)
: concurrent_flat_map(fr, std::forward<R>(rg), n, hf, key_equal(), a)
{
}
#endif
concurrent_flat_map( concurrent_flat_map(
std::initializer_list<value_type> il, const allocator_type& a) std::initializer_list<value_type> il, const allocator_type& a)
: concurrent_flat_map( : concurrent_flat_map(
@@ -189,10 +242,10 @@ namespace boost {
{ {
} }
template <typename Key2,
template <bool avoid_explicit_instantiation = true> typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
concurrent_flat_map( concurrent_flat_map(
unordered_flat_map<Key, T, Hash, Pred, Allocator>&& other) unordered_flat_map<Key2, T, Hash, Pred, Allocator>&& other)
: table_(std::move(other.table_)) : table_(std::move(other.table_))
{ {
} }
@@ -423,12 +476,26 @@ namespace boost {
size_type insert(InputIterator begin, InputIterator end) size_type insert(InputIterator begin, InputIterator end)
{ {
size_type count_elements = 0; size_type count_elements = 0;
for (auto pos = begin; pos != end; ++pos, ++count_elements) { for (auto pos = begin; pos != end; ++pos) {
table_.emplace(*pos); if (table_.emplace(*pos)) ++count_elements;
} }
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R>
size_type insert_range(R&& rg)
{
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
while (first != last) {
if (table_.emplace(*first++)) ++count_elements;
}
return count_elements;
}
#endif
size_type insert(std::initializer_list<value_type> ilist) size_type insert(std::initializer_list<value_type> ilist)
{ {
return this->insert(ilist.begin(), ilist.end()); return this->insert(ilist.begin(), ilist.end());
@@ -484,6 +551,21 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R, class F>
size_type insert_range_or_visit(R&& rg, F f)
{
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_or_visit(*first, f);
}
return count_elements;
}
#endif
template <class F> template <class F>
size_type insert_or_visit(std::initializer_list<value_type> ilist, F f) size_type insert_or_visit(std::initializer_list<value_type> ilist, F f)
{ {
@@ -517,6 +599,21 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R, class F>
size_type insert_range_or_cvisit(R&& rg, F f)
{
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_or_cvisit(*first, f);
}
return count_elements;
}
#endif
template <class F> template <class F>
size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f) size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
{ {
@@ -554,6 +651,24 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::container_compatible_range<value_type> R, class F1, class F2
>
size_type insert_range_and_visit(R&& rg, F1 f1, F2 f2)
{
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_and_visit(*first, f1, f2);
}
return count_elements;
}
#endif
template <class F1, class F2> template <class F1, class F2>
size_type insert_and_visit( size_type insert_and_visit(
std::initializer_list<value_type> ilist, F1 f1, F2 f2) std::initializer_list<value_type> ilist, F1 f1, F2 f2)
@@ -594,6 +709,24 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::container_compatible_range<value_type> R, class F1, class F2
>
size_type insert_range_and_cvisit(R&& rg, F1 f1, F2 f2)
{
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_and_cvisit(*first, f1, f2);
}
return count_elements;
}
#endif
template <class F1, class F2> template <class F1, class F2>
size_type insert_and_cvisit( size_type insert_and_cvisit(
std::initializer_list<value_type> ilist, F1 f1, F2 f2) std::initializer_list<value_type> ilist, F1 f1, F2 f2)
@@ -979,6 +1112,27 @@ namespace boost {
boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred, boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash =
boost::hash<boost::unordered::detail::range_key_t<R> >,
class Pred =
std::equal_to<boost::unordered::detail::range_key_t<R> >,
class Allocator = std::allocator<
boost::unordered::detail::range_to_alloc_t<R> >,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_pred_v<Pred> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_flat_map(FromRangeT&&, R&&,
std::size_t = boost::unordered::detail::foa::default_bucket_count,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> concurrent_flat_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>, Hash, Pred,
Allocator>;
#endif
template <class Key, class T, template <class Key, class T,
class Hash = boost::hash<std::remove_const_t<Key> >, class Hash = boost::hash<std::remove_const_t<Key> >,
class Pred = std::equal_to<std::remove_const_t<Key> >, class Pred = std::equal_to<std::remove_const_t<Key> >,
@@ -1026,6 +1180,42 @@ namespace boost {
std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >, std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_flat_map(FromRangeT&&, R&&, std::size_t, Allocator)
-> concurrent_flat_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>,
boost::hash<boost::unordered::detail::range_key_t<R> >,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_flat_map(FromRangeT&&, R&&, Allocator)
-> concurrent_flat_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>,
boost::hash<boost::unordered::detail::range_key_t<R> >,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash, class Allocator,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_flat_map(
FromRangeT&&, R&&, std::size_t, Hash, Allocator)
-> concurrent_flat_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>, Hash,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
#endif
template <class Key, class T, class Allocator, template <class Key, class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_flat_map(std::initializer_list<std::pair<Key, T> >, std::size_t, concurrent_flat_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
+191 -6
View File
@@ -1,7 +1,8 @@
/* Fast open-addressing concurrent hashset. /* Fast open-addressing concurrent hashset.
* *
* Copyright 2023 Christian Mazakas. * Copyright 2023 Christian Mazakas.
* Copyright 2023-2024 Joaquin M Lopez Munoz. * Copyright 2023-2026 Joaquin M Lopez Munoz.
* Copyright 2026 Braden Ganetsky
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -16,6 +17,7 @@
#include <boost/unordered/detail/concurrent_static_asserts.hpp> #include <boost/unordered/detail/concurrent_static_asserts.hpp>
#include <boost/unordered/detail/foa/concurrent_table.hpp> #include <boost/unordered/detail/foa/concurrent_table.hpp>
#include <boost/unordered/detail/foa/flat_set_types.hpp> #include <boost/unordered/detail/foa/flat_set_types.hpp>
#include <boost/unordered/detail/ranges_support.hpp>
#include <boost/unordered/detail/type_traits.hpp> #include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_flat_set_fwd.hpp> #include <boost/unordered/unordered_flat_set_fwd.hpp>
@@ -98,6 +100,21 @@ namespace boost {
this->insert(f, l); this->insert(f, l);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_flat_set(FromRangeT&&, R&& rg,
size_type n = detail::foa::default_bucket_count,
const hasher& hf = hasher(), const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type())
: table_(n, hf, eql, a)
{
this->insert_range(std::forward<R>(rg));
}
#endif
concurrent_flat_set(concurrent_flat_set const& rhs) concurrent_flat_set(concurrent_flat_set const& rhs)
: table_(rhs.table_, : table_(rhs.table_,
boost::allocator_select_on_container_copy_construction( boost::allocator_select_on_container_copy_construction(
@@ -117,6 +134,19 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_flat_set(
FromRangeT&& fr, R&& rg, allocator_type const& a)
: concurrent_flat_set(
fr, std::forward<R>(rg), 0, hasher(), key_equal(), a)
{
}
#endif
explicit concurrent_flat_set(allocator_type const& a) explicit concurrent_flat_set(allocator_type const& a)
: table_(detail::foa::default_bucket_count, hasher(), key_equal(), a) : table_(detail::foa::default_bucket_count, hasher(), key_equal(), a)
{ {
@@ -167,6 +197,29 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_flat_set(
FromRangeT&& fr, R&& rg, size_type n, const allocator_type& a)
: concurrent_flat_set(
fr, std::forward<R>(rg), n, hasher(), key_equal(), a)
{
}
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_flat_set(FromRangeT&& fr, R&& rg, size_type n,
const hasher& hf, const allocator_type& a)
: concurrent_flat_set(fr, std::forward<R>(rg), n, hf, key_equal(), a)
{
}
#endif
concurrent_flat_set( concurrent_flat_set(
std::initializer_list<value_type> il, const allocator_type& a) std::initializer_list<value_type> il, const allocator_type& a)
: concurrent_flat_set( : concurrent_flat_set(
@@ -186,10 +239,10 @@ namespace boost {
{ {
} }
template <typename Key2,
template <bool avoid_explicit_instantiation = true> typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
concurrent_flat_set( concurrent_flat_set(
unordered_flat_set<Key, Hash, Pred, Allocator>&& other) unordered_flat_set<Key2, Hash, Pred, Allocator>&& other)
: table_(std::move(other.table_)) : table_(std::move(other.table_))
{ {
} }
@@ -429,12 +482,26 @@ namespace boost {
size_type insert(InputIterator begin, InputIterator end) size_type insert(InputIterator begin, InputIterator end)
{ {
size_type count_elements = 0; size_type count_elements = 0;
for (auto pos = begin; pos != end; ++pos, ++count_elements) { for (auto pos = begin; pos != end; ++pos) {
table_.emplace(*pos); if (table_.emplace(*pos)) ++count_elements;
} }
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R>
size_type insert_range(R&& rg)
{
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
while (first != last) {
if (table_.emplace(*first++)) ++count_elements;
}
return count_elements;
}
#endif
size_type insert(std::initializer_list<value_type> ilist) size_type insert(std::initializer_list<value_type> ilist)
{ {
return this->insert(ilist.begin(), ilist.end()); return this->insert(ilist.begin(), ilist.end());
@@ -475,6 +542,21 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R, class F>
size_type insert_range_or_visit(R&& rg, F f)
{
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_or_visit(*first, f);
}
return count_elements;
}
#endif
template <class F> template <class F>
size_type insert_or_visit(std::initializer_list<value_type> ilist, F f) size_type insert_or_visit(std::initializer_list<value_type> ilist, F f)
{ {
@@ -517,6 +599,21 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R, class F>
size_type insert_range_or_cvisit(R&& rg, F f)
{
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_or_cvisit(*first, f);
}
return count_elements;
}
#endif
template <class F> template <class F>
size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f) size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
{ {
@@ -565,6 +662,24 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::container_compatible_range<value_type> R, class F1, class F2
>
size_type insert_range_and_visit(R&& rg, F1 f1, F2 f2)
{
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_and_visit(*first, f1, f2);
}
return count_elements;
}
#endif
template <class F1, class F2> template <class F1, class F2>
size_type insert_and_visit(std::initializer_list<value_type> ilist, F1 f1, F2 f2) size_type insert_and_visit(std::initializer_list<value_type> ilist, F1 f1, F2 f2)
{ {
@@ -615,6 +730,24 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::container_compatible_range<value_type> R, class F1, class F2
>
size_type insert_range_and_cvisit(R&& rg, F1 f1, F2 f2)
{
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_and_cvisit(*first, f1, f2);
}
return count_elements;
}
#endif
template <class F1, class F2> template <class F1, class F2>
size_type insert_and_cvisit( size_type insert_and_cvisit(
std::initializer_list<value_type> ilist, F1 f1, F2 f2) std::initializer_list<value_type> ilist, F1 f1, F2 f2)
@@ -852,6 +985,25 @@ namespace boost {
typename std::iterator_traits<InputIterator>::value_type, Hash, Pred, typename std::iterator_traits<InputIterator>::value_type, Hash, Pred,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash =
boost::hash<std::ranges::range_value_t<R> >,
class Pred =
std::equal_to<std::ranges::range_value_t<R> >,
class Allocator = std::allocator<std::ranges::range_value_t<R> >,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_pred_v<Pred> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_flat_set(FromRangeT&&, R&&,
std::size_t = boost::unordered::detail::foa::default_bucket_count,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> concurrent_flat_set<std::ranges::range_value_t<R>,
Hash, Pred, Allocator>;
#endif
template <class T, class Hash = boost::hash<T>, template <class T, class Hash = boost::hash<T>,
class Pred = std::equal_to<T>, class Allocator = std::allocator<T>, class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
class = std::enable_if_t<detail::is_hash_v<Hash> >, class = std::enable_if_t<detail::is_hash_v<Hash> >,
@@ -893,6 +1045,39 @@ namespace boost {
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>, std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_flat_set(FromRangeT&&, R&&, std::size_t, Allocator)
-> concurrent_flat_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R> >,
std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash, class Allocator,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_flat_set(
FromRangeT&&, R&&, std::size_t, Hash, Allocator)
-> concurrent_flat_set<std::ranges::range_value_t<R>,
Hash, std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_flat_set(FromRangeT&&, R&&, Allocator)
-> concurrent_flat_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R> >,
std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
#endif
template <class T, class Allocator, template <class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_flat_set(std::initializer_list<T>, std::size_t, Allocator) concurrent_flat_set(std::initializer_list<T>, std::size_t, Allocator)
+196 -5
View File
@@ -1,7 +1,8 @@
/* Fast open-addressing, node-based concurrent hashmap. /* Fast open-addressing, node-based concurrent hashmap.
* *
* Copyright 2023 Christian Mazakas. * Copyright 2023 Christian Mazakas.
* Copyright 2023-2024 Joaquin M Lopez Munoz. * Copyright 2023-2026 Joaquin M Lopez Munoz.
* Copyright 2026 Braden Ganetsky
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -18,6 +19,7 @@
#include <boost/unordered/detail/foa/element_type.hpp> #include <boost/unordered/detail/foa/element_type.hpp>
#include <boost/unordered/detail/foa/node_map_handle.hpp> #include <boost/unordered/detail/foa/node_map_handle.hpp>
#include <boost/unordered/detail/foa/node_map_types.hpp> #include <boost/unordered/detail/foa/node_map_types.hpp>
#include <boost/unordered/detail/ranges_support.hpp>
#include <boost/unordered/detail/type_traits.hpp> #include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_node_map_fwd.hpp> #include <boost/unordered/unordered_node_map_fwd.hpp>
@@ -109,6 +111,21 @@ namespace boost {
this->insert(f, l); this->insert(f, l);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_node_map(FromRangeT&&, R&& rg,
size_type n = detail::foa::default_bucket_count,
const hasher& hf = hasher(), const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type())
: table_(n, hf, eql, a)
{
this->insert_range(std::forward<R>(rg));
}
#endif
concurrent_node_map(concurrent_node_map const& rhs) concurrent_node_map(concurrent_node_map const& rhs)
: table_(rhs.table_, : table_(rhs.table_,
boost::allocator_select_on_container_copy_construction( boost::allocator_select_on_container_copy_construction(
@@ -128,6 +145,19 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_node_map(
FromRangeT&& fr, R&& rg, allocator_type const& a)
: concurrent_node_map(
fr, std::forward<R>(rg), 0, hasher(), key_equal(), a)
{
}
#endif
explicit concurrent_node_map(allocator_type const& a) explicit concurrent_node_map(allocator_type const& a)
: table_(detail::foa::default_bucket_count, hasher(), key_equal(), a) : table_(detail::foa::default_bucket_count, hasher(), key_equal(), a)
{ {
@@ -178,6 +208,29 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_node_map(
FromRangeT&& fr, R&& rg, size_type n, const allocator_type& a)
: concurrent_node_map(
fr, std::forward<R>(rg), n, hasher(), key_equal(), a)
{
}
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_node_map(FromRangeT&& fr, R&& rg, size_type n,
const hasher& hf, const allocator_type& a)
: concurrent_node_map(fr, std::forward<R>(rg), n, hf, key_equal(), a)
{
}
#endif
concurrent_node_map( concurrent_node_map(
std::initializer_list<value_type> il, const allocator_type& a) std::initializer_list<value_type> il, const allocator_type& a)
: concurrent_node_map( : concurrent_node_map(
@@ -197,9 +250,10 @@ namespace boost {
{ {
} }
template <bool avoid_explicit_instantiation = true> template <typename Key2,
typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
concurrent_node_map( concurrent_node_map(
unordered_node_map<Key, T, Hash, Pred, Allocator>&& other) unordered_node_map<Key2, T, Hash, Pred, Allocator>&& other)
: table_(std::move(other.table_)) : table_(std::move(other.table_))
{ {
} }
@@ -430,12 +484,26 @@ namespace boost {
size_type insert(InputIterator begin, InputIterator end) size_type insert(InputIterator begin, InputIterator end)
{ {
size_type count_elements = 0; size_type count_elements = 0;
for (auto pos = begin; pos != end; ++pos, ++count_elements) { for (auto pos = begin; pos != end; ++pos) {
table_.emplace(*pos); if (table_.emplace(*pos)) ++count_elements;
} }
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R>
size_type insert_range(R&& rg)
{
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
while (first != last) {
if (table_.emplace(*first++)) ++count_elements;
}
return count_elements;
}
#endif
size_type insert(std::initializer_list<value_type> ilist) size_type insert(std::initializer_list<value_type> ilist)
{ {
return this->insert(ilist.begin(), ilist.end()); return this->insert(ilist.begin(), ilist.end());
@@ -510,6 +578,21 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R, class F>
size_type insert_range_or_visit(R&& rg, F f)
{
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_or_visit(*first, f);
}
return count_elements;
}
#endif
template <class F> template <class F>
size_type insert_or_visit(std::initializer_list<value_type> ilist, F f) size_type insert_or_visit(std::initializer_list<value_type> ilist, F f)
{ {
@@ -564,6 +647,21 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R, class F>
size_type insert_range_or_cvisit(R&& rg, F f)
{
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_or_cvisit(*first, f);
}
return count_elements;
}
#endif
template <class F> template <class F>
size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f) size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
{ {
@@ -622,6 +720,24 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::container_compatible_range<value_type> R, class F1, class F2
>
size_type insert_range_and_visit(R&& rg, F1 f1, F2 f2)
{
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_and_visit(*first, f1, f2);
}
return count_elements;
}
#endif
template <class F1, class F2> template <class F1, class F2>
size_type insert_and_visit( size_type insert_and_visit(
std::initializer_list<value_type> ilist, F1 f1, F2 f2) std::initializer_list<value_type> ilist, F1 f1, F2 f2)
@@ -684,6 +800,24 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::container_compatible_range<value_type> R, class F1, class F2
>
size_type insert_range_and_cvisit(R&& rg, F1 f1, F2 f2)
{
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_and_cvisit(*first, f1, f2);
}
return count_elements;
}
#endif
template <class F1, class F2> template <class F1, class F2>
size_type insert_and_cvisit( size_type insert_and_cvisit(
std::initializer_list<value_type> ilist, F1 f1, F2 f2) std::initializer_list<value_type> ilist, F1 f1, F2 f2)
@@ -1126,6 +1260,27 @@ namespace boost {
boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred, boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash =
boost::hash<boost::unordered::detail::range_key_t<R> >,
class Pred =
std::equal_to<boost::unordered::detail::range_key_t<R> >,
class Allocator = std::allocator<
boost::unordered::detail::range_to_alloc_t<R> >,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_pred_v<Pred> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_node_map(FromRangeT&&, R&&,
std::size_t = boost::unordered::detail::foa::default_bucket_count,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> concurrent_node_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>, Hash, Pred,
Allocator>;
#endif
template <class Key, class T, template <class Key, class T,
class Hash = boost::hash<std::remove_const_t<Key> >, class Hash = boost::hash<std::remove_const_t<Key> >,
class Pred = std::equal_to<std::remove_const_t<Key> >, class Pred = std::equal_to<std::remove_const_t<Key> >,
@@ -1173,6 +1328,42 @@ namespace boost {
std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >, std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_node_map(FromRangeT&&, R&&, std::size_t, Allocator)
-> concurrent_node_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>,
boost::hash<boost::unordered::detail::range_key_t<R> >,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_node_map(FromRangeT&&, R&&, Allocator)
-> concurrent_node_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>,
boost::hash<boost::unordered::detail::range_key_t<R> >,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash, class Allocator,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_node_map(
FromRangeT&&, R&&, std::size_t, Hash, Allocator)
-> concurrent_node_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>, Hash,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
#endif
template <class Key, class T, class Allocator, template <class Key, class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_node_map(std::initializer_list<std::pair<Key, T> >, std::size_t, concurrent_node_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
+192 -5
View File
@@ -1,7 +1,8 @@
/* Fast open-addressing, node-based concurrent hashset. /* Fast open-addressing, node-based concurrent hashset.
* *
* Copyright 2023 Christian Mazakas. * Copyright 2023 Christian Mazakas.
* Copyright 2023-2024 Joaquin M Lopez Munoz. * Copyright 2023-2026 Joaquin M Lopez Munoz.
* Copyright 2026 Braden Ganetsky
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -18,6 +19,7 @@
#include <boost/unordered/detail/foa/element_type.hpp> #include <boost/unordered/detail/foa/element_type.hpp>
#include <boost/unordered/detail/foa/node_set_handle.hpp> #include <boost/unordered/detail/foa/node_set_handle.hpp>
#include <boost/unordered/detail/foa/node_set_types.hpp> #include <boost/unordered/detail/foa/node_set_types.hpp>
#include <boost/unordered/detail/ranges_support.hpp>
#include <boost/unordered/detail/type_traits.hpp> #include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_node_set_fwd.hpp> #include <boost/unordered/unordered_node_set_fwd.hpp>
@@ -106,6 +108,21 @@ namespace boost {
this->insert(f, l); this->insert(f, l);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_node_set(FromRangeT&&, R&& rg,
size_type n = detail::foa::default_bucket_count,
const hasher& hf = hasher(), const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type())
: table_(n, hf, eql, a)
{
this->insert_range(std::forward<R>(rg));
}
#endif
concurrent_node_set(concurrent_node_set const& rhs) concurrent_node_set(concurrent_node_set const& rhs)
: table_(rhs.table_, : table_(rhs.table_,
boost::allocator_select_on_container_copy_construction( boost::allocator_select_on_container_copy_construction(
@@ -125,6 +142,19 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_node_set(
FromRangeT&& fr, R&& rg, allocator_type const& a)
: concurrent_node_set(
fr, std::forward<R>(rg), 0, hasher(), key_equal(), a)
{
}
#endif
explicit concurrent_node_set(allocator_type const& a) explicit concurrent_node_set(allocator_type const& a)
: table_(detail::foa::default_bucket_count, hasher(), key_equal(), a) : table_(detail::foa::default_bucket_count, hasher(), key_equal(), a)
{ {
@@ -175,6 +205,29 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_node_set(
FromRangeT&& fr, R&& rg, size_type n, const allocator_type& a)
: concurrent_node_set(
fr, std::forward<R>(rg), n, hasher(), key_equal(), a)
{
}
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
concurrent_node_set(FromRangeT&& fr, R&& rg, size_type n,
const hasher& hf, const allocator_type& a)
: concurrent_node_set(fr, std::forward<R>(rg), n, hf, key_equal(), a)
{
}
#endif
concurrent_node_set( concurrent_node_set(
std::initializer_list<value_type> il, const allocator_type& a) std::initializer_list<value_type> il, const allocator_type& a)
: concurrent_node_set( : concurrent_node_set(
@@ -194,9 +247,10 @@ namespace boost {
{ {
} }
template <bool avoid_explicit_instantiation = true> template <typename Key2,
typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
concurrent_node_set( concurrent_node_set(
unordered_node_set<Key, Hash, Pred, Allocator>&& other) unordered_node_set<Key2, Hash, Pred, Allocator>&& other)
: table_(std::move(other.table_)) : table_(std::move(other.table_))
{ {
} }
@@ -436,12 +490,26 @@ namespace boost {
size_type insert(InputIterator begin, InputIterator end) size_type insert(InputIterator begin, InputIterator end)
{ {
size_type count_elements = 0; size_type count_elements = 0;
for (auto pos = begin; pos != end; ++pos, ++count_elements) { for (auto pos = begin; pos != end; ++pos) {
table_.emplace(*pos); if (table_.emplace(*pos)) ++count_elements;
} }
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R>
size_type insert_range(R&& rg)
{
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
while (first != last) {
if (table_.emplace(*first++)) ++count_elements;
}
return count_elements;
}
#endif
size_type insert(std::initializer_list<value_type> ilist) size_type insert(std::initializer_list<value_type> ilist)
{ {
return this->insert(ilist.begin(), ilist.end()); return this->insert(ilist.begin(), ilist.end());
@@ -501,6 +569,21 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R, class F>
size_type insert_range_or_visit(R&& rg, F f)
{
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_or_visit(*first, f);
}
return count_elements;
}
#endif
template <class F> template <class F>
size_type insert_or_visit(std::initializer_list<value_type> ilist, F f) size_type insert_or_visit(std::initializer_list<value_type> ilist, F f)
{ {
@@ -564,6 +647,21 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R, class F>
size_type insert_range_or_cvisit(R&& rg, F f)
{
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_or_cvisit(*first, f);
}
return count_elements;
}
#endif
template <class F> template <class F>
size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f) size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
{ {
@@ -633,6 +731,24 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::container_compatible_range<value_type> R, class F1, class F2
>
size_type insert_range_and_visit(R&& rg, F1 f1, F2 f2)
{
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_and_visit(*first, f1, f2);
}
return count_elements;
}
#endif
template <class F1, class F2> template <class F1, class F2>
size_type insert_and_visit( size_type insert_and_visit(
std::initializer_list<value_type> ilist, F1 f1, F2 f2) std::initializer_list<value_type> ilist, F1 f1, F2 f2)
@@ -706,6 +822,24 @@ namespace boost {
return count_elements; return count_elements;
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::container_compatible_range<value_type> R, class F1, class F2
>
size_type insert_range_and_cvisit(R&& rg, F1 f1, F2 f2)
{
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
size_type count_elements = 0;
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
for (; first != last; ++first, ++count_elements) {
table_.emplace_and_cvisit(*first, f1, f2);
}
return count_elements;
}
#endif
template <class F1, class F2> template <class F1, class F2>
size_type insert_and_cvisit( size_type insert_and_cvisit(
std::initializer_list<value_type> ilist, F1 f1, F2 f2) std::initializer_list<value_type> ilist, F1 f1, F2 f2)
@@ -1000,6 +1134,26 @@ namespace boost {
typename std::iterator_traits<InputIterator>::value_type, Hash, Pred, typename std::iterator_traits<InputIterator>::value_type, Hash, Pred,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash =
boost::hash<std::ranges::range_value_t<R> >,
class Pred =
std::equal_to<std::ranges::range_value_t<R> >,
class Allocator = std::allocator<std::ranges::range_value_t<R> >,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_pred_v<Pred> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_node_set(FromRangeT&&, R&&,
std::size_t = boost::unordered::detail::foa::default_bucket_count,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> concurrent_node_set<std::ranges::range_value_t<R>,
Hash, Pred, Allocator>;
#endif
template <class T, class Hash = boost::hash<T>, template <class T, class Hash = boost::hash<T>,
class Pred = std::equal_to<T>, class Allocator = std::allocator<T>, class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
class = std::enable_if_t<detail::is_hash_v<Hash> >, class = std::enable_if_t<detail::is_hash_v<Hash> >,
@@ -1041,6 +1195,39 @@ namespace boost {
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>, std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_node_set(FromRangeT&&, R&&, std::size_t, Allocator)
-> concurrent_node_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R> >,
std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash, class Allocator,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_node_set(
FromRangeT&&, R&&, std::size_t, Hash, Allocator)
-> concurrent_node_set<std::ranges::range_value_t<R>,
Hash, std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_node_set(FromRangeT&&, R&&, Allocator)
-> concurrent_node_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R> >,
std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
#endif
template <class T, class Allocator, template <class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_node_set(std::initializer_list<T>, std::size_t, Allocator) concurrent_node_set(std::initializer_list<T>, std::size_t, Allocator)
+34 -8
View File
@@ -1,4 +1,4 @@
// Copyright (C) 2022-2024 Joaquin M Lopez Munoz. // Copyright (C) 2022-2025 Joaquin M Lopez Munoz.
// Copyright (C) 2022 Christian Mazakas // Copyright (C) 2022 Christian Mazakas
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -134,11 +134,37 @@ namespace boost {
namespace unordered { namespace unordered {
namespace detail { namespace detail {
template <class ValueType, class VoidPtr> struct node;
// access to node::value_type and node::pointer for incomplete node
template<class Node> struct node_value_type_impl;
template <class ValueType, class VoidPtr>
struct node_value_type_impl<node<ValueType, VoidPtr>>
{
typedef ValueType type;
};
template<class Node> using node_value_type =
typename node_value_type_impl<Node>::type;
template<class Node> struct node_pointer_impl;
template <class ValueType, class VoidPtr>
struct node_pointer_impl<node<ValueType, VoidPtr>>
{
typedef typename boost::pointer_traits<VoidPtr>::template rebind_to<
node<ValueType, VoidPtr>>::type type;
};
template<class Node> using node_pointer =
typename node_pointer_impl<Node>::type;
template <class ValueType, class VoidPtr> struct node template <class ValueType, class VoidPtr> struct node
{ {
typedef ValueType value_type; typedef node_value_type<node> value_type;
typedef typename boost::pointer_traits<VoidPtr>::template rebind_to< typedef detail::node_pointer<node> node_pointer;
node>::type node_pointer;
node_pointer next; node_pointer next;
opt_storage<value_type> buf; opt_storage<value_type> buf;
@@ -304,10 +330,10 @@ namespace boost {
template <class Node> struct grouped_local_bucket_iterator template <class Node> struct grouped_local_bucket_iterator
{ {
typedef typename Node::node_pointer node_pointer; typedef detail::node_pointer<Node> node_pointer;
public: public:
typedef typename Node::value_type value_type; typedef detail::node_value_type<Node> value_type;
typedef value_type element_type; typedef value_type element_type;
typedef value_type* pointer; typedef value_type* pointer;
typedef value_type& reference; typedef value_type& reference;
@@ -370,10 +396,10 @@ namespace boost {
template <class Node> struct const_grouped_local_bucket_iterator template <class Node> struct const_grouped_local_bucket_iterator
{ {
typedef typename Node::node_pointer node_pointer; typedef detail::node_pointer<Node> node_pointer;
public: public:
typedef typename Node::value_type const value_type; typedef detail::node_value_type<Node> const value_type;
typedef value_type const element_type; typedef value_type const element_type;
typedef value_type const* pointer; typedef value_type const* pointer;
typedef value_type const& reference; typedef value_type const& reference;
@@ -1,6 +1,6 @@
/* Fast open-addressing concurrent hash table. /* Fast open-addressing concurrent hash table.
* *
* Copyright 2023-2024 Joaquin M Lopez Munoz. * Copyright 2023-2026 Joaquin M Lopez Munoz.
* Copyright 2024 Braden Ganetsky. * Copyright 2024 Braden Ganetsky.
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@@ -697,9 +697,9 @@ public:
} }
/* Optimizations for maps for (k,v) to avoid eagerly constructing value */ /* Optimizations for maps for (k,v) to avoid eagerly constructing value */
template <typename K, typename V> template <typename K, typename V, typename Table = concurrent_table>
BOOST_FORCEINLINE auto emplace(K&& k, V&& v) -> BOOST_FORCEINLINE auto emplace(K&& k, V&& v) ->
typename std::enable_if<is_emplace_kv_able<concurrent_table, K>::value, typename std::enable_if<is_emplace_kv_able<Table, K>::value,
bool>::type bool>::type
{ {
alloc_cted_or_fwded_key_type<type_policy, Allocator, K&&> x( alloc_cted_or_fwded_key_type<type_policy, Allocator, K&&> x(
+5 -3
View File
@@ -1,6 +1,6 @@
/* Common base for Boost.Unordered open-addressing tables. /* Common base for Boost.Unordered open-addressing tables.
* *
* Copyright 2022-2025 Joaquin M Lopez Munoz. * Copyright 2022-2026 Joaquin M Lopez Munoz.
* Copyright 2023 Christian Mazakas. * Copyright 2023 Christian Mazakas.
* Copyright 2024 Braden Ganetsky. * Copyright 2024 Braden Ganetsky.
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
@@ -29,7 +29,7 @@
#include <boost/unordered/detail/mulx.hpp> #include <boost/unordered/detail/mulx.hpp>
#include <boost/unordered/detail/static_assert.hpp> #include <boost/unordered/detail/static_assert.hpp>
#include <boost/unordered/detail/type_traits.hpp> #include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_printers.hpp> #include <boost/unordered/detail/unordered_printers.hpp>
#include <climits> #include <climits>
#include <cmath> #include <cmath>
#include <cstddef> #include <cstddef>
@@ -923,6 +923,8 @@ inline unsigned int unchecked_countr_zero(int x)
unsigned long r; unsigned long r;
_BitScanForward(&r,(unsigned long)x); _BitScanForward(&r,(unsigned long)x);
return (unsigned int)r; return (unsigned int)r;
#elif defined(BOOST_GCC)||defined(BOOST_CLANG)
return (unsigned int)__builtin_ctz((unsigned int)x);
#else #else
BOOST_UNORDERED_ASSUME(x!=0); BOOST_UNORDERED_ASSUME(x!=0);
return (unsigned int)boost::core::countr_zero((unsigned int)x); return (unsigned int)boost::core::countr_zero((unsigned int)x);
@@ -1347,7 +1349,7 @@ template <typename Container, typename K>
using is_emplace_kv_able = std::integral_constant<bool, using is_emplace_kv_able = std::integral_constant<bool,
is_map<Container>::value && is_map<Container>::value &&
(is_similar<K, typename Container::key_type>::value || (is_similar<K, typename Container::key_type>::value ||
is_complete_and_move_constructible<typename Container::key_type>::value)>; std::is_move_constructible<typename Container::key_type>::value)>;
/* table_core. The TypePolicy template parameter is used to generate /* table_core. The TypePolicy template parameter is used to generate
* instantiations suitable for either maps or sets, and introduces non-standard * instantiations suitable for either maps or sets, and introduces non-standard
+3 -3
View File
@@ -1,6 +1,6 @@
/* Fast open-addressing hash table. /* Fast open-addressing hash table.
* *
* Copyright 2022-2025 Joaquin M Lopez Munoz. * Copyright 2022-2026 Joaquin M Lopez Munoz.
* Copyright 2023 Christian Mazakas. * Copyright 2023 Christian Mazakas.
* Copyright 2024 Braden Ganetsky. * Copyright 2024 Braden Ganetsky.
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
@@ -422,9 +422,9 @@ public:
} }
/* Optimizations for maps for (k,v) to avoid eagerly constructing value */ /* Optimizations for maps for (k,v) to avoid eagerly constructing value */
template <typename K, typename V> template <typename K, typename V, typename Table = table>
BOOST_FORCEINLINE BOOST_FORCEINLINE
typename std::enable_if<is_emplace_kv_able<table, K>::value, typename std::enable_if<is_emplace_kv_able<Table, K>::value,
std::pair<iterator, bool> >::type std::pair<iterator, bool> >::type
emplace(K&& k, V&& v) emplace(K&& k, V&& v)
{ {
@@ -1,6 +1,6 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2016 Daniel James // Copyright (C) 2005-2016 Daniel James
// Copyright (C) 2022-2024 Joaquin M Lopez Munoz. // Copyright (C) 2022-2026 Joaquin M Lopez Munoz.
// Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 2024 Braden Ganetsky // Copyright (C) 2024 Braden Ganetsky
// //
@@ -18,12 +18,14 @@
#include <boost/unordered/detail/allocator_constructed.hpp> #include <boost/unordered/detail/allocator_constructed.hpp>
#include <boost/unordered/detail/fca.hpp> #include <boost/unordered/detail/fca.hpp>
#include <boost/unordered/detail/opt_storage.hpp> #include <boost/unordered/detail/opt_storage.hpp>
#include <boost/unordered/detail/ranges_support.hpp>
#include <boost/unordered/detail/serialize_tracked_address.hpp> #include <boost/unordered/detail/serialize_tracked_address.hpp>
#include <boost/unordered/detail/static_assert.hpp> #include <boost/unordered/detail/static_assert.hpp>
#include <boost/unordered/detail/type_traits.hpp> #include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_printers.hpp> #include <boost/unordered/detail/unordered_printers.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/config/workaround.hpp>
#include <boost/core/allocator_traits.hpp> #include <boost/core/allocator_traits.hpp>
#include <boost/core/bit.hpp> #include <boost/core/bit.hpp>
#include <boost/core/invoke_swap.hpp> #include <boost/core/invoke_swap.hpp>
@@ -174,6 +176,29 @@ namespace boost {
boost::unordered::detail::insert_size(i, j), num_buckets); boost::unordered::detail::insert_size(i, j), num_buckets);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<std::ranges::input_range R>
inline std::size_t insert_size(R&& rg)
{
if constexpr (std::ranges::sized_range<R>)
return std::ranges::size(std::forward<R>(rg));
else if constexpr (std::ranges::forward_range<R>)
return std::ranges::distance(std::forward<R>(rg));
else
return 1;
}
template <std::ranges::input_range R>
inline std::size_t initial_size(R&& rg,
std::size_t num_buckets =
boost::unordered::detail::default_bucket_count)
{
return (std::max)(
boost::unordered::detail::insert_size(std::forward<R>(rg)),
num_buckets);
}
#endif
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// compressed // compressed
@@ -954,10 +979,14 @@ namespace boost {
inline std::size_t double_to_size(double f) inline std::size_t double_to_size(double f)
{ {
return f >= static_cast<double>( #if BOOST_WORKAROUND(BOOST_CLANG_VERSION, < 30900)
(std::numeric_limits<std::size_t>::max)()) // https://github.com/boostorg/unordered/pull/354
? (std::numeric_limits<std::size_t>::max)() volatile
: static_cast<std::size_t>(f); #endif
const double double_size_t_max =
static_cast<double>((std::numeric_limits<std::size_t>::max)());
return f >= double_size_t_max?
(std::numeric_limits<std::size_t>::max)(): static_cast<std::size_t>(f);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@@ -969,7 +998,7 @@ namespace boost {
template <class Node, class Bucket> class iterator template <class Node, class Bucket> class iterator
{ {
public: public:
typedef typename Node::value_type value_type; typedef typename detail::node_value_type<Node> value_type;
typedef value_type element_type; typedef value_type element_type;
typedef value_type* pointer; typedef value_type* pointer;
typedef value_type& reference; typedef value_type& reference;
@@ -1023,7 +1052,7 @@ namespace boost {
} }
private: private:
typedef typename Node::node_pointer node_pointer; typedef detail::node_pointer<Node> node_pointer;
typedef grouped_bucket_iterator<Bucket> bucket_iterator; typedef grouped_bucket_iterator<Bucket> bucket_iterator;
node_pointer p; node_pointer p;
@@ -1076,7 +1105,7 @@ namespace boost {
template <class Node, class Bucket> class c_iterator template <class Node, class Bucket> class c_iterator
{ {
public: public:
typedef typename Node::value_type value_type; typedef typename detail::node_value_type<Node> value_type;
typedef value_type const element_type; typedef value_type const element_type;
typedef value_type const* pointer; typedef value_type const* pointer;
typedef value_type const& reference; typedef value_type const& reference;
@@ -1131,7 +1160,7 @@ namespace boost {
} }
private: private:
typedef typename Node::node_pointer node_pointer; typedef detail::node_pointer<Node> node_pointer;
typedef grouped_bucket_iterator<Bucket> bucket_iterator; typedef grouped_bucket_iterator<Bucket> bucket_iterator;
node_pointer p; node_pointer p;
@@ -1781,7 +1810,7 @@ namespace boost {
static std::size_t min_buckets(std::size_t num_elements, float mlf) static std::size_t min_buckets(std::size_t num_elements, float mlf)
{ {
std::size_t num_buckets = static_cast<std::size_t>( std::size_t num_buckets = boost::unordered::detail::double_to_size(
std::ceil(static_cast<float>(num_elements) / mlf)); std::ceil(static_cast<float>(num_elements) / mlf));
if (num_buckets == 0 && num_elements > 0) { // mlf == inf if (num_buckets == 0 && num_elements > 0) { // mlf == inf
@@ -2150,8 +2179,8 @@ namespace boost {
// if hash function throws, or inserting > 1 element, basic exception // if hash function throws, or inserting > 1 element, basic exception
// safety strong otherwise // safety strong otherwise
template <class InputIt> template <class InputIt, class Sentinel>
void insert_range_unique(no_key, InputIt i, InputIt j) void insert_range_unique(no_key, InputIt i, Sentinel j)
{ {
hasher const& hf = this->hash_function(); hasher const& hf = this->hash_function();
node_allocator_type alloc = this->node_alloc(); node_allocator_type alloc = this->node_alloc();
@@ -2538,14 +2567,20 @@ namespace boost {
// if hash function throws, or inserting > 1 element, basic exception // if hash function throws, or inserting > 1 element, basic exception
// safety. Strong otherwise // safety. Strong otherwise
template <class I> template <class I, class S>
typename boost::unordered::detail::enable_if_forward<I, void>::type typename boost::unordered::detail::enable_if_forward<I, void>::type
insert_range_equiv(I i, I j) insert_range_equiv(I i, S j)
{ {
if (i == j) if (i == j)
return; return;
#if !defined(BOOST_UNORDERED_NO_RANGES)
std::size_t distance = static_cast<std::size_t>(
std::ranges::distance(i, j));
#else
std::size_t distance = static_cast<std::size_t>(std::distance(i, j)); std::size_t distance = static_cast<std::size_t>(std::distance(i, j));
#endif
if (distance == 1) { if (distance == 1) {
emplace_equiv(boost::unordered::detail::func::construct_node( emplace_equiv(boost::unordered::detail::func::construct_node(
this->node_alloc(), *i)); this->node_alloc(), *i));
@@ -2561,9 +2596,9 @@ namespace boost {
} }
} }
template <class I> template <class I, class S>
typename boost::unordered::detail::disable_if_forward<I, void>::type typename boost::unordered::detail::disable_if_forward<I, void>::type
insert_range_equiv(I i, I j) insert_range_equiv(I i, S j)
{ {
for (; i != j; ++i) { for (; i != j; ++i) {
emplace_equiv(boost::unordered::detail::func::construct_node( emplace_equiv(boost::unordered::detail::func::construct_node(
@@ -2712,8 +2747,9 @@ namespace boost {
inline void table<Types>::reserve_for_insert(std::size_t num_elements) inline void table<Types>::reserve_for_insert(std::size_t num_elements)
{ {
if (num_elements > max_load_) { if (num_elements > max_load_) {
std::size_t const num_buckets = static_cast<std::size_t>( std::size_t const num_buckets = (std::max)(
1.0f + std::ceil(static_cast<float>(num_elements) / mlf_)); static_cast<std::size_t>(1.0f + std::ceil(static_cast<float>(num_elements) / mlf_)),
static_cast<std::size_t>(bucket_count() + 1));
this->rehash_impl(num_buckets); this->rehash_impl(num_buckets);
} }
@@ -2851,10 +2887,10 @@ namespace boost {
return no_key(); return no_key();
} }
template <class Arg1, class Arg2> template <class Arg1, class Arg2, class Key = key_type>
static typename std::conditional< static typename std::conditional<
(is_similar<Arg1, key_type>::value || (is_similar<Arg1, key_type>::value ||
is_complete_and_move_constructible<key_type>::value), std::is_move_constructible<Key>::value),
converting_key, no_key>::type converting_key, no_key>::type
extract(Arg1 const&, Arg2 const&) extract(Arg1 const&, Arg2 const&)
{ {
@@ -0,0 +1,104 @@
/* Copyright 2026 Joaquin M Lopez Munoz.
* 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)
*
* See https://www.boost.org/libs/unordered for library home page.
*/
#ifndef BOOST_UNORDERED_DETAIL_RANGES_SUPPORT_HPP
#define BOOST_UNORDERED_DETAIL_RANGES_SUPPORT_HPP
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#if defined(BOOST_NO_CXX20_HDR_CONCEPTS) || defined(BOOST_NO_CXX20_HDR_RANGES)
#define BOOST_UNORDERED_NO_RANGES
#elif BOOST_WORKAROUND(BOOST_CLANG_VERSION, < 170100) && \
defined(BOOST_LIBSTDCXX_VERSION)
/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109647
* https://github.com/llvm/llvm-project/issues/49620
*/
#define BOOST_UNORDERED_NO_RANGES
#endif
#if !defined(BOOST_UNORDERED_NO_RANGES)
#include <concepts>
#include <functional>
#include <ranges>
#include <tuple>
#include <type_traits>
#include <utility>
namespace boost {
namespace unordered {
struct from_range_t { explicit from_range_t() = default; };
inline constexpr from_range_t from_range{};
namespace detail {
/* Existence of std::from_range_t is governed by feature macro
* __cpp_lib_containers_ranges, but at least one stdlib implementation
* (GCC 14.1) does not honor it, hence the workadound below: code picks
* std::from_range_t if it exists, boost::unordered::from_range_t otherwise.
* Technique explained at
https://bannalia.blogspot.com/2016/09/compile-time-checking-existence-of.html
*/
struct from_range_t_hook{};
} /* namespace detail */
} /* namespace unordered */
} /* namespace boost */
namespace std {
template<> struct hash< ::boost::unordered::detail::from_range_t_hook>
{
using from_range_t_type = decltype([] {
using namespace ::boost::unordered;
return from_range_t{};
}());
/* make standard happy */
std::size_t operator()(
const ::boost::unordered::detail::from_range_t_hook&) const;
};
} /* namespace std */
namespace boost {
namespace unordered {
namespace detail {
template<typename T>
concept convertible_to_from_range_t =
std::is_convertible_v<T, boost::unordered::from_range_t> ||
std::is_convertible_v<T, std::hash<from_range_t_hook>::from_range_t_type>;
template<class R, class T>
concept container_compatible_range =
std::ranges::input_range<R> &&
std::convertible_to<std::ranges::range_reference_t<R>, T>;
template<std::ranges::input_range Range>
using range_key_t =
std::remove_cvref_t<
std::tuple_element_t<0, std::ranges::range_value_t<Range>>>;
template<std::ranges::input_range Range>
using range_mapped_t =
std::remove_cvref_t<
std::tuple_element_t<1, std::ranges::range_value_t<Range>>>;
template<std::ranges::input_range Range>
using range_to_alloc_t =
std::pair<const range_key_t<Range>, range_mapped_t<Range>>;
} /* namespace detail */
} /* namespace unordered */
} /* namespace boost */
#endif /* !defined(BOOST_UNORDERED_NO_RANGES) */
#endif
+1 -14
View File
@@ -1,5 +1,6 @@
// Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 2024 Braden Ganetsky // Copyright (C) 2024 Braden Ganetsky
// Copyright (C) 2026 Joaquin M Lopez Munoz
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -49,20 +50,6 @@ namespace boost {
template <typename... Ts> using void_t = typename make_void<Ts...>::type; template <typename... Ts> using void_t = typename make_void<Ts...>::type;
template <class T, class = void> struct is_complete : std::false_type
{
};
template <class T>
struct is_complete<T, void_t<int[sizeof(T)]> > : std::true_type
{
};
template <class T>
using is_complete_and_move_constructible =
typename std::conditional<is_complete<T>::value,
std::is_move_constructible<T>, std::false_type>::type;
#if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION, < 50000) #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION, < 50000)
/* std::is_trivially_default_constructible not provided */ /* std::is_trivially_default_constructible not provided */
template <class T> template <class T>
@@ -1,11 +1,11 @@
// Copyright 2024 Braden Ganetsky // Copyright 2024-2026 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0. // Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt // https://www.boost.org/LICENSE_1_0.txt
// Generated on 2024-08-25T17:48:54 // Generated on 2026-01-24T00:34:53
#ifndef BOOST_UNORDERED_UNORDERED_PRINTERS_HPP #ifndef BOOST_UNORDERED_DETAIL_UNORDERED_PRINTERS_HPP
#define BOOST_UNORDERED_UNORDERED_PRINTERS_HPP #define BOOST_UNORDERED_DETAIL_UNORDERED_PRINTERS_HPP
#ifndef BOOST_ALL_NO_EMBEDDED_GDB_SCRIPTS #ifndef BOOST_ALL_NO_EMBEDDED_GDB_SCRIPTS
#if defined(__ELF__) #if defined(__ELF__)
@@ -14,7 +14,7 @@
#pragma clang diagnostic ignored "-Woverlength-strings" #pragma clang diagnostic ignored "-Woverlength-strings"
#endif #endif
__asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n" __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
".ascii \"\\4gdb.inlined-script.BOOST_UNORDERED_UNORDERED_PRINTERS_HPP\\n\"\n" ".ascii \"\\4gdb.inlined-script.BOOST_UNORDERED_DETAIL_UNORDERED_PRINTERS_HPP\\n\"\n"
".ascii \"import gdb.printing\\n\"\n" ".ascii \"import gdb.printing\\n\"\n"
".ascii \"import gdb.xmethod\\n\"\n" ".ascii \"import gdb.xmethod\\n\"\n"
".ascii \"import re\\n\"\n" ".ascii \"import re\\n\"\n"
@@ -29,8 +29,14 @@ __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
".ascii \" return n\\n\"\n" ".ascii \" return n\\n\"\n"
".ascii \" def maybe_unwrap_foa_element(e):\\n\"\n" ".ascii \" def maybe_unwrap_foa_element(e):\\n\"\n"
".ascii \" if f\\\"{e.type.strip_typedefs()}\\\".startswith(\\\"boost::unordered::detail::foa::element_type<\\\"):\\n\"\n" ".ascii \" # Sometimes the complex typedefs can't be resolved through a pointer\\n\"\n"
".ascii \" return e[\\\"p\\\"]\\n\"\n" ".ascii \" if e.type.strip_typedefs().code == gdb.TYPE_CODE_PTR:\\n\"\n"
".ascii \" foa_element = e.dereference()\\n\"\n"
".ascii \" else:\\n\"\n"
".ascii \" foa_element = e\\n\"\n"
".ascii \" if f\\\"{foa_element.type.strip_typedefs()}\\\".startswith(\\\"boost::unordered::detail::foa::element_type<\\\"):\\n\"\n"
".ascii \" return foa_element[\\\"p\\\"]\\n\"\n"
".ascii \" else:\\n\"\n" ".ascii \" else:\\n\"\n"
".ascii \" return e\\n\"\n" ".ascii \" return e\\n\"\n"
@@ -58,14 +64,15 @@ __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
".ascii \"class BoostUnorderedFcaPrinter:\\n\"\n" ".ascii \"class BoostUnorderedFcaPrinter:\\n\"\n"
".ascii \" def __init__(self, val):\\n\"\n" ".ascii \" def __init__(self, val):\\n\"\n"
".ascii \" self.val = BoostUnorderedHelpers.maybe_unwrap_reference(val)\\n\"\n" ".ascii \" val = BoostUnorderedHelpers.maybe_unwrap_reference(val)\\n\"\n"
".ascii \" self.name = f\\\"{self.val.type.strip_typedefs()}\\\".split(\\\"<\\\")[0]\\n\"\n" ".ascii \" self.table = val[\\\"table_\\\"]\\n\"\n"
".ascii \" self.name = f\\\"{val.type.strip_typedefs()}\\\".split(\\\"<\\\")[0]\\n\"\n"
".ascii \" self.name = self.name.replace(\\\"boost::unordered::\\\", \\\"boost::\\\")\\n\"\n" ".ascii \" self.name = self.name.replace(\\\"boost::unordered::\\\", \\\"boost::\\\")\\n\"\n"
".ascii \" self.is_map = self.name.endswith(\\\"map\\\")\\n\"\n" ".ascii \" self.is_map = self.name.endswith(\\\"map\\\")\\n\"\n"
".ascii \" self.cpo = BoostUnorderedPointerCustomizationPoint(self.val[\\\"table_\\\"][\\\"buckets_\\\"][\\\"buckets\\\"])\\n\"\n" ".ascii \" self.cpo = BoostUnorderedPointerCustomizationPoint(self.table[\\\"buckets_\\\"][\\\"buckets\\\"])\\n\"\n"
".ascii \" def to_string(self):\\n\"\n" ".ascii \" def to_string(self):\\n\"\n"
".ascii \" size = self.val[\\\"table_\\\"][\\\"size_\\\"]\\n\"\n" ".ascii \" size = self.table[\\\"size_\\\"]\\n\"\n"
".ascii \" return f\\\"{self.name} with {size} elements\\\"\\n\"\n" ".ascii \" return f\\\"{self.name} with {size} elements\\\"\\n\"\n"
".ascii \" def display_hint(self):\\n\"\n" ".ascii \" def display_hint(self):\\n\"\n"
@@ -73,7 +80,7 @@ __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
".ascii \" def children(self):\\n\"\n" ".ascii \" def children(self):\\n\"\n"
".ascii \" def generator():\\n\"\n" ".ascii \" def generator():\\n\"\n"
".ascii \" grouped_buckets = self.val[\\\"table_\\\"][\\\"buckets_\\\"]\\n\"\n" ".ascii \" grouped_buckets = self.table[\\\"buckets_\\\"]\\n\"\n"
".ascii \" size = grouped_buckets[\\\"size_\\\"]\\n\"\n" ".ascii \" size = grouped_buckets[\\\"size_\\\"]\\n\"\n"
".ascii \" buckets = grouped_buckets[\\\"buckets\\\"]\\n\"\n" ".ascii \" buckets = grouped_buckets[\\\"buckets\\\"]\\n\"\n"
@@ -167,14 +174,20 @@ __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
".ascii \"class BoostUnorderedFoaPrinter:\\n\"\n" ".ascii \"class BoostUnorderedFoaPrinter:\\n\"\n"
".ascii \" def __init__(self, val):\\n\"\n" ".ascii \" def __init__(self, val):\\n\"\n"
".ascii \" self.val = BoostUnorderedHelpers.maybe_unwrap_reference(val)\\n\"\n" ".ascii \" val = BoostUnorderedHelpers.maybe_unwrap_reference(val)\\n\"\n"
".ascii \" self.name = f\\\"{self.val.type.strip_typedefs()}\\\".split(\\\"<\\\")[0]\\n\"\n" ".ascii \" self.table = val[\\\"table_\\\"]\\n\"\n"
".ascii \" self.name = f\\\"{val.type.strip_typedefs()}\\\".split(\\\"<\\\")[0]\\n\"\n"
".ascii \" self.name = self.name.replace(\\\"boost::unordered::\\\", \\\"boost::\\\")\\n\"\n" ".ascii \" self.name = self.name.replace(\\\"boost::unordered::\\\", \\\"boost::\\\")\\n\"\n"
".ascii \" self.is_map = self.name.endswith(\\\"map\\\")\\n\"\n" ".ascii \" self.is_map = self.name.endswith(\\\"map\\\")\\n\"\n"
".ascii \" self.cpo = BoostUnorderedPointerCustomizationPoint(self.val[\\\"table_\\\"][\\\"arrays\\\"][\\\"groups_\\\"])\\n\"\n" ".ascii \" self.cpo = BoostUnorderedPointerCustomizationPoint(self.table[\\\"arrays\\\"][\\\"groups_\\\"])\\n\"\n"
".ascii \" self.groups = self.cpo.to_address(self.table[\\\"arrays\\\"][\\\"groups_\\\"])\\n\"\n"
".ascii \" self.elements = self.cpo.to_address(self.table[\\\"arrays\\\"][\\\"elements_\\\"])\\n\"\n"
".ascii \" self.N = 15 # `self.groups.dereference()[\\\"N\\\"]` may be optimized out\\n\"\n"
".ascii \" self.sentinel_ = 1 # `self.groups.dereference()[\\\"sentinel_\\\"]` may be optimized out\\n\"\n"
".ascii \" def to_string(self):\\n\"\n" ".ascii \" def to_string(self):\\n\"\n"
".ascii \" size = BoostUnorderedHelpers.maybe_unwrap_atomic(self.val[\\\"table_\\\"][\\\"size_ctrl\\\"][\\\"size\\\"])\\n\"\n" ".ascii \" size = BoostUnorderedHelpers.maybe_unwrap_atomic(self.table[\\\"size_ctrl\\\"][\\\"size\\\"])\\n\"\n"
".ascii \" return f\\\"{self.name} with {size} elements\\\"\\n\"\n" ".ascii \" return f\\\"{self.name} with {size} elements\\\"\\n\"\n"
".ascii \" def display_hint(self):\\n\"\n" ".ascii \" def display_hint(self):\\n\"\n"
@@ -204,30 +217,21 @@ __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
".ascii \" m = group[\\\"m\\\"]\\n\"\n" ".ascii \" m = group[\\\"m\\\"]\\n\"\n"
".ascii \" at = lambda b: BoostUnorderedHelpers.maybe_unwrap_atomic(m[b][\\\"n\\\"])\\n\"\n" ".ascii \" at = lambda b: BoostUnorderedHelpers.maybe_unwrap_atomic(m[b][\\\"n\\\"])\\n\"\n"
".ascii \" N = group[\\\"N\\\"]\\n\"\n"
".ascii \" sentinel_ = group[\\\"sentinel_\\\"]\\n\"\n"
".ascii \" if self.is_regular_layout(group):\\n\"\n" ".ascii \" if self.is_regular_layout(group):\\n\"\n"
".ascii \" return pos == N-1 and at(N-1) == sentinel_\\n\"\n" ".ascii \" return pos == self.N-1 and at(self.N-1) == self.sentinel_\\n\"\n"
".ascii \" else:\\n\"\n" ".ascii \" else:\\n\"\n"
".ascii \" return pos == N-1 and (at(0) & 0x4000400040004000) == 0x4000 and (at(1) & 0x4000400040004000) == 0\\n\"\n" ".ascii \" return pos == self.N-1 and (at(0) & 0x4000400040004000) == 0x4000 and (at(1) & 0x4000400040004000) == 0\\n\"\n"
".ascii \" def children(self):\\n\"\n" ".ascii \" def children(self):\\n\"\n"
".ascii \" def generator():\\n\"\n" ".ascii \" def generator():\\n\"\n"
".ascii \" table = self.val[\\\"table_\\\"]\\n\"\n" ".ascii \" pc_ = self.groups.cast(gdb.lookup_type(\\\"unsigned char\\\").pointer())\\n\"\n"
".ascii \" groups = self.cpo.to_address(table[\\\"arrays\\\"][\\\"groups_\\\"])\\n\"\n" ".ascii \" p_ = self.elements\\n\"\n"
".ascii \" elements = self.cpo.to_address(table[\\\"arrays\\\"][\\\"elements_\\\"])\\n\"\n"
".ascii \" pc_ = groups.cast(gdb.lookup_type(\\\"unsigned char\\\").pointer())\\n\"\n"
".ascii \" p_ = elements\\n\"\n"
".ascii \" first_time = True\\n\"\n" ".ascii \" first_time = True\\n\"\n"
".ascii \" mask = 0\\n\"\n"
".ascii \" n0 = 0\\n\"\n"
".ascii \" n = 0\\n\"\n"
".ascii \" count = 0\\n\"\n" ".ascii \" count = 0\\n\"\n"
".ascii \" while p_ != 0:\\n\"\n" ".ascii \" while p_ != 0:\\n\"\n"
".ascii \" # This if block mirrors the condition in the begin() call\\n\"\n" ".ascii \" # This if block mirrors the condition in the begin() call\\n\"\n"
".ascii \" if (not first_time) or (self.match_occupied(groups.dereference()) & 1):\\n\"\n" ".ascii \" if (not first_time) or (self.match_occupied(self.groups.dereference()) & 1):\\n\"\n"
".ascii \" pointer = BoostUnorderedHelpers.maybe_unwrap_foa_element(p_)\\n\"\n" ".ascii \" pointer = BoostUnorderedHelpers.maybe_unwrap_foa_element(p_)\\n\"\n"
".ascii \" value = self.cpo.to_address(pointer).dereference()\\n\"\n" ".ascii \" value = self.cpo.to_address(pointer).dereference()\\n\"\n"
".ascii \" if self.is_map:\\n\"\n" ".ascii \" if self.is_map:\\n\"\n"
@@ -241,17 +245,17 @@ __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
".ascii \" count += 1\\n\"\n" ".ascii \" count += 1\\n\"\n"
".ascii \" first_time = False\\n\"\n" ".ascii \" first_time = False\\n\"\n"
".ascii \" n0 = pc_.cast(gdb.lookup_type(\\\"uintptr_t\\\")) % groups.dereference().type.sizeof\\n\"\n" ".ascii \" n0 = pc_.cast(gdb.lookup_type(\\\"uintptr_t\\\")) % self.groups.dereference().type.sizeof\\n\"\n"
".ascii \" pc_ = self.cpo.next(pc_, -n0)\\n\"\n" ".ascii \" pc_ = self.cpo.next(pc_, -n0)\\n\"\n"
".ascii \" mask = (self.match_occupied(pc_.cast(groups.type).dereference()) >> (n0+1)) << (n0+1)\\n\"\n" ".ascii \" mask = (self.match_occupied(pc_.cast(self.groups.type).dereference()) >> (n0+1)) << (n0+1)\\n\"\n"
".ascii \" while mask == 0:\\n\"\n" ".ascii \" while mask == 0:\\n\"\n"
".ascii \" pc_ = self.cpo.next(pc_, groups.dereference().type.sizeof)\\n\"\n" ".ascii \" pc_ = self.cpo.next(pc_, self.groups.dereference().type.sizeof)\\n\"\n"
".ascii \" p_ = self.cpo.next(p_, groups.dereference()[\\\"N\\\"])\\n\"\n" ".ascii \" p_ = self.cpo.next(p_, self.N)\\n\"\n"
".ascii \" mask = self.match_occupied(pc_.cast(groups.type).dereference())\\n\"\n" ".ascii \" mask = self.match_occupied(pc_.cast(self.groups.type).dereference())\\n\"\n"
".ascii \" n = BoostUnorderedHelpers.countr_zero(mask)\\n\"\n" ".ascii \" n = BoostUnorderedHelpers.countr_zero(mask)\\n\"\n"
".ascii \" if self.is_sentinel(pc_.cast(groups.type).dereference(), n):\\n\"\n" ".ascii \" if self.is_sentinel(pc_.cast(self.groups.type).dereference(), n):\\n\"\n"
".ascii \" p_ = 0\\n\"\n" ".ascii \" p_ = 0\\n\"\n"
".ascii \" else:\\n\"\n" ".ascii \" else:\\n\"\n"
".ascii \" pc_ = self.cpo.next(pc_, n)\\n\"\n" ".ascii \" pc_ = self.cpo.next(pc_, n)\\n\"\n"
@@ -411,4 +415,4 @@ __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
#endif // defined(__ELF__) #endif // defined(__ELF__)
#endif // !defined(BOOST_ALL_NO_EMBEDDED_GDB_SCRIPTS) #endif // !defined(BOOST_ALL_NO_EMBEDDED_GDB_SCRIPTS)
#endif // !defined(BOOST_UNORDERED_UNORDERED_PRINTERS_HPP) #endif // !defined(BOOST_UNORDERED_DETAIL_UNORDERED_PRINTERS_HPP)
+121 -3
View File
@@ -1,5 +1,6 @@
// Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 2024-2025 Joaquin M Lopez Munoz // Copyright (C) 2024-2026 Joaquin M Lopez Munoz
// Copyright (C) 2026 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -14,6 +15,7 @@
#include <boost/unordered/concurrent_flat_map_fwd.hpp> #include <boost/unordered/concurrent_flat_map_fwd.hpp>
#include <boost/unordered/detail/foa/flat_map_types.hpp> #include <boost/unordered/detail/foa/flat_map_types.hpp>
#include <boost/unordered/detail/foa/table.hpp> #include <boost/unordered/detail/foa/table.hpp>
#include <boost/unordered/detail/ranges_support.hpp>
#include <boost/unordered/detail/serialize_container.hpp> #include <boost/unordered/detail/serialize_container.hpp>
#include <boost/unordered/detail/throw_exception.hpp> #include <boost/unordered/detail/throw_exception.hpp>
#include <boost/unordered/detail/type_traits.hpp> #include <boost/unordered/detail/type_traits.hpp>
@@ -107,6 +109,19 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_flat_map(
FromRangeT&& fr, R&& rg, allocator_type const& a)
: unordered_flat_map(
fr, std::forward<R>(rg), size_type(0), hasher(), key_equal(), a)
{
}
#endif
explicit unordered_flat_map(allocator_type const& a) explicit unordered_flat_map(allocator_type const& a)
: unordered_flat_map(0, a) : unordered_flat_map(0, a)
{ {
@@ -135,6 +150,41 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_flat_map(FromRangeT&&, R&& rg, size_type n = 0,
hasher const& h = hasher(), key_equal const& pred = key_equal(),
allocator_type const& a = allocator_type())
: unordered_flat_map(n, h, pred, a)
{
this->insert_range(std::forward<R>(rg));
}
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_flat_map(
FromRangeT&& fr, R&& rg, size_type n, allocator_type const& a)
: unordered_flat_map(
fr, std::forward<R>(rg), n, hasher(), key_equal(), a)
{
}
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_flat_map(FromRangeT&& fr, R&& rg, size_type n,
hasher const& h, allocator_type const& a)
: unordered_flat_map(fr, std::forward<R>(rg), n, h, key_equal(), a)
{
}
#endif
unordered_flat_map(unordered_flat_map const& other) : table_(other.table_) unordered_flat_map(unordered_flat_map const& other) : table_(other.table_)
{ {
} }
@@ -182,9 +232,10 @@ namespace boost {
{ {
} }
template <bool avoid_explicit_instantiation = true> template <typename Key2,
typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
unordered_flat_map( unordered_flat_map(
concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator>&& other) concurrent_flat_map<Key2, T, Hash, KeyEqual, Allocator>&& other)
: table_(std::move(other.table_)) : table_(std::move(other.table_))
{ {
} }
@@ -276,6 +327,16 @@ namespace boost {
} }
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R>
BOOST_FORCEINLINE void insert_range(R&& rg)
{
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
while (first != last) table_.emplace(*first++);
}
#endif
void insert(std::initializer_list<value_type> ilist) void insert(std::initializer_list<value_type> ilist)
{ {
this->insert(ilist.begin(), ilist.end()); this->insert(ilist.begin(), ilist.end());
@@ -754,6 +815,27 @@ namespace boost {
boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred, boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash =
boost::hash<boost::unordered::detail::range_key_t<R> >,
class Pred =
std::equal_to<boost::unordered::detail::range_key_t<R> >,
class Allocator = std::allocator<
boost::unordered::detail::range_to_alloc_t<R> >,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_pred_v<Pred> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_flat_map(FromRangeT&&, R&&,
std::size_t = boost::unordered::detail::foa::default_bucket_count,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_flat_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>, Hash, Pred,
Allocator>;
#endif
template <class Key, class T, template <class Key, class T,
class Hash = boost::hash<std::remove_const_t<Key> >, class Hash = boost::hash<std::remove_const_t<Key> >,
class Pred = std::equal_to<std::remove_const_t<Key> >, class Pred = std::equal_to<std::remove_const_t<Key> >,
@@ -798,6 +880,42 @@ namespace boost {
std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >, std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_flat_map(FromRangeT&&, R&&, std::size_t, Allocator)
-> unordered_flat_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>,
boost::hash<boost::unordered::detail::range_key_t<R> >,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_flat_map(FromRangeT&&, R&&, Allocator)
-> unordered_flat_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>,
boost::hash<boost::unordered::detail::range_key_t<R> >,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash, class Allocator,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_flat_map(
FromRangeT&&, R&&, std::size_t, Hash, Allocator)
-> unordered_flat_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>, Hash,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
#endif
template <class Key, class T, class Allocator, template <class Key, class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_flat_map(std::initializer_list<std::pair<Key, T> >, std::size_t, unordered_flat_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
+118 -3
View File
@@ -1,5 +1,6 @@
// Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 2024-2025 Joaquin M Lopez Munoz // Copyright (C) 2024-2026 Joaquin M Lopez Munoz
// Copyright (C) 2026 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -14,6 +15,7 @@
#include <boost/unordered/concurrent_flat_set_fwd.hpp> #include <boost/unordered/concurrent_flat_set_fwd.hpp>
#include <boost/unordered/detail/foa/flat_set_types.hpp> #include <boost/unordered/detail/foa/flat_set_types.hpp>
#include <boost/unordered/detail/foa/table.hpp> #include <boost/unordered/detail/foa/table.hpp>
#include <boost/unordered/detail/ranges_support.hpp>
#include <boost/unordered/detail/serialize_container.hpp> #include <boost/unordered/detail/serialize_container.hpp>
#include <boost/unordered/detail/type_traits.hpp> #include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_flat_set_fwd.hpp> #include <boost/unordered/unordered_flat_set_fwd.hpp>
@@ -103,6 +105,19 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_flat_set(
FromRangeT&& fr, R&& rg, allocator_type const& a)
: unordered_flat_set(
fr, std::forward<R>(rg), size_type(0), hasher(), key_equal(), a)
{
}
#endif
explicit unordered_flat_set(allocator_type const& a) explicit unordered_flat_set(allocator_type const& a)
: unordered_flat_set(0, a) : unordered_flat_set(0, a)
{ {
@@ -131,6 +146,41 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_flat_set(FromRangeT&&, R&& rg, size_type n = 0,
hasher const& h = hasher(), key_equal const& pred = key_equal(),
allocator_type const& a = allocator_type())
: unordered_flat_set(n, h, pred, a)
{
this->insert_range(std::forward<R>(rg));
}
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_flat_set(
FromRangeT&& fr, R&& rg, size_type n, allocator_type const& a)
: unordered_flat_set(
fr, std::forward<R>(rg), n, hasher(), key_equal(), a)
{
}
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_flat_set(FromRangeT&& fr, R&& rg, size_type n,
hasher const& h, allocator_type const& a)
: unordered_flat_set(fr, std::forward<R>(rg), n, h, key_equal(), a)
{
}
#endif
unordered_flat_set(unordered_flat_set const& other) : table_(other.table_) unordered_flat_set(unordered_flat_set const& other) : table_(other.table_)
{ {
} }
@@ -178,9 +228,10 @@ namespace boost {
{ {
} }
template <bool avoid_explicit_instantiation = true> template <typename Key2,
typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
unordered_flat_set( unordered_flat_set(
concurrent_flat_set<Key, Hash, KeyEqual, Allocator>&& other) concurrent_flat_set<Key2, Hash, KeyEqual, Allocator>&& other)
: table_(std::move(other.table_)) : table_(std::move(other.table_))
{ {
} }
@@ -287,6 +338,16 @@ namespace boost {
} }
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R>
void insert_range(R&& rg)
{
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
while (first != last) table_.emplace(*first++);
}
#endif
void insert(std::initializer_list<value_type> ilist) void insert(std::initializer_list<value_type> ilist)
{ {
this->insert(ilist.begin(), ilist.end()); this->insert(ilist.begin(), ilist.end());
@@ -572,6 +633,25 @@ namespace boost {
typename std::iterator_traits<InputIterator>::value_type, Hash, Pred, typename std::iterator_traits<InputIterator>::value_type, Hash, Pred,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash =
boost::hash<std::ranges::range_value_t<R> >,
class Pred =
std::equal_to<std::ranges::range_value_t<R> >,
class Allocator = std::allocator<std::ranges::range_value_t<R> >,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_pred_v<Pred> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_flat_set(FromRangeT&&, R&&,
std::size_t = boost::unordered::detail::foa::default_bucket_count,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_flat_set<std::ranges::range_value_t<R>,
Hash, Pred, Allocator>;
#endif
template <class T, class Hash = boost::hash<T>, template <class T, class Hash = boost::hash<T>,
class Pred = std::equal_to<T>, class Allocator = std::allocator<T>, class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
class = std::enable_if_t<detail::is_hash_v<Hash> >, class = std::enable_if_t<detail::is_hash_v<Hash> >,
@@ -603,6 +683,29 @@ namespace boost {
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>, std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_flat_set(FromRangeT&&, R&&, std::size_t, Allocator)
-> unordered_flat_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R> >,
std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash, class Allocator,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_flat_set(
FromRangeT&&, R&&, std::size_t, Hash, Allocator)
-> unordered_flat_set<std::ranges::range_value_t<R>,
Hash, std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
#endif
template <class T, class Allocator, template <class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_flat_set(std::initializer_list<T>, std::size_t, Allocator) unordered_flat_set(std::initializer_list<T>, std::size_t, Allocator)
@@ -624,6 +727,18 @@ namespace boost {
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>, std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_flat_set(FromRangeT&&, R&&, Allocator)
-> unordered_flat_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R> >,
std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
#endif
template <class T, class Allocator, template <class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_flat_set(std::initializer_list<T>, Allocator) unordered_flat_set(std::initializer_list<T>, Allocator)
+338 -1
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2011 Daniel James. // Copyright (C) 2005-2011 Daniel James.
// Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 2024 Joaquin M Lopez Munoz. // Copyright (C) 2024-2026 Joaquin M Lopez Munoz.
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,6 +16,7 @@
#endif #endif
#include <boost/unordered/detail/map.hpp> #include <boost/unordered/detail/map.hpp>
#include <boost/unordered/detail/ranges_support.hpp>
#include <boost/unordered/detail/serialize_fca_container.hpp> #include <boost/unordered/detail/serialize_fca_container.hpp>
#include <boost/unordered/detail/throw_exception.hpp> #include <boost/unordered/detail/throw_exception.hpp>
#include <boost/unordered/detail/type_traits.hpp> #include <boost/unordered/detail/type_traits.hpp>
@@ -92,6 +93,17 @@ namespace boost {
const hasher& = hasher(), const key_equal& = key_equal(), const hasher& = hasher(), const key_equal& = key_equal(),
const allocator_type& = allocator_type()); const allocator_type& = allocator_type());
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_map(FromRangeT&&, R&&,
size_type = boost::unordered::detail::default_bucket_count,
const hasher& = hasher(), const key_equal& = key_equal(),
const allocator_type& = allocator_type());
#endif
unordered_map(unordered_map const&); unordered_map(unordered_map const&);
unordered_map(unordered_map&& other) unordered_map(unordered_map&& other)
@@ -126,6 +138,27 @@ namespace boost {
unordered_map( unordered_map(
InputIt, InputIt, size_type, const hasher&, const allocator_type&); InputIt, InputIt, size_type, const hasher&, const allocator_type&);
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_map(FromRangeT&&, R&&, const allocator_type&);
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_map(FromRangeT&&, R&&, size_type, const allocator_type&);
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_map(
FromRangeT&&, R&&, size_type, const hasher&, const allocator_type&);
#endif
unordered_map(std::initializer_list<value_type>, const allocator_type&); unordered_map(std::initializer_list<value_type>, const allocator_type&);
unordered_map( unordered_map(
@@ -248,6 +281,11 @@ namespace boost {
template <class InputIt> void insert(InputIt, InputIt); template <class InputIt> void insert(InputIt, InputIt);
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <detail::container_compatible_range<std::pair<const K, T> > R>
void insert_range(R&&);
#endif
void insert(std::initializer_list<value_type>); void insert(std::initializer_list<value_type>);
// extract // extract
@@ -622,6 +660,27 @@ namespace boost {
boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred, boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash =
boost::hash<boost::unordered::detail::range_key_t<R> >,
class Pred =
std::equal_to<boost::unordered::detail::range_key_t<R> >,
class Allocator = std::allocator<
boost::unordered::detail::range_to_alloc_t<R> >,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_pred_v<Pred> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_map(FromRangeT&&, R&&,
std::size_t = boost::unordered::detail::default_bucket_count,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>, Hash, Pred,
Allocator>;
#endif
template <class Key, class T, template <class Key, class T,
class Hash = boost::hash<std::remove_const_t<Key> >, class Hash = boost::hash<std::remove_const_t<Key> >,
class Pred = std::equal_to<std::remove_const_t<Key> >, class Pred = std::equal_to<std::remove_const_t<Key> >,
@@ -664,6 +723,42 @@ namespace boost {
std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >, std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_map(FromRangeT&&, R&&, std::size_t, Allocator)
-> unordered_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>,
boost::hash<boost::unordered::detail::range_key_t<R> >,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_map(FromRangeT&&, R&&, Allocator)
-> unordered_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>,
boost::hash<boost::unordered::detail::range_key_t<R> >,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash, class Allocator,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_map(
FromRangeT&&, R&&, std::size_t, Hash, Allocator)
-> unordered_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>, Hash,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
#endif
template <class Key, class T, class Allocator, template <class Key, class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_map(std::initializer_list<std::pair<Key, T> >, std::size_t, unordered_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
@@ -742,6 +837,17 @@ namespace boost {
const hasher& = hasher(), const key_equal& = key_equal(), const hasher& = hasher(), const key_equal& = key_equal(),
const allocator_type& = allocator_type()); const allocator_type& = allocator_type());
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_multimap(FromRangeT&&, R&&,
size_type = boost::unordered::detail::default_bucket_count,
const hasher& = hasher(), const key_equal& = key_equal(),
const allocator_type& = allocator_type());
#endif
unordered_multimap(unordered_multimap const&); unordered_multimap(unordered_multimap const&);
unordered_multimap(unordered_multimap&& other) unordered_multimap(unordered_multimap&& other)
@@ -777,6 +883,27 @@ namespace boost {
unordered_multimap( unordered_multimap(
InputIt, InputIt, size_type, const hasher&, const allocator_type&); InputIt, InputIt, size_type, const hasher&, const allocator_type&);
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_multimap(FromRangeT&&, R&&, const allocator_type&);
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_multimap(FromRangeT&&, R&&, size_type, const allocator_type&);
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_multimap(
FromRangeT&&, R&&, size_type, const hasher&, const allocator_type&);
#endif
unordered_multimap( unordered_multimap(
std::initializer_list<value_type>, const allocator_type&); std::initializer_list<value_type>, const allocator_type&);
@@ -894,6 +1021,11 @@ namespace boost {
template <class InputIt> void insert(InputIt, InputIt); template <class InputIt> void insert(InputIt, InputIt);
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <detail::container_compatible_range<std::pair<const K, T> > R>
void insert_range(R&&);
#endif
void insert(std::initializer_list<value_type>); void insert(std::initializer_list<value_type>);
// extract // extract
@@ -1141,6 +1273,26 @@ namespace boost {
boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred, boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash =
boost::hash<boost::unordered::detail::range_key_t<R> >,
class Pred =
std::equal_to<boost::unordered::detail::range_key_t<R> >,
class Allocator = std::allocator<
boost::unordered::detail::range_to_alloc_t<R> >,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_pred_v<Pred> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_multimap(FromRangeT&&, R&&,
std::size_t = boost::unordered::detail::default_bucket_count,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_multimap<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>, Hash, Pred,
Allocator>;
#endif
template <class Key, class T, template <class Key, class T,
class Hash = boost::hash<std::remove_const_t<Key> >, class Hash = boost::hash<std::remove_const_t<Key> >,
class Pred = std::equal_to<std::remove_const_t<Key> >, class Pred = std::equal_to<std::remove_const_t<Key> >,
@@ -1184,6 +1336,42 @@ namespace boost {
std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >, std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_multimap(FromRangeT&&, R&&, std::size_t, Allocator)
-> unordered_multimap<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>,
boost::hash<boost::unordered::detail::range_key_t<R> >,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_multimap(FromRangeT&&, R&&, Allocator)
-> unordered_multimap<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>,
boost::hash<boost::unordered::detail::range_key_t<R> >,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash, class Allocator,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_multimap(
FromRangeT&&, R&&, std::size_t, Hash, Allocator)
-> unordered_multimap<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>, Hash,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
#endif
template <class Key, class T, class Allocator, template <class Key, class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_multimap(std::initializer_list<std::pair<Key, T> >, std::size_t, unordered_multimap(std::initializer_list<std::pair<Key, T> >, std::size_t,
@@ -1231,6 +1419,23 @@ namespace boost {
this->insert(f, l); this->insert(f, l);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <class K, class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_map<K, T, H, P, A>::unordered_map(FromRangeT&&, R&& rg,
size_type n, const hasher& hf, const key_equal& eql,
const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(std::forward<R>(rg), n),
hf, eql, a)
{
this->insert_range(std::forward<R>(rg));
}
#endif
template <class K, class T, class H, class P, class A> template <class K, class T, class H, class P, class A>
unordered_map<K, T, H, P, A>::unordered_map(unordered_map const& other) unordered_map<K, T, H, P, A>::unordered_map(unordered_map const& other)
: table_(other.table_, : table_(other.table_,
@@ -1303,6 +1508,7 @@ namespace boost {
this->insert(f, l); this->insert(f, l);
} }
template <class K, class T, class H, class P, class A> template <class K, class T, class H, class P, class A>
template <class InputIt> template <class InputIt>
unordered_map<K, T, H, P, A>::unordered_map( unordered_map<K, T, H, P, A>::unordered_map(
@@ -1323,6 +1529,51 @@ namespace boost {
this->insert(f, l); this->insert(f, l);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <class K, class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_map<K, T, H, P, A>::unordered_map(
FromRangeT&&, R&& rg, const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(
std::forward<R>(rg), detail::default_bucket_count),
hasher(), key_equal(), a)
{
this->insert_range(std::forward<R>(rg));
}
template <class K, class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_map<K, T, H, P, A>::unordered_map(
FromRangeT&&, R&& rg, size_type n, const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(std::forward<R>(rg), n),
hasher(), key_equal(), a)
{
this->insert_range(std::forward<R>(rg));
}
template <class K, class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_map<K, T, H, P, A>::unordered_map(FromRangeT&&, R&& rg,
size_type n, const hasher& hf, const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(std::forward<R>(rg), n),
hf, key_equal(), a)
{
this->insert_range(std::forward<R>(rg));
}
#endif
template <class K, class T, class H, class P, class A> template <class K, class T, class H, class P, class A>
unordered_map<K, T, H, P, A>::unordered_map( unordered_map<K, T, H, P, A>::unordered_map(
std::initializer_list<value_type> list, const allocator_type& a) std::initializer_list<value_type> list, const allocator_type& a)
@@ -1395,6 +1646,20 @@ namespace boost {
} }
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <class K, class T, class H, class P, class A>
template <detail::container_compatible_range<std::pair<const K, T> > R>
void unordered_map<K, T, H, P, A>::insert_range(R&& rg)
{
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
if (first != last) {
table_.insert_range_unique(
table::extractor::extract(*first), first, last);
}
}
#endif
template <class K, class T, class H, class P, class A> template <class K, class T, class H, class P, class A>
void unordered_map<K, T, H, P, A>::insert( void unordered_map<K, T, H, P, A>::insert(
std::initializer_list<value_type> list) std::initializer_list<value_type> list)
@@ -1757,6 +2022,23 @@ namespace boost {
this->insert(f, l); this->insert(f, l);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <class K, class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_multimap<K, T, H, P, A>::unordered_multimap(FromRangeT&&, R&& rg,
size_type n, const hasher& hf, const key_equal& eql,
const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(std::forward<R>(rg), n),
hf, eql, a)
{
this->insert_range(std::forward<R>(rg));
}
#endif
template <class K, class T, class H, class P, class A> template <class K, class T, class H, class P, class A>
unordered_multimap<K, T, H, P, A>::unordered_multimap( unordered_multimap<K, T, H, P, A>::unordered_multimap(
unordered_multimap const& other) unordered_multimap const& other)
@@ -1851,6 +2133,51 @@ namespace boost {
this->insert(f, l); this->insert(f, l);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <class K, class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_multimap<K, T, H, P, A>::unordered_multimap(
FromRangeT&&, R&& rg, const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(
std::forward<R>(rg), detail::default_bucket_count),
hasher(), key_equal(), a)
{
this->insert_range(std::forward<R>(rg));
}
template <class K, class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_multimap<K, T, H, P, A>::unordered_multimap(
FromRangeT&&, R&& rg, size_type n, const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(std::forward<R>(rg), n),
hasher(), key_equal(), a)
{
this->insert_range(std::forward<R>(rg));
}
template <class K, class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<std::pair<const K, T> > R
>
unordered_multimap<K, T, H, P, A>::unordered_multimap(FromRangeT&&, R&& rg,
size_type n, const hasher& hf, const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(std::forward<R>(rg), n),
hf, key_equal(), a)
{
this->insert_range(std::forward<R>(rg));
}
#endif
template <class K, class T, class H, class P, class A> template <class K, class T, class H, class P, class A>
unordered_multimap<K, T, H, P, A>::unordered_multimap( unordered_multimap<K, T, H, P, A>::unordered_multimap(
std::initializer_list<value_type> list, const allocator_type& a) std::initializer_list<value_type> list, const allocator_type& a)
@@ -1921,6 +2248,16 @@ namespace boost {
table_.insert_range_equiv(first, last); table_.insert_range_equiv(first, last);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <class K, class T, class H, class P, class A>
template <detail::container_compatible_range<std::pair<const K, T> > R>
void unordered_multimap<K, T, H, P, A>::insert_range(R&& rg)
{
table_.insert_range_equiv(std::ranges::begin(rg), std::ranges::end(rg));
}
#endif
template <class K, class T, class H, class P, class A> template <class K, class T, class H, class P, class A>
void unordered_multimap<K, T, H, P, A>::insert( void unordered_multimap<K, T, H, P, A>::insert(
std::initializer_list<value_type> list) std::initializer_list<value_type> list)
+121 -3
View File
@@ -1,5 +1,6 @@
// Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 2024-2025 Joaquin M Lopez Munoz // Copyright (C) 2024-2026 Joaquin M Lopez Munoz
// Copyright (C) 2026 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,6 +16,7 @@
#include <boost/unordered/detail/foa/node_map_handle.hpp> #include <boost/unordered/detail/foa/node_map_handle.hpp>
#include <boost/unordered/detail/foa/node_map_types.hpp> #include <boost/unordered/detail/foa/node_map_types.hpp>
#include <boost/unordered/detail/foa/table.hpp> #include <boost/unordered/detail/foa/table.hpp>
#include <boost/unordered/detail/ranges_support.hpp>
#include <boost/unordered/detail/serialize_container.hpp> #include <boost/unordered/detail/serialize_container.hpp>
#include <boost/unordered/detail/throw_exception.hpp> #include <boost/unordered/detail/throw_exception.hpp>
#include <boost/unordered/detail/type_traits.hpp> #include <boost/unordered/detail/type_traits.hpp>
@@ -114,6 +116,19 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_node_map(
FromRangeT&& fr, R&& rg, allocator_type const& a)
: unordered_node_map(
fr, std::forward<R>(rg), size_type(0), hasher(), key_equal(), a)
{
}
#endif
explicit unordered_node_map(allocator_type const& a) explicit unordered_node_map(allocator_type const& a)
: unordered_node_map(0, a) : unordered_node_map(0, a)
{ {
@@ -142,6 +157,41 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_node_map(FromRangeT&&, R&& rg, size_type n = 0,
hasher const& h = hasher(), key_equal const& pred = key_equal(),
allocator_type const& a = allocator_type())
: unordered_node_map(n, h, pred, a)
{
this->insert_range(std::forward<R>(rg));
}
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_node_map(
FromRangeT&& fr, R&& rg, size_type n, allocator_type const& a)
: unordered_node_map(
fr, std::forward<R>(rg), n, hasher(), key_equal(), a)
{
}
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_node_map(FromRangeT&& fr, R&& rg, size_type n,
hasher const& h, allocator_type const& a)
: unordered_node_map(fr, std::forward<R>(rg), n, h, key_equal(), a)
{
}
#endif
unordered_node_map(unordered_node_map const& other) : table_(other.table_) unordered_node_map(unordered_node_map const& other) : table_(other.table_)
{ {
} }
@@ -189,9 +239,10 @@ namespace boost {
{ {
} }
template <bool avoid_explicit_instantiation = true> template <typename Key2,
typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
unordered_node_map( unordered_node_map(
concurrent_node_map<Key, T, Hash, KeyEqual, Allocator>&& other) concurrent_node_map<Key2, T, Hash, KeyEqual, Allocator>&& other)
: table_(std::move(other.table_)) : table_(std::move(other.table_))
{ {
} }
@@ -283,6 +334,16 @@ namespace boost {
} }
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R>
BOOST_FORCEINLINE void insert_range(R&& rg)
{
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
while (first != last) table_.emplace(*first++);
}
#endif
void insert(std::initializer_list<value_type> ilist) void insert(std::initializer_list<value_type> ilist)
{ {
this->insert(ilist.begin(), ilist.end()); this->insert(ilist.begin(), ilist.end());
@@ -828,6 +889,27 @@ namespace boost {
boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred, boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash =
boost::hash<boost::unordered::detail::range_key_t<R> >,
class Pred =
std::equal_to<boost::unordered::detail::range_key_t<R> >,
class Allocator = std::allocator<
boost::unordered::detail::range_to_alloc_t<R> >,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_pred_v<Pred> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_node_map(FromRangeT&&, R&&,
std::size_t = boost::unordered::detail::foa::default_bucket_count,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_node_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>, Hash, Pred,
Allocator>;
#endif
template <class Key, class T, template <class Key, class T,
class Hash = boost::hash<std::remove_const_t<Key> >, class Hash = boost::hash<std::remove_const_t<Key> >,
class Pred = std::equal_to<std::remove_const_t<Key> >, class Pred = std::equal_to<std::remove_const_t<Key> >,
@@ -872,6 +954,42 @@ namespace boost {
std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >, std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_node_map(FromRangeT&&, R&&, std::size_t, Allocator)
-> unordered_node_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>,
boost::hash<boost::unordered::detail::range_key_t<R> >,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_node_map(FromRangeT&&, R&&, Allocator)
-> unordered_node_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>,
boost::hash<boost::unordered::detail::range_key_t<R> >,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash, class Allocator,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_node_map(
FromRangeT&&, R&&, std::size_t, Hash, Allocator)
-> unordered_node_map<boost::unordered::detail::range_key_t<R>,
boost::unordered::detail::range_mapped_t<R>, Hash,
std::equal_to<boost::unordered::detail::range_key_t<R> >,
Allocator>;
#endif
template <class Key, class T, class Allocator, template <class Key, class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_node_map(std::initializer_list<std::pair<Key, T> >, std::size_t, unordered_node_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
+118 -3
View File
@@ -1,5 +1,6 @@
// Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 2024-2025 Joaquin M Lopez Munoz // Copyright (C) 2024-2026 Joaquin M Lopez Munoz
// Copyright (C) 2026 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,6 +17,7 @@
#include <boost/unordered/detail/foa/node_set_handle.hpp> #include <boost/unordered/detail/foa/node_set_handle.hpp>
#include <boost/unordered/detail/foa/node_set_types.hpp> #include <boost/unordered/detail/foa/node_set_types.hpp>
#include <boost/unordered/detail/foa/table.hpp> #include <boost/unordered/detail/foa/table.hpp>
#include <boost/unordered/detail/ranges_support.hpp>
#include <boost/unordered/detail/serialize_container.hpp> #include <boost/unordered/detail/serialize_container.hpp>
#include <boost/unordered/detail/type_traits.hpp> #include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_node_set_fwd.hpp> #include <boost/unordered/unordered_node_set_fwd.hpp>
@@ -112,6 +114,19 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_node_set(
FromRangeT&& fr, R&& rg, allocator_type const& a)
: unordered_node_set(
fr, std::forward<R>(rg), size_type(0), hasher(), key_equal(), a)
{
}
#endif
explicit unordered_node_set(allocator_type const& a) explicit unordered_node_set(allocator_type const& a)
: unordered_node_set(0, a) : unordered_node_set(0, a)
{ {
@@ -140,6 +155,41 @@ namespace boost {
{ {
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_node_set(FromRangeT&&, R&& rg, size_type n = 0,
hasher const& h = hasher(), key_equal const& pred = key_equal(),
allocator_type const& a = allocator_type())
: unordered_node_set(n, h, pred, a)
{
this->insert_range(std::forward<R>(rg));
}
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_node_set(
FromRangeT&& fr, R&& rg, size_type n, allocator_type const& a)
: unordered_node_set(
fr, std::forward<R>(rg), n, hasher(), key_equal(), a)
{
}
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<value_type> R
>
unordered_node_set(FromRangeT&& fr, R&& rg, size_type n,
hasher const& h, allocator_type const& a)
: unordered_node_set(fr, std::forward<R>(rg), n, h, key_equal(), a)
{
}
#endif
unordered_node_set(unordered_node_set const& other) : table_(other.table_) unordered_node_set(unordered_node_set const& other) : table_(other.table_)
{ {
} }
@@ -187,9 +237,10 @@ namespace boost {
{ {
} }
template <bool avoid_explicit_instantiation = true> template <typename Key2,
typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
unordered_node_set( unordered_node_set(
concurrent_node_set<Key, Hash, KeyEqual, Allocator>&& other) concurrent_node_set<Key2, Hash, KeyEqual, Allocator>&& other)
: table_(std::move(other.table_)) : table_(std::move(other.table_))
{ {
} }
@@ -296,6 +347,16 @@ namespace boost {
} }
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<detail::container_compatible_range<value_type> R>
void insert_range(R&& rg)
{
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
while (first != last) table_.emplace(*first++);
}
#endif
void insert(std::initializer_list<value_type> ilist) void insert(std::initializer_list<value_type> ilist)
{ {
this->insert(ilist.begin(), ilist.end()); this->insert(ilist.begin(), ilist.end());
@@ -648,6 +709,25 @@ namespace boost {
typename std::iterator_traits<InputIterator>::value_type, Hash, Pred, typename std::iterator_traits<InputIterator>::value_type, Hash, Pred,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash =
boost::hash<std::ranges::range_value_t<R> >,
class Pred =
std::equal_to<std::ranges::range_value_t<R> >,
class Allocator = std::allocator<std::ranges::range_value_t<R> >,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_pred_v<Pred> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_node_set(FromRangeT&&, R&&,
std::size_t = boost::unordered::detail::foa::default_bucket_count,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_node_set<std::ranges::range_value_t<R>,
Hash, Pred, Allocator>;
#endif
template <class T, class Hash = boost::hash<T>, template <class T, class Hash = boost::hash<T>,
class Pred = std::equal_to<T>, class Allocator = std::allocator<T>, class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
class = std::enable_if_t<detail::is_hash_v<Hash> >, class = std::enable_if_t<detail::is_hash_v<Hash> >,
@@ -679,6 +759,29 @@ namespace boost {
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>, std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_node_set(FromRangeT&&, R&&, std::size_t, Allocator)
-> unordered_node_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R> >,
std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash, class Allocator,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_node_set(
FromRangeT&&, R&&, std::size_t, Hash, Allocator)
-> unordered_node_set<std::ranges::range_value_t<R>,
Hash, std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
#endif
template <class T, class Allocator, template <class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_node_set(std::initializer_list<T>, std::size_t, Allocator) unordered_node_set(std::initializer_list<T>, std::size_t, Allocator)
@@ -700,6 +803,18 @@ namespace boost {
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>, std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_node_set(FromRangeT&&, R&&, Allocator)
-> unordered_node_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R> >,
std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
#endif
template <class T, class Allocator, template <class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_node_set(std::initializer_list<T>, Allocator) unordered_node_set(std::initializer_list<T>, Allocator)
+333 -1
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2011 Daniel James. // Copyright (C) 2005-2011 Daniel James.
// Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 2024 Joaquin M Lopez Munoz. // Copyright (C) 2024-2026 Joaquin M Lopez Munoz.
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,6 +15,7 @@
#pragma once #pragma once
#endif #endif
#include <boost/unordered/detail/ranges_support.hpp>
#include <boost/unordered/detail/serialize_fca_container.hpp> #include <boost/unordered/detail/serialize_fca_container.hpp>
#include <boost/unordered/detail/set.hpp> #include <boost/unordered/detail/set.hpp>
#include <boost/unordered/detail/type_traits.hpp> #include <boost/unordered/detail/type_traits.hpp>
@@ -88,6 +89,17 @@ namespace boost {
const hasher& = hasher(), const key_equal& = key_equal(), const hasher& = hasher(), const key_equal& = key_equal(),
const allocator_type& = allocator_type()); const allocator_type& = allocator_type());
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_set(FromRangeT&&, R&&,
size_type = boost::unordered::detail::default_bucket_count,
const hasher& = hasher(), const key_equal& = key_equal(),
const allocator_type& = allocator_type());
#endif
unordered_set(unordered_set const&); unordered_set(unordered_set const&);
unordered_set(unordered_set&& other) unordered_set(unordered_set&& other)
@@ -122,6 +134,27 @@ namespace boost {
unordered_set( unordered_set(
InputIt, InputIt, size_type, const hasher&, const allocator_type&); InputIt, InputIt, size_type, const hasher&, const allocator_type&);
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_set(FromRangeT&&, R&&, const allocator_type&);
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_set(FromRangeT&&, R&&, size_type, const allocator_type&);
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_set(
FromRangeT&&, R&&, size_type, const hasher&, const allocator_type&);
#endif
unordered_set(std::initializer_list<value_type>, const allocator_type&); unordered_set(std::initializer_list<value_type>, const allocator_type&);
unordered_set( unordered_set(
@@ -246,6 +279,11 @@ namespace boost {
template <class InputIt> void insert(InputIt, InputIt); template <class InputIt> void insert(InputIt, InputIt);
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <detail::container_compatible_range<T> R>
void insert_range(R&&);
#endif
void insert(std::initializer_list<value_type>); void insert(std::initializer_list<value_type>);
// extract // extract
@@ -478,6 +516,25 @@ namespace boost {
-> unordered_set<typename std::iterator_traits<InputIterator>::value_type, -> unordered_set<typename std::iterator_traits<InputIterator>::value_type,
Hash, Pred, Allocator>; Hash, Pred, Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash =
boost::hash<std::ranges::range_value_t<R> >,
class Pred =
std::equal_to<std::ranges::range_value_t<R> >,
class Allocator = std::allocator<std::ranges::range_value_t<R> >,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_pred_v<Pred> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_set(FromRangeT&&, R&&,
std::size_t = boost::unordered::detail::default_bucket_count,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_set<std::ranges::range_value_t<R>,
Hash, Pred, Allocator>;
#endif
template <class T, class Hash = boost::hash<T>, template <class T, class Hash = boost::hash<T>,
class Pred = std::equal_to<T>, class Allocator = std::allocator<T>, class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
class = std::enable_if_t<detail::is_hash_v<Hash> >, class = std::enable_if_t<detail::is_hash_v<Hash> >,
@@ -507,6 +564,29 @@ namespace boost {
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>, std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_set(FromRangeT&&, R&&, std::size_t, Allocator)
-> unordered_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R> >,
std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash, class Allocator,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_set(
FromRangeT&&, R&&, std::size_t, Hash, Allocator)
-> unordered_set<std::ranges::range_value_t<R>,
Hash, std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
#endif
template <class T, class Allocator, template <class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_set(std::initializer_list<T>, std::size_t, Allocator) unordered_set(std::initializer_list<T>, std::size_t, Allocator)
@@ -527,6 +607,18 @@ namespace boost {
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>, std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_set(FromRangeT&&, R&&, Allocator)
-> unordered_set<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R> >,
std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
#endif
template <class T, class Allocator, template <class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_set(std::initializer_list<T>, Allocator) unordered_set(std::initializer_list<T>, Allocator)
@@ -585,6 +677,18 @@ namespace boost {
const hasher& = hasher(), const key_equal& = key_equal(), const hasher& = hasher(), const key_equal& = key_equal(),
const allocator_type& = allocator_type()); const allocator_type& = allocator_type());
#if !defined(BOOST_UNORDERED_NO_RANGES)
template<
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_multiset(FromRangeT&&, R&&,
size_type = boost::unordered::detail::default_bucket_count,
const hasher& = hasher(), const key_equal& = key_equal(),
const allocator_type& = allocator_type());
#endif
unordered_multiset(unordered_multiset const&); unordered_multiset(unordered_multiset const&);
unordered_multiset(unordered_multiset&& other) unordered_multiset(unordered_multiset&& other)
@@ -620,6 +724,27 @@ namespace boost {
unordered_multiset( unordered_multiset(
InputIt, InputIt, size_type, const hasher&, const allocator_type&); InputIt, InputIt, size_type, const hasher&, const allocator_type&);
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_multiset(FromRangeT&&, R&&, const allocator_type&);
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_multiset(FromRangeT&&, R&&, size_type, const allocator_type&);
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_multiset(
FromRangeT&&, R&&, size_type, const hasher&, const allocator_type&);
#endif
unordered_multiset( unordered_multiset(
std::initializer_list<value_type>, const allocator_type&); std::initializer_list<value_type>, const allocator_type&);
@@ -720,6 +845,11 @@ namespace boost {
template <class InputIt> void insert(InputIt, InputIt); template <class InputIt> void insert(InputIt, InputIt);
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <detail::container_compatible_range<T> R>
void insert_range(R&&);
#endif
void insert(std::initializer_list<value_type>); void insert(std::initializer_list<value_type>);
// extract // extract
@@ -942,6 +1072,25 @@ namespace boost {
typename std::iterator_traits<InputIterator>::value_type, Hash, Pred, typename std::iterator_traits<InputIterator>::value_type, Hash, Pred,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <
boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash =
boost::hash<std::ranges::range_value_t<R> >,
class Pred =
std::equal_to<std::ranges::range_value_t<R> >,
class Allocator = std::allocator<std::ranges::range_value_t<R> >,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_pred_v<Pred> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_multiset(FromRangeT&&, R&&,
std::size_t = boost::unordered::detail::default_bucket_count,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_multiset<std::ranges::range_value_t<R>,
Hash, Pred, Allocator>;
#endif
template <class T, class Hash = boost::hash<T>, template <class T, class Hash = boost::hash<T>,
class Pred = std::equal_to<T>, class Allocator = std::allocator<T>, class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
class = std::enable_if_t<detail::is_hash_v<Hash> >, class = std::enable_if_t<detail::is_hash_v<Hash> >,
@@ -973,6 +1122,29 @@ namespace boost {
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>, std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_multiset(FromRangeT&&, R&&, std::size_t, Allocator)
-> unordered_multiset<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R> >,
std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Hash, class Allocator,
class = std::enable_if_t<detail::is_hash_v<Hash> >,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_multiset(
FromRangeT&&, R&&, std::size_t, Hash, Allocator)
-> unordered_multiset<std::ranges::range_value_t<R>,
Hash, std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
#endif
template <class T, class Allocator, template <class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_multiset(std::initializer_list<T>, std::size_t, Allocator) unordered_multiset(std::initializer_list<T>, std::size_t, Allocator)
@@ -994,6 +1166,18 @@ namespace boost {
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>, std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
Allocator>; Allocator>;
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <boost::unordered::detail::convertible_to_from_range_t FromRangeT,
std::ranges::input_range R,
class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_multiset(FromRangeT&&, R&&, Allocator)
-> unordered_multiset<std::ranges::range_value_t<R>,
boost::hash<std::ranges::range_value_t<R> >,
std::equal_to<std::ranges::range_value_t<R> >,
Allocator>;
#endif
template <class T, class Allocator, template <class T, class Allocator,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > > class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_multiset(std::initializer_list<T>, Allocator) unordered_multiset(std::initializer_list<T>, Allocator)
@@ -1023,6 +1207,23 @@ namespace boost {
this->insert(f, l); this->insert(f, l);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_set<T, H, P, A>::unordered_set(FromRangeT&&, R&& rg,
size_type n, const hasher& hf, const key_equal& eql,
const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(std::forward<R>(rg), n),
hf, eql, a)
{
this->insert_range(std::forward<R>(rg));
}
#endif
template <class T, class H, class P, class A> template <class T, class H, class P, class A>
unordered_set<T, H, P, A>::unordered_set(unordered_set const& other) unordered_set<T, H, P, A>::unordered_set(unordered_set const& other)
: table_(other.table_, : table_(other.table_,
@@ -1115,6 +1316,51 @@ namespace boost {
this->insert(f, l); this->insert(f, l);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_set<T, H, P, A>::unordered_set(
FromRangeT&&, R&& rg, const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(
std::forward<R>(rg), detail::default_bucket_count),
hasher(), key_equal(), a)
{
this->insert_range(std::forward<R>(rg));
}
template <class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_set<T, H, P, A>::unordered_set(
FromRangeT&&, R&& rg, size_type n, const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(std::forward<R>(rg), n),
hasher(), key_equal(), a)
{
this->insert_range(std::forward<R>(rg));
}
template <class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_set<T, H, P, A>::unordered_set(FromRangeT&&, R&& rg,
size_type n, const hasher& hf, const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(std::forward<R>(rg), n),
hf, key_equal(), a)
{
this->insert_range(std::forward<R>(rg));
}
#endif
template <class T, class H, class P, class A> template <class T, class H, class P, class A>
unordered_set<T, H, P, A>::unordered_set( unordered_set<T, H, P, A>::unordered_set(
std::initializer_list<value_type> list, const allocator_type& a) std::initializer_list<value_type> list, const allocator_type& a)
@@ -1187,6 +1433,20 @@ namespace boost {
} }
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <class T, class H, class P, class A>
template <detail::container_compatible_range<T> R>
void unordered_set<T, H, P, A>::insert_range(R&& rg)
{
auto first = std::ranges::begin(rg);
auto last = std::ranges::end(rg);
if (first != last) {
table_.insert_range_unique(
table::extractor::extract(*first), first, last);
}
}
#endif
template <class T, class H, class P, class A> template <class T, class H, class P, class A>
void unordered_set<T, H, P, A>::insert( void unordered_set<T, H, P, A>::insert(
std::initializer_list<value_type> list) std::initializer_list<value_type> list)
@@ -1420,6 +1680,23 @@ namespace boost {
this->insert(f, l); this->insert(f, l);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_multiset<T, H, P, A>::unordered_multiset(FromRangeT&&, R&& rg,
size_type n, const hasher& hf, const key_equal& eql,
const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(std::forward<R>(rg), n),
hf, eql, a)
{
this->insert_range(std::forward<R>(rg));
}
#endif
template <class T, class H, class P, class A> template <class T, class H, class P, class A>
unordered_multiset<T, H, P, A>::unordered_multiset( unordered_multiset<T, H, P, A>::unordered_multiset(
unordered_multiset const& other) unordered_multiset const& other)
@@ -1513,6 +1790,51 @@ namespace boost {
this->insert(f, l); this->insert(f, l);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_multiset<T, H, P, A>::unordered_multiset(
FromRangeT&&, R&& rg, const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(
std::forward<R>(rg), detail::default_bucket_count),
hasher(), key_equal(), a)
{
this->insert_range(std::forward<R>(rg));
}
template <class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_multiset<T, H, P, A>::unordered_multiset(
FromRangeT&&, R&& rg, size_type n, const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(std::forward<R>(rg), n),
hasher(), key_equal(), a)
{
this->insert_range(std::forward<R>(rg));
}
template <class T, class H, class P, class A>
template <
detail::convertible_to_from_range_t FromRangeT,
detail::container_compatible_range<T> R
>
unordered_multiset<T, H, P, A>::unordered_multiset(FromRangeT&&, R&& rg,
size_type n, const hasher& hf, const allocator_type& a)
: table_(
boost::unordered::detail::initial_size(std::forward<R>(rg), n),
hf, key_equal(), a)
{
this->insert_range(std::forward<R>(rg));
}
#endif
template <class T, class H, class P, class A> template <class T, class H, class P, class A>
unordered_multiset<T, H, P, A>::unordered_multiset( unordered_multiset<T, H, P, A>::unordered_multiset(
std::initializer_list<value_type> list, const allocator_type& a) std::initializer_list<value_type> list, const allocator_type& a)
@@ -1582,6 +1904,16 @@ namespace boost {
table_.insert_range_equiv(first, last); table_.insert_range_equiv(first, last);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <class T, class H, class P, class A>
template <detail::container_compatible_range<T> R>
void unordered_multiset<T, H, P, A>::insert_range(R&& rg)
{
table_.insert_range_equiv(
std::ranges::begin(rg), std::ranges::end(rg));
}
#endif
template <class T, class H, class P, class A> template <class T, class H, class P, class A>
void unordered_multiset<T, H, P, A>::insert( void unordered_multiset<T, H, P, A>::insert(
std::initializer_list<value_type> list) std::initializer_list<value_type> list)
+20 -1
View File
@@ -136,7 +136,17 @@ foa_tests(SOURCES exception/merge_exception_tests.cpp)
# CFOA tests # CFOA tests
cfoa_tests(SOURCES cfoa/insert_tests.cpp COMPILE_OPTIONS $<$<CXX_COMPILER_ID:MSVC>:/bigobj>) set(cfoa_insert_test_options $<$<CXX_COMPILER_ID:MSVC>:/bigobj>)
if(MINGW AND CMAKE_SIZEOF_VOID_P EQUAL 4)
list(APPEND cfoa_insert_test_options
-O0 -g0
--param=ggc-min-expand=10
--param=ggc-min-heapsize=16384
) # GCC MinGW32 OOMs otherwise
endif()
cfoa_tests(SOURCES cfoa/insert_tests.cpp COMPILE_OPTIONS ${cfoa_insert_test_options})
cfoa_tests(SOURCES cfoa/erase_tests.cpp) cfoa_tests(SOURCES cfoa/erase_tests.cpp)
cfoa_tests(SOURCES cfoa/try_emplace_tests.cpp) cfoa_tests(SOURCES cfoa/try_emplace_tests.cpp)
cfoa_tests(SOURCES cfoa/emplace_tests.cpp) cfoa_tests(SOURCES cfoa/emplace_tests.cpp)
@@ -163,4 +173,13 @@ cfoa_tests(SOURCES cfoa/rw_spinlock_test6.cpp)
cfoa_tests(SOURCES cfoa/rw_spinlock_test7.cpp) cfoa_tests(SOURCES cfoa/rw_spinlock_test7.cpp)
cfoa_tests(SOURCES cfoa/rw_spinlock_test8.cpp) cfoa_tests(SOURCES cfoa/rw_spinlock_test8.cpp)
# Compile tests
fca_tests(TYPE compile NAME explicit_instantiation_tests SOURCES unordered/explicit_instantiation_tests.cpp)
foa_tests(TYPE compile NAME explicit_instantiation_tests SOURCES unordered/explicit_instantiation_tests.cpp)
cfoa_tests(TYPE compile NAME explicit_instantiation_tests SOURCES cfoa/explicit_instantiation_tests.cpp)
foa_tests(TYPE compile NAME conversion_operator_tests SOURCES unordered/conversion_operator_tests.cpp)
cfoa_tests(TYPE compile NAME conversion_operator_tests SOURCES cfoa/conversion_operator_tests.cpp)
endif() endif()
+7 -5
View File
@@ -12,10 +12,7 @@ import config : requires ;
path-constant TOP : . ; path-constant TOP : . ;
# Adding -Wundef is blocked on (at least) local gcc-flags = -Wsign-promo -Wconversion -Wsign-conversion -Wfloat-equal -Wshadow -Wundef -Wno-variadic-macros ;
# https://github.com/boostorg/type_traits/issues/165
local gcc-flags = -Wsign-promo -Wconversion -Wsign-conversion -Wfloat-equal -Wshadow -Wno-variadic-macros ;
local clang-flags = $(gcc-flags) -Wno-c99-extensions ; local clang-flags = $(gcc-flags) -Wno-c99-extensions ;
local msvc-flags = /wd4494 ; local msvc-flags = /wd4494 ;
@@ -169,6 +166,9 @@ compile unordered/explicit_instantiation_tests.cpp :
compile unordered/explicit_instantiation_tests.cpp : <define>BOOST_UNORDERED_FOA_TESTS : foa_explicit_instantiation_tests ; compile unordered/explicit_instantiation_tests.cpp : <define>BOOST_UNORDERED_FOA_TESTS : foa_explicit_instantiation_tests ;
compile cfoa/explicit_instantiation_tests.cpp : : cfoa_explicit_instantiation_tests ; compile cfoa/explicit_instantiation_tests.cpp : : cfoa_explicit_instantiation_tests ;
compile unordered/conversion_operator_tests.cpp : <define>BOOST_UNORDERED_FOA_TESTS : foa_conversion_operator_tests ;
compile cfoa/conversion_operator_tests.cpp : : cfoa_conversion_operator_tests ;
local FCA_EXCEPTION_TESTS = local FCA_EXCEPTION_TESTS =
constructor_exception_tests constructor_exception_tests
copy_exception_tests copy_exception_tests
@@ -362,6 +362,7 @@ local CFOA_TESTS =
pmr_allocator_tests pmr_allocator_tests
stats_tests stats_tests
node_handle_allocator_tests node_handle_allocator_tests
incomplete_tests
; ;
for local test in $(CFOA_TESTS) for local test in $(CFOA_TESTS)
@@ -378,7 +379,8 @@ run cfoa/insert_tests.cpp
: $(CPP11) <threading>multi : $(CPP11) <threading>multi
<toolset>msvc:<cxxflags>/bigobj <toolset>msvc:<cxxflags>/bigobj
<toolset>gcc:<inlining>on <toolset>gcc:<inlining>on
<toolset>gcc:<optimization>space <toolset>gcc:<optimization>off
<toolset>gcc:<cxxflags>-g0
<toolset>clang:<inlining>on <toolset>clang:<inlining>on
<toolset>clang:<optimization>space <toolset>clang:<optimization>space
: cfoa_insert_tests ; : cfoa_insert_tests ;
+101 -1
View File
@@ -1,5 +1,5 @@
// Copyright (C) 2023 Christian Mazakas // Copyright (C) 2023 Christian Mazakas
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz // Copyright (C) 2023-2026 Joaquin M Lopez Munoz
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -10,6 +10,8 @@
#include <boost/unordered/concurrent_node_map.hpp> #include <boost/unordered/concurrent_node_map.hpp>
#include <boost/unordered/concurrent_node_set.hpp> #include <boost/unordered/concurrent_node_set.hpp>
#include <list>
test::seed_t initialize_seed(4122023); test::seed_t initialize_seed(4122023);
using test::default_generator; using test::default_generator;
@@ -702,6 +704,97 @@ namespace {
} }
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
template <class X, class IL>
void range_with_all_params(std::pair<X*, IL> p)
{
using value_type = typename X::value_type;
static constexpr auto value_type_cardinality =
value_cardinality<value_type>::value;
using allocator_type = typename X::allocator_type;
auto init_list = p.second;
auto init_std_list = std::list<value_type>{init_list};
auto sentineled_rg = init_std_list | std::views::take(init_list.size());
{
raii::reset_counts();
X x(
boost::unordered::from_range,
init_list, 0, hasher(1), key_equal(2), allocator_type(3));
BOOST_TEST_EQ(x.size(), 11u);
BOOST_TEST_EQ(x.hash_function(), hasher(1));
BOOST_TEST_EQ(x.key_eq(), key_equal(2));
BOOST_TEST(x.get_allocator() == allocator_type(3));
BOOST_TEST_EQ(raii::default_constructor, 0u);
BOOST_TEST_EQ(
raii::copy_constructor, value_type_cardinality * init_list.size() / 2u);
BOOST_TEST_EQ(
raii::move_constructor, 0u);
}
check_raii_counts();
{
raii::reset_counts();
X x(boost::unordered::from_range, sentineled_rg, allocator_type(3));
BOOST_TEST_EQ(x.size(), 11u);
BOOST_TEST_EQ(x.hash_function(), hasher());
BOOST_TEST_EQ(x.key_eq(), key_equal());
BOOST_TEST(x.get_allocator() == allocator_type(3));
BOOST_TEST_EQ(raii::default_constructor, 0u);
BOOST_TEST_EQ(
raii::copy_constructor, value_type_cardinality * init_list.size() / 2u);
BOOST_TEST_EQ(
raii::move_constructor, 0u);
}
check_raii_counts();
{
raii::reset_counts();
X x(boost::unordered::from_range, init_list, 0, allocator_type(3));
BOOST_TEST_EQ(x.size(), 11u);
BOOST_TEST_EQ(x.hash_function(), hasher());
BOOST_TEST_EQ(x.key_eq(), key_equal());
BOOST_TEST(x.get_allocator() == allocator_type(3));
BOOST_TEST_EQ(raii::default_constructor, 0u);
BOOST_TEST_EQ(
raii::copy_constructor, value_type_cardinality * init_list.size() / 2u);
BOOST_TEST_EQ(
raii::move_constructor, 0u);
}
check_raii_counts();
{
raii::reset_counts();
X x(
boost::unordered::from_range,
sentineled_rg, 0, hasher(1), allocator_type(3));
BOOST_TEST_EQ(x.size(), 11u);
BOOST_TEST_EQ(x.hash_function(), hasher(1));
BOOST_TEST_EQ(x.key_eq(), key_equal());
BOOST_TEST(x.get_allocator() == allocator_type(3));
BOOST_TEST_EQ(raii::default_constructor, 0u);
BOOST_TEST_EQ(
raii::copy_constructor, value_type_cardinality * init_list.size() / 2u);
BOOST_TEST_EQ(
raii::move_constructor, 0u);
}
check_raii_counts();
}
#endif
template <class X, class IL> template <class X, class IL>
void initializer_list_with_all_params(std::pair<X*, IL> p) void initializer_list_with_all_params(std::pair<X*, IL> p)
{ {
@@ -1040,6 +1133,13 @@ UNORDERED_TEST(
explicit_allocator, explicit_allocator,
((test_map)(test_node_map)(test_set)(test_node_set))) ((test_map)(test_node_map)(test_set)(test_node_set)))
#if !defined(BOOST_UNORDERED_NO_RANGES)
UNORDERED_TEST(
range_with_all_params,
((test_map_and_init_list)(test_node_map_and_init_list)
(test_set_and_init_list)(test_node_set_and_init_list)))
#endif
UNORDERED_TEST( UNORDERED_TEST(
initializer_list_with_all_params, initializer_list_with_all_params,
((test_map_and_init_list)(test_node_map_and_init_list) ((test_map_and_init_list)(test_node_map_and_init_list)
+42
View File
@@ -0,0 +1,42 @@
// Copyright 2026 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/static_assert.hpp>
#include <boost/unordered/concurrent_flat_map.hpp>
#include <boost/unordered/concurrent_flat_set.hpp>
#include <boost/unordered/concurrent_node_map.hpp>
#include <boost/unordered/concurrent_node_set.hpp>
// Don't include the FOA headers here!
using c_flat_map = boost::unordered::concurrent_flat_map<int, int>;
using c_flat_set = boost::unordered::concurrent_flat_set<int>;
using c_node_map = boost::unordered::concurrent_node_map<int, int>;
using c_node_set = boost::unordered::concurrent_node_set<int>;
struct constrained_template_converter
{
struct dummy
{
};
template <class T, typename std::enable_if<
std::is_constructible<T, dummy>::value, int>::type = 0>
operator T() const
{
return T{};
}
};
// Check whether the corresponding FOA container gets instantiated.
// The FOA headers aren't included, so this would fail to compile if the FOA
// container was instantiated.
BOOST_STATIC_ASSERT(
(!std::is_constructible<c_flat_map, constrained_template_converter>::value));
BOOST_STATIC_ASSERT(
(!std::is_constructible<c_flat_set, constrained_template_converter>::value));
BOOST_STATIC_ASSERT(
(!std::is_constructible<c_node_map, constrained_template_converter>::value));
BOOST_STATIC_ASSERT(
(!std::is_constructible<c_node_set, constrained_template_converter>::value));
int main() { return 0; }
+6
View File
@@ -0,0 +1,6 @@
// Copyright 2025 Joaquin M Lopez Munoz.
// 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)
#define BOOST_UNORDERED_CFOA_TESTS
#include "../unordered/incomplete_test.cpp"
+241 -9
View File
@@ -1,5 +1,5 @@
// Copyright (C) 2023 Christian Mazakas // Copyright (C) 2023 Christian Mazakas
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz // Copyright (C) 2023-2026 Joaquin M Lopez Munoz
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -148,12 +148,18 @@ namespace {
values2.push_back(raii_convertible(v)); values2.push_back(raii_convertible(v));
} }
thread_runner(values2, [&x](boost::span<raii_convertible> s) { auto sz = x.size();
BOOST_TEST_EQ(x.insert(s.begin(), s.end()), s.size()); std::atomic<std::uint64_t> num_inserts{0};
std::atomic<std::uint64_t> num_attempted_inserts{0};
thread_runner(values2, [&x, &num_inserts, &num_attempted_inserts](boost::span<raii_convertible> s) {
num_inserts += x.insert(s.begin(), s.begin() + s.size() / 2);
num_inserts += x.insert(s.begin(), s.end());
num_attempted_inserts += s.size() + s.size() / 2;
}); });
BOOST_TEST_EQ(x.size(), sz + num_inserts);
BOOST_TEST_EQ( BOOST_TEST_EQ(
raii::default_constructor, value_type_cardinality * values2.size()); raii::default_constructor, value_type_cardinality * num_attempted_inserts);
#if BOOST_WORKAROUND(BOOST_GCC_VERSION, >= 50300) && \ #if BOOST_WORKAROUND(BOOST_GCC_VERSION, >= 50300) && \
BOOST_WORKAROUND(BOOST_GCC_VERSION, < 50500) BOOST_WORKAROUND(BOOST_GCC_VERSION, < 50500)
// some versions of old gcc have trouble eliding copies here // some versions of old gcc have trouble eliding copies here
@@ -169,6 +175,39 @@ namespace {
} }
} iterator_range_inserter; } iterator_range_inserter;
#if !defined(BOOST_UNORDERED_NO_RANGES)
struct range_inserter_type
{
template <class T, class X> void operator()(std::vector<T>& values, X& x)
{
static constexpr auto value_type_cardinality =
value_cardinality<typename X::value_type>::value;
std::vector<raii_convertible> values2;
values2.reserve(values.size());
for (auto const& v : values) {
values2.push_back(raii_convertible(v));
}
auto sz = x.size();
std::atomic<std::uint64_t> num_inserts{0};
std::atomic<std::uint64_t> num_attempted_inserts{0};
thread_runner(values2, [&x, &num_inserts, &num_attempted_inserts](boost::span<raii_convertible> s) {
num_inserts += x.insert_range(s | std::views::take(s.size() / 2));
num_inserts += x.insert_range(s);
num_attempted_inserts += s.size() + s.size() / 2;
});
BOOST_TEST_EQ(x.size(), sz + num_inserts);
BOOST_TEST_EQ(
raii::default_constructor, value_type_cardinality * num_attempted_inserts);
BOOST_TEST_EQ(raii::copy_constructor, 0u);
BOOST_TEST_EQ(raii::copy_assignment, 0u);
BOOST_TEST_EQ(raii::move_assignment, 0u);
}
} range_inserter;
#endif
struct lvalue_insert_or_assign_copy_assign_type struct lvalue_insert_or_assign_copy_assign_type
{ {
template <class T, class X> void operator()(std::vector<T>& values, X& x) template <class T, class X> void operator()(std::vector<T>& values, X& x)
@@ -792,6 +831,41 @@ namespace {
} }
} iterator_range_insert_or_cvisit; } iterator_range_insert_or_cvisit;
#if !defined(BOOST_UNORDERED_NO_RANGES)
struct insert_range_or_cvisit_type
{
template <class T, class X> void operator()(std::vector<T>& values, X& x)
{
static constexpr auto value_type_cardinality =
value_cardinality<typename X::value_type>::value;
std::vector<raii_convertible> values2;
values2.reserve(values.size());
for (auto const& v : values) {
values2.push_back(raii_convertible(v));
}
std::atomic<std::uint64_t> num_invokes{0};
thread_runner(
values2, [&x, &num_invokes](boost::span<raii_convertible> s) {
BOOST_TEST_EQ(x.insert_range_or_cvisit(s,
[&num_invokes](typename X::value_type const& v) {
(void)v;
++num_invokes;
}),
s.size());
});
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
BOOST_TEST_EQ(
raii::default_constructor, value_type_cardinality * values2.size());
BOOST_TEST_EQ(raii::copy_constructor, 0u);
BOOST_TEST_GT(raii::move_constructor, 0u);
}
} insert_range_or_cvisit;
#endif
struct iterator_range_insert_and_cvisit_type struct iterator_range_insert_and_cvisit_type
{ {
template <class T, class X> void operator()(std::vector<T>& values, X& x) template <class T, class X> void operator()(std::vector<T>& values, X& x)
@@ -846,6 +920,55 @@ namespace {
} }
} iterator_range_insert_and_cvisit; } iterator_range_insert_and_cvisit;
#if !defined(BOOST_UNORDERED_NO_RANGES)
struct insert_range_and_cvisit_type
{
template <class T, class X> void operator()(std::vector<T>& values, X& x)
{
static constexpr auto value_type_cardinality =
value_cardinality<typename X::value_type>::value;
// concurrent_flat_set visit is always const access
using arg_type = typename std::conditional<
std::is_same<typename X::key_type, typename X::value_type>::value,
typename X::value_type const,
typename X::value_type
>::type;
std::vector<raii_convertible> values2;
values2.reserve(values.size());
for (auto const& v : values) {
values2.push_back(raii_convertible(v));
}
std::atomic<std::uint64_t> num_inserts{0};
std::atomic<std::uint64_t> num_invokes{0};
thread_runner(values2,
[&x, &num_inserts, &num_invokes](boost::span<raii_convertible> s) {
BOOST_TEST_EQ(x.insert_range_and_cvisit(
s,
[&num_inserts](arg_type& v) {
(void)v;
++num_inserts;
},
[&num_invokes](typename X::value_type const& v) {
(void)v;
++num_invokes;
}),
s.size());
});
BOOST_TEST_EQ(num_inserts, x.size());
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
BOOST_TEST_EQ(
raii::default_constructor, value_type_cardinality * values2.size());
BOOST_TEST_EQ(raii::copy_constructor, 0u);
BOOST_TEST_GT(raii::move_constructor, 0u);
}
} insert_range_and_cvisit;
#endif
struct iterator_range_insert_or_visit_type struct iterator_range_insert_or_visit_type
{ {
template <class T, class X> void operator()(std::vector<T>& values, X& x) template <class T, class X> void operator()(std::vector<T>& values, X& x)
@@ -893,6 +1016,48 @@ namespace {
} }
} iterator_range_insert_or_visit; } iterator_range_insert_or_visit;
#if !defined(BOOST_UNORDERED_NO_RANGES)
struct insert_range_or_visit_type
{
template <class T, class X> void operator()(std::vector<T>& values, X& x)
{
static constexpr auto value_type_cardinality =
value_cardinality<typename X::value_type>::value;
// concurrent_flat_set visit is always const access
using arg_type = typename std::conditional<
std::is_same<typename X::key_type, typename X::value_type>::value,
typename X::value_type const,
typename X::value_type
>::type;
std::vector<raii_convertible> values2;
values2.reserve(values.size());
for (auto const& v : values) {
values2.push_back(raii_convertible(v));
}
std::atomic<std::uint64_t> num_invokes{0};
thread_runner(
values2, [&x, &num_invokes](boost::span<raii_convertible> s) {
BOOST_TEST_EQ(x.insert_range_or_visit(s,
[&num_invokes](arg_type& v) {
(void)v;
++num_invokes;
}),
s.size());
});
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
BOOST_TEST_EQ(
raii::default_constructor, value_type_cardinality * values2.size());
BOOST_TEST_EQ(raii::copy_constructor, 0u);
BOOST_TEST_GT(raii::move_constructor, 0u);
}
} insert_range_or_visit;
#endif
struct iterator_range_insert_and_visit_type struct iterator_range_insert_and_visit_type
{ {
template <class T, class X> void operator()(std::vector<T>& values, X& x) template <class T, class X> void operator()(std::vector<T>& values, X& x)
@@ -947,6 +1112,55 @@ namespace {
} }
} iterator_range_insert_and_visit; } iterator_range_insert_and_visit;
#if !defined(BOOST_UNORDERED_NO_RANGES)
struct insert_range_and_visit_type
{
template <class T, class X> void operator()(std::vector<T>& values, X& x)
{
static constexpr auto value_type_cardinality =
value_cardinality<typename X::value_type>::value;
// concurrent_flat_set visit is always const access
using arg_type = typename std::conditional<
std::is_same<typename X::key_type, typename X::value_type>::value,
typename X::value_type const,
typename X::value_type
>::type;
std::vector<raii_convertible> values2;
values2.reserve(values.size());
for (auto const& v : values) {
values2.push_back(raii_convertible(v));
}
std::atomic<std::uint64_t> num_inserts{0};
std::atomic<std::uint64_t> num_invokes{0};
thread_runner(values2,
[&x, &num_inserts, &num_invokes](boost::span<raii_convertible> s) {
BOOST_TEST_EQ(x.insert_range_and_visit(
s,
[&num_inserts](arg_type& v) {
(void)v;
++num_inserts;
},
[&num_invokes](typename X::value_type const& v) {
(void)v;
++num_invokes;
}),
s.size());
});
BOOST_TEST_EQ(num_inserts, x.size());
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
BOOST_TEST_EQ(
raii::default_constructor, value_type_cardinality * values2.size());
BOOST_TEST_EQ(raii::copy_constructor, 0u);
BOOST_TEST_GT(raii::move_constructor, 0u);
}
} insert_range_and_visit;
#endif
struct non_copyable_function struct non_copyable_function
{ {
non_copyable_function() = default; non_copyable_function() = default;
@@ -1010,9 +1224,11 @@ namespace {
{ {
X x; X x;
thread_runner(dummy, [&x, &init_list](boost::span<raii>) { std::atomic<std::uint64_t> num_inserts{0};
BOOST_TEST_EQ(x.insert(init_list), init_list.size()); thread_runner(dummy, [&x, &init_list, &num_inserts](boost::span<raii>) {
num_inserts += x.insert(init_list);
}); });
BOOST_TEST_EQ(num_inserts, x.size());
BOOST_TEST_EQ(x.size(), reference_cont.size()); BOOST_TEST_EQ(x.size(), reference_cont.size());
@@ -1257,16 +1473,31 @@ UNORDERED_TEST(
((map_and_init_list)(node_map_and_init_list) ((map_and_init_list)(node_map_and_init_list)
(set_and_init_list)(node_set_and_init_list))) (set_and_init_list)(node_set_and_init_list)))
#if !defined(BOOST_UNORDERED_NO_RANGES)
#define RANGE_INSERTER (range_inserter)
#define INSERT_RANGE_OR_CVISIT (insert_range_or_cvisit)
#define INSERT_RANGE_OR_VISIT (insert_range_or_visit)
#define INSERT_RANGE_AND_CVISIT (insert_range_and_cvisit)
#define INSERT_RANGE_AND_VISIT (insert_range_and_visit)
#else
#define RANGE_INSERTER
#define INSERT_RANGE_OR_CVISIT
#define INSERT_RANGE_OR_VISIT
#define INSERT_RANGE_AND_CVISIT
#define INSERT_RANGE_AND_VISIT
#endif
UNORDERED_TEST( UNORDERED_TEST(
insert, insert,
((map)(fancy_map)(node_map)(fancy_node_map) ((map)(fancy_map)(node_map)(fancy_node_map)
(set)(fancy_set)(node_set)(fancy_node_set)) (set)(fancy_set)(node_set)(fancy_node_set))
((value_type_generator_factory)(init_type_generator_factory)) ((value_type_generator_factory)(init_type_generator_factory))
((lvalue_inserter)(rvalue_inserter)(iterator_range_inserter) ((lvalue_inserter)(rvalue_inserter)(iterator_range_inserter)
(norehash_lvalue_inserter)(norehash_rvalue_inserter) RANGE_INSERTER (norehash_lvalue_inserter)(norehash_rvalue_inserter)
(lvalue_insert_or_cvisit)(lvalue_insert_or_visit) (lvalue_insert_or_cvisit)(lvalue_insert_or_visit)
(rvalue_insert_or_cvisit)(rvalue_insert_or_visit) (rvalue_insert_or_cvisit)(rvalue_insert_or_visit)
(iterator_range_insert_or_cvisit)(iterator_range_insert_or_visit)) (iterator_range_insert_or_cvisit)(iterator_range_insert_or_visit)
INSERT_RANGE_OR_CVISIT INSERT_RANGE_OR_VISIT )
((default_generator)(sequential)(limited_range))) ((default_generator)(sequential)(limited_range)))
UNORDERED_TEST( UNORDERED_TEST(
@@ -1276,7 +1507,8 @@ UNORDERED_TEST(
((value_type_generator_factory)(init_type_generator_factory)) ((value_type_generator_factory)(init_type_generator_factory))
((lvalue_insert_and_cvisit)(lvalue_insert_and_visit) ((lvalue_insert_and_cvisit)(lvalue_insert_and_visit)
(rvalue_insert_and_cvisit)(rvalue_insert_and_visit) (rvalue_insert_and_cvisit)(rvalue_insert_and_visit)
(iterator_range_insert_and_cvisit)(iterator_range_insert_and_visit)) (iterator_range_insert_and_cvisit)(iterator_range_insert_and_visit)
INSERT_RANGE_AND_CVISIT INSERT_RANGE_AND_VISIT )
((default_generator)(sequential)(limited_range))) ((default_generator)(sequential)(limited_range)))
UNORDERED_TEST( UNORDERED_TEST(
-5
View File
@@ -18,14 +18,9 @@ assert
config config
container_hash container_hash
core core
move
mp11 mp11
predef predef
preprocessor
static_assert
throw_exception throw_exception
tuple
type_traits
# Secondary dependencies # Secondary dependencies
+31 -2
View File
@@ -11,6 +11,7 @@
#ifndef BOOST_NO_CXX17_HDR_MEMORY_RESOURCE #ifndef BOOST_NO_CXX17_HDR_MEMORY_RESOURCE
#include <memory_resource> #include <memory_resource>
#include <new>
namespace test { namespace test {
class counted_new_delete_resource : public std::pmr::memory_resource class counted_new_delete_resource : public std::pmr::memory_resource
@@ -25,17 +26,45 @@ namespace test {
void* do_allocate(std::size_t bytes, std::size_t alignment) override void* do_allocate(std::size_t bytes, std::size_t alignment) override
{ {
_count += bytes; _count += bytes;
#if defined(__cpp_aligned_new) && __cpp_aligned_new >= 201606L
return ::operator new(bytes, std::align_val_t(alignment)); return ::operator new(bytes, std::align_val_t(alignment));
#else
return ::operator new(bytes);
(void)alignment;
#endif
} }
void do_deallocate( void do_deallocate(
void* p, std::size_t bytes, std::size_t alignment) override void* p, std::size_t bytes, std::size_t alignment) override
{ {
_count -= bytes; _count -= bytes;
#if __cpp_sized_deallocation
#if defined(__cpp_aligned_new) && __cpp_aligned_new >= 201606L
# if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L
::operator delete(p, bytes, std::align_val_t(alignment)); ::operator delete(p, bytes, std::align_val_t(alignment));
#else
# else
::operator delete(p, std::align_val_t(alignment)); ::operator delete(p, std::align_val_t(alignment));
# endif
#else
# if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L
::operator delete(p, bytes);
# else
::operator delete(p);
(void)alignment;
# endif
#endif #endif
} }
+201
View File
@@ -1,6 +1,7 @@
// Copyright 2006-2010 Daniel James. // Copyright 2006-2010 Daniel James.
// Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 2026 Joaquin M Lopez Munoz
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -14,6 +15,7 @@
#include "../helpers/tracker.hpp" #include "../helpers/tracker.hpp"
#include "../objects/test.hpp" #include "../objects/test.hpp"
#include <list>
#include <vector> #include <vector>
namespace constructor_tests { namespace constructor_tests {
@@ -337,6 +339,205 @@ namespace constructor_tests {
// //
std::vector<value_type> expected(vec.begin(), vec.begin() + 3); std::vector<value_type> expected(vec.begin(), vec.begin() + 3);
#if !defined(BOOST_UNORDERED_NO_RANGES)
auto std_list = std::list{vec[0], vec[1], vec[2]};
auto sentineled_rg = std_list | std::views::take(3);
UNORDERED_SUB_TEST("Range construct 1")
{
test::check_instances check_;
{
T x(boost::unordered::from_range, list);
BOOST_TEST(x.empty());
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
}
{
T x(boost::unordered::from_range, std::vector{vec[0], vec[1], vec[2]});
BOOST_TEST_NOT(x.empty());
BOOST_TEST_GT(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));
test::check_container(x, expected);
}
}
UNORDERED_SUB_TEST("Range construct 2")
{
test::check_instances check_;
{
T x(boost::unordered::from_range, list, 1000);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 1000);
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
}
{
T x(boost::unordered::from_range, sentineled_rg, 1000);
BOOST_TEST_NOT(x.empty());
BOOST_TEST(x.bucket_count() >= 1000);
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_container(x, expected);
}
}
UNORDERED_SUB_TEST("Range construct 3")
{
{
test::check_instances check_;
T x(boost::unordered::from_range, list, 10, hf1);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 10);
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
}
{
test::check_instances check_;
T x(
boost::unordered::from_range, std::vector{vec[0], vec[1], vec[2]},
10, hf1);
BOOST_TEST_NOT(x.empty());
BOOST_TEST(x.bucket_count() >= 10);
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_container(x, expected);
}
}
UNORDERED_SUB_TEST("Range construct 4")
{
{
test::check_instances check_;
T x(boost::unordered::from_range, list, 10, hf1, eq1);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 10);
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
}
{
test::check_instances check_;
T x(boost::unordered::from_range, sentineled_rg, 10, hf1, eq1);
BOOST_TEST_NOT(x.empty());
BOOST_TEST(x.bucket_count() >= 10);
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_container(x, expected);
}
}
UNORDERED_SUB_TEST("Range construct 5")
{
{
test::check_instances check_;
T x(boost::unordered::from_range, list, 10, hf1, eq1, al1);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 10);
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
}
{
test::check_instances check_;
T x(
boost::unordered::from_range,
std::vector{vec[0], vec[1], vec[2]}, 10, hf1, eq1, al1);
BOOST_TEST_NOT(x.empty());
BOOST_TEST(x.bucket_count() >= 10);
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
test::check_container(x, expected);
}
}
UNORDERED_SUB_TEST("Range construct 6")
{
{
test::check_instances check_;
T x(boost::unordered::from_range, list, 10, al1);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 10);
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
}
{
test::check_instances check_;
T x(boost::unordered::from_range, sentineled_rg, 10, al1);
BOOST_TEST_NOT(x.empty());
BOOST_TEST(x.bucket_count() >= 10);
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
test::check_container(x, expected);
}
}
UNORDERED_SUB_TEST("Range construct 7")
{
{
test::check_instances check_;
T x(boost::unordered::from_range, list, 10, hf1, al1);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 10);
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
}
{
test::check_instances check_;
T x(
boost::unordered::from_range,
std::vector{vec[0], vec[1], vec[2]}, 10, hf1, al1);
BOOST_TEST_NOT(x.empty());
BOOST_TEST(x.bucket_count() >= 10);
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
test::check_container(x, expected);
}
}
UNORDERED_SUB_TEST("Range construct 8")
{
test::check_instances check_;
{
T x(boost::unordered::from_range, list, al1);
BOOST_TEST(x.empty());
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
}
{
T x(boost::unordered::from_range, sentineled_rg, al1);
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
test::check_container(x, expected);
}
}
#endif
UNORDERED_SUB_TEST("Initializer list construct 1") UNORDERED_SUB_TEST("Initializer list construct 1")
{ {
test::check_instances check_; test::check_instances check_;
@@ -0,0 +1,46 @@
// Copyright 2026 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if !defined(BOOST_UNORDERED_FOA_TESTS)
#error "This test is only for the FOA-style conatiners"
#endif
#include <boost/static_assert.hpp>
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/unordered/unordered_flat_set.hpp>
#include <boost/unordered/unordered_node_map.hpp>
#include <boost/unordered/unordered_node_set.hpp>
// Don't include the CFOA headers here!
using flat_map = boost::unordered::unordered_flat_map<int, int>;
using flat_set = boost::unordered::unordered_flat_set<int>;
using node_map = boost::unordered::unordered_node_map<int, int>;
using node_set = boost::unordered::unordered_node_set<int>;
struct constrained_template_converter
{
struct dummy
{
};
template <class T, typename std::enable_if<
std::is_constructible<T, dummy>::value, int>::type = 0>
operator T() const
{
return T{};
}
};
// Check whether the corresponding CFOA container gets instantiated.
// The CFOA headers aren't included, so this would fail to compile if the CFOA
// container was instantiated.
BOOST_STATIC_ASSERT(
(!std::is_constructible<flat_map, constrained_template_converter>::value));
BOOST_STATIC_ASSERT(
(!std::is_constructible<flat_set, constrained_template_converter>::value));
BOOST_STATIC_ASSERT(
(!std::is_constructible<node_map, constrained_template_converter>::value));
BOOST_STATIC_ASSERT(
(!std::is_constructible<node_set, constrained_template_converter>::value));
int main() { return 0; }
+197 -5
View File
@@ -1,19 +1,26 @@
// Copyright 2017-2018 Daniel James. // Copyright 2017-2018 Daniel James.
// Copyright 2026 Joaquin M Lopez Munoz.
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_map.hpp>
#include <iostream>
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
#include <boost/core/lightweight_test_trait.hpp> #include <boost/core/lightweight_test_trait.hpp>
#include <boost/unordered_map.hpp> #include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp> #include <boost/unordered_set.hpp>
#include <iostream>
#include <vector>
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
#include <boost/unordered/unordered_flat_map.hpp> #include <boost/unordered/unordered_flat_map.hpp>
#include <boost/unordered/unordered_flat_set.hpp> #include <boost/unordered/unordered_flat_set.hpp>
#include <boost/unordered/unordered_node_map.hpp>
#include <boost/unordered/unordered_node_set.hpp>
#include <boost/unordered/concurrent_flat_map.hpp> #include <boost/unordered/concurrent_flat_map.hpp>
#include <boost/unordered/concurrent_flat_set.hpp>
#include <boost/unordered/concurrent_node_map.hpp>
#include <boost/unordered/concurrent_node_set.hpp>
#include <vector>
struct hash_equals struct hash_equals
{ {
@@ -87,6 +94,44 @@ template <template <class...> class UnorderedMap> void map_tests()
test_allocator<std::pair<const int, int> > >); test_allocator<std::pair<const int, int> > >);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
/*
template<ranges::input_range R, class Hash = hash<range-key-type<R>>,
class Pred = equal_to<range-key-type<R>>,
class Allocator = allocator<range-to-alloc-type<R>>>
unordered_map(from_range_t, R&&,
typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_map<
range-key-type<R>, range-mapped-type<R>, Hash, Pred, Allocator>;
*/
{
UnorderedMap m(boost::unordered::from_range, x);
BOOST_TEST_TRAIT_SAME(decltype(m), UnorderedMap<int, int>);
}
{
UnorderedMap m(boost::unordered::from_range, x, 0, std::hash<int>());
BOOST_TEST_TRAIT_SAME(decltype(m), UnorderedMap<int, int, std::hash<int> >);
}
{
UnorderedMap m(
boost::unordered::from_range, x, 0, std::hash<int>(), std::equal_to<int>());
BOOST_TEST_TRAIT_SAME(
decltype(m), UnorderedMap<int, int, std::hash<int>, std::equal_to<int> >);
}
{
UnorderedMap m(boost::unordered::from_range, x, 0, std::hash<int>(),
std::equal_to<int>(), pair_allocator);
BOOST_TEST_TRAIT_SAME(
decltype(m), UnorderedMap<int, int, std::hash<int>, std::equal_to<int>,
test_allocator<std::pair<const int, int> > >);
}
#endif
/* /*
template<class Key, class T, class Hash = hash<Key>, template<class Key, class T, class Hash = hash<Key>,
class Pred = equal_to<Key>, class Allocator = allocator<pair<const class Pred = equal_to<Key>, class Allocator = allocator<pair<const
@@ -162,6 +207,24 @@ template <template <class...> class UnorderedMap> void map_tests()
test_allocator<std::pair<const int, int> > >); test_allocator<std::pair<const int, int> > >);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
/*
template<ranges::input_range R, class Allocator>
unordered_map(
from_range_t, R&&, typename see below::size_type, Allocator)
-> unordered_map<
range-key-type<R>, range-mapped-type<R>, hash<range-key-type<R>>,
equal_to<range-key-type<R>>, Allocator>;
*/
{
UnorderedMap m(boost::unordered::from_range, x, 0u, pair_allocator);
BOOST_TEST_TRAIT_SAME(
decltype(m), UnorderedMap<int, int, boost::hash<int>, std::equal_to<int>,
test_allocator<std::pair<const int, int> > >);
}
#endif
/* /*
template<class InputIterator, class Allocator> template<class InputIterator, class Allocator>
unordered_map(InputIterator, InputIterator, Allocator) unordered_map(InputIterator, InputIterator, Allocator)
@@ -178,6 +241,23 @@ template <template <class...> class UnorderedMap> void map_tests()
test_allocator<std::pair<const int, int> > >); test_allocator<std::pair<const int, int> > >);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
/*
template<ranges::input_range R, class Allocator>
unordered_map(from_range_t, R&&, Allocator)
-> unordered_map<
range-key-type<R>, range-mapped-type<R>, hash<range-key-type<R>>,
equal_to<range-key-type<R>>, Allocator>;
*/
{
UnorderedMap m(boost::unordered::from_range, x, pair_allocator);
BOOST_TEST_TRAIT_SAME(
decltype(m), UnorderedMap<int, int, boost::hash<int>, std::equal_to<int>,
test_allocator<std::pair<const int, int> > >);
}
#endif
/* /*
template<class InputIterator, class Hash, class Allocator> template<class InputIterator, class Hash, class Allocator>
unordered_map(InputIterator, InputIterator, typename see below::size_type, unordered_map(InputIterator, InputIterator, typename see below::size_type,
@@ -194,6 +274,23 @@ template <template <class...> class UnorderedMap> void map_tests()
test_allocator<std::pair<const int, int> > >); test_allocator<std::pair<const int, int> > >);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
/*
template<ranges::input_range R, class Hash, class Allocator>
unordered_map(
from_range_t, R&&, typename see below::size_type, Hash, Allocator)
-> unordered_map<range-key-type<R>, range-mapped-type<R>, Hash,
equal_to<range-key-type<R>>, Allocator>;
*/
{
UnorderedMap m(boost::unordered::from_range, x, 0u, f, pair_allocator);
BOOST_TEST_TRAIT_SAME(
decltype(m), UnorderedMap<int, int, hash_equals, std::equal_to<int>,
test_allocator<std::pair<const int, int> > >);
}
#endif
/* /*
template<class Key, class T, typename Allocator> template<class Key, class T, typename Allocator>
unordered_map(initializer_list<pair<const Key, T>>, typename see unordered_map(initializer_list<pair<const Key, T>>, typename see
@@ -305,6 +402,45 @@ template <template <class...> class UnorderedSet> void set_tests()
test_allocator<int> >); test_allocator<int> >);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
/*
template<ranges::input_range R,
class Hash = hash<ranges::range_value_t<R>>,
class Pred = equal_to<ranges::range_value_t<R>>,
class Allocator = allocator<ranges::range_value_t<R>>>
unordered_set(from_range_t, R&&,
typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_set<ranges::range_value_t<R>, Hash, Pred, Allocator>;
*/
{
UnorderedSet s(boost::unordered::from_range, y);
BOOST_TEST_TRAIT_SAME(decltype(s), UnorderedSet<int>);
}
{
UnorderedSet s(boost::unordered::from_range, y, 0, std::hash<int>());
BOOST_TEST_TRAIT_SAME(decltype(s), UnorderedSet<int, std::hash<int> >);
}
{
UnorderedSet s(
boost::unordered::from_range, y, 0, std::hash<int>(),
std::equal_to<int>());
BOOST_TEST_TRAIT_SAME(
decltype(s), UnorderedSet<int, std::hash<int>, std::equal_to<int> >);
}
{
UnorderedSet s(boost::unordered::from_range, y, 0, std::hash<int>(),
std::equal_to<int>(), int_allocator);
BOOST_TEST_TRAIT_SAME(
decltype(s), UnorderedSet<int, std::hash<int>, std::equal_to<int>,
test_allocator<int> >);
}
#endif
/* template<class T, /* template<class T,
class Hash = std::hash<T>, class Hash = std::hash<T>,
class Pred = std::equal_to<T>, class Pred = std::equal_to<T>,
@@ -358,6 +494,24 @@ template <template <class...> class UnorderedSet> void set_tests()
test_allocator<int> >); test_allocator<int> >);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
/*
template<ranges::input_range R, class Allocator>
unordered_set(from_range_t, R&&,
typename see below::size_type, Allocator)
-> unordered_set<ranges::range_value_t<R>,
hash<ranges::range_value_t<R>>,
equal_to<ranges::range_value_t<R>>, Allocator>;
*/
{
UnorderedSet s(boost::unordered::from_range, y, 0u, int_allocator);
BOOST_TEST_TRAIT_SAME(
decltype(s), UnorderedSet<int, boost::hash<int>, std::equal_to<int>,
test_allocator<int> >);
}
#endif
/* template<class InputIt, class Hash, class Alloc> /* template<class InputIt, class Hash, class Alloc>
unordered_set(InputIt, InputIt, typename see below::size_type, Hash, Alloc) unordered_set(InputIt, InputIt, typename see below::size_type, Hash, Alloc)
-> unordered_set<typename std::iterator_traits<InputIt>::value_type, Hash, -> unordered_set<typename std::iterator_traits<InputIt>::value_type, Hash,
@@ -370,6 +524,22 @@ template <template <class...> class UnorderedSet> void set_tests()
UnorderedSet<int, hash_equals, std::equal_to<int>, test_allocator<int> >); UnorderedSet<int, hash_equals, std::equal_to<int>, test_allocator<int> >);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
/*
template<ranges::input_range R, class Hash, class Allocator>
unordered_set(from_range_t, R&&, typename see below::size_type,
Hash, Allocator)
-> unordered_set<ranges::range_value_t<R>, Hash,
equal_to<ranges::range_value_t<R>>, Allocator>;
*/
{
UnorderedSet s(boost::unordered::from_range, y, 0u, f, int_allocator);
BOOST_TEST_TRAIT_SAME(decltype(s),
UnorderedSet<int, hash_equals, std::equal_to<int>, test_allocator<int> >);
}
#endif
/* template<class T, class Allocator> /* template<class T, class Allocator>
unordered_set(std::initializer_list<T>, typename see below::size_type, unordered_set(std::initializer_list<T>, typename see below::size_type,
Allocator) Allocator)
@@ -408,6 +578,23 @@ template <template <class...> class UnorderedSet> void set_tests()
test_allocator<int> >); test_allocator<int> >);
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
/*
template<ranges::input_range R, class Allocator>
unordered_set(from_range_t, R&&, Allocator)
-> unordered_set<ranges::range_value_t<R>,
hash<ranges::range_value_t<R>>,
equal_to<ranges::range_value_t<R>>, Allocator>;
*/
{
UnorderedSet s(boost::unordered::from_range, y, int_allocator);
BOOST_TEST_TRAIT_SAME(
decltype(s), UnorderedSet<int, boost::hash<int>, std::equal_to<int>,
test_allocator<int> >);
}
#endif
/* /*
template<class T, class Allocator> template<class T, class Allocator>
unordered_set(initializer_list<T>, Allocator) unordered_set(initializer_list<T>, Allocator)
@@ -433,10 +620,15 @@ int main()
map_tests<boost::unordered_map>(); map_tests<boost::unordered_map>();
map_tests<boost::unordered_multimap>(); map_tests<boost::unordered_multimap>();
map_tests<boost::unordered_flat_map>(); map_tests<boost::unordered_flat_map>();
map_tests<boost::unordered_node_map>();
map_tests<boost::concurrent_flat_map>(); map_tests<boost::concurrent_flat_map>();
map_tests<boost::concurrent_node_map>();
set_tests<boost::unordered_set>(); set_tests<boost::unordered_set>();
set_tests<boost::unordered_multiset>(); set_tests<boost::unordered_multiset>();
set_tests<boost::unordered_flat_set>(); set_tests<boost::unordered_flat_set>();
set_tests<boost::unordered_node_set>();
set_tests<boost::concurrent_flat_set>();
set_tests<boost::concurrent_node_set>();
return boost::report_errors(); return boost::report_errors();
#endif #endif
+114 -23
View File
@@ -1,17 +1,28 @@
// Copyright 2009 Daniel James. // Copyright 2009 Daniel James.
// Copyright 2022-2023 Christian Mazakas. // Copyright 2022-2023 Christian Mazakas.
// Copyright 2025 Joaquin M Lopez Munoz
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/unordered.hpp" #include "../helpers/unordered.hpp"
#ifdef BOOST_UNORDERED_CFOA_TESTS
#include <boost/unordered/concurrent_flat_set.hpp>
#include <boost/unordered/concurrent_flat_map.hpp>
#include <boost/unordered/concurrent_node_map.hpp>
#include <boost/unordered/concurrent_node_set.hpp>
#endif
#include <utility> #include <utility>
namespace x { namespace x {
struct D struct D
{ {
#ifdef BOOST_UNORDERED_FOA_TESTS #if defined(BOOST_UNORDERED_CFOA_TESTS)
boost::concurrent_flat_map<D, D> x;
boost::concurrent_node_map<D, D> y;
#elif defined(BOOST_UNORDERED_FOA_TESTS)
boost::unordered_flat_map<D, D> x; boost::unordered_flat_map<D, D> x;
boost::unordered_node_map<D, D> y; boost::unordered_node_map<D, D> y;
#else #else
@@ -30,26 +41,36 @@ namespace incomplete_test {
// Declare some instances // Declare some instances
#ifdef BOOST_UNORDERED_FOA_TESTS #if defined(BOOST_UNORDERED_CFOA_TESTS)
typedef boost::concurrent_flat_map<value, value, hash, equals,
allocator<std::pair<value const, value> > >
map1;
typedef boost::concurrent_flat_set<value, hash, equals, allocator<value> > set1;
typedef boost::concurrent_node_map<value, value, hash, equals,
allocator<std::pair<value const, value> > >
map2;
typedef boost::concurrent_node_set<value, hash, equals, allocator<value> >
set2;
#elif defined(BOOST_UNORDERED_FOA_TESTS)
typedef boost::unordered_flat_map<value, value, hash, equals, typedef boost::unordered_flat_map<value, value, hash, equals,
allocator<std::pair<value const, value> > > allocator<std::pair<value const, value> > >
map; map1;
typedef boost::unordered_flat_set<value, hash, equals, allocator<value> > set; typedef boost::unordered_flat_set<value, hash, equals, allocator<value> > set1;
typedef boost::unordered_node_map<value, value, hash, equals, typedef boost::unordered_node_map<value, value, hash, equals,
allocator<std::pair<value const, value> > > allocator<std::pair<value const, value> > >
multimap; map2;
typedef boost::unordered_node_set<value, hash, equals, allocator<value> > typedef boost::unordered_node_set<value, hash, equals, allocator<value> >
multiset; set2;
#else #else
typedef boost::unordered_map<value, value, hash, equals, typedef boost::unordered_map<value, value, hash, equals,
allocator<std::pair<value const, value> > > allocator<std::pair<value const, value> > >
map; map1;
typedef boost::unordered_multimap<value, value, hash, equals, typedef boost::unordered_multimap<value, value, hash, equals,
allocator<std::pair<value const, value> > > allocator<std::pair<value const, value> > >
multimap; map2;
typedef boost::unordered_set<value, hash, equals, allocator<value> > set; typedef boost::unordered_set<value, hash, equals, allocator<value> > set1;
typedef boost::unordered_multiset<value, hash, equals, allocator<value> > typedef boost::unordered_multiset<value, hash, equals, allocator<value> >
multiset; set2;
#endif #endif
// Now define the types which are stored as members, as they are needed for // Now define the types which are stored as members, as they are needed for
@@ -132,24 +153,60 @@ namespace incomplete_test {
boost::unordered_multiset<struct4, hash, equals, allocator<struct4> > x; boost::unordered_multiset<struct4, hash, equals, allocator<struct4> > x;
}; };
#endif #endif
// Now define the value type.
struct value
{
};
// Create some instances. // Create some instances.
incomplete_test::map m1; incomplete_test::map1 m1;
incomplete_test::multimap m2; #ifndef BOOST_UNORDERED_CFOA_TESTS
incomplete_test::set s1; incomplete_test::map1::iterator itm1;
incomplete_test::multiset s2; incomplete_test::map1::const_iterator citm1;
#ifndef BOOST_UNORDERED_FOA_TESTS
incomplete_test::map1::local_iterator litm1;
incomplete_test::map1::const_local_iterator clitm1;
#endif
#endif
incomplete_test::map2 m2;
#ifndef BOOST_UNORDERED_CFOA_TESTS
incomplete_test::map2::iterator itm2;
incomplete_test::map2::const_iterator citm2;
#ifndef BOOST_UNORDERED_FOA_TESTS
incomplete_test::map2::local_iterator litm2;
incomplete_test::map2::const_local_iterator clitm2;
#endif
#endif
incomplete_test::set1 s1;
#ifndef BOOST_UNORDERED_CFOA_TESTS
incomplete_test::set1::iterator its1;
incomplete_test::set1::const_iterator cits1;
#ifndef BOOST_UNORDERED_FOA_TESTS
incomplete_test::set1::local_iterator lits1;
incomplete_test::set1::const_local_iterator clits1;
#endif
#endif
incomplete_test::set2 s2;
#ifndef BOOST_UNORDERED_CFOA_TESTS
incomplete_test::set2::iterator its2;
incomplete_test::set2::const_iterator cits2;
#ifndef BOOST_UNORDERED_FOA_TESTS
incomplete_test::set2::local_iterator lits2;
incomplete_test::set2::const_local_iterator clits2;
#endif
#endif
incomplete_test::struct1 c1; incomplete_test::struct1 c1;
incomplete_test::struct2 c2; incomplete_test::struct2 c2;
incomplete_test::struct3 c3; incomplete_test::struct3 c3;
incomplete_test::struct4 c4; incomplete_test::struct4 c4;
// Now define the value type.
struct value
{
};
// Now declare, but don't define, the operators required for comparing // Now declare, but don't define, the operators required for comparing
// elements. // elements.
@@ -171,11 +228,45 @@ namespace incomplete_test {
void use_types() void use_types()
{ {
incomplete_test::value x; incomplete_test::value x;
m1[x] = x; m1.insert(std::make_pair(x, x));
m2.insert(std::make_pair(x, x)); #ifndef BOOST_UNORDERED_CFOA_TESTS
s1.insert(x); itm1 = m1.begin();
s2.insert(x); citm1 = m1.cbegin();
#ifndef BOOST_UNORDERED_FOA_TESTS
litm1 = m1.begin(0);
clitm1 = m1.cbegin(0);
#endif
#endif
m2.insert(std::make_pair(x, x));
#ifndef BOOST_UNORDERED_CFOA_TESTS
itm2 = m2.begin();
citm2 = m2.cbegin();
#ifndef BOOST_UNORDERED_FOA_TESTS
litm2 = m2.begin(0);
clitm2 = m2.cbegin(0);
#endif
#endif
s1.insert(x);
#ifndef BOOST_UNORDERED_CFOA_TESTS
its1 = s1.begin();
cits1 = s1.cbegin();
#ifndef BOOST_UNORDERED_FOA_TESTS
lits1 = s1.begin(0);
clits1 = s1.cbegin(0);
#endif
#endif
s2.insert(x);
#ifndef BOOST_UNORDERED_CFOA_TESTS
its2 = s2.begin();
cits2 = s2.cbegin();
#ifndef BOOST_UNORDERED_FOA_TESTS
lits2 = s2.begin(0);
clits2 = s2.cbegin(0);
#endif
#endif
c1.x.insert(std::make_pair(c1, c1)); c1.x.insert(std::make_pair(c1, c1));
c2.x.insert(std::make_pair(c2, c2)); c2.x.insert(std::make_pair(c2, c2));
c3.x.insert(c3); c3.x.insert(c3);
+22
View File
@@ -1,6 +1,7 @@
// Copyright 2006-2010 Daniel James. // Copyright 2006-2010 Daniel James.
// Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 2026 Joaquin M Lopez Munoz
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -405,6 +406,27 @@ namespace insert_tests {
test::check_equivalent_keys(x); test::check_equivalent_keys(x);
} }
} }
#if !defined(BOOST_UNORDERED_NO_RANGES)
UNORDERED_SUB_TEST("insert_range tests")
{
test::check_instances check_;
X x;
test::random_values<X> v(1000, generator);
x.insert_range(v);
test::check_container(x, v);
test::check_equivalent_keys(x);
x.clear();
x.insert_range(v | std::views::take(v.size()));
test::check_container(x, v);
test::check_equivalent_keys(x);
}
#endif
} }
template <class X> template <class X>
+99
View File
@@ -1,6 +1,7 @@
// Copyright 2006-2009 Daniel James. // Copyright 2006-2009 Daniel James.
// Copyright 2022-2023 Christian Mazakas. // Copyright 2022-2023 Christian Mazakas.
// Copyright 2026 Joaquin M Lopez Munoz.
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -587,6 +588,102 @@ namespace rehash_tests {
} }
} }
// White-box tests for https://github.com/boostorg/unordered/pull/348
struct failing_allocator_exception { std::size_t n; };
template<typename T>
struct failing_allocator
{
using value_type = T;
failing_allocator() = default;
template<typename U> failing_allocator(const failing_allocator<U>&) {}
T* allocate(std::size_t n) { throw failing_allocator_exception{n}; }
void deallocate(T*, std::size_t) { }
bool operator==(const failing_allocator&) const { return true; }
bool operator!=(const failing_allocator&) const { return false; }
};
using test_gh348_table = typename boost::unordered::detail::set<
failing_allocator<int>, int, boost::hash<int>, std::equal_to<int>>::table;
static std::size_t test_gh348_table_bucket_count = 0;
} // namespace rehash_tests
namespace boost {
namespace unordered {
namespace detail {
template<>
auto ::rehash_tests::test_gh348_table::bucket_count() const ->
::rehash_tests::test_gh348_table::size_type
{
return ::rehash_tests::test_gh348_table_bucket_count;
}
} // namespace detail
} // namespace unordered
} // namespace boost
namespace rehash_tests {
void test_gh348_1(int /* dummy for UNORDERED_TEST */)
{
using primes = boost::unordered::detail::prime_fmod_size<>;
const auto size_t_max = (std::numeric_limits<std::size_t>::max)();
for(double mlf = 0.1; mlf < 10.0; mlf += 0.1) {
for(std::size_t i = 0; i < primes::sizes_len; ++i) {
test_gh348_table t;
t.mlf_ = (float)mlf;
test_gh348_table_bucket_count = 0;
auto bc = primes::sizes[i];
std::size_t n = boost::unordered::detail::double_to_size(
0.9 * static_cast<double>(t.mlf_) * static_cast<double>(bc));
if(n == size_t_max) continue;
try {
t.reserve(n);
}
catch(const failing_allocator_exception& e) {
test_gh348_table_bucket_count = e.n;
BOOST_TEST_LE(bc, test_gh348_table_bucket_count);
}
t.max_load_ = boost::unordered::detail::double_to_size(
static_cast<double>(t.mlf_) *
static_cast<double>(test_gh348_table_bucket_count));
if(t.max_load_ == size_t_max) continue;
try {
t.reserve_for_insert(t.max_load_ + 1);
}
catch(const failing_allocator_exception& e) {
if(i == primes::sizes_len - 1) {
BOOST_TEST_EQ(test_gh348_table_bucket_count, e.n);
}
else{
BOOST_TEST_LT(test_gh348_table_bucket_count, e.n);
}
}
}
}
}
void test_gh348_2(int /* dummy for UNORDERED_TEST */)
{
for(double mlf = 0.1; mlf < 2.0; mlf += 0.1) {
test_gh348_table t;
t.mlf_ = (float)mlf;
try {
t.reserve((std::numeric_limits<std::size_t>::max)());
}
catch(const failing_allocator_exception& e) {
BOOST_TEST_GT(e.n, 1000u);
}
}
}
using test::default_generator; using test::default_generator;
using test::generate_collisions; using test::generate_collisions;
using test::limited_range; using test::limited_range;
@@ -739,6 +836,8 @@ namespace rehash_tests {
(test_multiset_ptr)(int_multimap_ptr) (test_multiset_ptr)(int_multimap_ptr)
(test_multiset_tracking)(test_multimap_tracking))( (test_multiset_tracking)(test_multimap_tracking))(
(default_generator)(generate_collisions)(limited_range))) (default_generator)(generate_collisions)(limited_range)))
UNORDERED_TEST(test_gh348_1, ((0)))
UNORDERED_TEST(test_gh348_2, ((0)))
// clang-format on // clang-format on
#endif #endif
} // namespace rehash_tests } // namespace rehash_tests
+5 -5
View File
@@ -1205,7 +1205,7 @@ template <class UnorderedMap> void test_map_non_transparent_erase(UnorderedMap*)
BOOST_TEST_EQ(key::count_, key_count); BOOST_TEST_EQ(key::count_, key_count);
} }
#if BOOST_UNORDERED_FOA_TESTS #ifdef BOOST_UNORDERED_FOA_TESTS
typedef boost::unordered_flat_set<int, transparent_hasher, typedef boost::unordered_flat_set<int, transparent_hasher,
transparent_key_equal> transparent_key_equal>
transparent_unordered_set; transparent_unordered_set;
@@ -1689,14 +1689,14 @@ template <class UnorderedMap> void test_map_transparent_at(UnorderedMap*)
map.at(0) = 7331; map.at(0) = 7331;
BOOST_TEST_EQ(key::count_, key_count); BOOST_TEST_EQ(key::count_, key_count);
BOOST_TEST_THROWS(map.at(4), std::out_of_range) BOOST_TEST_THROWS(map.at(4), std::out_of_range);
BOOST_TEST_EQ(key::count_, key_count); BOOST_TEST_EQ(key::count_, key_count);
UnorderedMap const& m = map; UnorderedMap const& m = map;
BOOST_TEST_EQ(m.at(0), 7331); BOOST_TEST_EQ(m.at(0), 7331);
BOOST_TEST_EQ(key::count_, key_count); BOOST_TEST_EQ(key::count_, key_count);
BOOST_TEST_THROWS(m.at(4), std::out_of_range) BOOST_TEST_THROWS(m.at(4), std::out_of_range);
BOOST_TEST_EQ(key::count_, key_count); BOOST_TEST_EQ(key::count_, key_count);
} }
@@ -1719,7 +1719,7 @@ template <class UnorderedMap> void test_map_non_transparent_at(UnorderedMap*)
BOOST_TEST_EQ(key::count_, key_count + 1); BOOST_TEST_EQ(key::count_, key_count + 1);
key_count = key::count_; key_count = key::count_;
BOOST_TEST_THROWS(map.at(4), std::out_of_range) BOOST_TEST_THROWS(map.at(4), std::out_of_range);
BOOST_TEST_EQ(key::count_, key_count + 1); BOOST_TEST_EQ(key::count_, key_count + 1);
key_count = key::count_; key_count = key::count_;
@@ -1728,7 +1728,7 @@ template <class UnorderedMap> void test_map_non_transparent_at(UnorderedMap*)
BOOST_TEST_EQ(key::count_, key_count + 1); BOOST_TEST_EQ(key::count_, key_count + 1);
key_count = key::count_; key_count = key::count_;
BOOST_TEST_THROWS(m.at(4), std::out_of_range) BOOST_TEST_THROWS(m.at(4), std::out_of_range);
BOOST_TEST_EQ(key::count_, key_count + 1); BOOST_TEST_EQ(key::count_, key_count + 1);
} }