From: Tomasz KamiĆski <tkami...@redhat.com> This is another piece of P1206R7, adding new members to std::stack, std::queue, and std::priority_queue.
PR libstdc++/111055 libstdc++-v3/ChangeLog: * include/bits/stl_queue.h (queue(from_range_t, _Rg&&)) (queue(from_range_t, _Rg&&, const _Alloc&), push_range): Define. (priority_queue(from_range_t, R&&, const Compare&)) (push_range): Define. * include/bits/stl_stack.h (stack(from_range_t, R&&)) (stack(from_range_t, R&&, const Alloc&), push_range): Define. * testsuite/util/testsuite_iterators.h (test_range_nocopy): Define. * testsuite/23_containers/priority_queue/cons_from_range.cc: New test. * testsuite/23_containers/priority_queue/members/push_range.cc: New test. * testsuite/23_containers/queue/cons_from_range.cc: New test. * testsuite/23_containers/queue/members/push_range.cc: New test. * testsuite/23_containers/stack/cons_from_range.cc: New test. * testsuite/23_containers/stack/members/push_range.cc: New test. --- Pushed to trunk. Approved by Jonathan Wakely on sourceforge: https://forge.sourceware.org/gcc/gcc-TEST/pulls/43#issuecomment-780. libstdc++-v3/include/bits/stl_queue.h | 102 ++++++++++++++++ libstdc++-v3/include/bits/stl_stack.h | 46 ++++++++ .../priority_queue/cons_from_range.cc | 111 ++++++++++++++++++ .../priority_queue/members/push_range.cc | 86 ++++++++++++++ .../23_containers/queue/cons_from_range.cc | 88 ++++++++++++++ .../23_containers/queue/members/push_range.cc | 73 ++++++++++++ .../23_containers/stack/cons_from_range.cc | 89 ++++++++++++++ .../23_containers/stack/members/push_range.cc | 74 ++++++++++++ .../testsuite/util/testsuite_iterators.h | 11 ++ 9 files changed, 680 insertions(+) create mode 100644 libstdc++-v3/testsuite/23_containers/priority_queue/cons_from_range.cc create mode 100644 libstdc++-v3/testsuite/23_containers/priority_queue/members/push_range.cc create mode 100644 libstdc++-v3/testsuite/23_containers/queue/cons_from_range.cc create mode 100644 libstdc++-v3/testsuite/23_containers/queue/members/push_range.cc create mode 100644 libstdc++-v3/testsuite/23_containers/stack/cons_from_range.cc create mode 100644 libstdc++-v3/testsuite/23_containers/stack/members/push_range.cc diff --git a/libstdc++-v3/include/bits/stl_queue.h b/libstdc++-v3/include/bits/stl_queue.h index 627d5e4e63b..2a4b62918a0 100644 --- a/libstdc++-v3/include/bits/stl_queue.h +++ b/libstdc++-v3/include/bits/stl_queue.h @@ -61,6 +61,10 @@ #if __cplusplus >= 201103L # include <bits/uses_allocator.h> #endif +#if __glibcxx_ranges_to_container // C++ >= 23 +# include <ranges> // ranges::to +# include <bits/ranges_algobase.h> // ranges::copy +#endif namespace std _GLIBCXX_VISIBILITY(default) { @@ -209,6 +213,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : c(__first, __last, __a) { } #endif +#if __glibcxx_ranges_to_container // C++ >= 23 + /** + * @brief Construct a queue from a range. + * @since C++23 + */ + template<__detail::__container_compatible_range<_Tp> _Rg> + queue(from_range_t, _Rg&& __rg) + : c(ranges::to<_Sequence>(std::forward<_Rg>(__rg))) + { } + + /** + * @brief Construct a queue from a range. + * @since C++23 + */ + template<__detail::__container_compatible_range<_Tp> _Rg, + typename _Alloc> + queue(from_range_t, _Rg&& __rg, const _Alloc& __a) + : c(ranges::to<_Sequence>(std::forward<_Rg>(__rg), __a)) + { } +#endif + /** * Returns true if the %queue is empty. */ @@ -301,6 +326,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif #endif +#if __glibcxx_ranges_to_container // C++ >= 23 + template<__detail::__container_compatible_range<_Tp> _Rg> + void + push_range(_Rg&& __rg) + { + if constexpr (requires { c.append_range(std::forward<_Rg>(__rg)); }) + c.append_range(std::forward<_Rg>(__rg)); + else + ranges::copy(__rg, std::back_inserter(c)); + } +#endif + /** * @brief Removes first element. * @@ -359,6 +396,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION queue(_InputIterator, _InputIterator, _Allocator) -> queue<_ValT, deque<_ValT, _Allocator>>; #endif + +#if __glibcxx_ranges_to_container // C++ >= 23 + template<ranges::input_range _Rg> + queue(from_range_t, _Rg&&) -> queue<ranges::range_value_t<_Rg>>; + + template<ranges::input_range _Rg, __allocator_like _Alloc> + queue(from_range_t, _Rg&&, _Alloc) + -> queue<ranges::range_value_t<_Rg>, + deque<ranges::range_value_t<_Rg>, _Alloc>>; +#endif #endif /** @@ -719,6 +766,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif +#if __glibcxx_ranges_to_container // C++ >= 23 + /** + * @brief Construct a priority_queue from a range. + * @since C++23 + * + * @{ + */ + template<__detail::__container_compatible_range<_Tp> _Rg> + priority_queue(from_range_t, _Rg&& __rg, + const _Compare& __x = _Compare()) + : c(ranges::to<_Sequence>(std::forward<_Rg>(__rg))), comp(__x) + { std::make_heap(c.begin(), c.end(), comp); } + + template<__detail::__container_compatible_range<_Tp> _Rg, typename _Alloc> + priority_queue(from_range_t, _Rg&& __rg, const _Compare& __x, + const _Alloc& __a) + : c(ranges::to<_Sequence>(std::forward<_Rg>(__rg), __a)), comp(__x) + { std::make_heap(c.begin(), c.end(), comp); } + + template<__detail::__container_compatible_range<_Tp> _Rg, typename _Alloc> + priority_queue(from_range_t, _Rg&& __rg, const _Alloc& __a) + : c(ranges::to<_Sequence>(std::forward<_Rg>(__rg), __a)), comp() + { std::make_heap(c.begin(), c.end(), comp); } + /// @} +#endif + /** * Returns true if the %queue is empty. */ @@ -776,6 +849,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif +#if __glibcxx_ranges_to_container // C++ >= 23 + template<__detail::__container_compatible_range<_Tp> _Rg> + void + push_range(_Rg&& __rg) + { + if constexpr (requires { c.append_range(std::forward<_Rg>(__rg)); }) + c.append_range(std::forward<_Rg>(__rg)); + else + ranges::copy(__rg, std::back_inserter(c)); + std::make_heap(c.begin(), c.end(), comp); + } +#endif + /** * @brief Removes first element. * @@ -837,6 +923,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename = _RequireNotAllocator<_Container>> priority_queue(_Compare, _Container, _Allocator) -> priority_queue<typename _Container::value_type, _Container, _Compare>; + +#if __glibcxx_ranges_to_container // C++ >= 23 + template<ranges::input_range _Rg, + __not_allocator_like _Compare = less<ranges::range_value_t<_Rg>>, + __allocator_like _Alloc = std::allocator<ranges::range_value_t<_Rg>>> + priority_queue(from_range_t, _Rg&&, _Compare = _Compare(), + _Alloc = _Alloc()) + -> priority_queue<ranges::range_value_t<_Rg>, + vector<ranges::range_value_t<_Rg>, _Alloc>, + _Compare>; + + template<ranges::input_range _Rg, __allocator_like _Alloc> + priority_queue(from_range_t, _Rg&&, _Alloc) + -> priority_queue<ranges::range_value_t<_Rg>, + vector<ranges::range_value_t<_Rg>, _Alloc>>; +#endif #endif // No equality/comparison operators are provided for priority_queue. diff --git a/libstdc++-v3/include/bits/stl_stack.h b/libstdc++-v3/include/bits/stl_stack.h index ce749f2f8b9..2a274bf4c3a 100644 --- a/libstdc++-v3/include/bits/stl_stack.h +++ b/libstdc++-v3/include/bits/stl_stack.h @@ -61,6 +61,10 @@ #if __cplusplus >= 201103L # include <bits/uses_allocator.h> #endif +#if __glibcxx_ranges_to_container // C++ >= 23 +# include <ranges> // ranges::to +# include <bits/ranges_algobase.h> // ranges::copy +#endif namespace std _GLIBCXX_VISIBILITY(default) { @@ -177,6 +181,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : c(__first, __last) { } #endif +#if __glibcxx_ranges_to_container // C++ >= 23 + /** + * @brief Construct a stack from a range. + * @since C++23 + */ + template<__detail::__container_compatible_range<_Tp> _Rg> + stack(from_range_t, _Rg&& __rg) + : c(ranges::to<_Sequence>(std::forward<_Rg>(__rg))) + { } + + /** + * @brief Construct a stack from a range. + * @since C++23 + */ + template<__detail::__container_compatible_range<_Tp> _Rg, + typename _Alloc> + stack(from_range_t, _Rg&& __rg, const _Alloc& __a) + : c(ranges::to<_Sequence>(std::forward<_Rg>(__rg), __a)) + { } +#endif template<typename _Alloc, typename _Requires = _Uses<_Alloc>> explicit @@ -276,6 +300,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif #endif +#if __glibcxx_ranges_to_container // C++ >= 23 + template<__detail::__container_compatible_range<_Tp> _Rg> + void + push_range(_Rg&& __rg) + { + if constexpr (requires { c.append_range(std::forward<_Rg>(__rg)); }) + c.append_range(std::forward<_Rg>(__rg)); + else + ranges::copy(__rg, std::back_inserter(c)); + } +#endif + /** * @brief Removes first element. * @@ -334,6 +370,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION stack(_InputIterator, _InputIterator, _Allocator) -> stack<_ValT, deque<_ValT, _Allocator>>; #endif + +#if __glibcxx_ranges_to_container // C++ >= 23 + template<ranges::input_range _Rg> + stack(from_range_t, _Rg&&) -> stack<ranges::range_value_t<_Rg>>; + + template<ranges::input_range _Rg, __allocator_like _Alloc> + stack(from_range_t, _Rg&&, _Alloc) + -> stack<ranges::range_value_t<_Rg>, + deque<ranges::range_value_t<_Rg>, _Alloc>>; +#endif #endif /** diff --git a/libstdc++-v3/testsuite/23_containers/priority_queue/cons_from_range.cc b/libstdc++-v3/testsuite/23_containers/priority_queue/cons_from_range.cc new file mode 100644 index 00000000000..a7ff3e3b037 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/priority_queue/cons_from_range.cc @@ -0,0 +1,111 @@ +// { dg-do run { target c++23 } } + +#include <queue> +#include <ranges> +#include <span> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> +#include <vector> + +struct Gt { + template<typename T, typename U> + bool operator()(T const& l, U const & r) { + return l > r; + } +}; + +void +test_deduction_guide(long* p) +{ + __gnu_test::test_input_range<long> r(p, p); + std::priority_queue pq(std::from_range, r); + static_assert(std::is_same_v<decltype(pq), std::priority_queue<long>>); + + Gt cmp; + std::priority_queue pq3(std::from_range, r, cmp); + static_assert(std::is_same_v<decltype(pq3), std::priority_queue<long, std::vector<long>, Gt>>); + + using Alloc = __gnu_test::SimpleAllocator<long>; + Alloc alloc; + std::priority_queue pq2(std::from_range, r, alloc); + static_assert(std::is_same_v<decltype(pq2), std::priority_queue<long, std::vector<long, Alloc>>>); + + std::priority_queue pq4(std::from_range, r, cmp, alloc); + static_assert(std::is_same_v<decltype(pq4), std::priority_queue<long, std::vector<long, Alloc>, Gt>>); +} + +template<typename Range, typename Cont, typename Cmp = std::less<int>> +constexpr void +do_test(Cmp cmp = Cmp()) +{ + // The queue's value_type. + using V = typename Cont::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 = [&](std::priority_queue<V, Cont, Cmp>& l, std::span<T> r) { + if (l.size() != r.size()) + return false; + + std::vector<T> s(r.begin(), r.end()); + std::ranges::sort(s, cmp); + for (auto const& v : s | std::views::reverse) { + if (v != l.top()) + return false; + l.pop(); + } + return true; + }; + + std::priority_queue<V, Cont, Cmp> pq0(std::from_range, Range(a, a+0)); + VERIFY( pq0.empty() ); + + std::priority_queue<V, Cont, Cmp> pq4(std::from_range, Range(a, a+4), cmp); + VERIFY( eq(pq4, {a, 4}) ); + + typename Cont::allocator_type alloc; + std::priority_queue<V, Cont, Cmp> pq7(std::from_range, Range(a, a+7), alloc); + VERIFY( eq(pq7, {a, 7}) ); + + std::priority_queue<V, Cont, Cmp> pq9(std::from_range, Range(a, a+9), cmp, alloc); + VERIFY( eq(pq9, {a, 9}) ); +} + +template<typename T, typename Alloc = std::allocator<T>> +struct NoFromRangeCont : std::vector<T, Alloc> +{ + NoFromRangeCont() = default; + NoFromRangeCont(const Alloc& a) : std::vector<T, Alloc>(a) {} +}; + +template<typename Range> +void +do_test_c() +{ + do_test<Range, std::vector<int>>(); + do_test<Range, std::vector<int, __gnu_test::SimpleAllocator<int>>>(); + do_test<Range, std::vector<int>, Gt>(); + do_test<Range, std::vector<int, __gnu_test::SimpleAllocator<int>>, Gt>(); + do_test<Range, std::deque<int>>(); + do_test<Range, NoFromRangeCont<int>>(); +} + +bool +test_ranges() +{ + using namespace __gnu_test; + + do_test_c<test_forward_range<int>>(); + do_test_c<test_range_nocopy<int, input_iterator_wrapper_nocopy>>(); + do_test_c<test_forward_range<short>>(); + + return true; +} + +int main() +{ + test_ranges(); +} diff --git a/libstdc++-v3/testsuite/23_containers/priority_queue/members/push_range.cc b/libstdc++-v3/testsuite/23_containers/priority_queue/members/push_range.cc new file mode 100644 index 00000000000..a380dbd1098 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/priority_queue/members/push_range.cc @@ -0,0 +1,86 @@ +// { dg-do run { target c++23 } } + +#include <queue> +#include <ranges> +#include <span> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> +#include <vector> + +struct Gt { + template<typename T, typename U> + bool operator()(T const& l, U const & r) { + return l > r; + } +}; + +template<typename Range, typename Cont, typename Cmp = std::less<int>> +constexpr void +do_test(Cmp cmp = Cmp()) +{ + // The queue's value_type. + using V = typename Cont::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 = [&](std::priority_queue<V, Cont, Cmp> l, std::span<T> r) { + if (l.size() != r.size()) + return false; + + std::vector<T> s(r.begin(), r.end()); + std::ranges::sort(s, cmp); + for (auto const& v : s | std::views::reverse) { + if (v != l.top()) + return false; + l.pop(); + } + return true; + }; + + std::priority_queue<V, Cont, Cmp> pq(std::from_range, Range(a, a+0)); + pq.push_range(Range(a, a+0)); + VERIFY( pq.empty() ); + + pq.push_range(Range(a, a+4)); + VERIFY( eq(pq, {a, 4}) ); + + pq.push_range(Range(a+4, a+9)); + VERIFY( eq(pq, {a, 9}) ); +} + +template<typename T, typename Alloc = std::allocator<T>> +struct NoAppendRangeCont : std::vector<T, Alloc> +{ + template<typename R> + void append_range(R&&) = delete; +}; + +template<typename Range> +void +do_test_c() +{ + do_test<Range, std::vector<int>>(); + do_test<Range, std::vector<int>, Gt>(); + do_test<Range, std::deque<int>>(); + do_test<Range, NoAppendRangeCont<int>>(); +} + +bool +test_ranges() +{ + using namespace __gnu_test; + + do_test_c<test_forward_range<int>>(); + do_test_c<test_range_nocopy<int, input_iterator_wrapper_nocopy>>(); + do_test_c<test_forward_range<short>>(); + + return true; +} + +int main() +{ + test_ranges(); +} diff --git a/libstdc++-v3/testsuite/23_containers/queue/cons_from_range.cc b/libstdc++-v3/testsuite/23_containers/queue/cons_from_range.cc new file mode 100644 index 00000000000..c21f52cb1e2 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/queue/cons_from_range.cc @@ -0,0 +1,88 @@ +// { dg-do run { target c++23 } } + +#include <list> +#include <queue> +#include <span> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +void +test_deduction_guide(long* p) +{ + __gnu_test::test_input_range<long> r(p, p); + std::queue q(std::from_range, r); + static_assert(std::is_same_v<decltype(q), std::queue<long>>); + + using Alloc = __gnu_test::SimpleAllocator<long>; + Alloc alloc; + std::queue q2(std::from_range, r, alloc); + static_assert(std::is_same_v<decltype(q2), std::queue<long, std::deque<long, Alloc>>>); +} + +template<typename Range, typename Cont> +constexpr void +do_test() +{ + // The queue's value_type. + using V = typename Cont::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 = [](std::queue<V, Cont>& l, std::span<T> r) { + if (l.size() != r.size()) + return false; + for (auto const& v : r) { + if (v != l.front()) + return false; + l.pop(); + } + return true; + }; + + std::queue<V, Cont> q0(std::from_range, Range(a, a+0)); + VERIFY( q0.empty() ); + + std::queue<V, Cont> q4(std::from_range, Range(a, a+4)); + VERIFY( eq(q4, {a, 4}) ); + + typename Cont::allocator_type alloc; + std::queue<V, Cont> q9(std::from_range, Range(a, a+9), alloc); + VERIFY( eq(q9, {a, 9}) ); +} + +template<typename T, typename Alloc = std::allocator<T>> +struct NoFromRangeCont : std::deque<T, Alloc> +{ + NoFromRangeCont() = default; + NoFromRangeCont(const Alloc& a) : std::deque<T, Alloc>(a) {} +}; + +template<typename Range> +void +do_test_c() +{ + do_test<Range, std::deque<int>>(); + do_test<Range, std::deque<int, __gnu_test::SimpleAllocator<int>>>(); + do_test<Range, std::list<int>>(); + do_test<Range, NoFromRangeCont<int>>(); +} + +bool +test_ranges() +{ + using namespace __gnu_test; + + do_test_c<test_forward_range<int>>(); + do_test_c<test_range_nocopy<int, input_iterator_wrapper_nocopy>>(); + do_test_c<test_forward_range<short>>(); + + return true; +} + +int main() +{ + test_ranges(); +} diff --git a/libstdc++-v3/testsuite/23_containers/queue/members/push_range.cc b/libstdc++-v3/testsuite/23_containers/queue/members/push_range.cc new file mode 100644 index 00000000000..bf82b869c1b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/queue/members/push_range.cc @@ -0,0 +1,73 @@ +// { dg-do run { target c++23 } } + +#include <list> +#include <queue> +#include <span> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +template<typename Range, typename Cont> +constexpr void +do_test() +{ + // The queue's value_type. + using V = typename Cont::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 = [](std::queue<V, Cont> l, std::span<T> r) { + if (l.size() != r.size()) + return false; + for (auto const& v : r) { + if (v != l.front()) + return false; + l.pop(); + } + return true; + }; + + std::queue<V, Cont> q; + q.push_range(Range(a, a+0)); + VERIFY( q.empty() ); + + q.push_range(Range(a, a+4)); + VERIFY( eq(q, {a, 4}) ); + + q.push_range(Range(a+4, a+9)); + VERIFY( eq(q, {a, 9}) ); +} + +template<typename T, typename Alloc = std::allocator<T>> +struct NoAppendRangeCont : std::deque<T, Alloc> +{ + template<typename R> + void append_range(R&&) = delete; +}; + +template<typename Range> +void +do_test_c() +{ + do_test<Range, std::deque<int>>(); + do_test<Range, std::list<int>>(); + do_test<Range, NoAppendRangeCont<int>>(); +} + +bool +test_ranges() +{ + using namespace __gnu_test; + + do_test_c<test_forward_range<int>>(); + do_test_c<test_range_nocopy<int, input_iterator_wrapper_nocopy>>(); + do_test_c<test_forward_range<short>>(); + + return true; +} + +int main() +{ + test_ranges(); +} diff --git a/libstdc++-v3/testsuite/23_containers/stack/cons_from_range.cc b/libstdc++-v3/testsuite/23_containers/stack/cons_from_range.cc new file mode 100644 index 00000000000..e957d0c4450 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/stack/cons_from_range.cc @@ -0,0 +1,89 @@ +// { dg-do run { target c++23 } } + +#include <ranges> +#include <span> +#include <stack> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> +#include <vector> + +void +test_deduction_guide(long* p) +{ + __gnu_test::test_input_range<long> r(p, p); + std::stack s(std::from_range, r); + static_assert(std::is_same_v<decltype(s), std::stack<long>>); + + using Alloc = __gnu_test::SimpleAllocator<long>; + Alloc alloc; + std::stack s2(std::from_range, r, alloc); + static_assert(std::is_same_v<decltype(s2), std::stack<long, std::deque<long, Alloc>>>); +} + +template<typename Range, typename Cont> +constexpr void +do_test() +{ + // The stack's value_type. + using V = typename Cont::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 = [](std::stack<V, Cont>& l, std::span<T> r) { + if (l.size() != r.size()) + return false; + for (auto const& v : r | std::views::reverse) { + if (v != l.top()) + return false; + l.pop(); + } + return true; + }; + + std::stack<V, Cont> s0(std::from_range, Range(a, a+0)); + VERIFY( s0.empty() ); + + std::stack<V, Cont> s4(std::from_range, Range(a, a+4)); + VERIFY( eq(s4, {a, 4}) ); + + typename Cont::allocator_type alloc; + std::stack<V, Cont> s9(std::from_range, Range(a, a+9), alloc); + VERIFY( eq(s9, {a, 9}) ); +} + +template<typename T, typename Alloc = std::allocator<T>> +struct NoFromRangeCont : std::deque<T, Alloc> +{ + NoFromRangeCont() = default; + NoFromRangeCont(const Alloc& a) : std::deque<T, Alloc>(a) {} +}; + +template<typename Range> +void +do_test_c() +{ + do_test<Range, std::deque<int>>(); + do_test<Range, std::deque<int, __gnu_test::SimpleAllocator<int>>>(); + do_test<Range, std::vector<int>>(); + do_test<Range, NoFromRangeCont<int>>(); +} + +bool +test_ranges() +{ + using namespace __gnu_test; + + do_test_c<test_forward_range<int>>(); + do_test_c<test_range_nocopy<int, input_iterator_wrapper_nocopy>>(); + do_test_c<test_forward_range<short>>(); + + return true; +} + +int main() +{ + test_ranges(); +} diff --git a/libstdc++-v3/testsuite/23_containers/stack/members/push_range.cc b/libstdc++-v3/testsuite/23_containers/stack/members/push_range.cc new file mode 100644 index 00000000000..78b826a7028 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/stack/members/push_range.cc @@ -0,0 +1,74 @@ +// { dg-do run { target c++23 } } + +#include <ranges> +#include <span> +#include <stack> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> +#include <vector> + +template<typename Range, typename Cont> +constexpr void +do_test() +{ + // The stack's value_type. + using V = typename Cont::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 = [](std::stack<V, Cont> l, std::span<T> r) { + if (l.size() != r.size()) + return false; + for (auto const& v : r | std::views::reverse) { + if (v != l.top()) + return false; + l.pop(); + } + return true; + }; + + std::stack<V, Cont> s; + s.push_range(Range(a, a+0)); + VERIFY( s.empty() ); + + s.push_range(Range(a, a+4)); + VERIFY( eq(s, {a, 4}) ); + + s.push_range(Range(a+4, a+9)); + VERIFY( eq(s, {a, 9}) ); +} + +template<typename T, typename Alloc = std::allocator<T>> +struct NoAppendRangeCont : std::deque<T, Alloc> +{ + template<typename R> + void append_range(R&&) = delete; +}; + +template<typename Range> +void +do_test_c() +{ + do_test<Range, std::deque<int>>(); + do_test<Range, std::vector<int>>(); + do_test<Range, NoAppendRangeCont<int>>(); +} + +bool +test_ranges() +{ + using namespace __gnu_test; + + do_test_c<test_forward_range<int>>(); + do_test_c<test_range_nocopy<int, input_iterator_wrapper_nocopy>>(); + do_test_c<test_forward_range<short>>(); + + return true; +} + +int main() +{ + test_ranges(); +} diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h index 2895ff8c1b9..0df6dcc5af5 100644 --- a/libstdc++-v3/testsuite/util/testsuite_iterators.h +++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h @@ -867,6 +867,17 @@ namespace __gnu_test typename Iter<T>::ContainerType bounds; }; + // A move-only type meeting the minimum std::range requirements + template<typename T, template<typename> class Iter> + struct test_range_nocopy : test_range<T, Iter> + { + test_range_nocopy(T* first, T* last) : test_range<T, Iter>(first, last) + {} + + test_range_nocopy(test_range_nocopy&&) = default; + test_range_nocopy& operator=(test_range_nocopy&&) = default; + }; + template<typename T> using test_contiguous_range = test_range<T, contiguous_iterator_wrapper>; -- 2.48.1