On Wed, 19 Mar 2025 at 12:06, Tomasz Kamiński <tkami...@redhat.com> wrote:
>
> This patch implements part of LWG2713 covering the from_range
> constructors, which makes std::ranges::to<std::unordered_set>(alloc) 
> well-formed.
> Likewise for rest of unordered containers.
>
> As this consturctors were added to v15, this has no impact
> on code that compiled with previous versions.
>
> libstdc++-v3/ChangeLog:
>
>         * include/bits/unordered_map.h
>         (unordered_map(from_range_t, _Rg&&, const allocator_type&))
>         (unordered_multimap(from_range_t, _Rg&&, const allocator_type&)):
>         Define.
>         * include/bits/unordered_set.h
>         (unordered_set(from_range_t, _Rg&&, const allocator_type&))
>         (unordered_multiset(from_range_t, _Rg&&, const allocator_type&)):
>         Define.
>         * testsuite/23_containers/unordered_map/cons/from_range.cc: New tests.
>         New tests.
>         * testsuite/23_containers/unordered_multimap/cons/from_range.cc:
>         New tests.
>         * testsuite/23_containers/unordered_multiset/cons/from_range.cc:
>         New tests.
>         * testsuite/23_containers/unordered_set/cons/from_range.cc: New tests.
>         * testsuite/std/ranges/conv/1.cc: New tests.
> ---
> Testing on x86_64-linux, *unordered_*map* tests passed.
> OK for trunk once all tests passes?

OK, thanks.

