Implements LWG4121, "ranges::to constructs associative containers
via c.emplace(c.end(), *it)".

Using emplace_hint(it, arg) provides support for associative container
without from_range constructor, from which emplace(it, arg) constructrs
elements from it, arg. All statndard sequence containers that provides
emplace(it, arg) overload, provides push_back/emplace_back and are
handled by eariel branches.

libstdc++-v3/ChangeLog:

        * include/std/ranges (ranges::to): Replace emplace(__c.end(), *__it)
        with emplace_hint(__c.end(), *__it)
        * testsuite/std/ranges/conv/1.cc: Update tests accordingly.
---
Testing on x86_64-linux. *ranges* test already passed in all
standard modes. OK for trunk when all test passes?

 libstdc++-v3/include/std/ranges             |  8 +--
 libstdc++-v3/testsuite/std/ranges/conv/1.cc | 60 +++++++++++----------
 2 files changed, 36 insertions(+), 32 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 37f048e3d0d..5963647c378 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -9563,7 +9563,9 @@ namespace __detail
                
__c.reserve(static_cast<range_size_t<_Cont>>(ranges::size(__r)));
              // _GLIBCXX_RESOLVE_LIB_DEFECTS
              // 4016. container-insertable checks do not match what
-             // container-inserter does
+             //       container-inserter does
+             // 4121. ranges::to constructs associative containers
+             //       via c.emplace(c.end(), *it)
              auto __it = ranges::begin(__r);
              const auto __sent = ranges::end(__r);
              while (__it != __sent)
@@ -9572,8 +9574,8 @@ namespace __detail
                    __c.emplace_back(*__it);
                  else if constexpr (requires { __c.push_back(*__it); })
                    __c.push_back(*__it);
-                 else if constexpr (requires { __c.emplace(__c.end(), *__it); 
})
-                   __c.emplace(__c.end(), *__it);
+                 else if constexpr (requires { __c.emplace_hint(__c.end(), 
*__it); })
+                   __c.emplace_hint(__c.end(), *__it);
                  else
                    __c.insert(__c.end(), *__it);
                  ++__it;
diff --git a/libstdc++-v3/testsuite/std/ranges/conv/1.cc 
b/libstdc++-v3/testsuite/std/ranges/conv/1.cc
index 2caa1b83f30..14b52f6dd3c 100644
--- a/libstdc++-v3/testsuite/std/ranges/conv/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/conv/1.cc
@@ -9,6 +9,7 @@
 #include <list>
 #include <forward_list>
 #include <map>
+#include <set>
 #include <testsuite_hooks.h>
 #include <testsuite_allocator.h>
 #include <testsuite_iterators.h>
@@ -204,13 +205,13 @@ test_2_1_3()
   VERIFY( c2.c.get_allocator() == Alloc(78) );
 }
 
-enum AppendKind { None, EmplaceBack, PushBack, Emplace, Insert };
+enum AppendKind { None, EmplaceBack, PushBack, EmplaceHint, Insert };
 
 template<typename C, AppendKind Kind>
 struct Cont4
 {
   // Only support construction with no args or an allocator.
-  // This forces the use of either emplace_back, push_back, emplace or insert.
+  // This forces the use of either emplace_back, push_back, emplace_hint or 
insert.
   Cont4() { }
   Cont4(typename C::allocator_type a) : c(a) { }
 
@@ -235,13 +236,13 @@ struct Cont4
     }
 
   template<typename T>
-    requires (Kind <= Emplace)
-    && requires(C& c, T&& t) { c.emplace(c.end(), std::forward<T>(t)); }
+    requires (Kind <= EmplaceHint)
+    && requires(C& c, T&& t) { c.emplace_hint(c.end(), std::forward<T>(t)); }
     void
-    emplace(typename C::iterator pos, T&& t)
+    emplace_hint(typename C::iterator pos, T&& t)
     {
-      kind = Emplace;
-      c.emplace(pos, std::forward<T>(t));
+      kind = EmplaceHint;
+      c.emplace_hint(pos, std::forward<T>(t));
     }
 
   template<typename T>
@@ -287,6 +288,7 @@ test_2_1_4()
   using Alloc2 = __gnu_test::uneq_allocator<short>;
   using V = std::vector<int, Alloc>;
   using List = std::list<short, Alloc2>;
+  using Set = std::set<int>;
 
   std::list<unsigned> l{1u, 2u, 3u};
   std::list<long> l2{4l, 5l, 6l};
@@ -337,30 +339,30 @@ test_2_1_4()
   VERIFY( c6.kind == PushBack );
   VERIFY( ! c6.used_reserve );
 
-  // use vector::emplace and vector::reserve
-  auto c7 = std::ranges::to<Cont4<V, Emplace>>(l);
-  static_assert(std::is_same_v<decltype(c7), Cont4<V, Emplace>>);
-  VERIFY( c7.c == V(l.begin(), l.end()) );
-  VERIFY( c7.kind == Emplace );
-  VERIFY( c7.used_reserve );
-
-  // use vector::emplace and vector::reserve
-  auto c8 = std::ranges::to<Cont4<V, Emplace>>(l2, Alloc(78));
-  static_assert(std::is_same_v<decltype(c8), Cont4<V, Emplace>>);
-  VERIFY( c8.c == V(l2.begin(), l2.end()) );
-  VERIFY( c8.c.get_allocator() == Alloc(78) );
-  VERIFY( c8.kind == Emplace );
-  VERIFY( c8.used_reserve );
-
-  // use list::emplace
-  auto c9 = std::ranges::to<Cont4<List, Emplace>>(c.c, Alloc2(99));
-  static_assert(std::is_same_v<decltype(c9), Cont4<List, Emplace>>);
-  VERIFY( c9.c == List(l.begin(), l.end()) );
-  VERIFY( c9.c.get_allocator() == Alloc(99) );
-  VERIFY( c9.kind == Emplace );
+  // use list::emplace_back
+  auto c7 = std::ranges::to<Cont4<List, EmplaceBack>>(c.c, Alloc2(99));
+  static_assert(std::is_same_v<decltype(c7), Cont4<List, EmplaceBack>>);
+  VERIFY( c7.c == List(l.begin(), l.end()) );
+  VERIFY( c7.c.get_allocator() == Alloc(99) );
+  VERIFY( c7.kind == EmplaceBack );
+  VERIFY( ! c7.used_reserve );
+ 
+  // use set::emplace_hint
+  auto c8 = std::ranges::to<Cont4<Set, EmplaceHint>>(l);
+  static_assert(std::is_same_v<decltype(c8), Cont4<Set, EmplaceHint>>);
+  VERIFY( c8.c == Set(l.begin(), l.end()) );
+  VERIFY( c8.kind == EmplaceHint );
+  VERIFY( ! c8.used_reserve );
+
+  // use set::emplace_hint 
+  auto c9 = std::ranges::to<Cont4<Set, EmplaceHint>>(l2, Alloc(78));
+  static_assert(std::is_same_v<decltype(c9), Cont4<Set, EmplaceHint>>);
+  VERIFY( c9.c == Set(l2.begin(), l2.end()) );
+  VERIFY( c9.c.get_allocator() == Alloc(78) );
+  VERIFY( c9.kind == EmplaceHint );
   VERIFY( ! c9.used_reserve );
 
-  // use vector::insert and vector::reserve
+ // use vector::insert and vector::reserve
   auto c10 = std::ranges::to<Cont4<V, Insert>>(l);
   static_assert(std::is_same_v<decltype(c10), Cont4<V, Insert>>);
   VERIFY( c10.c == V(l.begin(), l.end()) );
-- 
2.55.0

Reply via email to