Compare commits

...

27 Commits

Author SHA1 Message Date
joaquintides 636164f135 updated release notes 2026-06-17 17:00:28 +02:00
joaquintides 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
joaquintides 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
kraldan 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
joaquintides 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
joaquintides 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
joaquintides 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
joaquintides 846ea5a38c typos (closes #349) 2026-05-22 20:31:55 +02:00
joaquintides 669918498c run npm audit fix (#346) 2026-04-08 16:54:24 +02:00
Braden Ganetsky 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
joaquintides 4fd90dc706 fixed https://nvd.nist.gov/vuln/detail/CVE-2026-27903 (#345) 2026-03-06 10:35:06 +01:00
joaquintides 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 Ganetsky 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 Dimov 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
joaquintides 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
joaquintides 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 Darwin c09d52fe84 Docs: download extension (#332) 2026-01-04 11:18:49 +01:00
joaquintides af47772876 simplified doc/Jamfile.v2 (#336) 2026-01-03 16:50:37 +01:00
Peter Dimov 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
joaquintides c5cd88e2a8 solved https://www.cve.org/CVERecord?id=CVE-2025-64718 (#335) 2026-01-01 19:50:07 +01: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
61 changed files with 5497 additions and 236 deletions
+6 -8
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" }
@@ -145,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
@@ -350,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]
@@ -386,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()
+14 -43
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
+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==
+32 -21
View File
@@ -4,6 +4,10 @@
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "doc",
"dependencies": {
"@cppalliance/antora-downloads-extension": "^0.0.2"
},
"devDependencies": { "devDependencies": {
"@antora/cli": ">=3.1.14", "@antora/cli": ">=3.1.14",
"@antora/site-generator": ">=3.1.14", "@antora/site-generator": ">=3.1.14",
@@ -286,6 +290,12 @@
"yarn": ">=1.1.0" "yarn": ">=1.1.0"
} }
}, },
"node_modules/@cppalliance/antora-downloads-extension": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/@cppalliance/antora-downloads-extension/-/antora-downloads-extension-0.0.2.tgz",
"integrity": "sha512-2wXahlvRz9J75ZSfzDeP4XpIZiqIm+w/YjmCWJxFPp6oWgP7e8f6ps7HqdtHNGxnK5mG38OjiCFdHjmHYfgbDA==",
"license": "BSL-1.0"
},
"node_modules/@iarna/toml": { "node_modules/@iarna/toml": {
"version": "2.2.5", "version": "2.2.5",
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
@@ -459,9 +469,9 @@
] ]
}, },
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
"version": "1.1.12", "version": "1.1.13",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
@@ -609,9 +619,9 @@
"dev": true "dev": true
}, },
"node_modules/convict": { "node_modules/convict": {
"version": "6.2.4", "version": "6.2.5",
"resolved": "https://registry.npmjs.org/convict/-/convict-6.2.4.tgz", "resolved": "https://registry.npmjs.org/convict/-/convict-6.2.5.tgz",
"integrity": "sha512-qN60BAwdMVdofckX7AlohVJ2x9UvjTNoKVXCL2LxFk1l7757EJqf1nySdMkPQer0bt8kQ5lQiyZ9/2NvrFBuwQ==", "integrity": "sha512-JtXpxqDqJ8P0UwEHwhxLzCIXQy97vlYBZR222Sbzb1q1Erex9ASrztJ29SyhWFQjod1AeFBaPzEEC8YvtZMIYg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"lodash.clonedeep": "^4.5.0", "lodash.clonedeep": "^4.5.0",
@@ -934,9 +944,9 @@
} }
}, },
"node_modules/handlebars": { "node_modules/handlebars": {
"version": "4.7.8", "version": "4.7.9",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz",
"integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"minimist": "^1.2.5", "minimist": "^1.2.5",
@@ -1164,10 +1174,11 @@
} }
}, },
"node_modules/js-yaml": { "node_modules/js-yaml": {
"version": "4.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"argparse": "^2.0.1" "argparse": "^2.0.1"
}, },
@@ -1225,9 +1236,9 @@
} }
}, },
"node_modules/micromatch/node_modules/picomatch": { "node_modules/micromatch/node_modules/picomatch": {
"version": "2.3.1", "version": "2.3.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=8.6" "node": ">=8.6"
@@ -1270,9 +1281,9 @@
} }
}, },
"node_modules/minimatch": { "node_modules/minimatch": {
"version": "3.1.2", "version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
@@ -1354,9 +1365,9 @@
"dev": true "dev": true
}, },
"node_modules/picomatch": { "node_modules/picomatch": {
"version": "4.0.3", "version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
+3
View File
@@ -3,5 +3,8 @@
"@antora/cli": ">=3.1.14", "@antora/cli": ">=3.1.14",
"@antora/site-generator": ">=3.1.14", "@antora/site-generator": ">=3.1.14",
"antora": ">=3.1.14" "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'
+9 -3
View File
@@ -1,4 +1,4 @@
# Copyright 2024-2025 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
+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)
@@ -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(
+2 -2
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.
@@ -1349,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/detail/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);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@@ -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,8 +1,8 @@
// Copyright 2024-2025 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 2025-08-21T03:09:19 // Generated on 2026-01-24T00:34:53
#ifndef BOOST_UNORDERED_DETAIL_UNORDERED_PRINTERS_HPP #ifndef BOOST_UNORDERED_DETAIL_UNORDERED_PRINTERS_HPP
#define BOOST_UNORDERED_DETAIL_UNORDERED_PRINTERS_HPP #define BOOST_UNORDERED_DETAIL_UNORDERED_PRINTERS_HPP
@@ -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"
+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()
+6 -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
@@ -379,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; }
+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
+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
+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
+1 -1
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;