Compare commits

...

29 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
Peter Dimov 665371e6da Check __cpp_aligned_new in test/helpers/pmr.hpp before using std::align_val_t 2026-01-01 19:25:00 +02:00
Peter Dimov c70208609e Add clang-19, clang-20, macos-26 to ci.yml. Replace macos-13 with macos-latest. 2026-01-01 15:20:55 +02:00
Braden Ganetsky 009bd32c3d Mark natvis file as PUBLIC in CMakeLists.txt, mirroring the CMake in Boost.Assert 2025-12-31 17:46:15 -06:00
62 changed files with 5537 additions and 241 deletions
+15 -11
View File
@@ -60,6 +60,9 @@ jobs:
- { compiler: gcc-12, cxxstd: '11,14,17,20', os: 'ubuntu-22.04', install: 'g++-12' }
- { compiler: gcc-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-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,
compiler: gcc-14, cxxstd: '11', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san1" }
- { 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" }
- { 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" }
- { 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" }
@@ -101,6 +103,10 @@ jobs:
- { compiler: 'clang-17', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-17 libc++-17-dev libc++abi-17-dev' }
- { compiler: 'clang-18', cxxstd: '11,14', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev' }
- { compiler: 'clang-18', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev' }
- { compiler: 'clang-19', cxxstd: '11,14', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-19 libc++-19-dev libc++abi-19-dev' }
- { compiler: 'clang-19', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-19 libc++-19-dev libc++abi-19-dev' }
- { compiler: 'clang-20', cxxstd: '11,14,17', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-20 libc++-20-dev libc++abi-20-dev' }
- { compiler: 'clang-20', cxxstd: '20,23,2c', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-20 libc++-20-dev libc++abi-20-dev' }
# not using libc++ because of https://github.com/llvm/llvm-project/issues/52771
- { name: "clang-18 w/ sanitizers (11,14)", sanitize: yes,
@@ -117,10 +123,12 @@ jobs:
stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev', ccache_key: "tsan" }
# OSX, clang
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-13', sanitize: yes, ccache: no, ccache_key: "san1" }
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-13', thread-sanitize: yes, targets: 'libs/unordered/test//cfoa_tests', ccache: no, ccache_key: "tsan" }
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-latest', sanitize: yes, ccache: no, ccache_key: "san1" }
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-latest', thread-sanitize: yes, targets: 'libs/unordered/test//cfoa_tests', ccache: no, ccache_key: "tsan" }
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-14' }
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-15' }
- { compiler: clang, cxxstd: '11,14,17,20,23,2c', os: 'macos-15' }
- { compiler: clang, cxxstd: '11,14,17,20,23,2c', os: 'macos-26' }
timeout-minutes: 360
# posix (gcc-12 w/ sanitizers is taking longer than 210 minutes
@@ -139,12 +147,7 @@ jobs:
fi
if [ -n "${{matrix.container}}" ] && [ -f "/etc/debian_version" ]; then
apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common
# Need (newer) git, and the older Ubuntu container may require requesting the key manually using port 80
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys E1DD270288B4E6030699E45FA1715D88E1DF1F24
for i in {1..${NET_RETRY_COUNT:-3}}; do sudo -E add-apt-repository -y ppa:git-core/ppa && break || sleep 10; done
apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y g++ python-is-python3 git
apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common git g++
fi
# For jobs not compatible with ccache, use "ccache: no" in the matrix
if [[ "${{ matrix.ccache }}" == "no" ]]; then
@@ -344,7 +347,7 @@ jobs:
fail-fast: false
matrix:
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' }
needs: [runner-selection]
@@ -380,6 +383,7 @@ jobs:
B2_SANITIZE: ${{matrix.sanitize}}
B2_STDLIB: ${{matrix.stdlib}}
B2_VARIANT: ${{matrix.variant}}
B2_CXXFLAGS: ${{ matrix.cxxflags }}
run: ci/github/install.sh
- name: Run tests
+21 -5
View File
@@ -23,12 +23,28 @@ target_link_libraries(boost_unordered
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)
source_group(TREE ${PROJECT_SOURCE_DIR}/include FILES ${boost_unordered_IDEFILES} PREFIX "Header Files")
list(APPEND boost_unordered_IDEFILES extra/boost_unordered.natvis)
target_sources(boost_unordered PRIVATE ${boost_unordered_IDEFILES})
if(NOT CMAKE_VERSION VERSION_LESS 3.19)
# Using target_sources with PRIVATE or PUBLIC on INTERFACE targets requires 3.19
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()
+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 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
{
bash $(>)
}
# this globs after its sources are created
rule delayed-glob ( project name : property-set : sources * )
path-constant DOC_DIR : . ;
.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)
{
# 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) ;
rm -rf $(.node_modules)
}
###############################################################################
alias boostdoc ;
explicit boostdoc ;
alias boostrelease : install ;
explicit boostrelease ;
alias boostrelease : html_ cleanup_node_modules_ ;
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
: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
* 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 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
@@ -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_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);
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,
size_type n = _implementation-defined_
const hasher& hf = hasher(),
@@ -90,6 +96,13 @@ namespace unordered {
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,
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_bucket_count_and_allocator[concurrent_flat_map](std::initializer_list<value_type> il, size_type n,
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](init_type&& obj);
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);
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);
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);
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_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);
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);
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>
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>
@@ -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,
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>,
class Pred = std::equal_to<Key>,
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,
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>
concurrent_flat_map(std::initializer_list<std::pair<Key, T>>, typename xref:#concurrent_flat_map_deduction_guides[__see below__]::size_type,
Allocator)
@@ -444,6 +499,15 @@ Chunk size internally used in xref:concurrent_flat_map_bulk_visit[bulk visit] op
=== 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
```c++
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
[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
```c++
@@ -696,7 +833,7 @@ concurrent_flat_map(std::initializer_list<value_type> il, size_type n, const has
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]
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]
Returns:;; The number of elements in the table.
[horizontal]
Complexity:;; Constant time.
Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect
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
```c++
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
```c++
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>
size_type insert_or_cvisit(InputIterator first, InputIterator last, F f);
size_type insert_or_cvisit(InputIterator first, InputIterator last, F f);
```
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
```c++
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
```c++
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
-----
==== __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
==== 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_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);
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,
size_type n = _implementation-defined_
const hasher& hf = hasher(),
@@ -85,6 +91,13 @@ namespace unordered {
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,
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_bucket_count_and_allocator[concurrent_flat_set](std::initializer_list<value_type> il, size_type n,
const allocator_type& a);
@@ -145,6 +158,8 @@ namespace unordered {
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 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);
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);
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);
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_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);
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);
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>
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>
@@ -236,6 +259,16 @@ namespace unordered {
Hash = Hash(), Pred = Pred(), Allocator = 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>,
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__],
@@ -260,6 +293,27 @@ namespace unordered {
-> 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>;
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>
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>;
@@ -391,6 +445,15 @@ Chunk size internally used in xref:concurrent_flat_set_bulk_visit[bulk visit] op
=== 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
```c++
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
[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
```c++
@@ -643,7 +779,7 @@ concurrent_flat_set(std::initializer_list<value_type> il, size_type n, const has
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]
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]
Returns:;; The number of elements in the table.
[horizontal]
Complexity:;; Constant time.
Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect
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
```c++
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
```c++
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
```c++
template<class F1, class F2>
@@ -1517,6 +1713,16 @@ template<class InputIterator>
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
==== 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_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);
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,
size_type n = _implementation-defined_
const hasher& hf = hasher(),
@@ -93,6 +99,13 @@ namespace unordered {
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,
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_bucket_count_and_allocator[concurrent_node_map](std::initializer_list<value_type> il, size_type n,
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](init_type&& obj);
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);
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);
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);
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_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);
@@ -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);
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);
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>
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>
@@ -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,
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>,
class Pred = std::equal_to<Key>,
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,
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>
concurrent_node_map(std::initializer_list<std::pair<Key, T>>, typename xref:#concurrent_node_map_deduction_guides[__see below__]::size_type,
Allocator)
@@ -496,6 +551,15 @@ Chunk size internally used in xref:concurrent_node_map_bulk_visit[bulk visit] op
=== 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
```c++
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
[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
```c++
@@ -977,8 +1114,7 @@ size_type size() const noexcept;
[horizontal]
Returns:;; The number of elements in the table.
[horizontal]
Complexity:;; Constant time.
Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect
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
```c++
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
```c++
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
```c++
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
-----
==== __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
==== 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_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);
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,
size_type n = _implementation-defined_
const hasher& hf = hasher(),
@@ -88,6 +94,13 @@ namespace unordered {
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,
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_bucket_count_and_allocator[concurrent_node_set](std::initializer_list<value_type> il, size_type n,
const allocator_type& a);
@@ -148,6 +161,8 @@ namespace unordered {
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 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);
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);
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);
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_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);
@@ -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);
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);
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>
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>
@@ -253,6 +276,16 @@ namespace unordered {
Hash = Hash(), Pred = Pred(), Allocator = 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>,
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__],
@@ -277,6 +310,26 @@ namespace unordered {
-> 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>;
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>
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>;
@@ -441,6 +494,15 @@ Chunk size internally used in xref:concurrent_node_set_bulk_visit[bulk visit] op
=== 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
```c++
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
[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
```c++
@@ -916,8 +1051,7 @@ size_type size() const noexcept;
[horizontal]
Returns:;; The number of elements in the table.
[horizontal]
Complexity:;; Constant time.
Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect
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
```c++
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
```c++
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
```c++
template<class F1, class F2>
@@ -1640,6 +1836,16 @@ template<class InputIterator>
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
==== operator==
@@ -19,6 +19,10 @@ namespace unordered {
class Allocator = std::allocator<std::pair<const Key, T>>>
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
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,
@@ -39,7 +43,7 @@ namespace unordered {
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);
// Pmr aliases (C++17 and up)
// Pmr aliases (pass:[C++17] and up)
namespace pmr {
template<class Key,
class T,
@@ -18,6 +18,10 @@ namespace unordered {
class Allocator = std::allocator<Key>>
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
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,
@@ -38,7 +42,7 @@ namespace unordered {
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);
// Pmr aliases (C++17 and up)
// Pmr aliases (pass:[C++17] and up)
namespace pmr {
template<class Key,
class Hash = boost::hash<Key>,
@@ -19,6 +19,10 @@ namespace unordered {
class Allocator = std::allocator<std::pair<const Key, T>>>
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
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,
@@ -39,7 +43,7 @@ namespace unordered {
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);
// Pmr aliases (C++17 and up)
// Pmr aliases (pass:[C++17] and up)
namespace pmr {
template<class Key,
class T,
@@ -18,6 +18,10 @@ namespace unordered {
class Allocator = std::allocator<Key>>
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
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,
@@ -38,7 +42,7 @@ namespace unordered {
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);
// Pmr aliases (C++17 and up)
// Pmr aliases (pass:[C++17] and up)
namespace pmr {
template<class Key,
class Hash = boost::hash<Key>,
@@ -19,6 +19,10 @@ namespace unordered {
class Allocator = std::allocator<std::pair<const Key, T>>>
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
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,
@@ -39,7 +43,7 @@ namespace unordered {
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);
// Pmr aliases (C++17 and up)
// Pmr aliases (pass:[C++17] and up)
namespace pmr {
template<class Key,
class T,
@@ -18,6 +18,10 @@ namespace unordered {
class Allocator = std::allocator<Key>>
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
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,
@@ -38,7 +42,7 @@ namespace unordered {
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);
// Pmr aliases (C++17 and up)
// Pmr aliases (pass:[C++17] and up)
namespace pmr {
template<class Key,
class Hash = boost::hash<Key>,
@@ -20,6 +20,10 @@ namespace unordered {
class Allocator = std::allocator<std::pair<const Key, T>>>
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
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,
@@ -67,7 +71,7 @@ namespace unordered {
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);
// Pmr aliases (C++17 and up)
// Pmr aliases (pass:[C++17] and up)
namespace pmr {
template<class Key,
class T,
@@ -19,6 +19,10 @@ namespace unordered {
class Allocator = std::allocator<std::pair<const Key, T>>>
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
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,
@@ -39,7 +43,7 @@ namespace unordered {
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);
// Pmr aliases (C++17 and up)
// Pmr aliases (pass:[C++17] and up)
namespace pmr {
template<class Key,
class T,
@@ -18,6 +18,10 @@ namespace unordered {
class Allocator = std::allocator<Key>>
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
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,
@@ -38,7 +42,7 @@ namespace unordered {
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);
// Pmr aliases (C++17 and up)
// Pmr aliases (pass:[C++17] and up)
namespace pmr {
template<class Key,
class Hash = boost::hash<Key>,
@@ -19,6 +19,10 @@ namespace unordered {
class Allocator = std::allocator<Key>>
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
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,
@@ -65,7 +69,7 @@ namespace unordered {
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);
// Pmr aliases (C++17 and up)
// Pmr aliases (pass:[C++17] and up)
namespace pmr {
template<class 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_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);
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,
size_type n = _implementation-defined_
const hasher& hf = hasher(),
@@ -94,6 +100,13 @@ namespace unordered {
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,
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_bucket_count_and_allocator[unordered_flat_map](std::initializer_list<value_type> il, size_type n,
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_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<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>);
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,
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>,
class Pred = std::equal_to<Key>,
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,
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>
unordered_flat_map(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type,
Allocator)
@@ -358,6 +405,15 @@ The iterator category is at least a forward iterator.
=== 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
```c++
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
[source,c++,subs="+quotes"]
----
@@ -506,7 +583,7 @@ unordered_flat_map(std::initializer_list<value_type> il,
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]
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
```c++
@@ -729,7 +858,8 @@ size_type size() const noexcept;
```
[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
```c++
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
-----
==== __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
==== 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_.
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.
- 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);
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);
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,
size_type n = _implementation-defined_
const hasher& hf = hasher(),
@@ -88,6 +94,13 @@ namespace unordered {
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,
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_bucket_count_and_allocator[unordered_flat_set](std::initializer_list<value_type> il, size_type n,
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);
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<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>);
_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())
-> 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>,
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__],
@@ -216,6 +241,27 @@ namespace unordered {
-> 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>;
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>
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>;
@@ -307,6 +353,15 @@ The iterator category is at least a forward iterator.
=== 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
```c++
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
[source,c++,subs="+quotes"]
----
@@ -455,7 +531,7 @@ unordered_flat_set(std::initializer_list<value_type> il,
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]
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
```c++
@@ -550,7 +678,7 @@ unordered_flat_set(std::initializer_list<value_type> il, size_type n, const hash
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]
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]
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
```c++
void insert(std::initializer_list<value_type>);
@@ -1193,6 +1338,16 @@ template<class InputIterator>
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
==== operator==
@@ -61,8 +61,14 @@ namespace unordered {
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_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,
size_type n = _implementation-defined_
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
@@ -73,6 +79,13 @@ namespace unordered {
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,
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_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,
@@ -109,6 +122,8 @@ namespace unordered {
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 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>);
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>>>
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())
-> unordered_map<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash, Pred,
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, 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>,
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,
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>
unordered_map(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_map_deduction_guides[__see below__]::size_type,
Allocator)
@@ -397,6 +444,15 @@ with `Iterator` = `iterator` and `NodeType` = `node_type`.
=== 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
```c++
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
[source,c++,subs="+quotes"]
----
unordered_map(std::initializer_list<value_type> il,
size_type n = _implementation-defined_
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
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
```c++
@@ -749,7 +878,8 @@ size_type size() const noexcept;
```
[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
```c++
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
-----
==== __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
==== operator==
@@ -60,6 +60,12 @@ namespace unordered {
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_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,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
@@ -72,6 +78,13 @@ namespace unordered {
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,
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_bucket_count_and_allocator[unordered_multimap](std::initializer_list<value_type> il, size_type n,
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);
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<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);
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,
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>,
class Pred = std::equal_to<Key>,
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,
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>
unordered_multimap(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type,
Allocator)
@@ -341,6 +388,15 @@ See node_handle_map for details.
=== 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
```c++
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
[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
```c++
@@ -692,7 +821,8 @@ size_type size() const noexcept;
```
[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
```c++
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
-----
==== __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
==== operator==
@@ -58,6 +58,12 @@ namespace unordered {
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_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,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
@@ -70,6 +76,13 @@ namespace unordered {
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,
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_bucket_count_and_allocator[unordered_multiset](std::initializer_list<value_type> il, size_type n,
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_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<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);
node_type xref:#unordered_multiset_extract_by_iterator[extract](const_iterator position);
@@ -195,6 +210,16 @@ namespace unordered {
Hash = Hash(), Pred = Pred(), Allocator = 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>,
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__],
@@ -219,6 +244,27 @@ namespace unordered {
-> 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>;
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>
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>;
@@ -329,6 +375,15 @@ See node_handle_set for details.
=== 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
```c++
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
[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
```c++
@@ -683,7 +811,8 @@ size_type size() const noexcept;
```
[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
```c++
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]
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
-----
==== __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
==== 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_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);
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,
size_type n = _implementation-defined_
const hasher& hf = hasher(),
@@ -93,6 +99,13 @@ namespace unordered {
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,
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_bucket_count_and_allocator[unordered_node_map](std::initializer_list<value_type> il, size_type n,
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_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<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>);
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);
@@ -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,
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>,
class Pred = std::equal_to<Key>,
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,
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>
unordered_node_map(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_node_map_deduction_guides[__see below__]::size_type,
Allocator)
@@ -395,6 +442,15 @@ with `Iterator` = `iterator` and `NodeType` = `node_type`.
=== 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
```c++
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
[source,c++,subs="+quotes"]
----
@@ -540,7 +617,7 @@ unordered_node_map(std::initializer_list<value_type> il,
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]
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
```c++
@@ -763,7 +892,8 @@ size_type size() const noexcept;
```
[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
```c++
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
-----
==== __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
==== 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_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);
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,
size_type n = _implementation-defined_
const hasher& hf = hasher(),
@@ -88,6 +94,13 @@ namespace unordered {
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,
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_bucket_count_and_allocator[unordered_node_set](std::initializer_list<value_type> il, size_type n,
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);
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<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>);
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);
@@ -197,6 +212,16 @@ namespace unordered {
Hash = Hash(), Pred = Pred(), Allocator = 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>,
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__],
@@ -221,6 +246,27 @@ namespace unordered {
-> 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>;
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>
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>;
@@ -345,6 +391,15 @@ with `Iterator` = `iterator` and `NodeType` = `node_type`.
=== 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
```c++
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
[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
```c++
@@ -588,7 +716,7 @@ unordered_node_set(std::initializer_list<value_type> il, size_type n, const hash
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]
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]
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
```c++
void insert(std::initializer_list<value_type>);
@@ -1301,6 +1446,16 @@ template<class InputIterator>
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
==== operator==
@@ -59,6 +59,12 @@ namespace unordered {
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_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,
size_type n = _implementation-defined_,
const hasher& hf = hasher(),
@@ -71,6 +77,13 @@ namespace unordered {
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,
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_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,
@@ -107,6 +120,8 @@ namespace unordered {
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 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>);
node_type xref:#unordered_set_extract_by_iterator[extract](const_iterator position);
@@ -197,6 +212,16 @@ namespace unordered {
Hash = Hash(), Pred = Pred(), Allocator = 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>,
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__],
@@ -220,6 +245,27 @@ namespace unordered {
-> 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>;
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>
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>;
@@ -353,6 +399,16 @@ with `Iterator` = `iterator` and `NodeType` = `node_type`.
=== 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
```c++
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
[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
```c++
@@ -707,7 +836,8 @@ size_type size() const noexcept;
```
[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
```c++
void insert(std::initializer_list<value_type>);
@@ -1423,6 +1571,16 @@ template<class InputIterator>
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
==== operator==
+32 -21
View File
@@ -4,6 +4,10 @@
"requires": true,
"packages": {
"": {
"name": "doc",
"dependencies": {
"@cppalliance/antora-downloads-extension": "^0.0.2"
},
"devDependencies": {
"@antora/cli": ">=3.1.14",
"@antora/site-generator": ">=3.1.14",
@@ -286,6 +290,12 @@
"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": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
@@ -459,9 +469,9 @@
]
},
"node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
@@ -609,9 +619,9 @@
"dev": true
},
"node_modules/convict": {
"version": "6.2.4",
"resolved": "https://registry.npmjs.org/convict/-/convict-6.2.4.tgz",
"integrity": "sha512-qN60BAwdMVdofckX7AlohVJ2x9UvjTNoKVXCL2LxFk1l7757EJqf1nySdMkPQer0bt8kQ5lQiyZ9/2NvrFBuwQ==",
"version": "6.2.5",
"resolved": "https://registry.npmjs.org/convict/-/convict-6.2.5.tgz",
"integrity": "sha512-JtXpxqDqJ8P0UwEHwhxLzCIXQy97vlYBZR222Sbzb1q1Erex9ASrztJ29SyhWFQjod1AeFBaPzEEC8YvtZMIYg==",
"dev": true,
"dependencies": {
"lodash.clonedeep": "^4.5.0",
@@ -934,9 +944,9 @@
}
},
"node_modules/handlebars": {
"version": "4.7.8",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
"integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
"version": "4.7.9",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz",
"integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==",
"dev": true,
"dependencies": {
"minimist": "^1.2.5",
@@ -1164,10 +1174,11 @@
}
},
"node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"dev": true,
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
@@ -1225,9 +1236,9 @@
}
},
"node_modules/micromatch/node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true,
"engines": {
"node": ">=8.6"
@@ -1270,9 +1281,9 @@
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
@@ -1354,9 +1365,9 @@
"dev": true
},
"node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"engines": {
"node": ">=12"
+3
View File
@@ -3,5 +3,8 @@
"@antora/cli": ">=3.1.14",
"@antora/site-generator": ">=3.1.14",
"antora": ">=3.1.14"
},
"dependencies": {
"@cppalliance/antora-downloads-extension": "^0.0.2"
}
}
+4
View File
@@ -12,3 +12,7 @@ ui:
bundle:
url: https://github.com/boostorg/unordered-ui-bundle/raw/c80db72a7ba804256beb36e3a46d9c7df265d8d7/ui-bundle.zip
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.
# https://www.boost.org/LICENSE_1_0.txt
@@ -16,8 +16,14 @@ class BoostUnorderedHelpers:
return n
def maybe_unwrap_foa_element(e):
if f"{e.type.strip_typedefs()}".startswith("boost::unordered::detail::foa::element_type<"):
return e["p"]
# Sometimes the complex typedefs can't be resolved through a pointer
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:
return e
+196 -6
View File
@@ -1,7 +1,8 @@
/* Fast open-addressing concurrent hashmap.
*
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
@@ -16,6 +17,7 @@
#include <boost/unordered/detail/concurrent_static_asserts.hpp>
#include <boost/unordered/detail/foa/concurrent_table.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/unordered_flat_map_fwd.hpp>
@@ -101,6 +103,21 @@ namespace boost {
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)
: table_(rhs.table_,
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)
: 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(
std::initializer_list<value_type> il, const allocator_type& a)
: concurrent_flat_map(
@@ -189,10 +242,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_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_))
{
}
@@ -423,12 +476,26 @@ namespace boost {
size_type insert(InputIterator begin, InputIterator end)
{
size_type count_elements = 0;
for (auto pos = begin; pos != end; ++pos, ++count_elements) {
table_.emplace(*pos);
for (auto pos = begin; pos != end; ++pos) {
if (table_.emplace(*pos)) ++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)
{
return this->insert(ilist.begin(), ilist.end());
@@ -484,6 +551,21 @@ namespace boost {
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>
size_type insert_or_visit(std::initializer_list<value_type> ilist, F f)
{
@@ -517,6 +599,21 @@ namespace boost {
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>
size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
{
@@ -554,6 +651,24 @@ namespace boost {
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>
size_type insert_and_visit(
std::initializer_list<value_type> ilist, F1 f1, F2 f2)
@@ -594,6 +709,24 @@ namespace boost {
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>
size_type insert_and_cvisit(
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,
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,
class Hash = boost::hash<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> >,
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,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
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.
*
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
@@ -16,6 +17,7 @@
#include <boost/unordered/detail/concurrent_static_asserts.hpp>
#include <boost/unordered/detail/foa/concurrent_table.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/unordered_flat_set_fwd.hpp>
@@ -98,6 +100,21 @@ namespace boost {
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)
: table_(rhs.table_,
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)
: 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(
std::initializer_list<value_type> il, const allocator_type& a)
: concurrent_flat_set(
@@ -186,10 +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>
concurrent_flat_set(
unordered_flat_set<Key, Hash, Pred, Allocator>&& other)
unordered_flat_set<Key2, Hash, Pred, Allocator>&& other)
: table_(std::move(other.table_))
{
}
@@ -429,12 +482,26 @@ namespace boost {
size_type insert(InputIterator begin, InputIterator end)
{
size_type count_elements = 0;
for (auto pos = begin; pos != end; ++pos, ++count_elements) {
table_.emplace(*pos);
for (auto pos = begin; pos != end; ++pos) {
if (table_.emplace(*pos)) ++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)
{
return this->insert(ilist.begin(), ilist.end());
@@ -475,6 +542,21 @@ namespace boost {
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>
size_type insert_or_visit(std::initializer_list<value_type> ilist, F f)
{
@@ -517,6 +599,21 @@ namespace boost {
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>
size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
{
@@ -565,6 +662,24 @@ namespace boost {
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>
size_type insert_and_visit(std::initializer_list<value_type> ilist, F1 f1, F2 f2)
{
@@ -615,6 +730,24 @@ namespace boost {
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>
size_type insert_and_cvisit(
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,
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>,
class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
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>,
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,
class = std::enable_if_t<detail::is_allocator_v<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.
*
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
* 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/node_map_handle.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/unordered_node_map_fwd.hpp>
@@ -109,6 +111,21 @@ namespace boost {
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)
: table_(rhs.table_,
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)
: 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(
std::initializer_list<value_type> il, const allocator_type& a)
: 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(
unordered_node_map<Key, T, Hash, Pred, Allocator>&& other)
unordered_node_map<Key2, T, Hash, Pred, Allocator>&& other)
: table_(std::move(other.table_))
{
}
@@ -430,12 +484,26 @@ namespace boost {
size_type insert(InputIterator begin, InputIterator end)
{
size_type count_elements = 0;
for (auto pos = begin; pos != end; ++pos, ++count_elements) {
table_.emplace(*pos);
for (auto pos = begin; pos != end; ++pos) {
if (table_.emplace(*pos)) ++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)
{
return this->insert(ilist.begin(), ilist.end());
@@ -510,6 +578,21 @@ namespace boost {
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>
size_type insert_or_visit(std::initializer_list<value_type> ilist, F f)
{
@@ -564,6 +647,21 @@ namespace boost {
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>
size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
{
@@ -622,6 +720,24 @@ namespace boost {
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>
size_type insert_and_visit(
std::initializer_list<value_type> ilist, F1 f1, F2 f2)
@@ -684,6 +800,24 @@ namespace boost {
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>
size_type insert_and_cvisit(
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,
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,
class Hash = boost::hash<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> >,
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,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
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.
*
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
* 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/node_set_handle.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/unordered_node_set_fwd.hpp>
@@ -106,6 +108,21 @@ namespace boost {
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)
: table_(rhs.table_,
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)
: 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(
std::initializer_list<value_type> il, const allocator_type& a)
: 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(
unordered_node_set<Key, Hash, Pred, Allocator>&& other)
unordered_node_set<Key2, Hash, Pred, Allocator>&& other)
: table_(std::move(other.table_))
{
}
@@ -436,12 +490,26 @@ namespace boost {
size_type insert(InputIterator begin, InputIterator end)
{
size_type count_elements = 0;
for (auto pos = begin; pos != end; ++pos, ++count_elements) {
table_.emplace(*pos);
for (auto pos = begin; pos != end; ++pos) {
if (table_.emplace(*pos)) ++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)
{
return this->insert(ilist.begin(), ilist.end());
@@ -501,6 +569,21 @@ namespace boost {
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>
size_type insert_or_visit(std::initializer_list<value_type> ilist, F f)
{
@@ -564,6 +647,21 @@ namespace boost {
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>
size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
{
@@ -633,6 +731,24 @@ namespace boost {
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>
size_type insert_and_visit(
std::initializer_list<value_type> ilist, F1 f1, F2 f2)
@@ -706,6 +822,24 @@ namespace boost {
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>
size_type insert_and_cvisit(
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,
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>,
class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
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>,
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,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
concurrent_node_set(std::initializer_list<T>, std::size_t, Allocator)
@@ -1,6 +1,6 @@
/* Fast open-addressing concurrent hash table.
*
* Copyright 2023-2024 Joaquin M Lopez Munoz.
* Copyright 2023-2026 Joaquin M Lopez Munoz.
* Copyright 2024 Braden Ganetsky.
* Distributed under the Boost Software License, Version 1.0.
* (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 */
template <typename K, typename V>
template <typename K, typename V, typename Table = concurrent_table>
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
{
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.
*
* Copyright 2022-2025 Joaquin M Lopez Munoz.
* Copyright 2022-2026 Joaquin M Lopez Munoz.
* Copyright 2023 Christian Mazakas.
* Copyright 2024 Braden Ganetsky.
* 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,
is_map<Container>::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
* instantiations suitable for either maps or sets, and introduces non-standard
+3 -3
View File
@@ -1,6 +1,6 @@
/* Fast open-addressing hash table.
*
* Copyright 2022-2025 Joaquin M Lopez Munoz.
* Copyright 2022-2026 Joaquin M Lopez Munoz.
* Copyright 2023 Christian Mazakas.
* Copyright 2024 Braden Ganetsky.
* 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 */
template <typename K, typename V>
template <typename K, typename V, typename Table = table>
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
emplace(K&& k, V&& v)
{
@@ -1,6 +1,6 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// 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) 2024 Braden Ganetsky
//
@@ -18,12 +18,14 @@
#include <boost/unordered/detail/allocator_constructed.hpp>
#include <boost/unordered/detail/fca.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/static_assert.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/detail/unordered_printers.hpp>
#include <boost/assert.hpp>
#include <boost/config/workaround.hpp>
#include <boost/core/allocator_traits.hpp>
#include <boost/core/bit.hpp>
#include <boost/core/invoke_swap.hpp>
@@ -174,6 +176,29 @@ namespace boost {
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
@@ -954,10 +979,14 @@ namespace boost {
inline std::size_t double_to_size(double f)
{
return f >= static_cast<double>(
(std::numeric_limits<std::size_t>::max)())
? (std::numeric_limits<std::size_t>::max)()
: static_cast<std::size_t>(f);
#if BOOST_WORKAROUND(BOOST_CLANG_VERSION, < 30900)
// https://github.com/boostorg/unordered/pull/354
volatile
#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)
{
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));
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
// safety strong otherwise
template <class InputIt>
void insert_range_unique(no_key, InputIt i, InputIt j)
template <class InputIt, class Sentinel>
void insert_range_unique(no_key, InputIt i, Sentinel j)
{
hasher const& hf = this->hash_function();
node_allocator_type alloc = this->node_alloc();
@@ -2538,14 +2567,20 @@ namespace boost {
// if hash function throws, or inserting > 1 element, basic exception
// safety. Strong otherwise
template <class I>
template <class I, class S>
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)
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));
#endif
if (distance == 1) {
emplace_equiv(boost::unordered::detail::func::construct_node(
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
insert_range_equiv(I i, I j)
insert_range_equiv(I i, S j)
{
for (; i != j; ++i) {
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)
{
if (num_elements > max_load_) {
std::size_t const num_buckets = static_cast<std::size_t>(
1.0f + std::ceil(static_cast<float>(num_elements) / mlf_));
std::size_t const num_buckets = (std::max)(
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);
}
@@ -2851,10 +2887,10 @@ namespace boost {
return no_key();
}
template <class Arg1, class Arg2>
template <class Arg1, class Arg2, class Key = key_type>
static typename std::conditional<
(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
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) 2024 Braden Ganetsky
// Copyright (C) 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)
@@ -49,20 +50,6 @@ namespace boost {
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)
/* std::is_trivially_default_constructible not provided */
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.
// 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
#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 \" 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 \" return e[\\\"p\\\"]\\n\"\n"
".ascii \" # Sometimes the complex typedefs can't be resolved through a pointer\\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 \" return e\\n\"\n"
+121 -3
View File
@@ -1,5 +1,6 @@
// 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
// 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/detail/foa/flat_map_types.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/throw_exception.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)
: 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_)
{
}
@@ -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(
concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator>&& other)
concurrent_flat_map<Key2, T, Hash, KeyEqual, Allocator>&& other)
: 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)
{
this->insert(ilist.begin(), ilist.end());
@@ -754,6 +815,27 @@ namespace boost {
boost::unordered::detail::iter_val_t<InputIterator>, 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<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,
class Hash = boost::hash<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> >,
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,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
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) 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
// 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/detail/foa/flat_set_types.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/type_traits.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)
: 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_)
{
}
@@ -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(
concurrent_flat_set<Key, Hash, KeyEqual, Allocator>&& other)
concurrent_flat_set<Key2, Hash, KeyEqual, Allocator>&& other)
: 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)
{
this->insert(ilist.begin(), ilist.end());
@@ -572,6 +633,25 @@ namespace boost {
typename std::iterator_traits<InputIterator>::value_type, 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_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>,
class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
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>,
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,
class = std::enable_if_t<detail::is_allocator_v<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>,
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,
class = std::enable_if_t<detail::is_allocator_v<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) 2005-2011 Daniel James.
// 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
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,6 +16,7 @@
#endif
#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/throw_exception.hpp>
#include <boost/unordered/detail/type_traits.hpp>
@@ -92,6 +93,17 @@ namespace boost {
const hasher& = hasher(), const key_equal& = key_equal(),
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&& other)
@@ -126,6 +138,27 @@ namespace boost {
unordered_map(
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(
@@ -248,6 +281,11 @@ namespace boost {
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>);
// extract
@@ -622,6 +660,27 @@ namespace boost {
boost::unordered::detail::iter_val_t<InputIterator>, 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<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,
class Hash = boost::hash<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> >,
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,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
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 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&& other)
@@ -777,6 +883,27 @@ namespace boost {
unordered_multimap(
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(
std::initializer_list<value_type>, const allocator_type&);
@@ -894,6 +1021,11 @@ namespace boost {
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>);
// extract
@@ -1141,6 +1273,26 @@ namespace boost {
boost::unordered::detail::iter_val_t<InputIterator>, 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<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,
class Hash = boost::hash<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> >,
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,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_multimap(std::initializer_list<std::pair<Key, T> >, std::size_t,
@@ -1231,6 +1419,23 @@ namespace boost {
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>
unordered_map<K, T, H, P, A>::unordered_map(unordered_map const& other)
: table_(other.table_,
@@ -1303,6 +1508,7 @@ namespace boost {
this->insert(f, l);
}
template <class K, class T, class H, class P, class A>
template <class InputIt>
unordered_map<K, T, H, P, A>::unordered_map(
@@ -1323,6 +1529,51 @@ namespace boost {
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>
unordered_map<K, T, H, P, A>::unordered_map(
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>
void unordered_map<K, T, H, P, A>::insert(
std::initializer_list<value_type> list)
@@ -1757,6 +2022,23 @@ namespace boost {
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>
unordered_multimap<K, T, H, P, A>::unordered_multimap(
unordered_multimap const& other)
@@ -1851,6 +2133,51 @@ namespace boost {
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>
unordered_multimap<K, T, H, P, A>::unordered_multimap(
std::initializer_list<value_type> list, const allocator_type& a)
@@ -1921,6 +2248,16 @@ namespace boost {
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>
void unordered_multimap<K, T, H, P, A>::insert(
std::initializer_list<value_type> list)
+121 -3
View File
@@ -1,5 +1,6 @@
// 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
// 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_types.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/throw_exception.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)
: 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_)
{
}
@@ -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(
concurrent_node_map<Key, T, Hash, KeyEqual, Allocator>&& other)
concurrent_node_map<Key2, T, Hash, KeyEqual, Allocator>&& other)
: 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)
{
this->insert(ilist.begin(), ilist.end());
@@ -828,6 +889,27 @@ namespace boost {
boost::unordered::detail::iter_val_t<InputIterator>, 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<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,
class Hash = boost::hash<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> >,
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,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
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) 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
// 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_types.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/type_traits.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)
: 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_)
{
}
@@ -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(
concurrent_node_set<Key, Hash, KeyEqual, Allocator>&& other)
concurrent_node_set<Key2, Hash, KeyEqual, Allocator>&& other)
: 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)
{
this->insert(ilist.begin(), ilist.end());
@@ -648,6 +709,25 @@ namespace boost {
typename std::iterator_traits<InputIterator>::value_type, 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_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>,
class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
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>,
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,
class = std::enable_if_t<detail::is_allocator_v<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>,
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,
class = std::enable_if_t<detail::is_allocator_v<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) 2005-2011 Daniel James.
// 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
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,6 +15,7 @@
#pragma once
#endif
#include <boost/unordered/detail/ranges_support.hpp>
#include <boost/unordered/detail/serialize_fca_container.hpp>
#include <boost/unordered/detail/set.hpp>
#include <boost/unordered/detail/type_traits.hpp>
@@ -88,6 +89,17 @@ namespace boost {
const hasher& = hasher(), const key_equal& = key_equal(),
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&& other)
@@ -122,6 +134,27 @@ namespace boost {
unordered_set(
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(
@@ -246,6 +279,11 @@ namespace boost {
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>);
// extract
@@ -478,6 +516,25 @@ namespace boost {
-> unordered_set<typename std::iterator_traits<InputIterator>::value_type,
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>,
class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
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>,
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,
class = std::enable_if_t<detail::is_allocator_v<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>,
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,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_set(std::initializer_list<T>, Allocator)
@@ -585,6 +677,18 @@ namespace boost {
const hasher& = hasher(), const key_equal& = key_equal(),
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&& other)
@@ -620,6 +724,27 @@ namespace boost {
unordered_multiset(
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(
std::initializer_list<value_type>, const allocator_type&);
@@ -720,6 +845,11 @@ namespace boost {
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>);
// extract
@@ -942,6 +1072,25 @@ namespace boost {
typename std::iterator_traits<InputIterator>::value_type, 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_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>,
class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
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>,
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,
class = std::enable_if_t<detail::is_allocator_v<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>,
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,
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
unordered_multiset(std::initializer_list<T>, Allocator)
@@ -1023,6 +1207,23 @@ namespace boost {
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>
unordered_set<T, H, P, A>::unordered_set(unordered_set const& other)
: table_(other.table_,
@@ -1115,6 +1316,51 @@ namespace boost {
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>
unordered_set<T, H, P, A>::unordered_set(
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>
void unordered_set<T, H, P, A>::insert(
std::initializer_list<value_type> list)
@@ -1420,6 +1680,23 @@ namespace boost {
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>
unordered_multiset<T, H, P, A>::unordered_multiset(
unordered_multiset const& other)
@@ -1513,6 +1790,51 @@ namespace boost {
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>
unordered_multiset<T, H, P, A>::unordered_multiset(
std::initializer_list<value_type> list, const allocator_type& a)
@@ -1582,6 +1904,16 @@ namespace boost {
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>
void unordered_multiset<T, H, P, A>::insert(
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(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/try_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_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()
+6 -5
View File
@@ -12,10 +12,7 @@ import config : requires ;
path-constant TOP : . ;
# Adding -Wundef is blocked on (at least)
# https://github.com/boostorg/type_traits/issues/165
local gcc-flags = -Wsign-promo -Wconversion -Wsign-conversion -Wfloat-equal -Wshadow -Wno-variadic-macros ;
local gcc-flags = -Wsign-promo -Wconversion -Wsign-conversion -Wfloat-equal -Wshadow -Wundef -Wno-variadic-macros ;
local clang-flags = $(gcc-flags) -Wno-c99-extensions ;
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 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 =
constructor_exception_tests
copy_exception_tests
@@ -379,7 +379,8 @@ run cfoa/insert_tests.cpp
: $(CPP11) <threading>multi
<toolset>msvc:<cxxflags>/bigobj
<toolset>gcc:<inlining>on
<toolset>gcc:<optimization>space
<toolset>gcc:<optimization>off
<toolset>gcc:<cxxflags>-g0
<toolset>clang:<inlining>on
<toolset>clang:<optimization>space
: cfoa_insert_tests ;
+101 -1
View File
@@ -1,5 +1,5 @@
// 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
// 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_set.hpp>
#include <list>
test::seed_t initialize_seed(4122023);
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>
void initializer_list_with_all_params(std::pair<X*, IL> p)
{
@@ -1040,6 +1133,13 @@ UNORDERED_TEST(
explicit_allocator,
((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(
initializer_list_with_all_params,
((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-2024 Joaquin M Lopez Munoz
// Copyright (C) 2023-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)
@@ -148,12 +148,18 @@ namespace {
values2.push_back(raii_convertible(v));
}
thread_runner(values2, [&x](boost::span<raii_convertible> s) {
BOOST_TEST_EQ(x.insert(s.begin(), s.end()), s.size());
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(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(
raii::default_constructor, value_type_cardinality * values2.size());
raii::default_constructor, value_type_cardinality * num_attempted_inserts);
#if BOOST_WORKAROUND(BOOST_GCC_VERSION, >= 50300) && \
BOOST_WORKAROUND(BOOST_GCC_VERSION, < 50500)
// some versions of old gcc have trouble eliding copies here
@@ -169,6 +175,39 @@ namespace {
}
} 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
{
template <class T, class X> void operator()(std::vector<T>& values, X& x)
@@ -792,6 +831,41 @@ namespace {
}
} 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
{
template <class T, class X> void operator()(std::vector<T>& values, X& x)
@@ -846,6 +920,55 @@ namespace {
}
} 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
{
template <class T, class X> void operator()(std::vector<T>& values, X& x)
@@ -893,6 +1016,48 @@ namespace {
}
} 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
{
template <class T, class X> void operator()(std::vector<T>& values, X& x)
@@ -947,6 +1112,55 @@ namespace {
}
} 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
{
non_copyable_function() = default;
@@ -1010,9 +1224,11 @@ namespace {
{
X x;
thread_runner(dummy, [&x, &init_list](boost::span<raii>) {
BOOST_TEST_EQ(x.insert(init_list), init_list.size());
std::atomic<std::uint64_t> num_inserts{0};
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());
@@ -1257,16 +1473,31 @@ UNORDERED_TEST(
((map_and_init_list)(node_map_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(
insert,
((map)(fancy_map)(node_map)(fancy_node_map)
(set)(fancy_set)(node_set)(fancy_node_set))
((value_type_generator_factory)(init_type_generator_factory))
((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)
(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)))
UNORDERED_TEST(
@@ -1276,7 +1507,8 @@ UNORDERED_TEST(
((value_type_generator_factory)(init_type_generator_factory))
((lvalue_insert_and_cvisit)(lvalue_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)))
UNORDERED_TEST(
-5
View File
@@ -18,14 +18,9 @@ assert
config
container_hash
core
move
mp11
predef
preprocessor
static_assert
throw_exception
tuple
type_traits
# Secondary dependencies
+31 -2
View File
@@ -11,6 +11,7 @@
#ifndef BOOST_NO_CXX17_HDR_MEMORY_RESOURCE
#include <memory_resource>
#include <new>
namespace test {
class counted_new_delete_resource : public std::pmr::memory_resource
@@ -25,17 +26,45 @@ namespace test {
void* do_allocate(std::size_t bytes, std::size_t alignment) override
{
_count += bytes;
#if defined(__cpp_aligned_new) && __cpp_aligned_new >= 201606L
return ::operator new(bytes, std::align_val_t(alignment));
#else
return ::operator new(bytes);
(void)alignment;
#endif
}
void do_deallocate(
void* p, std::size_t bytes, std::size_t alignment) override
{
_count -= bytes;
#if __cpp_sized_deallocation
#if defined(__cpp_aligned_new) && __cpp_aligned_new >= 201606L
# if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L
::operator delete(p, bytes, std::align_val_t(alignment));
#else
# else
::operator delete(p, std::align_val_t(alignment));
# endif
#else
# if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L
::operator delete(p, bytes);
# else
::operator delete(p);
(void)alignment;
# endif
#endif
}
+201
View File
@@ -1,6 +1,7 @@
// Copyright 2006-2010 Daniel James.
// Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 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)
@@ -14,6 +15,7 @@
#include "../helpers/tracker.hpp"
#include "../objects/test.hpp"
#include <list>
#include <vector>
namespace constructor_tests {
@@ -337,6 +339,205 @@ namespace constructor_tests {
//
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")
{
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 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)
#include <boost/unordered_map.hpp>
#include <iostream>
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/unordered_map.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_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_set.hpp>
#include <boost/unordered/concurrent_node_map.hpp>
#include <boost/unordered/concurrent_node_set.hpp>
#include <vector>
struct hash_equals
{
@@ -87,6 +94,44 @@ template <template <class...> class UnorderedMap> void map_tests()
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>,
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> > >);
}
#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>
unordered_map(InputIterator, InputIterator, Allocator)
@@ -178,6 +241,23 @@ template <template <class...> class UnorderedMap> void map_tests()
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>
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> > >);
}
#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>
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> >);
}
#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,
class Hash = std::hash<T>,
class Pred = std::equal_to<T>,
@@ -358,6 +494,24 @@ template <template <class...> class UnorderedSet> void set_tests()
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>
unordered_set(InputIt, InputIt, typename see below::size_type, Hash, Alloc)
-> 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> >);
}
#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>
unordered_set(std::initializer_list<T>, typename see below::size_type,
Allocator)
@@ -408,6 +578,23 @@ template <template <class...> class UnorderedSet> void set_tests()
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>
unordered_set(initializer_list<T>, Allocator)
@@ -433,10 +620,15 @@ int main()
map_tests<boost::unordered_map>();
map_tests<boost::unordered_multimap>();
map_tests<boost::unordered_flat_map>();
map_tests<boost::unordered_node_map>();
map_tests<boost::concurrent_flat_map>();
map_tests<boost::concurrent_node_map>();
set_tests<boost::unordered_set>();
set_tests<boost::unordered_multiset>();
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();
#endif
+22
View File
@@ -1,6 +1,7 @@
// Copyright 2006-2010 Daniel James.
// Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 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)
@@ -405,6 +406,27 @@ namespace insert_tests {
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>
+99
View File
@@ -1,6 +1,7 @@
// Copyright 2006-2009 Daniel James.
// Copyright 2022-2023 Christian Mazakas.
// 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)
@@ -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::generate_collisions;
using test::limited_range;
@@ -739,6 +836,8 @@ namespace rehash_tests {
(test_multiset_ptr)(int_multimap_ptr)
(test_multiset_tracking)(test_multimap_tracking))(
(default_generator)(generate_collisions)(limited_range)))
UNORDERED_TEST(test_gh348_1, ((0)))
UNORDERED_TEST(test_gh348_2, ((0)))
// clang-format on
#endif
} // 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);
}
#if BOOST_UNORDERED_FOA_TESTS
#ifdef BOOST_UNORDERED_FOA_TESTS
typedef boost::unordered_flat_set<int, transparent_hasher,
transparent_key_equal>
transparent_unordered_set;