This is another piece of P1206R7, adding new members to std::list and
std::forward_list.
libstdc++-v3/ChangeLog:
PR libstdc++/111055
* include/bits/forward_list.h
(forward_list(from_range, R&&, const Alloc&), assign_range)
(prepend_range, insert_range_after): Define.
* include/bits/stl_list.h: (list(from_range, R&&, const Alloc&))
(assign_range, prepend_range, append_range, insert_range):
Define.
* testsuite/23_containers/forward_list/cons/from_range.cc: New
test.
* testsuite/23_containers/forward_list/modifiers/assign_range.cc:
New test.
* testsuite/23_containers/forward_list/modifiers/insert_range_after.cc:
New test.
* testsuite/23_containers/forward_list/modifiers/prepend_range.cc:
New test.
* testsuite/23_containers/list/cons/from_range.cc: New test.
* testsuite/23_containers/list/modifiers/append_range.cc: New
test.
* testsuite/23_containers/list/modifiers/assign/assign_range.cc:
New test.
* testsuite/23_containers/list/modifiers/insert/insert_range.cc:
New test.
* testsuite/23_containers/list/modifiers/prepend_range.cc: New
test.
---
Tested x86_64-linux.
This is also available for review at:
https://forge.sourceware.org/gcc/gcc-TEST/pulls/11/files
libstdc++-v3/include/bits/forward_list.h | 121 +++++++++++++++++
libstdc++-v3/include/bits/stl_list.h | 126 ++++++++++++++++++
.../forward_list/cons/from_range.cc | 100 ++++++++++++++
.../forward_list/modifiers/assign_range.cc | 97 ++++++++++++++
.../modifiers/insert_range_after.cc | 93 +++++++++++++
.../forward_list/modifiers/prepend_range.cc | 86 ++++++++++++
.../23_containers/list/cons/from_range.cc | 100 ++++++++++++++
.../list/modifiers/append_range.cc | 86 ++++++++++++
.../list/modifiers/assign/assign_range.cc | 99 ++++++++++++++
.../list/modifiers/insert/insert_range.cc | 98 ++++++++++++++
.../list/modifiers/prepend_range.cc | 86 ++++++++++++
11 files changed, 1092 insertions(+)
create mode 100644
libstdc++-v3/testsuite/23_containers/forward_list/cons/from_range.cc
create mode 100644
libstdc++-v3/testsuite/23_containers/forward_list/modifiers/assign_range.cc
create mode 100644
libstdc++-v3/testsuite/23_containers/forward_list/modifiers/insert_range_after.cc
create mode 100644
libstdc++-v3/testsuite/23_containers/forward_list/modifiers/prepend_range.cc
create mode 100644 libstdc++-v3/testsuite/23_containers/list/cons/from_range.cc
create mode 100644
libstdc++-v3/testsuite/23_containers/list/modifiers/append_range.cc
create mode 100644
libstdc++-v3/testsuite/23_containers/list/modifiers/assign/assign_range.cc
create mode 100644
libstdc++-v3/testsuite/23_containers/list/modifiers/insert/insert_range.cc
create mode 100644
libstdc++-v3/testsuite/23_containers/list/modifiers/prepend_range.cc
diff --git a/libstdc++-v3/include/bits/forward_list.h
b/libstdc++-v3/include/bits/forward_list.h
index eee773c0212..6ccf2eb2bff 100644
--- a/libstdc++-v3/include/bits/forward_list.h
+++ b/libstdc++-v3/include/bits/forward_list.h
@@ -42,6 +42,10 @@
#include <bits/allocator.h>
#include <ext/alloc_traits.h>
#include <ext/aligned_buffer.h>
+#if __glibcxx_ranges_to_container // C++ >= 23
+# include <bits/ranges_base.h> // ranges::begin, ranges::distance etc.
+# include <bits/ranges_util.h> // ranges::subrange
+#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
@@ -564,6 +568,30 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
: _Base(_Node_alloc_type(__al))
{ _M_range_initialize(__first, __last); }
+#if __glibcxx_ranges_to_container // C++ >= 23
+ /**
+ * @brief Construct a forward_list from a range.
+ * @param __rg An input range with elements that are convertible to
+ * the forward_list's value_type.
+ * @param __a An allocator.
+ *
+ * @since C++23
+ */
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ forward_list(from_range_t, _Rg&& __rg, const _Alloc& __a = _Alloc())
+ : _Base(_Node_alloc_type(__a))
+ {
+ _Node_base* __to = &this->_M_impl._M_head;
+ auto __first = ranges::begin(__rg);
+ const auto __last = ranges::end(__rg);
+ for (; __first != __last; ++__first)
+ {
+ __to->_M_next = this->_M_create_node(*__first);
+ __to = __to->_M_next;
+ }
+ }
+#endif // ranges_to_container
+
/**
* @brief The %forward_list copy constructor.
* @param __list A %forward_list of identical element and allocator
@@ -675,6 +703,39 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
_M_assign(__first, __last, __assignable());
}
+#if __glibcxx_ranges_to_container // C++ >= 23
+ /**
+ * @brief Assign a range to a forward_list.
+ * @since C++23
+ */
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ void
+ assign_range(_Rg&& __rg)
+ {
+ static_assert(assignable_from<_Tp&, ranges::range_reference_t<_Rg>>);
+
+ auto __first = ranges::begin(__rg);
+ const auto __last = ranges::end(__rg);
+ iterator __prev = before_begin();
+ iterator __curr = begin();
+ const iterator __end = end();
+
+ while (__curr != __end && __first != __last)
+ {
+ *__curr = *__first;
+ __prev = __curr;
+ ++__first;
+ ++__curr;
+ }
+
+ if (__curr != __end)
+ erase_after(__prev, __end);
+ else
+ insert_range_after(__prev,
+ ranges::subrange(std::move(__first), __last));
+ }
+#endif // ranges_to_container
+
/**
* @brief Assigns a given value to a %forward_list.
* @param __n Number of elements to be assigned.
@@ -888,6 +949,33 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
push_front(_Tp&& __val)
{ this->_M_insert_after(cbefore_begin(), std::move(__val)); }
+#if __glibcxx_ranges_to_container // C++ >= 23
+ /**
+ * @brief Insert a range at the beginning of a forward_list.
+ * @param __rg An input range with elements that are convertible to
+ * the forward_list's value_type.
+ *
+ * The inserted elements will be in the same order as in the range,
+ * so they are not reversed as would happen with a simple loop calling
+ * emplace_front for each element of the range.
+ *
+ * No iterators to existing elements are invalidated by this function.
+ * If the insertion fails due to an exception, no elements will be added
+ * and so the list will be unchanged.
+ *
+ * @since C++23
+ */
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ void
+ prepend_range(_Rg&& __rg)
+ {
+ forward_list __tmp(from_range, std::forward<_Rg>(__rg),
+ get_allocator());
+ if (!__tmp.empty())
+ splice_after(before_begin(), __tmp);
+ }
+#endif // ranges_to_container
+
/**
* @brief Removes first element.
*
@@ -985,6 +1073,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
insert_after(const_iterator __pos,
_InputIterator __first, _InputIterator __last);
+#if __glibcxx_ranges_to_container // C++ >= 23
+ /**
+ * @brief Insert a rangeinto a forward_list.
+ * @param __position An iterator.
+ * @param __rg An input range of elements that can be converted to
+ * the forward_list's value type.
+ * @return An iterator pointing to the last element inserted,
+ * or `__position` if the range is empty.
+ *
+ * Inserts the elements of `__rg` after `__position`.
+ * No iterators to existing elements are invalidated by this function.
+ * If the insertion fails due to an exception, no elements will be added
+ * and so the list will be unchanged.
+ *
+ * @since C++23
+ */
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ iterator
+ insert_range_after(const_iterator __position, _Rg&& __rg)
+ {
+ forward_list __tmp(from_range, std::forward<_Rg>(__rg),
+ get_allocator());
+ return _M_splice_after(__position, __tmp.before_begin(), __tmp.end());
+ }
+#endif // ranges_to_container
+
/**
* @brief Inserts the contents of an initializer_list into
* %forward_list after the specified iterator.
@@ -1438,6 +1552,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
typename = _RequireAllocator<_Allocator>>
forward_list(_InputIterator, _InputIterator, _Allocator = _Allocator())
-> forward_list<_ValT, _Allocator>;
+
+#if __glibcxx_ranges_to_container // C++ >= 23
+ template<ranges::input_range _Rg,
+ typename _Alloc = allocator<ranges::range_value_t<_Rg>>>
+ forward_list(from_range_t, _Rg&&, _Alloc = _Alloc())
+ -> forward_list<ranges::range_value_t<_Rg>, _Alloc>;
+#endif
#endif
/**
diff --git a/libstdc++-v3/include/bits/stl_list.h
b/libstdc++-v3/include/bits/stl_list.h
index 8b2521960a8..2da753853ec 100644
--- a/libstdc++-v3/include/bits/stl_list.h
+++ b/libstdc++-v3/include/bits/stl_list.h
@@ -64,6 +64,10 @@
#include <bits/allocated_ptr.h>
#include <ext/aligned_buffer.h>
#endif
+#if __glibcxx_ranges_to_container // C++ >= 23
+# include <bits/ranges_base.h> // ranges::begin, ranges::distance etc.
+# include <bits/ranges_util.h> // ranges::subrange
+#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
@@ -892,6 +896,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
}
#endif
+#if __glibcxx_ranges_to_container // C++ >= 23
+ /**
+ * @brief Construct a list from a range.
+ * @since C++23
+ */
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ list(from_range_t, _Rg&& __rg, const _Alloc& __a = _Alloc())
+ : _Base(_Node_alloc_type(__a))
+ {
+ auto __first = ranges::begin(__rg);
+ const auto __last = ranges::end(__rg);
+ for (; __first != __last; ++__first)
+ emplace_back(*__first);
+ }
+#endif
+
#if __cplusplus >= 201103L
/**
* No explicit dtor needed as the _Base dtor takes care of
@@ -951,6 +971,30 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
}
#endif
+#if __glibcxx_ranges_to_container // C++ >= 23
+ /**
+ * @brief Assign a range to a list.
+ * @since C++23
+ */
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ void
+ assign_range(_Rg&& __rg)
+ {
+ iterator __first1 = begin();
+ const iterator __last1 = end();
+ auto __first2 = ranges::begin(__rg);
+ const auto __last2 = ranges::end(__rg);
+ for (; __first1 != __last1 && __first2 != __last2;
+ ++__first1, (void)++__first2)
+ *__first1 = *__first2;
+ if (__first2 == __last2)
+ erase(__first1, __last1);
+ else
+ insert_range(__last1,
+ ranges::subrange(std::move(__first2), __last2));
+ }
+#endif
+
/**
* @brief Assigns a given value to a %list.
* @param __n Number of elements to be assigned.
@@ -1275,6 +1319,50 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
}
#endif
+#if __glibcxx_ranges_to_container // C++ >= 23
+ /**
+ * @brief Insert a range at the beginning of a list.
+ * @param __rg An input range of elements that can be converted to
+ * the list's value type.
+ *
+ * Inserts the elements of `__rg` at the beginning of the list.
+ * No iterators to existing elements are invalidated by this function.
+ * If the insertion fails due to an exception, no elements will be added
+ * and so the list will be unchanged.
+ *
+ * @since C++23
+ */
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ void
+ prepend_range(_Rg&& __rg)
+ {
+ list __tmp(from_range, std::forward<_Rg>(__rg), get_allocator());
+ if (!__tmp.empty())
+ splice(begin(), __tmp);
+ }
+
+ /**
+ * @brief Insert a range at the end of a list.
+ * @param __rg An input range of elements that can be converted to
+ * the list's value type.
+ *
+ * Inserts the elements of `__rg` at the end of the list.
+ * No iterators to existing elements are invalidated by this function.
+ * If the insertion fails due to an exception, no elements will be added
+ * and so the list will be unchanged.
+ *
+ * @since C++23
+ */
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ void
+ append_range(_Rg&& __rg)
+ {
+ list __tmp(from_range, std::forward<_Rg>(__rg), get_allocator());
+ if (!__tmp.empty())
+ splice(end(), __tmp);
+ }
+#endif
+
/**
* @brief Removes first element.
*
@@ -1505,6 +1593,37 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
}
#endif
+#if __glibcxx_ranges_to_container // C++ >= 23
+ /**
+ * @brief Insert a range into a list.
+ * @param __position An iterator.
+ * @param __rg An input range of elements that can be converted to
+ * the list's value type.
+ * @return An iterator pointing to the first element inserted,
+ * or `__position` if the range is empty.
+ *
+ * Inserts the elements of `__rg` before `__position`.
+ * No iterators to existing elements are invalidated by this function.
+ * If the insertion fails due to an exception, no elements will be added
+ * and so the list will be unchanged.
+ *
+ * @since C++23
+ */
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ iterator
+ insert_range(const_iterator __position, _Rg&& __rg)
+ {
+ list __tmp(from_range, std::forward<_Rg>(__rg), get_allocator());
+ if (!__tmp.empty())
+ {
+ auto __it = __tmp.begin();
+ splice(__position, __tmp);
+ return __it;
+ }
+ return __position._M_const_cast();
+ }
+#endif
+
/**
* @brief Remove element at given position.
* @param __position Iterator pointing to element to be erased.
@@ -2102,6 +2221,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
typename = _RequireAllocator<_Allocator>>
list(_InputIterator, _InputIterator, _Allocator = _Allocator())
-> list<_ValT, _Allocator>;
+
+#if __glibcxx_ranges_to_container // C++ >= 23
+ template<ranges::input_range _Rg,
+ typename _Alloc = allocator<ranges::range_value_t<_Rg>>>
+ list(from_range_t, _Rg&&, _Alloc = _Alloc())
+ -> list<ranges::range_value_t<_Rg>, _Alloc>;
+#endif
#endif
_GLIBCXX_END_NAMESPACE_CXX11
diff --git
a/libstdc++-v3/testsuite/23_containers/forward_list/cons/from_range.cc
b/libstdc++-v3/testsuite/23_containers/forward_list/cons/from_range.cc
new file mode 100644
index 00000000000..65b378e6977
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/cons/from_range.cc
@@ -0,0 +1,100 @@
+// { dg-do run { target c++23 } }
+
+#include <forward_list>
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+void
+test_deduction_guide(long* p)
+{
+ __gnu_test::test_input_range<long> r(p, p);
+ std::forward_list v(std::from_range, r);
+ static_assert(std::is_same_v<decltype(v), std::forward_list<long>>);
+
+ using Alloc = __gnu_test::SimpleAllocator<long>;
+ Alloc alloc;
+ std::forward_list v2(std::from_range, r, alloc);
+ static_assert(std::is_same_v<decltype(v2), std::forward_list<long, Alloc>>);
+}
+
+template<typename Range, typename Alloc>
+constexpr void
+do_test(Alloc alloc)
+{
+ // The forward_list's value_type.
+ using V = typename std::allocator_traits<Alloc>::value_type;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9};
+
+ auto eq = [](const std::forward_list<V, Alloc>& l, std::span<T> r) {
+ if (std::distance(l.begin(), l.end()) != r.size())
+ return false;
+ unsigned i = 0;
+ for (auto& e : l)
+ if (e != r[i++])
+ return false;
+ return true;
+ };
+
+ std::forward_list<V, Alloc> v0(std::from_range, Range(a, a+0));
+ VERIFY( v0.empty() );
+ VERIFY( v0.get_allocator() == Alloc() );
+
+ std::forward_list<V, Alloc> v4(std::from_range, Range(a, a+4));
+ VERIFY( eq(v4, {a, 4}) );
+ VERIFY( v4.get_allocator() == Alloc() );
+
+ std::forward_list<V, Alloc> v9(std::from_range, Range(a, a+9), alloc);
+ VERIFY( eq(v9, {a, 9}) );
+ VERIFY( v9.get_allocator() == alloc );
+}
+
+template<typename Range>
+void
+do_test_a()
+{
+ do_test<Range>(std::allocator<int>());
+ do_test<Range>(__gnu_test::uneq_allocator<int>(42));
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_a<test_forward_range<int>>();
+ do_test_a<test_forward_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ do_test_a<test_input_range<int>>();
+ do_test_a<test_input_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ do_test_a<test_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ do_test_a<test_forward_range<short>>();
+ do_test_a<test_input_range<short>>();
+
+ // Not lvalue-convertible to bool
+ struct C {
+ C(int v) : val(v) { }
+ operator int() && { return val; }
+ bool operator==(int b) const { return b == val; }
+ int val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test<rvalue_input_range>(std::allocator<int>());
+
+ return true;
+}
+
+int main()
+{
+ test_ranges();
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/forward_list/modifiers/assign_range.cc
b/libstdc++-v3/testsuite/23_containers/forward_list/modifiers/assign_range.cc
new file mode 100644
index 00000000000..d8352539724
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/forward_list/modifiers/assign_range.cc
@@ -0,0 +1,97 @@
+// { dg-do run { target c++23 } }
+
+#include <forward_list>
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+template<typename Range, typename Alloc>
+constexpr void
+do_test()
+{
+ // The forward_list's value_type.
+ using V = typename std::allocator_traits<Alloc>::value_type;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9};
+
+ auto eq = [](const std::forward_list<V, Alloc>& l, std::span<T> r) {
+ if (std::distance(l.begin(), l.end()) != r.size())
+ return false;
+ unsigned i = 0;
+ for (auto& e : l)
+ if (e != r[i++])
+ return false;
+ return true;
+ };
+
+ // assign to empty forward_list
+ std::forward_list<V, Alloc> v;
+ v.assign_range(Range(a, a));
+ VERIFY( v.empty() );
+ v.assign_range(Range(a, a+4));
+ VERIFY( eq(v, {a, 4}) );
+ v.clear();
+ v.assign_range(Range(a));
+ VERIFY( eq(v, a) );
+
+ // assign to non-empty forward_list
+ v.assign_range(Range(a, a+4));
+ VERIFY( eq(v, {a, 4}) );
+ v.assign_range(Range(a)); // larger than size()
+ VERIFY( eq(v, a) );
+ v.assign_range(Range(a, a+4)); // smaller than size()
+ VERIFY( eq(v, {a, 4}) );
+ v.assign_range(Range(a+2, a+6)); // equal to size()
+ VERIFY( eq(v, {a+2, 4}) );
+ v.assign_range(Range(a, a));
+ VERIFY( v.empty() );
+}
+
+template<typename Range>
+void
+do_test_a()
+{
+ do_test<Range, std::allocator<int>>();
+ do_test<Range, __gnu_test::SimpleAllocator<int>>();
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_a<test_forward_range<int>>();
+ do_test_a<test_forward_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ do_test_a<test_input_range<int>>();
+ do_test_a<test_input_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ do_test_a<test_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ do_test_a<test_forward_range<short>>();
+ do_test_a<test_input_range<short>>();
+
+ // Not lvalue-convertible to int
+ struct C {
+ C(int v) : val(v) { }
+ operator int() && { return val; }
+ bool operator==(int b) const { return b == val; }
+ int val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test<rvalue_input_range, std::allocator<int>>();
+
+ return true;
+}
+
+int main()
+{
+ test_ranges();
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/forward_list/modifiers/insert_range_after.cc
b/libstdc++-v3/testsuite/23_containers/forward_list/modifiers/insert_range_after.cc
new file mode 100644
index 00000000000..32580a6ed1e
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/forward_list/modifiers/insert_range_after.cc
@@ -0,0 +1,93 @@
+// { dg-do run { target c++23 } }
+
+#include <forward_list>
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+template<typename Range, typename Alloc>
+constexpr void
+do_test()
+{
+ // The forward_list's value_type.
+ using V = typename std::allocator_traits<Alloc>::value_type;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9};
+
+ auto eq = [](const std::forward_list<V, Alloc>& l, std::span<T> r) {
+ if (std::distance(l.begin(), l.end()) != r.size())
+ return false;
+ unsigned i = 0;
+ for (auto& e : l)
+ if (e != r[i++])
+ return false;
+ return true;
+ };
+
+ std::forward_list<V, Alloc> v;
+ v.insert_range_after(v.before_begin(), Range(a, a));
+ VERIFY( v.empty() );
+ v.insert_range_after(v.before_begin(), Range(a, a+4));
+ VERIFY( eq(v, {a, a+4}) );
+ v.clear();
+ v.insert_range_after(v.before_begin(), Range(a+4, a+9));
+ VERIFY( eq(v, {a+4, a+9}) );
+ v.insert_range_after(v.before_begin(), Range(a, a+4));
+ VERIFY( eq(v, a) );
+ v.clear();
+ v.insert_range_after(v.before_begin(), Range(a, a+3));
+ v.insert_range_after(std::next(v.before_begin(), 3), Range(a+6, a+9));
+ v.insert_range_after(std::next(v.before_begin(), 3), Range(a+3, a+6));
+ VERIFY( eq(v, a) );
+ v.insert_range_after(std::next(v.before_begin(), 2), Range(a, a));
+ VERIFY( eq(v, a) );
+}
+
+template<typename Range>
+void
+do_test_a()
+{
+ do_test<Range, std::allocator<int>>();
+ do_test<Range, __gnu_test::SimpleAllocator<int>>();
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_a<test_forward_range<int>>();
+ do_test_a<test_forward_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ do_test_a<test_input_range<int>>();
+ do_test_a<test_input_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ do_test_a<test_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ do_test_a<test_forward_range<short>>();
+ do_test_a<test_input_range<short>>();
+
+ // Not lvalue-convertible to int
+ struct C {
+ C(int v) : val(v) { }
+ operator int() && { return val; }
+ bool operator==(int b) const { return b == val; }
+ int val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test<rvalue_input_range, std::allocator<int>>();
+
+ return true;
+}
+
+int main()
+{
+ test_ranges();
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/forward_list/modifiers/prepend_range.cc
b/libstdc++-v3/testsuite/23_containers/forward_list/modifiers/prepend_range.cc
new file mode 100644
index 00000000000..ae38fb7e791
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/forward_list/modifiers/prepend_range.cc
@@ -0,0 +1,86 @@
+// { dg-do run { target c++23 } }
+
+#include <forward_list>
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+template<typename Range, typename Alloc>
+constexpr void
+do_test()
+{
+ // The forward_list's value_type.
+ using V = typename std::allocator_traits<Alloc>::value_type;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9};
+
+ auto eq = [](const std::forward_list<V, Alloc>& l, std::span<T> r) {
+ if (std::distance(l.begin(), l.end()) != r.size())
+ return false;
+ unsigned i = 0;
+ for (auto& e : l)
+ if (e != r[i++])
+ return false;
+ return true;
+ };
+
+ std::forward_list<V, Alloc> v;
+ v.prepend_range(Range(a+4, a+9));
+ VERIFY( eq(v, {a+4, 5}) );
+ v.prepend_range(Range(a, a+4));
+ VERIFY( eq(v, a) );
+ v.prepend_range(Range(a, a));
+ VERIFY( eq(v, a) );
+ v.clear();
+ v.prepend_range(Range(a, a));
+ VERIFY( v.empty() );
+}
+
+template<typename Range>
+void
+do_test_a()
+{
+ do_test<Range, std::allocator<int>>();
+ do_test<Range, __gnu_test::SimpleAllocator<int>>();
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_a<test_forward_range<int>>();
+ do_test_a<test_forward_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ do_test_a<test_input_range<int>>();
+ do_test_a<test_input_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ do_test_a<test_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ do_test_a<test_forward_range<short>>();
+ do_test_a<test_input_range<short>>();
+
+ // Not lvalue-convertible to int
+ struct C {
+ C(int v) : val(v) { }
+ operator int() && { return val; }
+ bool operator==(int b) const { return b == val; }
+ int val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test<rvalue_input_range, std::allocator<int>>();
+
+ return true;
+}
+
+int main()
+{
+ test_ranges();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/list/cons/from_range.cc
b/libstdc++-v3/testsuite/23_containers/list/cons/from_range.cc
new file mode 100644
index 00000000000..31448b9122b
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/list/cons/from_range.cc
@@ -0,0 +1,100 @@
+// { dg-do run { target c++23 } }
+
+#include <list>
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+void
+test_deduction_guide(long* p)
+{
+ __gnu_test::test_input_range<long> r(p, p);
+ std::list v(std::from_range, r);
+ static_assert(std::is_same_v<decltype(v), std::list<long>>);
+
+ using Alloc = __gnu_test::SimpleAllocator<long>;
+ Alloc alloc;
+ std::list v2(std::from_range, r, alloc);
+ static_assert(std::is_same_v<decltype(v2), std::list<long, Alloc>>);
+}
+
+template<typename Range, typename Alloc>
+constexpr void
+do_test(Alloc alloc)
+{
+ // The list's value_type.
+ using V = typename std::allocator_traits<Alloc>::value_type;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9};
+
+ auto eq = [](const std::list<V, Alloc>& l, std::span<T> r) {
+ if (l.size() != r.size())
+ return false;
+ unsigned i = 0;
+ for (auto& e : l)
+ if (e != r[i++])
+ return false;
+ return true;
+ };
+
+ std::list<V, Alloc> v0(std::from_range, Range(a, a+0));
+ VERIFY( v0.empty() );
+ VERIFY( v0.get_allocator() == Alloc() );
+
+ std::list<V, Alloc> v4(std::from_range, Range(a, a+4));
+ VERIFY( eq(v4, {a, 4}) );
+ VERIFY( v4.get_allocator() == Alloc() );
+
+ std::list<V, Alloc> v9(std::from_range, Range(a, a+9), alloc);
+ VERIFY( eq(v9, {a, 9}) );
+ VERIFY( v9.get_allocator() == alloc );
+}
+
+template<typename Range>
+void
+do_test_a()
+{
+ do_test<Range>(std::allocator<int>());
+ do_test<Range>(__gnu_test::uneq_allocator<int>(42));
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_a<test_forward_range<int>>();
+ do_test_a<test_forward_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ do_test_a<test_input_range<int>>();
+ do_test_a<test_input_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ do_test_a<test_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ do_test_a<test_forward_range<short>>();
+ do_test_a<test_input_range<short>>();
+
+ // Not lvalue-convertible to bool
+ struct C {
+ C(int v) : val(v) { }
+ operator int() && { return val; }
+ bool operator==(int b) const { return b == val; }
+ int val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test<rvalue_input_range>(std::allocator<int>());
+
+ return true;
+}
+
+int main()
+{
+ test_ranges();
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/list/modifiers/append_range.cc
b/libstdc++-v3/testsuite/23_containers/list/modifiers/append_range.cc
new file mode 100644
index 00000000000..9ddfc7dbea3
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/list/modifiers/append_range.cc
@@ -0,0 +1,86 @@
+// { dg-do run { target c++23 } }
+
+#include <list>
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+template<typename Range, typename Alloc>
+constexpr void
+do_test()
+{
+ // The list's value_type.
+ using V = typename std::allocator_traits<Alloc>::value_type;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9};
+
+ auto eq = [](const std::list<V, Alloc>& l, std::span<T> r) {
+ if (l.size() != r.size())
+ return false;
+ unsigned i = 0;
+ for (auto& e : l)
+ if (e != r[i++])
+ return false;
+ return true;
+ };
+
+ std::list<V, Alloc> v;
+ v.append_range(Range(a, a+4));
+ VERIFY( eq(v, {a, 4}) );
+ v.append_range(Range(a+4, a+9));
+ VERIFY( eq(v, a) );
+ v.append_range(Range(a, a));
+ VERIFY( eq(v, a) );
+ v.clear();
+ v.append_range(Range(a, a));
+ VERIFY( v.empty() );
+}
+
+template<typename Range>
+void
+do_test_a()
+{
+ do_test<Range, std::allocator<int>>();
+ do_test<Range, __gnu_test::SimpleAllocator<int>>();
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_a<test_forward_range<int>>();
+ do_test_a<test_forward_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ do_test_a<test_input_range<int>>();
+ do_test_a<test_input_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ do_test_a<test_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ do_test_a<test_forward_range<short>>();
+ do_test_a<test_input_range<short>>();
+
+ // Not lvalue-convertible to int
+ struct C {
+ C(int v) : val(v) { }
+ operator int() && { return val; }
+ bool operator==(int b) const { return b == val; }
+ int val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test<rvalue_input_range, std::allocator<int>>();
+
+ return true;
+}
+
+int main()
+{
+ test_ranges();
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/list/modifiers/assign/assign_range.cc
b/libstdc++-v3/testsuite/23_containers/list/modifiers/assign/assign_range.cc
new file mode 100644
index 00000000000..84b9f07a8eb
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/list/modifiers/assign/assign_range.cc
@@ -0,0 +1,99 @@
+// { dg-do run { target c++23 } }
+
+#include <list>
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+template<typename Range, typename Alloc>
+constexpr void
+do_test()
+{
+ // The list's value_type.
+ using V = typename std::allocator_traits<Alloc>::value_type;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9};
+
+ auto eq = [](const std::list<V, Alloc>& l, std::span<T> r) {
+ if (l.size() != r.size())
+ return false;
+ unsigned i = 0;
+ for (auto& e : l)
+ if (e != r[i++])
+ return false;
+ return true;
+ };
+
+ // assign to empty list
+ std::list<V, Alloc> v;
+ v.assign_range(Range(a, a));
+ VERIFY( v.empty() );
+ v.assign_range(Range(a, a+4));
+ VERIFY( eq(v, {a, 4}) );
+ v.clear();
+ v.assign_range(Range(a));
+ VERIFY( eq(v, a) );
+
+ // assign to non-empty list
+ v.assign_range(Range(a, a+4));
+ VERIFY( eq(v, {a, 4}) );
+ v.assign_range(Range(a)); // larger than size()
+ VERIFY( eq(v, a) );
+ v.assign_range(Range(a, a+4)); // smaller than size()
+ VERIFY( eq(v, {a, 4}) );
+ v.clear();
+ v.resize(4);
+ v.assign_range(Range(a, a+4)); // equal to size()
+ VERIFY( eq(v, {a, 4}) );
+ v.assign_range(Range(a, a));
+ VERIFY( v.empty() );
+}
+
+template<typename Range>
+void
+do_test_a()
+{
+ do_test<Range, std::allocator<int>>();
+ do_test<Range, __gnu_test::SimpleAllocator<int>>();
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_a<test_forward_range<int>>();
+ do_test_a<test_forward_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ do_test_a<test_input_range<int>>();
+ do_test_a<test_input_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ do_test_a<test_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ do_test_a<test_forward_range<short>>();
+ do_test_a<test_input_range<short>>();
+
+ // Not lvalue-convertible to int
+ struct C {
+ C(int v) : val(v) { }
+ operator int() && { return val; }
+ bool operator==(int b) const { return b == val; }
+ int val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test<rvalue_input_range, std::allocator<int>>();
+
+ return true;
+}
+
+int main()
+{
+ test_ranges();
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/list/modifiers/insert/insert_range.cc
b/libstdc++-v3/testsuite/23_containers/list/modifiers/insert/insert_range.cc
new file mode 100644
index 00000000000..a15d51d7466
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/list/modifiers/insert/insert_range.cc
@@ -0,0 +1,98 @@
+// { dg-do run { target c++23 } }
+
+#include <list>
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+template<typename Range, typename Alloc>
+constexpr void
+do_test()
+{
+ // The list's value_type.
+ using V = typename std::allocator_traits<Alloc>::value_type;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9};
+
+ auto eq = [](const std::list<V, Alloc>& l, std::span<T> r) {
+ if (l.size() != r.size())
+ return false;
+ unsigned i = 0;
+ for (auto& e : l)
+ if (e != r[i++])
+ return false;
+ return true;
+ };
+
+ std::list<V, Alloc> v;
+ v.insert_range(v.begin(), Range(a, a));
+ VERIFY( v.empty() );
+ v.insert_range(v.begin(), Range(a, a+4));
+ VERIFY( eq(v, {a, a+4}) );
+ v.clear();
+ v.insert_range(v.begin(), Range(a+4, a+9));
+ VERIFY( eq(v, {a+4, a+9}) );
+ v.insert_range(v.begin(), Range(a, a+4));
+ VERIFY( eq(v, a) );
+ v.clear();
+ v.insert_range(v.begin(), Range(a, a+3));
+ v.insert_range(v.end(), Range(a+6, a+9));
+ v.insert_range(std::next(v.begin(), 3), Range(a+3, a+6));
+ VERIFY( eq(v, a) );
+ v.resize(3);
+ v.insert_range(std::next(v.begin()), Range(a+4, a+9));
+ v.insert_range(std::next(v.begin()), Range(a+1, a+4));
+ v.resize(9);
+ VERIFY( eq(v, a) );
+ v.insert_range(std::next(v.begin(), 6), Range(a, a));
+ VERIFY( eq(v, a) );
+}
+
+template<typename Range>
+void
+do_test_a()
+{
+ do_test<Range, std::allocator<int>>();
+ do_test<Range, __gnu_test::SimpleAllocator<int>>();
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_a<test_forward_range<int>>();
+ do_test_a<test_forward_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ do_test_a<test_input_range<int>>();
+ do_test_a<test_input_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ do_test_a<test_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ do_test_a<test_forward_range<short>>();
+ do_test_a<test_input_range<short>>();
+
+ // Not lvalue-convertible to int
+ struct C {
+ C(int v) : val(v) { }
+ operator int() && { return val; }
+ bool operator==(int b) const { return b == val; }
+ int val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test<rvalue_input_range, std::allocator<int>>();
+
+ return true;
+}
+
+int main()
+{
+ test_ranges();
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/list/modifiers/prepend_range.cc
b/libstdc++-v3/testsuite/23_containers/list/modifiers/prepend_range.cc
new file mode 100644
index 00000000000..fe217e19573
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/list/modifiers/prepend_range.cc
@@ -0,0 +1,86 @@
+// { dg-do run { target c++23 } }
+
+#include <list>
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+template<typename Range, typename Alloc>
+constexpr void
+do_test()
+{
+ // The list's value_type.
+ using V = typename std::allocator_traits<Alloc>::value_type;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9};
+
+ auto eq = [](const std::list<V, Alloc>& l, std::span<T> r) {
+ if (l.size() != r.size())
+ return false;
+ unsigned i = 0;
+ for (auto& e : l)
+ if (e != r[i++])
+ return false;
+ return true;
+ };
+
+ std::list<V, Alloc> v;
+ v.prepend_range(Range(a+4, a+9));
+ VERIFY( eq(v, {a+4, 5}) );
+ v.prepend_range(Range(a, a+4));
+ VERIFY( eq(v, a) );
+ v.prepend_range(Range(a, a));
+ VERIFY( eq(v, a) );
+ v.clear();
+ v.prepend_range(Range(a, a));
+ VERIFY( v.empty() );
+}
+
+template<typename Range>
+void
+do_test_a()
+{
+ do_test<Range, std::allocator<int>>();
+ do_test<Range, __gnu_test::SimpleAllocator<int>>();
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_a<test_forward_range<int>>();
+ do_test_a<test_forward_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ do_test_a<test_input_range<int>>();
+ do_test_a<test_input_sized_range<int>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ do_test_a<test_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ do_test_a<test_forward_range<short>>();
+ do_test_a<test_input_range<short>>();
+
+ // Not lvalue-convertible to int
+ struct C {
+ C(int v) : val(v) { }
+ operator int() && { return val; }
+ bool operator==(int b) const { return b == val; }
+ int val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test<rvalue_input_range, std::allocator<int>>();
+
+ return true;
+}
+
+int main()
+{
+ test_ranges();
+}
--
2.47.0