>
>  libstdc++-v3/include/bits/unordered_map.h     | 14 +++++++++++
>  libstdc++-v3/include/bits/unordered_set.h     | 15 ++++++++++++
>  .../unordered_map/cons/from_range.cc          | 24 +++++++++----------
>  .../unordered_multimap/cons/from_range.cc     | 24 +++++++++----------
>  .../unordered_multiset/cons/from_range.cc     | 22 ++++++++---------
>  .../unordered_set/cons/from_range.cc          |  9 ++++---
>  libstdc++-v3/testsuite/std/ranges/conv/1.cc   | 22 +++++++++++++++++
>  7 files changed, 87 insertions(+), 43 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/unordered_map.h 
> b/libstdc++-v3/include/bits/unordered_map.h
> index 5c930487190..5e11e61dfc1 100644
> --- a/libstdc++-v3/include/bits/unordered_map.h
> +++ b/libstdc++-v3/include/bits/unordered_map.h
> @@ -300,6 +300,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>           : _M_h(__n, __hf, __eql, __a)
>           { insert_range(std::forward<_Rg>(__rg)); }
>
> +       // _GLIBCXX_RESOLVE_LIB_DEFECTS
> +       // 2713. More missing allocator-extended constructors for unordered 
> containers
> +       template<__detail::__container_compatible_range<value_type> _Rg>
> +        unordered_map(from_range_t, _Rg&& __rg, const allocator_type& __a)
> +         : _M_h(0, hasher(), key_equal(), __a)
> +         { insert_range(std::forward<_Rg>(__rg)); }
> +
>         template<__detail::__container_compatible_range<value_type> _Rg>
>          unordered_map(from_range_t, _Rg&& __rg, size_type __n,
>                        const allocator_type& __a)
> @@ -1546,6 +1553,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>           : _M_h(__n, __hf, __eql, __a)
>           { insert_range(std::forward<_Rg>(__rg)); }
>
> +       // _GLIBCXX_RESOLVE_LIB_DEFECTS
> +       // 2713. More missing allocator-extended constructors for unordered 
> containers
> +       template<__detail::__container_compatible_range<value_type> _Rg>
> +        unordered_multimap(from_range_t, _Rg&& __rg, const allocator_type& 
> __a)
> +         : _M_h(0, hasher(), key_equal(), __a)
> +         { insert_range(std::forward<_Rg>(__rg)); }
> +
>         template<__detail::__container_compatible_range<value_type> _Rg>
>          unordered_multimap(from_range_t, _Rg&& __rg, size_type __n,
>                             const allocator_type& __a)
> diff --git a/libstdc++-v3/include/bits/unordered_set.h 
> b/libstdc++-v3/include/bits/unordered_set.h
> index 21ffdaf50a0..3b218f3394c 100644
> --- a/libstdc++-v3/include/bits/unordered_set.h
> +++ b/libstdc++-v3/include/bits/unordered_set.h
> @@ -294,6 +294,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>           : _M_h(__n, __hf, __eql, __a)
>           { insert_range(std::forward<_Rg>(__rg)); }
>
> +       // _GLIBCXX_RESOLVE_LIB_DEFECTS
> +       // 2713. More missing allocator-extended constructors for unordered 
> container
> +       template<__detail::__container_compatible_range<_Value> _Rg>
> +        unordered_set(from_range_t, _Rg&& __rg, const allocator_type& __a)
> +         : _M_h(0, hasher(), key_equal(), __a)
> +         { insert_range(std::forward<_Rg>(__rg)); }
> +
>         template<__detail::__container_compatible_range<_Value> _Rg>
>          unordered_set(from_range_t, _Rg&& __rg, size_type __n,
>                        const allocator_type& __a)
> @@ -1265,6 +1272,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>           : _M_h(__n, __hf, __eql, __a)
>           { insert_range(std::forward<_Rg>(__rg)); }
>
> +
> +       // _GLIBCXX_RESOLVE_LIB_DEFECTS
> +       // 2713. More missing allocator-extended constructors for unordered 
> container
> +       template<__detail::__container_compatible_range<_Value> _Rg>
> +        unordered_multiset(from_range_t, _Rg&& __rg, const allocator_type& 
> __a)
> +         : _M_h(0, hasher(), key_equal(), __a)
> +         { insert_range(std::forward<_Rg>(__rg)); }
> +
>         template<__detail::__container_compatible_range<_Value> _Rg>
>          unordered_multiset(from_range_t, _Rg&& __rg, size_type __n,
>                             const allocator_type& __a)
> diff --git 
> a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc 
> b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc
> index b3cbb2e6062..51f8538669a 100644
> --- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc
> +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc
> @@ -49,12 +49,11 @@ test_deduction_guide()
>
>    using Alloc = __gnu_test::SimpleAllocator<std::pair<const long, float>>;
>    Alloc alloc;
> -  // LWG2713: there is no matching constructor
> -  // std::unordered_map m5(std::from_range, r, alloc);
> -  // static_assert(std::is_same_v<
> -  //   decltype(m5),
> -  //   std::unordered_map<long, float,
> -  //                      std::hash<long>, std::equal_to<long>, Alloc>>);
> +  std::unordered_map m5(std::from_range, r, alloc);
> +  static_assert(std::is_same_v<
> +    decltype(m5),
> +    std::unordered_map<long, float,
> +                      std::hash<long>, std::equal_to<long>, Alloc>>);
>
>    std::unordered_map m6(std::from_range, r, 0, alloc);
>    static_assert(std::is_same_v<
> @@ -154,13 +153,12 @@ do_test(Alloc alloc, Hash hf, Equal eqf)
>    VERIFY( is_equal(m9.hash_function(), hf) );
>    VERIFY( is_equal(m9.key_eq(), eqf) );
>
> -  // LWG2713: there is no matching constructor
> -  // std::unordered_map<K, V, Hash, Equal, Alloc>
> -  //   ma1(std::from_range, Range(a, a+14), alloc);
> -  // VERIFY( eq(ma1, {a, 9}) );
> -  // VERIFY( is_equal(ma1.hash_function(), Hash()) );
> -  // VERIFY( is_equal(ma1.key_eq(), Equal()) );
> -  // VERIFY( ma1.get_allocator() == alloc );
> +  std::unordered_map<K, V, Hash, Equal, Alloc>
> +    ma1(std::from_range, Range(a, a+14), alloc);
> +  VERIFY( eq(ma1, {a, 9}) );
> +  VERIFY( is_equal(ma1.hash_function(), Hash()) );
> +  VERIFY( is_equal(ma1.key_eq(), Equal()) );
> +  VERIFY( ma1.get_allocator() == alloc );
>
>    std::unordered_map<K, V, Hash, Equal, Alloc>
>      ma2(std::from_range, Range(a, a+14), 2, alloc);
> diff --git 
> a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc 
> b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc
> index 9273ef0d57a..2e26cd2d201 100644
> --- 
> a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc
> +++ 
> b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc
> @@ -53,12 +53,11 @@ test_deduction_guide()
>
>    using Alloc = __gnu_test::SimpleAllocator<std::pair<const long, float>>;
>    Alloc alloc;
> -  // LWG2713: there is no matching constructor
> -  // std::unordered_multimap m5(std::from_range, r, alloc);
> -  // static_assert(std::is_same_v<
> -  //   decltype(m5),
> -  //   std::unordered_multimap<long, float,
> -  //                           std::hash<long>, std::equal_to<long>, 
> Alloc>>);
> +  std::unordered_multimap m5(std::from_range, r, alloc);
> +  static_assert(std::is_same_v<
> +    decltype(m5),
> +    std::unordered_multimap<long, float,
> +                           std::hash<long>, std::equal_to<long>, Alloc>>);
>
>    std::unordered_multimap m6(std::from_range, r, 0, alloc);
>    static_assert(std::is_same_v<
> @@ -159,13 +158,12 @@ do_test(Alloc alloc, Hash hf, Equal eqf)
>    VERIFY( is_equal(m9.hash_function(), hf) );
>    VERIFY( is_equal(m9.key_eq(), eqf) );
>
> -  // LWG2713: there is no matching constructor
> -  // std::unordered_multimap<K, V, Hash, Equal, Alloc>
> -  //   ma1(std::from_range, Range(a, a+14), alloc);
> -  // VERIFY( eq(ma1, {a, 14}) );
> -  // VERIFY( is_equal(ma1.hash_function(), Hash()) );
> -  // VERIFY( is_equal(ma1.key_eq(), Equal()) );
> -  // VERIFY( ma1.get_allocator() == alloc );
> +  std::unordered_multimap<K, V, Hash, Equal, Alloc>
> +    ma1(std::from_range, Range(a, a+14), alloc);
> +  VERIFY( eq(ma1, {a, 14}) );
> +  VERIFY( is_equal(ma1.hash_function(), Hash()) );
> +  VERIFY( is_equal(ma1.key_eq(), Equal()) );
> +  VERIFY( ma1.get_allocator() == alloc );
>
>    std::unordered_multimap<K, V, Hash, Equal, Alloc>
>      ma2(std::from_range, Range(a, a+14), 2, alloc);
> diff --git 
> a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc 
> b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc
> index fb388764423..ddbc7ff822f 100644
> --- 
> a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc
> +++ 
> b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc
> @@ -49,11 +49,10 @@ test_deduction_guide(long* p)
>
>    using Alloc = __gnu_test::SimpleAllocator<long>;
>    Alloc alloc;
> -  // LWG2713: there is no matching constructor
> -  // std::unordered_multiset s5(std::from_range, r, alloc);
> -  // static_assert(std::is_same_v<
> -  //   decltype(s5),
> -  //   std::unordered_multiset<long, std::hash<long>, std::equal_to<long>, 
> Alloc>>);
> +  std::unordered_multiset s5(std::from_range, r, alloc);
> +  static_assert(std::is_same_v<
> +    decltype(s5),
> +    std::unordered_multiset<long, std::hash<long>, std::equal_to<long>, 
> Alloc>>);
>
>    std::unordered_multiset s6(std::from_range, r, 0, alloc);
>    static_assert(std::is_same_v<
> @@ -136,13 +135,12 @@ do_test(Alloc alloc, Hash hf, Equal eqf)
>    VERIFY( is_equal(s9.hash_function(), hf) );
>    VERIFY( is_equal(s9.key_eq(), eqf) );
>
> -  // LWG2713: there is no matching constructor
> -  // std::unordered_multiset<V, Hash, Equal, Alloc>
> -  //   sa(std::from_range, Range(a, a+14), alloc);
> -  // VERIFY( eq(sa1, {a, 14}) );
> -  // VERIFY( is_equal(sa1.hash_function(), Hash()) );
> -  // VERIFY( is_equal(sa1.key_eq(), Equal()) );
> -  // VERIFY( sa1.get_allocator() == alloc );
> +  std::unordered_multiset<V, Hash, Equal, Alloc>
> +    sa1(std::from_range, Range(a, a+14), alloc);
> +  VERIFY( eq(sa1, {a, 14}) );
> +  VERIFY( is_equal(sa1.hash_function(), Hash()) );
> +  VERIFY( is_equal(sa1.key_eq(), Equal()) );
> +  VERIFY( sa1.get_allocator() == alloc );
>
>    std::unordered_multiset<V, Hash, Equal, Alloc>
>      sa2(std::from_range, Range(a, a+14), 2, alloc);
> diff --git 
> a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc 
> b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc
> index c1acf143661..adc14a7b98a 100644
> --- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc
> +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc
> @@ -49,11 +49,10 @@ test_deduction_guide(long* p)
>
>    using Alloc = __gnu_test::SimpleAllocator<long>;
>    Alloc alloc;
> -  // LWG2713: there is no matching constructor
> -  // std::unordered_set s5(std::from_range, r, alloc);
> -  // static_assert(std::is_same_v<
> -  //   decltype(s5),
> -  //   std::unordered_set<long, std::hash<long>, std::equal_to<long>, 
> Alloc>>);
> +  std::unordered_set s5(std::from_range, r, alloc);
> +  static_assert(std::is_same_v<
> +    decltype(s5),
> +    std::unordered_set<long, std::hash<long>, std::equal_to<long>, Alloc>>);
>
>    std::unordered_set s6(std::from_range, r, 0, alloc);
>    static_assert(std::is_same_v<
> diff --git a/libstdc++-v3/testsuite/std/ranges/conv/1.cc 
> b/libstdc++-v3/testsuite/std/ranges/conv/1.cc
> index 231cb9d9934..2caa1b83f30 100644
> --- a/libstdc++-v3/testsuite/std/ranges/conv/1.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/conv/1.cc
> @@ -12,6 +12,7 @@
>  #include <testsuite_hooks.h>
>  #include <testsuite_allocator.h>
>  #include <testsuite_iterators.h>
> +#include <unordered_map>
>
>  void
>  test_p1206r7_examples()
> @@ -478,6 +479,26 @@ test_pr119282()
>    return true;
>  }
>
> +void
> +test_lwg2713()
> +{
> +  using Alloc = __gnu_test::uneq_allocator<std::pair<const int, const 
> char*>>;
> +  const Alloc alloc(303);
> +  const std::map<int, const char*> m{{1, "one"}, {2, "two"}, {3, "three"}};
> +  namespace ranges = std::ranges;
> +
> +  // Call constructors with bucket count
> +  auto m1 = m | ranges::to<std::unordered_map>(0, alloc);
> +  VERIFY( m1.get_allocator() == alloc );
> +  auto m2 = m | ranges::to<std::unordered_multimap>(0, alloc);
> +  VERIFY( m2.get_allocator() == alloc );
> +  // These call constructors added in lwg2713
> +  auto m3 = m | ranges::to<std::unordered_map>(alloc);
> +  VERIFY( m3.get_allocator() == alloc );
> +  auto m4 = m | ranges::to<std::unordered_multimap>(alloc);
> +  VERIFY( m4.get_allocator() == alloc );
> +}
> +
>  int main()
>  {
>    test_p1206r7_examples();
> @@ -487,6 +508,7 @@ int main()
>    test_2_1_3();
>    test_2_1_4();
>    test_2_2();
> +  test_lwg2713();
>    test_lwg3984();
>    test_nodiscard();
>    test_constexpr();
> --
> 2.48.1
>

Reply via email to