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
This commit is contained in:
joaquintides
2026-06-17 09:00:00 +02:00
committed by GitHub
parent b785bb5501
commit 88f984e890
43 changed files with 5081 additions and 48 deletions
+2 -1
View File
@@ -347,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]
@@ -383,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
+8
View File
@@ -6,6 +6,14 @@
: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.
== Release 1.91.0
* Fixed the returned value of range insertion in concurrent containers
@@ -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^].
@@ -1013,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);
@@ -1095,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
@@ -1111,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);
@@ -1215,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>
@@ -1742,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^].
@@ -963,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);
@@ -1070,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);
@@ -1184,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>
@@ -1516,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++
@@ -1059,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);
@@ -1170,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);
@@ -1289,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>
@@ -1858,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++
@@ -1008,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);
@@ -1128,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);
@@ -1257,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>
@@ -1639,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++
@@ -884,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>);
@@ -1445,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==
@@ -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^].
@@ -857,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>);
@@ -1194,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++
@@ -944,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>);
@@ -1697,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++
@@ -874,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);
@@ -1414,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++
@@ -831,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.
@@ -1346,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++
@@ -918,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>);
@@ -1549,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^].
@@ -895,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>);
@@ -1302,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++
@@ -904,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>);
@@ -1424,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==
@@ -17,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>
@@ -102,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(
@@ -121,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)
{
@@ -171,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(
@@ -430,6 +482,20 @@ namespace boost {
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());
@@ -485,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)
{
@@ -518,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)
{
@@ -555,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)
@@ -595,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)
@@ -980,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> >,
@@ -1027,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,
@@ -17,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>
@@ -99,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(
@@ -118,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)
{
@@ -168,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(
@@ -436,6 +488,20 @@ namespace boost {
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());
@@ -476,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)
{
@@ -518,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)
{
@@ -566,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)
{
@@ -616,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)
@@ -853,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> >,
@@ -894,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)
@@ -19,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>
@@ -110,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(
@@ -129,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)
{
@@ -179,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(
@@ -438,6 +490,20 @@ namespace boost {
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());
@@ -512,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)
{
@@ -566,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)
{
@@ -624,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)
@@ -686,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)
@@ -1128,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> >,
@@ -1175,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,
@@ -19,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>
@@ -107,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(
@@ -126,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)
{
@@ -176,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(
@@ -444,6 +496,20 @@ namespace boost {
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());
@@ -503,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)
{
@@ -566,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)
{
@@ -635,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)
@@ -708,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)
@@ -1002,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> >,
@@ -1043,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)
@@ -18,6 +18,7 @@
#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>
@@ -175,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
@@ -2155,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();
@@ -2543,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));
@@ -2566,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(
@@ -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
+117 -1
View File
@@ -1,5 +1,5 @@
// 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 +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>
@@ -108,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)
{
@@ -136,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_)
{
}
@@ -278,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());
@@ -756,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> >,
@@ -800,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,
+114 -1
View File
@@ -1,5 +1,5 @@
// 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 +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>
@@ -104,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)
{
@@ -132,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_)
{
}
@@ -289,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());
@@ -574,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> >,
@@ -605,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)
@@ -626,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)
+117 -1
View File
@@ -1,5 +1,5 @@
// 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 +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>
@@ -115,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)
{
@@ -143,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_)
{
}
@@ -285,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());
@@ -830,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> >,
@@ -874,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,
+114 -1
View File
@@ -1,5 +1,5 @@
// 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)
@@ -17,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>
@@ -113,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)
{
@@ -141,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_)
{
}
@@ -298,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());
@@ -650,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> >,
@@ -681,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)
@@ -702,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)
+5 -1
View File
@@ -139,7 +139,11 @@ foa_tests(SOURCES exception/merge_exception_tests.cpp)
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) # GCC MinGW32 OOMs otherwise
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})
+2 -1
View File
@@ -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)
+227 -3
View File
@@ -175,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)
@@ -798,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)
@@ -852,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)
@@ -899,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)
@@ -953,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;
@@ -1265,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(
@@ -1284,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(
+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_;
+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>