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

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 );
+}

Reply via email to