diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50e73bbdb..7bc71b54e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -383,6 +383,7 @@ jobs: B2_SANITIZE: ${{matrix.sanitize}} B2_STDLIB: ${{matrix.stdlib}} B2_VARIANT: ${{matrix.variant}} + B2_JOBS: ${{ matrix.sys == 'MINGW32' && '2' || '' }} run: ci/github/install.sh - name: Run tests diff --git a/doc/modules/ROOT/pages/changes.adoc b/doc/modules/ROOT/pages/changes.adoc index 99532bbfd..af882c12d 100644 --- a/doc/modules/ROOT/pages/changes.adoc +++ b/doc/modules/ROOT/pages/changes.adoc @@ -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 diff --git a/doc/modules/ROOT/pages/reference/concurrent_flat_map.adoc b/doc/modules/ROOT/pages/reference/concurrent_flat_map.adoc index f9ef49b36..fa3aec855 100644 --- a/doc/modules/ROOT/pages/reference/concurrent_flat_map.adoc +++ b/doc/modules/ROOT/pages/reference/concurrent_flat_map.adoc @@ -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&& other); + template 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 il, size_type n = _implementation-defined_ const hasher& hf = hasher(), @@ -90,6 +96,13 @@ namespace unordered { template 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 R> + xref:#concurrent_flat_map_range_constructor_with_allocator[concurrent_flat_map](FromRangeT&&, R&& rg, const allocator_type& a); + template 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 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 il, const allocator_type& a); xref:#concurrent_flat_map_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_flat_map](std::initializer_list 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 size_type xref:#concurrent_flat_map_insert_iterator_range[insert](InputIterator first, InputIterator last); + template 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 il); template 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 size_type xref:#concurrent_flat_map_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f); + template R, class F> + size_type xref:#concurrent_flat_map_insert_range_or_visit[insert_range_or_visit](R&& rg, F f); + template R, class F> + size_type xref:#concurrent_flat_map_insert_range_or_visit[insert_range_or_cvisit](R&& rg, F f); template size_type xref:#concurrent_flat_map_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list il, F f); template size_type xref:#concurrent_flat_map_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list 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 size_type xref:#concurrent_flat_map_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2); + template 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 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 size_type xref:#concurrent_flat_map_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list il, F1 f1, F2 f2); template @@ -282,6 +305,17 @@ namespace unordered { -> concurrent_flat_map, xref:#concurrent_flat_map_iter_mapped_type[__iter-mapped-type__], Hash, Pred, Allocator>; + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + 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_mapped_type[__range-mapped-type__], + Hash, Pred,Allocator>; + template, class Pred = std::equal_to, class Allocator = std::allocator>> @@ -308,6 +342,27 @@ namespace unordered { -> concurrent_flat_map, xref:#concurrent_flat_map_iter_mapped_type[__iter-mapped-type__], Hash, std::equal_to>, Allocator>; + template + 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_mapped_type[__range-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + concurrent_flat_map(FromRangeT&&, R&&, Allocator) + -> concurrent_flat_map, xref:#concurrent_flat_map_range_mapped_type[__range-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + 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_mapped_type[__range-mapped-type__], + Hash, std::equal_to>, Allocator>; + template concurrent_flat_map(std::initializer_list>, 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 + concept container_compatible_range = + std::ranges::input_range && + std::convertible_to, 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 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 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 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 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 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 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(x)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + ==== Insert Initializer List ```c++ size_type insert(std::initializer_list il); @@ -1095,9 +1250,9 @@ only if `std::remove_reference::type` is `value_type`. ==== Insert Iterator Range or Visit ```c++ template - size_type insert_or_visit(InputIterator first, InputIterator last, F f); + size_type insert_or_visit(InputIterator first, InputIterator last, F f); template - 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 R, class F> + size_type insert_range_or_visit(R&& rg, F f); +template 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(x), std::ref(f)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + ==== Insert Initializer List or Visit ```c++ template size_type insert_or_visit(std::initializer_list il, F f); @@ -1215,6 +1391,28 @@ Returns:;; The number of elements inserted. --- +==== Insert Range and Visit +[source,c++,subs="+macros,+quotes"] +---- +template R, class F1, class F2> + size_type insert_range_and_visit(R&& rg, F1 f1, F2 f2); +template 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(x), std::ref(f1), std::ref(f2)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + ==== Insert Initializer List and Visit ```c++ template @@ -1742,6 +1940,42 @@ template std::tuple_element_t<1, xref:#concurrent_flat_map_iter_value_type[__iter-value-type__]>>; // exposition only ----- +==== __convertible-to-from-range_t__ +[listings,subs="+macros,+quotes"] +----- +template + concept __convertible-to-from_range_t__ = + // first clause not present if std::from_range_t does not exist + std::is_convertible_v || + std::is_convertible_v; // exposition only +----- + +==== __range-key-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-key-type__ = + std::remove_cvref_t< + std::tuple_element_t<0, std::ranges::range_value_t>>; // exposition only +----- + +==== __range-mapped-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-mapped-type__ = + std::remove_cvref_t< + std::tuple_element_t<1, std::ranges::range_value_t>>; // exposition only +----- + +==== __range-to-alloc-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-to-alloc-type__ = + std::pair, xref:#concurrent_flat_map_range_mapped_type[__range-mapped-type__]>; // exposition only +----- + === Equality Comparisons ==== operator== diff --git a/doc/modules/ROOT/pages/reference/concurrent_flat_set.adoc b/doc/modules/ROOT/pages/reference/concurrent_flat_set.adoc index e8483ba50..6203a5400 100644 --- a/doc/modules/ROOT/pages/reference/concurrent_flat_set.adoc +++ b/doc/modules/ROOT/pages/reference/concurrent_flat_set.adoc @@ -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&& other); + template 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 il, size_type n = _implementation-defined_ const hasher& hf = hasher(), @@ -85,6 +91,13 @@ namespace unordered { template 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 R> + xref:#concurrent_flat_set_range_constructor_with_allocator[concurrent_flat_set](FromRangeT&&, R&& rg, const allocator_type& a); + template 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 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 il, const allocator_type& a); xref:#concurrent_flat_set_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_flat_set](std::initializer_list 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 bool xref:#concurrent_flat_set_transparent_insert[insert](K&& k); template size_type xref:#concurrent_flat_set_insert_iterator_range[insert](InputIterator first, InputIterator last); + template 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 il); template 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 size_type xref:#concurrent_flat_set_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f); + template R, class F> + size_type xref:#concurrent_flat_set_insert_range_or_visit[insert_range_or_visit](R&& rg, F f); + template R, class F> + size_type xref:#concurrent_flat_set_insert_range_or_visit[insert_range_or_cvisit](R&& rg, F f); template size_type xref:#concurrent_flat_set_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list il, F f); template size_type xref:#concurrent_flat_set_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list 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 size_type xref:#concurrent_flat_set_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2); + template 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 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 size_type xref:#concurrent_flat_set_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list il, F1 f1, F2 f2); template @@ -236,6 +259,16 @@ namespace unordered { Hash = Hash(), Pred = Pred(), Allocator = Allocator()) -> concurrent_flat_set, Hash, Pred, Allocator>; + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator> + 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, Hash, Pred,Allocator>; + template, class Pred = std::equal_to, class Allocator = std::allocator> concurrent_flat_set(std::initializer_list, 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, Hash, std::equal_to>, Allocator>; + template + concurrent_flat_set(FromRangeT&&, R&&, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type, Allocator) + -> concurrent_flat_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + concurrent_flat_set(FromRangeT&&, R&&, Allocator) + -> concurrent_flat_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + concurrent_flat_set(FromRangeT&&, R&&, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> concurrent_flat_set, + Hash, std::equal_to>, Allocator>; + template concurrent_flat_set(std::initializer_list, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type, Allocator) -> concurrent_flat_set, std::equal_to, 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 + concept container_compatible_range = + std::ranges::input_range && + std::convertible_to, 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 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 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 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 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 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 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(x)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + ==== Insert Initializer List ```c++ size_type insert(std::initializer_list il); @@ -1070,6 +1224,27 @@ Returns:;; The number of elements inserted. --- +==== Insert Range or Visit +[source,c++,subs="+macros,+quotes"] +---- +template R, class F> + size_type insert_range_or_visit(R&& rg, F f); +template 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(x), std::ref(f)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + ==== Insert Initializer List or Visit ```c++ template size_type insert_or_visit(std::initializer_list il, F f); @@ -1184,6 +1359,28 @@ Returns:;; The number of elements inserted. --- +==== Insert Range and Visit +[source,c++,subs="+macros,+quotes"] +---- +template R, class F1, class F2> + size_type insert_range_and_visit(R&& rg, F1 f1, F2 f2); +template 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(x), std::ref(f1), std::ref(f2)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + ==== Insert Initializer List and Visit ```c++ template @@ -1516,6 +1713,16 @@ template typename std::iterator_traits::value_type; // exposition only ----- +==== __convertible-to-from-range_t__ +[listings,subs="+macros,+quotes"] +----- +template + concept __convertible-to-from_range_t__ = + // first clause not present if std::from_range_t does not exist + std::is_convertible_v || + std::is_convertible_v; // exposition only +----- + === Equality Comparisons ==== operator== diff --git a/doc/modules/ROOT/pages/reference/concurrent_node_map.adoc b/doc/modules/ROOT/pages/reference/concurrent_node_map.adoc index 17cc6d788..ff3376862 100644 --- a/doc/modules/ROOT/pages/reference/concurrent_node_map.adoc +++ b/doc/modules/ROOT/pages/reference/concurrent_node_map.adoc @@ -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&& other); + template 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 il, size_type n = _implementation-defined_ const hasher& hf = hasher(), @@ -93,6 +99,13 @@ namespace unordered { template 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 R> + xref:#concurrent_node_map_range_constructor_with_allocator[concurrent_node_map](FromRangeT&&, R&& rg, const allocator_type& a); + template 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 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 il, const allocator_type& a); xref:#concurrent_node_map_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_node_map](std::initializer_list 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 size_type xref:#concurrent_node_map_insert_iterator_range[insert](InputIterator first, InputIterator last); + template 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 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 size_type xref:#concurrent_node_map_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f); + template R, class F> + size_type xref:#concurrent_node_map_insert_range_or_visit[insert_range_or_visit](R&& rg, F f); + template R, class F> + size_type xref:#concurrent_node_map_insert_range_or_visit[insert_range_or_cvisit](R&& rg, F f); template size_type xref:#concurrent_node_map_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list il, F f); template size_type xref:#concurrent_node_map_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list il, F f); template 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 size_type xref:#concurrent_node_map_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2); + template 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 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 size_type xref:#concurrent_node_map_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list il, F1 f1, F2 f2); template @@ -300,6 +323,17 @@ namespace unordered { -> concurrent_node_map, xref:#concurrent_node_map_iter_mapped_type[__iter-mapped-type__], Hash, Pred, Allocator>; + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + 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_mapped_type[__range-mapped-type__], + Hash, Pred,Allocator>; + template, class Pred = std::equal_to, class Allocator = std::allocator>> @@ -326,6 +360,27 @@ namespace unordered { -> concurrent_node_map, xref:#concurrent_node_map_iter_mapped_type[__iter-mapped-type__], Hash, std::equal_to>, Allocator>; + template + 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_mapped_type[__range-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + concurrent_node_map(FromRangeT&&, R&&, Allocator) + -> concurrent_node_map, xref:#concurrent_node_map_range_mapped_type[__range-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + 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_mapped_type[__range-mapped-type__], + Hash, std::equal_to>, Allocator>; + template concurrent_node_map(std::initializer_list>, 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 + concept container_compatible_range = + std::ranges::input_range && + std::convertible_to, 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 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 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 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 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 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(x)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + ==== Insert Initializer List ```c++ size_type insert(std::initializer_list il); @@ -1170,6 +1325,27 @@ Returns:;; The number of elements inserted. --- +==== Insert Range or Visit +[source,c++,subs="+macros,+quotes"] +---- +template R, class F> + size_type insert_range_or_visit(R&& rg, F f); +template 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(x), std::ref(f)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + ==== Insert Initializer List or Visit ```c++ template size_type insert_or_visit(std::initializer_list il, F f); @@ -1289,6 +1465,28 @@ Returns:;; The number of elements inserted. --- +==== Insert Range and Visit +[source,c++,subs="+macros,+quotes"] +---- +template R, class F1, class F2> + size_type insert_range_and_visit(R&& rg, F1 f1, F2 f2); +template 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(x), std::ref(f1), std::ref(f2)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + ==== Insert Initializer List and Visit ```c++ template @@ -1858,6 +2056,42 @@ template std::tuple_element_t<1, xref:#concurrent_node_map_iter_value_type[__iter-value-type__]>>; // exposition only ----- +==== __convertible-to-from-range_t__ +[listings,subs="+macros,+quotes"] +----- +template + concept __convertible-to-from_range_t__ = + // first clause not present if std::from_range_t does not exist + std::is_convertible_v || + std::is_convertible_v; // exposition only +----- + +==== __range-key-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-key-type__ = + std::remove_cvref_t< + std::tuple_element_t<0, std::ranges::range_value_t>>; // exposition only +----- + +==== __range-mapped-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-mapped-type__ = + std::remove_cvref_t< + std::tuple_element_t<1, std::ranges::range_value_t>>; // exposition only +----- + +==== __range-to-alloc-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-to-alloc-type__ = + std::pair, xref:#concurrent_node_map_range_mapped_type[__range-mapped-type__]>; // exposition only +----- + === Equality Comparisons ==== operator== diff --git a/doc/modules/ROOT/pages/reference/concurrent_node_set.adoc b/doc/modules/ROOT/pages/reference/concurrent_node_set.adoc index fee0660e3..8900a42a3 100644 --- a/doc/modules/ROOT/pages/reference/concurrent_node_set.adoc +++ b/doc/modules/ROOT/pages/reference/concurrent_node_set.adoc @@ -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&& other); + template 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 il, size_type n = _implementation-defined_ const hasher& hf = hasher(), @@ -88,6 +94,13 @@ namespace unordered { template 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 R> + xref:#concurrent_node_set_range_constructor_with_allocator[concurrent_node_set](FromRangeT&&, R&& rg, const allocator_type& a); + template 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 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 il, const allocator_type& a); xref:#concurrent_node_set_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_node_set](std::initializer_list 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 bool xref:#concurrent_node_set_transparent_insert[insert](K&& k); template size_type xref:#concurrent_node_set_insert_iterator_range[insert](InputIterator first, InputIterator last); + template 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 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 size_type xref:#concurrent_node_set_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f); + template R, class F> + size_type xref:#concurrent_node_set_insert_range_or_visit[insert_range_or_visit](R&& rg, F f); + template R, class F> + size_type xref:#concurrent_node_set_insert_range_or_visit[insert_range_or_cvisit](R&& rg, F f); template size_type xref:#concurrent_node_set_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list il, F f); template size_type xref:#concurrent_node_set_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list il, F f); template 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 size_type xref:#concurrent_node_set_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2); + template 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 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 size_type xref:#concurrent_node_set_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list il, F1 f1, F2 f2); template @@ -253,6 +276,16 @@ namespace unordered { Hash = Hash(), Pred = Pred(), Allocator = Allocator()) -> concurrent_node_set, Hash, Pred, Allocator>; + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator> + 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, Hash, Pred,Allocator>; + template, class Pred = std::equal_to, class Allocator = std::allocator> concurrent_node_set(std::initializer_list, 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, Hash, std::equal_to>, Allocator>; + template + concurrent_node_set(FromRangeT&&, R&&, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type, Allocator) + -> concurrent_node_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + concurrent_node_set(FromRangeT&&, R&&, Allocator) + -> concurrent_node_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + concurrent_node_set(FromRangeT&&, R&&, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> concurrent_node_set, + Hash, std::equal_to>, Allocator>; template concurrent_node_set(std::initializer_list, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type, Allocator) -> concurrent_node_set, std::equal_to, 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 + concept container_compatible_range = + std::ranges::input_range && + std::convertible_to, 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 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 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 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 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 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(x)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + + ==== Insert Initializer List ```c++ size_type insert(std::initializer_list il); @@ -1128,6 +1282,27 @@ Returns:;; The number of elements inserted. --- +==== Insert Range or Visit +[source,c++,subs="+macros,+quotes"] +---- +template R, class F> + size_type insert_range_or_visit(R&& rg, F f); +template 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(x), std::ref(f)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + ==== Insert Initializer List or Visit ```c++ template size_type insert_or_visit(std::initializer_list il, F f); @@ -1257,6 +1432,28 @@ Returns:;; The number of elements inserted. --- +==== Insert Range and Visit +[source,c++,subs="+macros,+quotes"] +---- +template R, class F1, class F2> + size_type insert_range_and_visit(R&& rg, F1 f1, F2 f2); +template 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(x), std::ref(f1), std::ref(f2)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + ==== Insert Initializer List and Visit ```c++ template @@ -1639,6 +1836,16 @@ template typename std::iterator_traits::value_type; // exposition only ----- +==== __convertible-to-from-range_t__ +[listings,subs="+macros,+quotes"] +----- +template + concept __convertible-to-from_range_t__ = + // first clause not present if std::from_range_t does not exist + std::is_convertible_v || + std::is_convertible_v; // exposition only +----- + === Equality Comparisons ==== operator== diff --git a/doc/modules/ROOT/pages/reference/header_concurrent_flat_map.adoc b/doc/modules/ROOT/pages/reference/header_concurrent_flat_map.adoc index b7412866c..6e937b402 100644 --- a/doc/modules/ROOT/pages/reference/header_concurrent_flat_map.adoc +++ b/doc/modules/ROOT/pages/reference/header_concurrent_flat_map.adoc @@ -19,6 +19,10 @@ namespace unordered { class Allocator = std::allocator>> 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 bool xref:reference/concurrent_flat_map.adoc#concurrent_flat_map_operator[operator++==++](const concurrent_flat_map& x, @@ -39,7 +43,7 @@ namespace unordered { typename concurrent_flat_map::size_type xref:reference/concurrent_flat_map.adoc#concurrent_flat_map_erase_if[erase_if](concurrent_flat_map& c, Predicate pred); - // Pmr aliases (C++17 and up) + // Pmr aliases (pass:[C++17] and up) namespace pmr { template> 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 bool xref:reference/concurrent_flat_set.adoc#concurrent_flat_set_operator[operator++==++](const concurrent_flat_set& x, @@ -38,7 +42,7 @@ namespace unordered { typename concurrent_flat_set::size_type xref:reference/concurrent_flat_set.adoc#concurrent_flat_set_erase_if[erase_if](concurrent_flat_set& c, Predicate pred); - // Pmr aliases (C++17 and up) + // Pmr aliases (pass:[C++17] and up) namespace pmr { template, diff --git a/doc/modules/ROOT/pages/reference/header_concurrent_node_map.adoc b/doc/modules/ROOT/pages/reference/header_concurrent_node_map.adoc index aecf3cbc4..85b3efcbe 100644 --- a/doc/modules/ROOT/pages/reference/header_concurrent_node_map.adoc +++ b/doc/modules/ROOT/pages/reference/header_concurrent_node_map.adoc @@ -19,6 +19,10 @@ namespace unordered { class Allocator = std::allocator>> 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 bool xref:reference/concurrent_node_map.adoc#concurrent_node_map_operator[operator++==++](const concurrent_node_map& x, @@ -39,7 +43,7 @@ namespace unordered { typename concurrent_node_map::size_type xref:reference/concurrent_node_map.adoc#concurrent_node_map_erase_if[erase_if](concurrent_node_map& c, Predicate pred); - // Pmr aliases (C++17 and up) + // Pmr aliases (pass:[C++17] and up) namespace pmr { template> 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 bool xref:reference/concurrent_node_set.adoc#concurrent_node_set_operator[operator++==++](const concurrent_node_set& x, @@ -38,7 +42,7 @@ namespace unordered { typename concurrent_node_set::size_type xref:reference/concurrent_node_set.adoc#concurrent_node_set_erase_if[erase_if](concurrent_node_set& c, Predicate pred); - // Pmr aliases (C++17 and up) + // Pmr aliases (pass:[C++17] and up) namespace pmr { template, diff --git a/doc/modules/ROOT/pages/reference/header_unordered_flat_map.adoc b/doc/modules/ROOT/pages/reference/header_unordered_flat_map.adoc index f3623f3fb..3462f94ae 100644 --- a/doc/modules/ROOT/pages/reference/header_unordered_flat_map.adoc +++ b/doc/modules/ROOT/pages/reference/header_unordered_flat_map.adoc @@ -19,6 +19,10 @@ namespace unordered { class Allocator = std::allocator>> 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 bool xref:reference/unordered_flat_map.adoc#unordered_flat_map_operator_2[operator++==++](const unordered_flat_map& x, @@ -39,7 +43,7 @@ namespace unordered { typename unordered_flat_map::size_type xref:reference/unordered_flat_map.adoc#unordered_flat_map_erase_if[erase_if](unordered_flat_map& c, Predicate pred); - // Pmr aliases (C++17 and up) + // Pmr aliases (pass:[C++17] and up) namespace pmr { template> 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 bool xref:reference/unordered_flat_set.adoc#unordered_flat_set_operator[operator++==++](const unordered_flat_set& x, @@ -38,7 +42,7 @@ namespace unordered { typename unordered_flat_set::size_type xref:reference/unordered_flat_set.adoc#unordered_flat_set_erase_if[erase_if](unordered_flat_set& c, Predicate pred); - // Pmr aliases (C++17 and up) + // Pmr aliases (pass:[C++17] and up) namespace pmr { template, diff --git a/doc/modules/ROOT/pages/reference/header_unordered_map.adoc b/doc/modules/ROOT/pages/reference/header_unordered_map.adoc index be2bfafc5..9b2e6a63c 100644 --- a/doc/modules/ROOT/pages/reference/header_unordered_map.adoc +++ b/doc/modules/ROOT/pages/reference/header_unordered_map.adoc @@ -20,6 +20,10 @@ namespace unordered { class Allocator = std::allocator>> 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 bool xref:reference/unordered_map.adoc#unordered_map_operator_2[operator++==++](const unordered_map& x, @@ -67,7 +71,7 @@ namespace unordered { typename unordered_multimap::size_type xref:reference/unordered_multimap.adoc#unordered_multimap_erase_if[erase_if](unordered_multimap& c, Predicate pred); - // Pmr aliases (C++17 and up) + // Pmr aliases (pass:[C++17] and up) namespace pmr { template>> 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 bool xref:reference/unordered_node_map.adoc#unordered_node_map_operator_2[operator++==++](const unordered_node_map& x, @@ -39,7 +43,7 @@ namespace unordered { typename unordered_node_map::size_type xref:reference/unordered_node_map.adoc#unordered_node_map_erase_if[erase_if](unordered_node_map& c, Predicate pred); - // Pmr aliases (C++17 and up) + // Pmr aliases (pass:[C++17] and up) namespace pmr { template> 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 bool xref:reference/unordered_node_set.adoc#unordered_node_set_operator[operator++==++](const unordered_node_set& x, @@ -38,7 +42,7 @@ namespace unordered { typename unordered_node_set::size_type xref:reference/unordered_node_set.adoc#unordered_node_set_erase_if[erase_if](unordered_node_set& c, Predicate pred); - // Pmr aliases (C++17 and up) + // Pmr aliases (pass:[C++17] and up) namespace pmr { template, diff --git a/doc/modules/ROOT/pages/reference/header_unordered_set.adoc b/doc/modules/ROOT/pages/reference/header_unordered_set.adoc index b61dd5a6d..b153bba28 100644 --- a/doc/modules/ROOT/pages/reference/header_unordered_set.adoc +++ b/doc/modules/ROOT/pages/reference/header_unordered_set.adoc @@ -19,6 +19,10 @@ namespace unordered { class Allocator = std::allocator> 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 bool xref:reference/unordered_set.adoc#unordered_set_operator[operator++==++](const unordered_set& x, @@ -65,7 +69,7 @@ namespace unordered { typename unordered_multiset::size_type xref:reference/unordered_multiset.adoc#unordered_multiset_erase_if[erase_if](unordered_multiset& c, Predicate pred); - // Pmr aliases (C++17 and up) + // Pmr aliases (pass:[C++17] and up) namespace pmr { template, diff --git a/doc/modules/ROOT/pages/reference/unordered_flat_map.adoc b/doc/modules/ROOT/pages/reference/unordered_flat_map.adoc index c7a7b399d..ccf19d0d2 100644 --- a/doc/modules/ROOT/pages/reference/unordered_flat_map.adoc +++ b/doc/modules/ROOT/pages/reference/unordered_flat_map.adoc @@ -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&& other); + template 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 il, size_type n = _implementation-defined_ const hasher& hf = hasher(), @@ -94,6 +100,13 @@ namespace unordered { template 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 R> + xref:#unordered_flat_map_range_constructor_with_allocator[unordered_flat_map](FromRangeT&&, R&& rg, const allocator_type& a); + template 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 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 il, const allocator_type& a); xref:#unordered_flat_map_initializer_list_constructor_with_bucket_count_and_allocator[unordered_flat_map](std::initializer_list 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 void xref:#unordered_flat_map_insert_iterator_range[insert](InputIterator first, InputIterator last); + template R> + void xref:#unordered_flat_map_insert_range[insert_range](R&& rg); void xref:#unordered_flat_map_insert_initializer_list[insert](std::initializer_list); template @@ -235,6 +250,17 @@ namespace unordered { -> unordered_flat_map, xref:#unordered_flat_map_iter_mapped_type[__iter-mapped-type__], Hash, Pred, Allocator>; + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + 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_mapped_type[__range-mapped-type__], + Hash, Pred,Allocator>; + template, class Pred = std::equal_to, class Allocator = std::allocator>> @@ -261,6 +287,27 @@ namespace unordered { -> unordered_flat_map, xref:#unordered_flat_map_iter_mapped_type[__iter-mapped-type__], Hash, std::equal_to>, Allocator>; + template + 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_mapped_type[__range-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_flat_map(FromRangeT&&, R&&, Allocator) + -> unordered_flat_map, xref:#unordered_flat_map_range_mapped_type[__range-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + 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_mapped_type[__range-mapped-type__], + Hash, std::equal_to>, Allocator>; + template unordered_flat_map(std::initializer_list>, 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 + concept container_compatible_range = + std::ranges::input_range && + std::convertible_to, 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 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 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 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 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 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 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); @@ -1445,6 +1590,42 @@ template std::tuple_element_t<1, xref:#unordered_flat_map_iter_value_type[__iter-value-type__]>>; // exposition only ----- +==== __convertible-to-from-range_t__ +[listings,subs="+macros,+quotes"] +----- +template + concept __convertible-to-from_range_t__ = + // first clause not present if std::from_range_t does not exist + std::is_convertible_v || + std::is_convertible_v; // exposition only +----- + +==== __range-key-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-key-type__ = + std::remove_cvref_t< + std::tuple_element_t<0, std::ranges::range_value_t>>; // exposition only +----- + +==== __range-mapped-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-mapped-type__ = + std::remove_cvref_t< + std::tuple_element_t<1, std::ranges::range_value_t>>; // exposition only +----- + +==== __range-to-alloc-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-to-alloc-type__ = + std::pair, xref:#unordered_flat_map_range_mapped_type[__range-mapped-type__]>; // exposition only +----- + === Equality Comparisons ==== operator== diff --git a/doc/modules/ROOT/pages/reference/unordered_flat_set.adoc b/doc/modules/ROOT/pages/reference/unordered_flat_set.adoc index 5265c3cd5..b40346828 100644 --- a/doc/modules/ROOT/pages/reference/unordered_flat_set.adoc +++ b/doc/modules/ROOT/pages/reference/unordered_flat_set.adoc @@ -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&& other); + template 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 il, size_type n = _implementation-defined_ const hasher& hf = hasher(), @@ -88,6 +94,13 @@ namespace unordered { template 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 R> + xref:#unordered_flat_set_range_constructor_with_allocator[unordered_flat_set](FromRangeT&&, R&& rg, const allocator_type& a); + template 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 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 il, const allocator_type& a); xref:#unordered_flat_set_initializer_list_constructor_with_bucket_count_and_allocator[unordered_flat_set](std::initializer_list 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 iterator xref:#unordered_flat_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k); template void xref:#unordered_flat_set_insert_iterator_range[insert](InputIterator first, InputIterator last); + template R> + void xref:#unordered_flat_set_insert_range[insert_range](R&& rg); void xref:#unordered_flat_set_insert_initializer_list[insert](std::initializer_list); _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, Hash, Pred, Allocator>; + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator> + 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, Hash, Pred,Allocator>; + template, class Pred = std::equal_to, class Allocator = std::allocator> unordered_flat_set(std::initializer_list, 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, Hash, std::equal_to>, Allocator>; + template + unordered_flat_set(FromRangeT&&, R&&, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_flat_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_flat_set(FromRangeT&&, R&&, Allocator) + -> unordered_flat_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_flat_set(FromRangeT&&, R&&, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> unordered_flat_set, + Hash, std::equal_to>, Allocator>; + template unordered_flat_set(std::initializer_list, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Allocator) -> unordered_flat_set, std::equal_to, Allocator>; @@ -307,6 +353,15 @@ The iterator category is at least a forward iterator. === Constructors +==== __container-compatible-range__ +[listings,subs="+macros,+quotes"] +----- +template + concept container_compatible_range = + std::ranges::input_range && + std::convertible_to, 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 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 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 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 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 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 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 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); @@ -1194,6 +1338,16 @@ template typename std::iterator_traits::value_type; // exposition only ----- +==== __convertible-to-from-range_t__ +[listings,subs="+macros,+quotes"] +----- +template + concept __convertible-to-from_range_t__ = + // first clause not present if std::from_range_t does not exist + std::is_convertible_v || + std::is_convertible_v; // exposition only +----- + === Equality Comparisons ==== operator== diff --git a/doc/modules/ROOT/pages/reference/unordered_map.adoc b/doc/modules/ROOT/pages/reference/unordered_map.adoc index f26a511d1..424e14dd3 100644 --- a/doc/modules/ROOT/pages/reference/unordered_map.adoc +++ b/doc/modules/ROOT/pages/reference/unordered_map.adoc @@ -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 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 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 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 R> + xref:#unordered_map_range_constructor_with_allocator[unordered_map](FromRangeT&&, R&& rg, const allocator_type& a); + template R> + xref:#unordered_map_range_constructor_with_bucket_count_and_allocator[unordered_map](FromRangeT&&, R&& rg, size_type n, const allocator_type& a); + template 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 il, const allocator_type& a); xref:#unordered_map_initializer_list_constructor_with_bucket_count_and_allocator[unordered_map](std::initializer_list 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 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 iterator xref:#unordered_map_emplace_insert_with_hint[insert](const_iterator hint, P&& obj); template void xref:#unordered_map_insert_iterator_range[insert](InputIterator first, InputIterator last); + template R> + void xref:#unordered_map_insert_range[insert_range](R&& rg); void xref:#unordered_map_insert_initializer_list[insert](std::initializer_list); template @@ -231,8 +246,19 @@ namespace unordered { class Allocator = std::allocator>> 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_mapped_type[__iter-mapped-type__], Hash, Pred, - Allocator>; + -> unordered_map, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__], + Hash, Pred, Allocator>; + + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + 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_mapped_type[__range-mapped-type__], + Hash, Pred,Allocator>; template, class Pred = std::equal_to, @@ -259,6 +285,27 @@ namespace unordered { -> unordered_map, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__], Hash, std::equal_to>, Allocator>; + template + unordered_map(FromRangeT&&, R&&, typename xref:#unordered_map_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_map, xref:#unordered_map_range_mapped_type[__range-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_map(FromRangeT&&, R&&, Allocator) + -> unordered_map, xref:#unordered_map_range_mapped_type[__range-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_map(FromRangeT&&, R&&, typename xref:#unordered_map_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> unordered_map, xref:#unordered_map_range_mapped_type[__range-mapped-type__], + Hash, std::equal_to>, Allocator>; + template unordered_map(std::initializer_list>, 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 + concept container_compatible_range = + std::ranges::input_range && + std::convertible_to, 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 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 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 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 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 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 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); @@ -1697,6 +1844,42 @@ template std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]>>; // exposition only ----- +==== __convertible-to-from-range_t__ +[listings,subs="+macros,+quotes"] +----- +template + concept __convertible-to-from_range_t__ = + // first clause not present if std::from_range_t does not exist + std::is_convertible_v || + std::is_convertible_v; // exposition only +----- + +==== __range-key-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-key-type__ = + std::remove_cvref_t< + std::tuple_element_t<0, std::ranges::range_value_t>>; // exposition only +----- + +==== __range-mapped-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-mapped-type__ = + std::remove_cvref_t< + std::tuple_element_t<1, std::ranges::range_value_t>>; // exposition only +----- + +==== __range-to-alloc-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-to-alloc-type__ = + std::pair, xref:#unordered_map_range_mapped_type[__range-mapped-type__]>; // exposition only +----- + === Equality Comparisons ==== operator== diff --git a/doc/modules/ROOT/pages/reference/unordered_multimap.adoc b/doc/modules/ROOT/pages/reference/unordered_multimap.adoc index e35e6caf4..f9edf183d 100644 --- a/doc/modules/ROOT/pages/reference/unordered_multimap.adoc +++ b/doc/modules/ROOT/pages/reference/unordered_multimap.adoc @@ -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 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 il, size_type n = _implementation-defined_, const hasher& hf = hasher(), @@ -72,6 +78,13 @@ namespace unordered { template 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 R> + xref:#unordered_multimap_range_constructor_with_allocator[unordered_multimap](FromRangeT&&, R&& rg, const allocator_type& a); + template R> + xref:#unordered_multimap_range_constructor_with_bucket_count_and_allocator[unordered_multimap](FromRangeT&&, R&& rg, size_type n, const allocator_type& a); + template 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 il, const allocator_type& a); xref:#unordered_multimap_initializer_list_constructor_with_bucket_count_and_allocator[unordered_multimap](std::initializer_list 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 iterator xref:#unordered_multimap_emplace_insert_with_hint[insert](const_iterator hint, P&& obj); template void xref:#unordered_multimap_insert_iterator_range[insert](InputIterator first, InputIterator last); + template R> + void xref:#unordered_multimap_insert_range[insert_range](R&& rg); void xref:#unordered_multimap_insert_initializer_list[insert](std::initializer_list 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_mapped_type[__iter-mapped-type__], Hash, Pred, Allocator>; + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + 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_mapped_type[__range-mapped-type__], + Hash, Pred,Allocator>; + template, class Pred = std::equal_to, class Allocator = std::allocator>> @@ -226,6 +252,27 @@ namespace unordered { -> unordered_multimap, xref:#unordered_multimap_iter_mapped_type[__iter-mapped-type__], Hash, std::equal_to>, Allocator>; + template + unordered_multimap(FromRangeT&&, R&&, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_multimap, xref:#unordered_multimap_range_mapped_type[__range-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_multimap(FromRangeT&&, R&&, Allocator) + -> unordered_multimap, xref:#unordered_multimap_range_mapped_type[__range-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_multimap(FromRangeT&&, R&&, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> unordered_multimap, xref:#unordered_multimap_range_mapped_type[__range-mapped-type__], + Hash, std::equal_to>, Allocator>; + template unordered_multimap(std::initializer_list>, 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 + concept container_compatible_range = + std::ranges::input_range && + std::convertible_to, 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 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 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 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 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 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 il); @@ -1414,6 +1562,42 @@ template std::tuple_element_t<1, xref:#unordered_multimap_iter_value_type[__iter-value-type__]>>; // exposition only ----- +==== __convertible-to-from-range_t__ +[listings,subs="+macros,+quotes"] +----- +template + concept __convertible-to-from_range_t__ = + // first clause not present if std::from_range_t does not exist + std::is_convertible_v || + std::is_convertible_v; // exposition only +----- + +==== __range-key-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-key-type__ = + std::remove_cvref_t< + std::tuple_element_t<0, std::ranges::range_value_t>>; // exposition only +----- + +==== __range-mapped-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-mapped-type__ = + std::remove_cvref_t< + std::tuple_element_t<1, std::ranges::range_value_t>>; // exposition only +----- + +==== __range-to-alloc-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-to-alloc-type__ = + std::pair, xref:#unordered_multimap_range_mapped_type[__range-mapped-type__]>; // exposition only +----- + === Equality Comparisons ==== operator== diff --git a/doc/modules/ROOT/pages/reference/unordered_multiset.adoc b/doc/modules/ROOT/pages/reference/unordered_multiset.adoc index da8ae7348..e35efe414 100644 --- a/doc/modules/ROOT/pages/reference/unordered_multiset.adoc +++ b/doc/modules/ROOT/pages/reference/unordered_multiset.adoc @@ -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 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 il, size_type n = _implementation-defined_, const hasher& hf = hasher(), @@ -70,6 +76,13 @@ namespace unordered { template 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 R> + xref:#unordered_multiset_range_constructor_with_allocator[unordered_multiset](FromRangeT&&, R&& rg, const allocator_type& a); + template R> + xref:#unordered_multiset_range_constructor_with_bucket_count_and_allocator[unordered_multiset](FromRangeT&&, R&& rg, size_type n, const allocator_type& a); + template 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 il, const allocator_type& a); xref:#unordered_multiset_initializer_list_constructor_with_bucket_count_and_allocator[unordered_multiset](std::initializer_list 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 void xref:#unordered_multiset_insert_iterator_range[insert](InputIterator first, InputIterator last); + template R> + void xref:#unordered_multiset_insert_range[insert_range](R&& rg); void xref:#unordered_multiset_insert_initializer_list[insert](std::initializer_list 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, Hash, Pred, Allocator>; + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator> + 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, Hash, Pred,Allocator>; + template, class Pred = std::equal_to, class Allocator = std::allocator> unordered_multiset(std::initializer_list, 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, Hash, std::equal_to>, Allocator>; + template + unordered_multiset(FromRangeT&&, R&&, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_multiset, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_multiset(FromRangeT&&, R&&, Allocator) + -> unordered_multiset, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_multiset(FromRangeT&&, R&&, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> unordered_multiset, + Hash, std::equal_to>, Allocator>; + template unordered_multiset(std::initializer_list, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Allocator) -> unordered_multiset, std::equal_to, Allocator>; @@ -329,6 +375,15 @@ See node_handle_set for details. === Constructors +==== __container-compatible-range__ +[listings,subs="+macros,+quotes"] +----- +template + concept container_compatible_range = + std::ranges::input_range && + std::convertible_to, 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 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 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 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 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 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 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 typename std::iterator_traits::value_type; // exposition only ----- +==== __convertible-to-from-range_t__ +[listings,subs="+macros,+quotes"] +----- +template + concept __convertible-to-from_range_t__ = + // first clause not present if std::from_range_t does not exist + std::is_convertible_v || + std::is_convertible_v; // exposition only +----- + === Equality Comparisons ==== operator== diff --git a/doc/modules/ROOT/pages/reference/unordered_node_map.adoc b/doc/modules/ROOT/pages/reference/unordered_node_map.adoc index 525037332..bdc0ab4bc 100644 --- a/doc/modules/ROOT/pages/reference/unordered_node_map.adoc +++ b/doc/modules/ROOT/pages/reference/unordered_node_map.adoc @@ -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&& other); + template 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 il, size_type n = _implementation-defined_ const hasher& hf = hasher(), @@ -93,6 +99,13 @@ namespace unordered { template 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 R> + xref:#unordered_node_map_range_constructor_with_allocator[unordered_node_map](FromRangeT&&, R&& rg, const allocator_type& a); + template 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 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 il, const allocator_type& a); xref:#unordered_node_map_initializer_list_constructor_with_bucket_count_and_allocator[unordered_node_map](std::initializer_list 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 void xref:#unordered_node_map_insert_iterator_range[insert](InputIterator first, InputIterator last); + template R> + void xref:#unordered_node_map_insert_range[insert_range](R&& rg); void xref:#unordered_node_map_insert_initializer_list[insert](std::initializer_list); 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_mapped_type[__iter-mapped-type__], Hash, Pred, Allocator>; + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + 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_mapped_type[__range-mapped-type__], + Hash, Pred,Allocator>; + template, class Pred = std::equal_to, class Allocator = std::allocator>> @@ -265,6 +291,27 @@ namespace unordered { -> unordered_node_map, xref:#unordered_node_map_iter_mapped_type[__iter-mapped-type__], Hash, std::equal_to>, Allocator>; + template + 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_mapped_type[__range-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_node_map(FromRangeT&&, R&&, Allocator) + -> unordered_node_map, xref:#unordered_node_map_range_mapped_type[__range-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + 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_mapped_type[__range-mapped-type__], + Hash, std::equal_to>, Allocator>; + template unordered_node_map(std::initializer_list>, 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 + concept container_compatible_range = + std::ranges::input_range && + std::convertible_to, 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 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 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 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 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 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 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); @@ -1549,6 +1694,42 @@ template std::tuple_element_t<1, xref:#unordered_node_map_iter_value_type[__iter-value-type__]>>; // exposition only ----- +==== __convertible-to-from-range_t__ +[listings,subs="+macros,+quotes"] +----- +template + concept __convertible-to-from_range_t__ = + // first clause not present if std::from_range_t does not exist + std::is_convertible_v || + std::is_convertible_v; // exposition only +----- + +==== __range-key-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-key-type__ = + std::remove_cvref_t< + std::tuple_element_t<0, std::ranges::range_value_t>>; // exposition only +----- + +==== __range-mapped-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-mapped-type__ = + std::remove_cvref_t< + std::tuple_element_t<1, std::ranges::range_value_t>>; // exposition only +----- + +==== __range-to-alloc-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __range-to-alloc-type__ = + std::pair, xref:#unordered_node_map_range_mapped_type[__range-mapped-type__]>; // exposition only +----- + === Equality Comparisons ==== operator== diff --git a/doc/modules/ROOT/pages/reference/unordered_node_set.adoc b/doc/modules/ROOT/pages/reference/unordered_node_set.adoc index 846322b5f..a79182c3f 100644 --- a/doc/modules/ROOT/pages/reference/unordered_node_set.adoc +++ b/doc/modules/ROOT/pages/reference/unordered_node_set.adoc @@ -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&& other); + template 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 il, size_type n = _implementation-defined_ const hasher& hf = hasher(), @@ -88,6 +94,13 @@ namespace unordered { template 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 R> + xref:#unordered_node_set_range_constructor_with_allocator[unordered_node_set](FromRangeT&&, R&& rg, const allocator_type& a); + template 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 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 il, const allocator_type& a); xref:#unordered_node_set_initializer_list_constructor_with_bucket_count_and_allocator[unordered_node_set](std::initializer_list 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 iterator xref:#unordered_node_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k); template void xref:#unordered_node_set_insert_iterator_range[insert](InputIterator first, InputIterator last); + template R> + void xref:#unordered_node_set_insert_range[insert_range](R&& rg); void xref:#unordered_node_set_insert_initializer_list[insert](std::initializer_list); 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, Hash, Pred, Allocator>; + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator> + 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, Hash, Pred,Allocator>; + template, class Pred = std::equal_to, class Allocator = std::allocator> unordered_node_set(std::initializer_list, 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, Hash, std::equal_to>, Allocator>; + template + unordered_node_set(FromRangeT&&, R&&, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_node_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_node_set(FromRangeT&&, R&&, Allocator) + -> unordered_node_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_node_set(FromRangeT&&, R&&, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> unordered_node_set, + Hash, std::equal_to>, Allocator>; + template unordered_node_set(std::initializer_list, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type, Allocator) -> unordered_node_set, std::equal_to, Allocator>; @@ -345,6 +391,15 @@ with `Iterator` = `iterator` and `NodeType` = `node_type`. === Constructors +==== __container-compatible-range__ +[listings,subs="+macros,+quotes"] +----- +template + concept container_compatible_range = + std::ranges::input_range && + std::convertible_to, 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 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 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 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 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 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 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); @@ -1302,6 +1446,16 @@ template typename std::iterator_traits::value_type; // exposition only ----- +==== __convertible-to-from-range_t__ +[listings,subs="+macros,+quotes"] +----- +template + concept __convertible-to-from_range_t__ = + // first clause not present if std::from_range_t does not exist + std::is_convertible_v || + std::is_convertible_v; // exposition only +----- + === Equality Comparisons ==== operator== diff --git a/doc/modules/ROOT/pages/reference/unordered_set.adoc b/doc/modules/ROOT/pages/reference/unordered_set.adoc index c21fed883..1e7538bf4 100644 --- a/doc/modules/ROOT/pages/reference/unordered_set.adoc +++ b/doc/modules/ROOT/pages/reference/unordered_set.adoc @@ -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 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 il, size_type n = _implementation-defined_, const hasher& hf = hasher(), @@ -71,6 +77,13 @@ namespace unordered { template 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 R> + xref:#unordered_set_range_constructor_with_allocator[unordered_set](FromRangeT&&, R&& rg, const allocator_type& a); + template R> + xref:#unordered_set_range_constructor_with_bucket_count_and_allocator[unordered_set](FromRangeT&&, R&& rg, size_type n, const allocator_type& a); + template 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 il, const allocator_type& a); xref:#unordered_set_initializer_list_constructor_with_bucket_count_and_allocator[unordered_set](std::initializer_list 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 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 iterator xref:#unordered_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k); template void xref:#unordered_set_insert_iterator_range[insert](InputIterator first, InputIterator last); + template R> + void xref:#unordered_set_insert_range[insert_range](R&& rg); void xref:#unordered_set_insert_initializer_list[insert](std::initializer_list); 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, Hash, Pred, Allocator>; + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator> + 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, Hash, Pred,Allocator>; + template, class Pred = std::equal_to, class Allocator = std::allocator> unordered_set(std::initializer_list, 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, Hash, std::equal_to>, Allocator>; + template + unordered_set(FromRangeT&&, R&&, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_set(FromRangeT&&, R&&, Allocator) + -> unordered_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_set(FromRangeT&&, R&&, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> unordered_set, + Hash, std::equal_to>, Allocator>; + template unordered_set(std::initializer_list, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Allocator) -> unordered_set, std::equal_to, Allocator>; @@ -353,6 +399,16 @@ with `Iterator` = `iterator` and `NodeType` = `node_type`. === Constructors +==== __container-compatible-range__ +[listings,subs="+macros,+quotes"] +----- +template + concept container_compatible_range = + std::ranges::input_range && + std::convertible_to, 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 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 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 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 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 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); @@ -1424,6 +1571,16 @@ template typename std::iterator_traits::value_type; // exposition only ----- +==== __convertible-to-from-range_t__ +[listings,subs="+macros,+quotes"] +----- +template + concept __convertible-to-from_range_t__ = + // first clause not present if std::from_range_t does not exist + std::is_convertible_v || + std::is_convertible_v; // exposition only +----- + === Equality Comparisons ==== operator== diff --git a/include/boost/unordered/concurrent_flat_map.hpp b/include/boost/unordered/concurrent_flat_map.hpp index 7ba2286a0..002ac6666 100644 --- a/include/boost/unordered/concurrent_flat_map.hpp +++ b/include/boost/unordered/concurrent_flat_map.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -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 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(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 R + > + concurrent_flat_map( + FromRangeT&& fr, R&& rg, allocator_type const& a) + : concurrent_flat_map( + fr, std::forward(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 R + > + concurrent_flat_map( + FromRangeT&& fr, R&& rg, size_type n, const allocator_type& a) + : concurrent_flat_map( + fr, std::forward(rg), n, hasher(), key_equal(), a) + { + } + + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + concurrent_flat_map(FromRangeT&& fr, R&& rg, size_type n, + const hasher& hf, const allocator_type& a) + : concurrent_flat_map(fr, std::forward(rg), n, hf, key_equal(), a) + { + } +#endif + concurrent_flat_map( std::initializer_list il, const allocator_type& a) : concurrent_flat_map( @@ -430,6 +482,20 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template 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 ilist) { return this->insert(ilist.begin(), ilist.end()); @@ -485,6 +551,21 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template 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 size_type insert_or_visit(std::initializer_list ilist, F f) { @@ -518,6 +599,21 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template 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 size_type insert_or_cvisit(std::initializer_list ilist, F f) { @@ -555,6 +651,24 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template< + detail::container_compatible_range 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 size_type insert_and_visit( std::initializer_list 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 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 size_type insert_and_cvisit( std::initializer_list ilist, F1 f1, F2 f2) @@ -980,6 +1112,27 @@ namespace boost { boost::unordered::detail::iter_val_t, 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 >, + class Pred = + std::equal_to >, + class Allocator = std::allocator< + boost::unordered::detail::range_to_alloc_t >, + class = std::enable_if_t >, + class = std::enable_if_t >, + class = std::enable_if_t > > + 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_mapped_t, Hash, Pred, + Allocator>; +#endif + template >, class Pred = std::equal_to >, @@ -1027,6 +1180,42 @@ namespace boost { std::equal_to >, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + concurrent_flat_map(FromRangeT&&, R&&, std::size_t, Allocator) + -> concurrent_flat_map, + boost::unordered::detail::range_mapped_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template > > + concurrent_flat_map(FromRangeT&&, R&&, Allocator) + -> concurrent_flat_map, + boost::unordered::detail::range_mapped_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template >, + class = std::enable_if_t > > + concurrent_flat_map( + FromRangeT&&, R&&, std::size_t, Hash, Allocator) + -> concurrent_flat_map, + boost::unordered::detail::range_mapped_t, Hash, + std::equal_to >, + Allocator>; +#endif + template > > concurrent_flat_map(std::initializer_list >, std::size_t, diff --git a/include/boost/unordered/concurrent_flat_set.hpp b/include/boost/unordered/concurrent_flat_set.hpp index 162c4c283..3499d4378 100644 --- a/include/boost/unordered/concurrent_flat_set.hpp +++ b/include/boost/unordered/concurrent_flat_set.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -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 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(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 R + > + concurrent_flat_set( + FromRangeT&& fr, R&& rg, allocator_type const& a) + : concurrent_flat_set( + fr, std::forward(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 R + > + concurrent_flat_set( + FromRangeT&& fr, R&& rg, size_type n, const allocator_type& a) + : concurrent_flat_set( + fr, std::forward(rg), n, hasher(), key_equal(), a) + { + } + + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + concurrent_flat_set(FromRangeT&& fr, R&& rg, size_type n, + const hasher& hf, const allocator_type& a) + : concurrent_flat_set(fr, std::forward(rg), n, hf, key_equal(), a) + { + } +#endif + concurrent_flat_set( std::initializer_list il, const allocator_type& a) : concurrent_flat_set( @@ -436,6 +488,20 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template 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 ilist) { return this->insert(ilist.begin(), ilist.end()); @@ -476,6 +542,21 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template 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 size_type insert_or_visit(std::initializer_list ilist, F f) { @@ -518,6 +599,21 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template 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 size_type insert_or_cvisit(std::initializer_list ilist, F f) { @@ -566,6 +662,24 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template< + detail::container_compatible_range 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 size_type insert_and_visit(std::initializer_list 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 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 size_type insert_and_cvisit( std::initializer_list ilist, F1 f1, F2 f2) @@ -853,6 +985,25 @@ namespace boost { typename std::iterator_traits::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 >, + class Pred = + std::equal_to >, + class Allocator = std::allocator >, + class = std::enable_if_t >, + class = std::enable_if_t >, + class = std::enable_if_t > > + concurrent_flat_set(FromRangeT&&, R&&, + std::size_t = boost::unordered::detail::foa::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> concurrent_flat_set, + Hash, Pred, Allocator>; +#endif + template , class Pred = std::equal_to, class Allocator = std::allocator, class = std::enable_if_t >, @@ -894,6 +1045,39 @@ namespace boost { std::equal_to::value_type>, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + concurrent_flat_set(FromRangeT&&, R&&, std::size_t, Allocator) + -> concurrent_flat_set, + boost::hash >, + std::equal_to >, + Allocator>; + + template >, + class = std::enable_if_t > > + concurrent_flat_set( + FromRangeT&&, R&&, std::size_t, Hash, Allocator) + -> concurrent_flat_set, + Hash, std::equal_to >, + Allocator>; + + template > > + concurrent_flat_set(FromRangeT&&, R&&, Allocator) + -> concurrent_flat_set, + boost::hash >, + std::equal_to >, + Allocator>; +#endif + template > > concurrent_flat_set(std::initializer_list, std::size_t, Allocator) diff --git a/include/boost/unordered/concurrent_node_map.hpp b/include/boost/unordered/concurrent_node_map.hpp index 50f667bc3..1cfbf5dbd 100644 --- a/include/boost/unordered/concurrent_node_map.hpp +++ b/include/boost/unordered/concurrent_node_map.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -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 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(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 R + > + concurrent_node_map( + FromRangeT&& fr, R&& rg, allocator_type const& a) + : concurrent_node_map( + fr, std::forward(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 R + > + concurrent_node_map( + FromRangeT&& fr, R&& rg, size_type n, const allocator_type& a) + : concurrent_node_map( + fr, std::forward(rg), n, hasher(), key_equal(), a) + { + } + + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + concurrent_node_map(FromRangeT&& fr, R&& rg, size_type n, + const hasher& hf, const allocator_type& a) + : concurrent_node_map(fr, std::forward(rg), n, hf, key_equal(), a) + { + } +#endif + concurrent_node_map( std::initializer_list il, const allocator_type& a) : concurrent_node_map( @@ -438,6 +490,20 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template 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 ilist) { return this->insert(ilist.begin(), ilist.end()); @@ -512,6 +578,21 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template 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 size_type insert_or_visit(std::initializer_list ilist, F f) { @@ -566,6 +647,21 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template 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 size_type insert_or_cvisit(std::initializer_list ilist, F f) { @@ -624,6 +720,24 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template< + detail::container_compatible_range 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 size_type insert_and_visit( std::initializer_list 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 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 size_type insert_and_cvisit( std::initializer_list ilist, F1 f1, F2 f2) @@ -1128,6 +1260,27 @@ namespace boost { boost::unordered::detail::iter_val_t, 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 >, + class Pred = + std::equal_to >, + class Allocator = std::allocator< + boost::unordered::detail::range_to_alloc_t >, + class = std::enable_if_t >, + class = std::enable_if_t >, + class = std::enable_if_t > > + 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_mapped_t, Hash, Pred, + Allocator>; +#endif + template >, class Pred = std::equal_to >, @@ -1175,6 +1328,42 @@ namespace boost { std::equal_to >, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + concurrent_node_map(FromRangeT&&, R&&, std::size_t, Allocator) + -> concurrent_node_map, + boost::unordered::detail::range_mapped_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template > > + concurrent_node_map(FromRangeT&&, R&&, Allocator) + -> concurrent_node_map, + boost::unordered::detail::range_mapped_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template >, + class = std::enable_if_t > > + concurrent_node_map( + FromRangeT&&, R&&, std::size_t, Hash, Allocator) + -> concurrent_node_map, + boost::unordered::detail::range_mapped_t, Hash, + std::equal_to >, + Allocator>; +#endif + template > > concurrent_node_map(std::initializer_list >, std::size_t, diff --git a/include/boost/unordered/concurrent_node_set.hpp b/include/boost/unordered/concurrent_node_set.hpp index 3cdcd947f..fbfa4d1d9 100644 --- a/include/boost/unordered/concurrent_node_set.hpp +++ b/include/boost/unordered/concurrent_node_set.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -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 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(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 R + > + concurrent_node_set( + FromRangeT&& fr, R&& rg, allocator_type const& a) + : concurrent_node_set( + fr, std::forward(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 R + > + concurrent_node_set( + FromRangeT&& fr, R&& rg, size_type n, const allocator_type& a) + : concurrent_node_set( + fr, std::forward(rg), n, hasher(), key_equal(), a) + { + } + + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + concurrent_node_set(FromRangeT&& fr, R&& rg, size_type n, + const hasher& hf, const allocator_type& a) + : concurrent_node_set(fr, std::forward(rg), n, hf, key_equal(), a) + { + } +#endif + concurrent_node_set( std::initializer_list il, const allocator_type& a) : concurrent_node_set( @@ -444,6 +496,20 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template 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 ilist) { return this->insert(ilist.begin(), ilist.end()); @@ -503,6 +569,21 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template 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 size_type insert_or_visit(std::initializer_list ilist, F f) { @@ -566,6 +647,21 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template 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 size_type insert_or_cvisit(std::initializer_list ilist, F f) { @@ -635,6 +731,24 @@ namespace boost { return count_elements; } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template< + detail::container_compatible_range 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 size_type insert_and_visit( std::initializer_list 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 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 size_type insert_and_cvisit( std::initializer_list ilist, F1 f1, F2 f2) @@ -1002,6 +1134,26 @@ namespace boost { typename std::iterator_traits::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 >, + class Pred = + std::equal_to >, + class Allocator = std::allocator >, + class = std::enable_if_t >, + class = std::enable_if_t >, + class = std::enable_if_t > > + concurrent_node_set(FromRangeT&&, R&&, + std::size_t = boost::unordered::detail::foa::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> concurrent_node_set, + Hash, Pred, Allocator>; +#endif + + template , class Pred = std::equal_to, class Allocator = std::allocator, class = std::enable_if_t >, @@ -1043,6 +1195,39 @@ namespace boost { std::equal_to::value_type>, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + concurrent_node_set(FromRangeT&&, R&&, std::size_t, Allocator) + -> concurrent_node_set, + boost::hash >, + std::equal_to >, + Allocator>; + + template >, + class = std::enable_if_t > > + concurrent_node_set( + FromRangeT&&, R&&, std::size_t, Hash, Allocator) + -> concurrent_node_set, + Hash, std::equal_to >, + Allocator>; + + template > > + concurrent_node_set(FromRangeT&&, R&&, Allocator) + -> concurrent_node_set, + boost::hash >, + std::equal_to >, + Allocator>; +#endif + template > > concurrent_node_set(std::initializer_list, std::size_t, Allocator) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index b6ce49fe5..16e36493e 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -175,6 +176,29 @@ namespace boost { boost::unordered::detail::insert_size(i, j), num_buckets); } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template + inline std::size_t insert_size(R&& rg) + { + if constexpr (std::ranges::sized_range) + return std::ranges::size(std::forward(rg)); + else if constexpr (std::ranges::forward_range) + return std::ranges::distance(std::forward(rg)); + else + return 1; + } + + template + 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(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 - void insert_range_unique(no_key, InputIt i, InputIt j) + template + 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 + template typename boost::unordered::detail::enable_if_forward::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::ranges::distance(i, j)); +#else std::size_t distance = static_cast(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 + template typename boost::unordered::detail::disable_if_forward::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( diff --git a/include/boost/unordered/detail/ranges_support.hpp b/include/boost/unordered/detail/ranges_support.hpp new file mode 100644 index 000000000..ca61ec47e --- /dev/null +++ b/include/boost/unordered/detail/ranges_support.hpp @@ -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 +#include + +#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 +#include +#include +#include +#include +#include + +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 +concept convertible_to_from_range_t = + std::is_convertible_v || + std::is_convertible_v::from_range_t_type>; + +template +concept container_compatible_range = + std::ranges::input_range && + std::convertible_to, T>; + +template +using range_key_t = + std::remove_cvref_t< + std::tuple_element_t<0, std::ranges::range_value_t>>; + +template +using range_mapped_t = + std::remove_cvref_t< + std::tuple_element_t<1, std::ranges::range_value_t>>; + +template +using range_to_alloc_t = + std::pair, range_mapped_t>; + +} /* namespace detail */ +} /* namespace unordered */ +} /* namespace boost */ + +#endif /* !defined(BOOST_UNORDERED_NO_RANGES) */ +#endif diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index e478314af..18d07ea79 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -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 #include #include +#include #include #include #include @@ -108,6 +109,19 @@ namespace boost { { } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_flat_map( + FromRangeT&& fr, R&& rg, allocator_type const& a) + : unordered_flat_map( + fr, std::forward(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 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(rg)); + } + + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_flat_map( + FromRangeT&& fr, R&& rg, size_type n, allocator_type const& a) + : unordered_flat_map( + fr, std::forward(rg), n, hasher(), key_equal(), a) + { + } + + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_flat_map(FromRangeT&& fr, R&& rg, size_type n, + hasher const& h, allocator_type const& a) + : unordered_flat_map(fr, std::forward(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 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 ilist) { this->insert(ilist.begin(), ilist.end()); @@ -756,6 +815,27 @@ namespace boost { boost::unordered::detail::iter_val_t, 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 >, + class Pred = + std::equal_to >, + class Allocator = std::allocator< + boost::unordered::detail::range_to_alloc_t >, + class = std::enable_if_t >, + class = std::enable_if_t >, + class = std::enable_if_t > > + 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_mapped_t, Hash, Pred, + Allocator>; +#endif + template >, class Pred = std::equal_to >, @@ -800,6 +880,42 @@ namespace boost { std::equal_to >, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + unordered_flat_map(FromRangeT&&, R&&, std::size_t, Allocator) + -> unordered_flat_map, + boost::unordered::detail::range_mapped_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template > > + unordered_flat_map(FromRangeT&&, R&&, Allocator) + -> unordered_flat_map, + boost::unordered::detail::range_mapped_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template >, + class = std::enable_if_t > > + unordered_flat_map( + FromRangeT&&, R&&, std::size_t, Hash, Allocator) + -> unordered_flat_map, + boost::unordered::detail::range_mapped_t, Hash, + std::equal_to >, + Allocator>; +#endif + template > > unordered_flat_map(std::initializer_list >, std::size_t, diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 629750342..ffeaa43f2 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -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 #include #include +#include #include #include #include @@ -104,6 +105,19 @@ namespace boost { { } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_flat_set( + FromRangeT&& fr, R&& rg, allocator_type const& a) + : unordered_flat_set( + fr, std::forward(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 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(rg)); + } + + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_flat_set( + FromRangeT&& fr, R&& rg, size_type n, allocator_type const& a) + : unordered_flat_set( + fr, std::forward(rg), n, hasher(), key_equal(), a) + { + } + + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_flat_set(FromRangeT&& fr, R&& rg, size_type n, + hasher const& h, allocator_type const& a) + : unordered_flat_set(fr, std::forward(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 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 ilist) { this->insert(ilist.begin(), ilist.end()); @@ -574,6 +633,25 @@ namespace boost { typename std::iterator_traits::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 >, + class Pred = + std::equal_to >, + class Allocator = std::allocator >, + class = std::enable_if_t >, + class = std::enable_if_t >, + class = std::enable_if_t > > + unordered_flat_set(FromRangeT&&, R&&, + std::size_t = boost::unordered::detail::foa::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_flat_set, + Hash, Pred, Allocator>; +#endif + template , class Pred = std::equal_to, class Allocator = std::allocator, class = std::enable_if_t >, @@ -605,6 +683,29 @@ namespace boost { std::equal_to::value_type>, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + unordered_flat_set(FromRangeT&&, R&&, std::size_t, Allocator) + -> unordered_flat_set, + boost::hash >, + std::equal_to >, + Allocator>; + + template >, + class = std::enable_if_t > > + unordered_flat_set( + FromRangeT&&, R&&, std::size_t, Hash, Allocator) + -> unordered_flat_set, + Hash, std::equal_to >, + Allocator>; +#endif + template > > unordered_flat_set(std::initializer_list, std::size_t, Allocator) @@ -626,6 +727,18 @@ namespace boost { std::equal_to::value_type>, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + unordered_flat_set(FromRangeT&&, R&&, Allocator) + -> unordered_flat_set, + boost::hash >, + std::equal_to >, + Allocator>; +#endif + template > > unordered_flat_set(std::initializer_list, Allocator) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 6b7418b03..29b96679d 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -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 +#include #include #include #include @@ -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 > 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 > R + > + unordered_map(FromRangeT&&, R&&, const allocator_type&); + + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range > R + > + unordered_map(FromRangeT&&, R&&, size_type, const allocator_type&); + + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range > R + > + unordered_map( + FromRangeT&&, R&&, size_type, const hasher&, const allocator_type&); +#endif + unordered_map(std::initializer_list, const allocator_type&); unordered_map( @@ -248,6 +281,11 @@ namespace boost { template void insert(InputIt, InputIt); +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > R> + void insert_range(R&&); +#endif + void insert(std::initializer_list); // extract @@ -622,6 +660,27 @@ namespace boost { boost::unordered::detail::iter_val_t, 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 >, + class Pred = + std::equal_to >, + class Allocator = std::allocator< + boost::unordered::detail::range_to_alloc_t >, + class = std::enable_if_t >, + class = std::enable_if_t >, + class = std::enable_if_t > > + 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_mapped_t, Hash, Pred, + Allocator>; +#endif + template >, class Pred = std::equal_to >, @@ -664,6 +723,42 @@ namespace boost { std::equal_to >, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + unordered_map(FromRangeT&&, R&&, std::size_t, Allocator) + -> unordered_map, + boost::unordered::detail::range_mapped_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template > > + unordered_map(FromRangeT&&, R&&, Allocator) + -> unordered_map, + boost::unordered::detail::range_mapped_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template >, + class = std::enable_if_t > > + unordered_map( + FromRangeT&&, R&&, std::size_t, Hash, Allocator) + -> unordered_map, + boost::unordered::detail::range_mapped_t, Hash, + std::equal_to >, + Allocator>; +#endif + template > > unordered_map(std::initializer_list >, 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 > 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 > R + > + unordered_multimap(FromRangeT&&, R&&, const allocator_type&); + + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range > R + > + unordered_multimap(FromRangeT&&, R&&, size_type, const allocator_type&); + + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range > R + > + unordered_multimap( + FromRangeT&&, R&&, size_type, const hasher&, const allocator_type&); +#endif + unordered_multimap( std::initializer_list, const allocator_type&); @@ -894,6 +1021,11 @@ namespace boost { template void insert(InputIt, InputIt); +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > R> + void insert_range(R&&); +#endif + void insert(std::initializer_list); // extract @@ -1141,6 +1273,26 @@ namespace boost { boost::unordered::detail::iter_val_t, 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 >, + class Pred = + std::equal_to >, + class Allocator = std::allocator< + boost::unordered::detail::range_to_alloc_t >, + class = std::enable_if_t >, + class = std::enable_if_t >, + class = std::enable_if_t > > + 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_mapped_t, Hash, Pred, + Allocator>; +#endif template >, class Pred = std::equal_to >, @@ -1184,6 +1336,42 @@ namespace boost { std::equal_to >, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + unordered_multimap(FromRangeT&&, R&&, std::size_t, Allocator) + -> unordered_multimap, + boost::unordered::detail::range_mapped_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template > > + unordered_multimap(FromRangeT&&, R&&, Allocator) + -> unordered_multimap, + boost::unordered::detail::range_mapped_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template >, + class = std::enable_if_t > > + unordered_multimap( + FromRangeT&&, R&&, std::size_t, Hash, Allocator) + -> unordered_multimap, + boost::unordered::detail::range_mapped_t, Hash, + std::equal_to >, + Allocator>; +#endif + template > > unordered_multimap(std::initializer_list >, std::size_t, @@ -1231,6 +1419,23 @@ namespace boost { this->insert(f, l); } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range > R + > + unordered_map::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(rg), n), + hf, eql, a) + { + this->insert_range(std::forward(rg)); + } +#endif + template unordered_map::unordered_map(unordered_map const& other) : table_(other.table_, @@ -1303,6 +1508,7 @@ namespace boost { this->insert(f, l); } + template template unordered_map::unordered_map( @@ -1323,6 +1529,51 @@ namespace boost { this->insert(f, l); } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range > R + > + unordered_map::unordered_map( + FromRangeT&&, R&& rg, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size( + std::forward(rg), detail::default_bucket_count), + hasher(), key_equal(), a) + { + this->insert_range(std::forward(rg)); + } + + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range > R + > + unordered_map::unordered_map( + FromRangeT&&, R&& rg, size_type n, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(std::forward(rg), n), + hasher(), key_equal(), a) + { + this->insert_range(std::forward(rg)); + } + + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range > R + > + unordered_map::unordered_map(FromRangeT&&, R&& rg, + size_type n, const hasher& hf, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(std::forward(rg), n), + hf, key_equal(), a) + { + this->insert_range(std::forward(rg)); + } +#endif + template unordered_map::unordered_map( std::initializer_list list, const allocator_type& a) @@ -1395,6 +1646,20 @@ namespace boost { } } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template + template > R> + void unordered_map::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 void unordered_map::insert( std::initializer_list list) @@ -1757,6 +2022,23 @@ namespace boost { this->insert(f, l); } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range > R + > + unordered_multimap::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(rg), n), + hf, eql, a) + { + this->insert_range(std::forward(rg)); + } +#endif + template unordered_multimap::unordered_multimap( unordered_multimap const& other) @@ -1851,6 +2133,51 @@ namespace boost { this->insert(f, l); } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range > R + > + unordered_multimap::unordered_multimap( + FromRangeT&&, R&& rg, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size( + std::forward(rg), detail::default_bucket_count), + hasher(), key_equal(), a) + { + this->insert_range(std::forward(rg)); + } + + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range > R + > + unordered_multimap::unordered_multimap( + FromRangeT&&, R&& rg, size_type n, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(std::forward(rg), n), + hasher(), key_equal(), a) + { + this->insert_range(std::forward(rg)); + } + + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range > R + > + unordered_multimap::unordered_multimap(FromRangeT&&, R&& rg, + size_type n, const hasher& hf, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(std::forward(rg), n), + hf, key_equal(), a) + { + this->insert_range(std::forward(rg)); + } +#endif + template unordered_multimap::unordered_multimap( std::initializer_list list, const allocator_type& a) @@ -1921,6 +2248,16 @@ namespace boost { table_.insert_range_equiv(first, last); } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template + template > R> + void unordered_multimap::insert_range(R&& rg) + { + table_.insert_range_equiv(std::ranges::begin(rg), std::ranges::end(rg)); + } +#endif + + template void unordered_multimap::insert( std::initializer_list list) diff --git a/include/boost/unordered/unordered_node_map.hpp b/include/boost/unordered/unordered_node_map.hpp index 73dbdc841..a8b05cbd4 100644 --- a/include/boost/unordered/unordered_node_map.hpp +++ b/include/boost/unordered/unordered_node_map.hpp @@ -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 #include #include +#include #include #include #include @@ -115,6 +116,19 @@ namespace boost { { } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_node_map( + FromRangeT&& fr, R&& rg, allocator_type const& a) + : unordered_node_map( + fr, std::forward(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 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(rg)); + } + + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_node_map( + FromRangeT&& fr, R&& rg, size_type n, allocator_type const& a) + : unordered_node_map( + fr, std::forward(rg), n, hasher(), key_equal(), a) + { + } + + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_node_map(FromRangeT&& fr, R&& rg, size_type n, + hasher const& h, allocator_type const& a) + : unordered_node_map(fr, std::forward(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 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 ilist) { this->insert(ilist.begin(), ilist.end()); @@ -830,6 +889,27 @@ namespace boost { boost::unordered::detail::iter_val_t, 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 >, + class Pred = + std::equal_to >, + class Allocator = std::allocator< + boost::unordered::detail::range_to_alloc_t >, + class = std::enable_if_t >, + class = std::enable_if_t >, + class = std::enable_if_t > > + 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_mapped_t, Hash, Pred, + Allocator>; +#endif + template >, class Pred = std::equal_to >, @@ -874,6 +954,42 @@ namespace boost { std::equal_to >, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + unordered_node_map(FromRangeT&&, R&&, std::size_t, Allocator) + -> unordered_node_map, + boost::unordered::detail::range_mapped_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template > > + unordered_node_map(FromRangeT&&, R&&, Allocator) + -> unordered_node_map, + boost::unordered::detail::range_mapped_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template >, + class = std::enable_if_t > > + unordered_node_map( + FromRangeT&&, R&&, std::size_t, Hash, Allocator) + -> unordered_node_map, + boost::unordered::detail::range_mapped_t, Hash, + std::equal_to >, + Allocator>; +#endif + template > > unordered_node_map(std::initializer_list >, std::size_t, diff --git a/include/boost/unordered/unordered_node_set.hpp b/include/boost/unordered/unordered_node_set.hpp index 48a2e212d..200468590 100644 --- a/include/boost/unordered/unordered_node_set.hpp +++ b/include/boost/unordered/unordered_node_set.hpp @@ -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 #include #include +#include #include #include #include @@ -113,6 +114,19 @@ namespace boost { { } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_node_set( + FromRangeT&& fr, R&& rg, allocator_type const& a) + : unordered_node_set( + fr, std::forward(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 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(rg)); + } + + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_node_set( + FromRangeT&& fr, R&& rg, size_type n, allocator_type const& a) + : unordered_node_set( + fr, std::forward(rg), n, hasher(), key_equal(), a) + { + } + + template< + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_node_set(FromRangeT&& fr, R&& rg, size_type n, + hasher const& h, allocator_type const& a) + : unordered_node_set(fr, std::forward(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 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 ilist) { this->insert(ilist.begin(), ilist.end()); @@ -650,6 +709,25 @@ namespace boost { typename std::iterator_traits::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 >, + class Pred = + std::equal_to >, + class Allocator = std::allocator >, + class = std::enable_if_t >, + class = std::enable_if_t >, + class = std::enable_if_t > > + unordered_node_set(FromRangeT&&, R&&, + std::size_t = boost::unordered::detail::foa::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_node_set, + Hash, Pred, Allocator>; +#endif + template , class Pred = std::equal_to, class Allocator = std::allocator, class = std::enable_if_t >, @@ -681,6 +759,29 @@ namespace boost { std::equal_to::value_type>, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + unordered_node_set(FromRangeT&&, R&&, std::size_t, Allocator) + -> unordered_node_set, + boost::hash >, + std::equal_to >, + Allocator>; + + template >, + class = std::enable_if_t > > + unordered_node_set( + FromRangeT&&, R&&, std::size_t, Hash, Allocator) + -> unordered_node_set, + Hash, std::equal_to >, + Allocator>; +#endif + template > > unordered_node_set(std::initializer_list, std::size_t, Allocator) @@ -702,6 +803,18 @@ namespace boost { std::equal_to::value_type>, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + unordered_node_set(FromRangeT&&, R&&, Allocator) + -> unordered_node_set, + boost::hash >, + std::equal_to >, + Allocator>; +#endif + template > > unordered_node_set(std::initializer_list, Allocator) diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index eae846ddb..4821eb8bd 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -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 #include #include #include @@ -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 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 R + > + unordered_set(FromRangeT&&, R&&, const allocator_type&); + + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_set(FromRangeT&&, R&&, size_type, const allocator_type&); + + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_set( + FromRangeT&&, R&&, size_type, const hasher&, const allocator_type&); +#endif + unordered_set(std::initializer_list, const allocator_type&); unordered_set( @@ -246,6 +279,11 @@ namespace boost { template void insert(InputIt, InputIt); +#if !defined(BOOST_UNORDERED_NO_RANGES) + template R> + void insert_range(R&&); +#endif + void insert(std::initializer_list); // extract @@ -478,6 +516,25 @@ namespace boost { -> unordered_set::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 >, + class Pred = + std::equal_to >, + class Allocator = std::allocator >, + class = std::enable_if_t >, + class = std::enable_if_t >, + class = std::enable_if_t > > + unordered_set(FromRangeT&&, R&&, + std::size_t = boost::unordered::detail::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_set, + Hash, Pred, Allocator>; +#endif + template , class Pred = std::equal_to, class Allocator = std::allocator, class = std::enable_if_t >, @@ -507,6 +564,29 @@ namespace boost { std::equal_to::value_type>, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + unordered_set(FromRangeT&&, R&&, std::size_t, Allocator) + -> unordered_set, + boost::hash >, + std::equal_to >, + Allocator>; + + template >, + class = std::enable_if_t > > + unordered_set( + FromRangeT&&, R&&, std::size_t, Hash, Allocator) + -> unordered_set, + Hash, std::equal_to >, + Allocator>; +#endif + template > > unordered_set(std::initializer_list, std::size_t, Allocator) @@ -527,6 +607,18 @@ namespace boost { std::equal_to::value_type>, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + unordered_set(FromRangeT&&, R&&, Allocator) + -> unordered_set, + boost::hash >, + std::equal_to >, + Allocator>; +#endif + template > > unordered_set(std::initializer_list, 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 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 R + > + unordered_multiset(FromRangeT&&, R&&, const allocator_type&); + + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_multiset(FromRangeT&&, R&&, size_type, const allocator_type&); + + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_multiset( + FromRangeT&&, R&&, size_type, const hasher&, const allocator_type&); +#endif + unordered_multiset( std::initializer_list, const allocator_type&); @@ -720,6 +845,11 @@ namespace boost { template void insert(InputIt, InputIt); +#if !defined(BOOST_UNORDERED_NO_RANGES) + template R> + void insert_range(R&&); +#endif + void insert(std::initializer_list); // extract @@ -942,6 +1072,25 @@ namespace boost { typename std::iterator_traits::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 >, + class Pred = + std::equal_to >, + class Allocator = std::allocator >, + class = std::enable_if_t >, + class = std::enable_if_t >, + class = std::enable_if_t > > + unordered_multiset(FromRangeT&&, R&&, + std::size_t = boost::unordered::detail::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_multiset, + Hash, Pred, Allocator>; +#endif + template , class Pred = std::equal_to, class Allocator = std::allocator, class = std::enable_if_t >, @@ -973,6 +1122,29 @@ namespace boost { std::equal_to::value_type>, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + unordered_multiset(FromRangeT&&, R&&, std::size_t, Allocator) + -> unordered_multiset, + boost::hash >, + std::equal_to >, + Allocator>; + + template >, + class = std::enable_if_t > > + unordered_multiset( + FromRangeT&&, R&&, std::size_t, Hash, Allocator) + -> unordered_multiset, + Hash, std::equal_to >, + Allocator>; +#endif + template > > unordered_multiset(std::initializer_list, std::size_t, Allocator) @@ -994,6 +1166,18 @@ namespace boost { std::equal_to::value_type>, Allocator>; +#if !defined(BOOST_UNORDERED_NO_RANGES) + template > > + unordered_multiset(FromRangeT&&, R&&, Allocator) + -> unordered_multiset, + boost::hash >, + std::equal_to >, + Allocator>; +#endif + template > > unordered_multiset(std::initializer_list, Allocator) @@ -1023,6 +1207,23 @@ namespace boost { this->insert(f, l); } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_set::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(rg), n), + hf, eql, a) + { + this->insert_range(std::forward(rg)); + } +#endif + template unordered_set::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 + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_set::unordered_set( + FromRangeT&&, R&& rg, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size( + std::forward(rg), detail::default_bucket_count), + hasher(), key_equal(), a) + { + this->insert_range(std::forward(rg)); + } + + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_set::unordered_set( + FromRangeT&&, R&& rg, size_type n, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(std::forward(rg), n), + hasher(), key_equal(), a) + { + this->insert_range(std::forward(rg)); + } + + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_set::unordered_set(FromRangeT&&, R&& rg, + size_type n, const hasher& hf, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(std::forward(rg), n), + hf, key_equal(), a) + { + this->insert_range(std::forward(rg)); + } +#endif + template unordered_set::unordered_set( std::initializer_list list, const allocator_type& a) @@ -1187,6 +1433,20 @@ namespace boost { } } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template + template R> + void unordered_set::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 void unordered_set::insert( std::initializer_list list) @@ -1420,6 +1680,23 @@ namespace boost { this->insert(f, l); } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_multiset::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(rg), n), + hf, eql, a) + { + this->insert_range(std::forward(rg)); + } +#endif + template unordered_multiset::unordered_multiset( unordered_multiset const& other) @@ -1513,6 +1790,51 @@ namespace boost { this->insert(f, l); } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_multiset::unordered_multiset( + FromRangeT&&, R&& rg, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size( + std::forward(rg), detail::default_bucket_count), + hasher(), key_equal(), a) + { + this->insert_range(std::forward(rg)); + } + + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_multiset::unordered_multiset( + FromRangeT&&, R&& rg, size_type n, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(std::forward(rg), n), + hasher(), key_equal(), a) + { + this->insert_range(std::forward(rg)); + } + + template + template < + detail::convertible_to_from_range_t FromRangeT, + detail::container_compatible_range R + > + unordered_multiset::unordered_multiset(FromRangeT&&, R&& rg, + size_type n, const hasher& hf, const allocator_type& a) + : table_( + boost::unordered::detail::initial_size(std::forward(rg), n), + hf, key_equal(), a) + { + this->insert_range(std::forward(rg)); + } +#endif + template unordered_multiset::unordered_multiset( std::initializer_list list, const allocator_type& a) @@ -1582,6 +1904,16 @@ namespace boost { table_.insert_range_equiv(first, last); } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template + template R> + void unordered_multiset::insert_range(R&& rg) + { + table_.insert_range_equiv( + std::ranges::begin(rg), std::ranges::end(rg)); + } +#endif + template void unordered_multiset::insert( std::initializer_list list) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 31265e458..7ccaa1d01 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -379,7 +379,8 @@ run cfoa/insert_tests.cpp : $(CPP11) multi msvc:/bigobj gcc:on - gcc:space + gcc:off + gcc:-g0 clang:on clang:space : cfoa_insert_tests ; diff --git a/test/cfoa/constructor_tests.cpp b/test/cfoa/constructor_tests.cpp index 2d8c5f95f..64075f2a0 100644 --- a/test/cfoa/constructor_tests.cpp +++ b/test/cfoa/constructor_tests.cpp @@ -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 #include +#include + test::seed_t initialize_seed(4122023); using test::default_generator; @@ -702,6 +704,97 @@ namespace { } } +#if !defined(BOOST_UNORDERED_NO_RANGES) + template + void range_with_all_params(std::pair p) + { + using value_type = typename X::value_type; + static constexpr auto value_type_cardinality = + value_cardinality::value; + using allocator_type = typename X::allocator_type; + + auto init_list = p.second; + auto init_std_list = std::list{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 void initializer_list_with_all_params(std::pair 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) diff --git a/test/cfoa/insert_tests.cpp b/test/cfoa/insert_tests.cpp index 985f9a403..dfe067340 100644 --- a/test/cfoa/insert_tests.cpp +++ b/test/cfoa/insert_tests.cpp @@ -175,6 +175,39 @@ namespace { } } iterator_range_inserter; +#if !defined(BOOST_UNORDERED_NO_RANGES) + struct range_inserter_type + { + template void operator()(std::vector& values, X& x) + { + static constexpr auto value_type_cardinality = + value_cardinality::value; + + std::vector values2; + values2.reserve(values.size()); + for (auto const& v : values) { + values2.push_back(raii_convertible(v)); + } + + auto sz = x.size(); + std::atomic num_inserts{0}; + std::atomic num_attempted_inserts{0}; + thread_runner(values2, [&x, &num_inserts, &num_attempted_inserts](boost::span 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 void operator()(std::vector& 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 void operator()(std::vector& values, X& x) + { + static constexpr auto value_type_cardinality = + value_cardinality::value; + + std::vector values2; + values2.reserve(values.size()); + for (auto const& v : values) { + values2.push_back(raii_convertible(v)); + } + + std::atomic num_invokes{0}; + thread_runner( + values2, [&x, &num_invokes](boost::span 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 void operator()(std::vector& 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 void operator()(std::vector& values, X& x) + { + static constexpr auto value_type_cardinality = + value_cardinality::value; + + // concurrent_flat_set visit is always const access + using arg_type = typename std::conditional< + std::is_same::value, + typename X::value_type const, + typename X::value_type + >::type; + + std::vector values2; + values2.reserve(values.size()); + for (auto const& v : values) { + values2.push_back(raii_convertible(v)); + } + + std::atomic num_inserts{0}; + std::atomic num_invokes{0}; + thread_runner(values2, + [&x, &num_inserts, &num_invokes](boost::span 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 void operator()(std::vector& 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 void operator()(std::vector& values, X& x) + { + static constexpr auto value_type_cardinality = + value_cardinality::value; + + // concurrent_flat_set visit is always const access + using arg_type = typename std::conditional< + std::is_same::value, + typename X::value_type const, + typename X::value_type + >::type; + + std::vector values2; + values2.reserve(values.size()); + for (auto const& v : values) { + values2.push_back(raii_convertible(v)); + } + + std::atomic num_invokes{0}; + thread_runner( + values2, [&x, &num_invokes](boost::span 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 void operator()(std::vector& 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 void operator()(std::vector& values, X& x) + { + static constexpr auto value_type_cardinality = + value_cardinality::value; + + // concurrent_flat_set visit is always const access + using arg_type = typename std::conditional< + std::is_same::value, + typename X::value_type const, + typename X::value_type + >::type; + + std::vector values2; + values2.reserve(values.size()); + for (auto const& v : values) { + values2.push_back(raii_convertible(v)); + } + + std::atomic num_inserts{0}; + std::atomic num_invokes{0}; + thread_runner(values2, + [&x, &num_inserts, &num_invokes](boost::span 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( diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 7eaa99bc9..16b91c317 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -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 #include namespace constructor_tests { @@ -337,6 +339,205 @@ namespace constructor_tests { // std::vector 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_; diff --git a/test/unordered/deduction_tests.cpp b/test/unordered/deduction_tests.cpp index 7d3996e33..61bb8d631 100644 --- a/test/unordered/deduction_tests.cpp +++ b/test/unordered/deduction_tests.cpp @@ -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 #include -#include #include -#include #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES +#include +#include +#include #include #include +#include +#include #include +#include +#include +#include +#include struct hash_equals { @@ -87,6 +94,44 @@ template