[RFC] std::inplace_vector::assign avoid double loops

François Dumont frs.dumont@gmail.com
Mon Sep 21 17:42:48 GMT 2026


Hi

I wonder what you think about this patch.

Maybe this has already been discuss, sorry if so.

If fine I'll try to isolate _S_distance in a testable helper.

     libstdc++: Do not loop several times on range given to 
std::inplace_vector::assign

     std::inplace_vector::assign first compute the distance between the 
input iterators
     before running the assignment loop. The distance is computed as 
long as the input
     range is a sized-sentinel or forward iterators. It means that when 
computing distance
     on a forward_list like in the added test the range will be loop 
through twice.

     As inplace_vector do not need reallocation to increase its capacity 
it seems more
     optimal to only get the distance if it can be done in O(1). 
Otherwise we just loop
     through the range and add elements using emplace_back.

     libstdc++-v3/ChangeLog:

             * include/std/inplace_vector (inplace_vector::_S_distance): 
Return a distance
             only if sized_sentinel_for or iterator is derived from 
random_access_iterator_tag.
             * 
testsuite/23_containers/inplace_vector/modifiers/assign_forward_list.cc: 
New test
             case. Only checking that the right thing is done but not 
that it is done with only
             one loop on the input range.

Quickly tested with the added test case for now.

François

-------------- next part --------------
diff --git a/libstdc++-v3/include/std/inplace_vector b/libstdc++-v3/include/std/inplace_vector
index b16edcb98d9..016577e7c02 100644
--- a/libstdc++-v3/include/std/inplace_vector
+++ b/libstdc++-v3/include/std/inplace_vector
@@ -886,11 +886,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	constexpr static auto
 	_S_distance(_InputIterator __first, _InputIterator __last)
 	{
-	  if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>
-			  || forward_iterator<_InputIterator>)
+	  if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>)
 	    return (size_type)ranges::distance(__first, __last);
 	  else if constexpr (derived_from<__iter_category_t<_InputIterator>,
-				     forward_iterator_tag>)
+				     random_access_iterator_tag>)
 	    return (size_type)std::distance(__first, __last);
 	  else
 	    return false_type{};
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign_forward_list.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign_forward_list.cc
new file mode 100644
index 00000000000..d9fa686450f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign_forward_list.cc
@@ -0,0 +1,18 @@
+// { dg-do run { target c++26 } }
+
+#include <forward_list>
+#include <inplace_vector>
+
+#include <testsuite_hooks.h>
+
+int main()
+{
+  std::forward_list<int> fwd = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+  std::inplace_vector<int, 20> ipv;
+
+  auto fwdb = fwd.begin();
+  ++fwdb;
+
+  ipv.assign(fwdb, fwd.end());
+  VERIFY( ipv.size() == 10 );
+}


More information about the Libstdc++ mailing list