From 6d0dff49ca1539e14647c04cc1bb035ef4c2780b Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 29 Oct 2019 17:44:18 +0000 Subject: [PATCH] Add iterator concepts and range access customization points for C++20 This adds most of the new C++20 features to , as well as a few initial pieces of (but no actual header just yet). * include/Makefile.am: Add new header. * include/Makefile.in: Regenerate. * include/bits/iterator_concepts.h: New header. (contiguous_iterator_tag, iter_reference_t, ranges::iter_move) (iter_rvalue_reference_t, incrementable_traits, iter_difference_t) (readable_traits, iter_value_t, readable, iter_common_reference_t) (writable, waekly_incrementable, incrementable) (input_or_output_iterator, sentinel_for, disable_sized_sentinel) (sized_sentinel_for, input_iterator, output_iterator) (forward_iterator, bidirectional_iterator, random_access_iterator) (contiguous_iterator, indirectly_unary_invocable) (indirectly_regular_unary_invocable, indirect_unary_predicate) (indirect_relation, indirect_strict_weak_order, indirect_result_t) (projected, indirectly_movable, indirectly_movable_storable) (indirectly_copyable, indirectly_copyable_storable, ranges::iter_swap) (indirectly_swappable, indirectly_comparable, permutable, mergeable) (sortable, unreachable_sentinel_t, unreachable_sentinel) (default_sentinel_t, default_sentinel): Define. (__detail::__cpp17_iterator, __detail::__cpp17_input_iterator) (__detail::__cpp17_fwd_iterator, __detail::__cpp17_bidi_iterator) (__detail::__cpp17_randacc_iterator): Define. (__iterator_traits): Define constrained specializations. * include/bits/move.h (move): Only use old concept check for C++98. * include/bits/range_access.h (ranges::disable_sized_range) (ranges::begin, ranges::end, ranges::cbegin, ranges::cend) (ranges::rbegin, ranges::rend, ranges::crbegin, ranges::crend) (ranges::size, ranges::empty, ranges::data, ranges::cdata): Define new customization points for C++20. (ranges::range, ranges::sized_range): Define new concepts for C++20. (ranges::advance, ranges::distance, ranges::next, ranges::prev): Define new functions for C++20. (__adl_end, __adl_cdata, __adl_cbegin, __adl_cend, __adl_rbegin) (__adl_rend, __adl_crbegin, __adl_crend, __adl_cdata, __adl_size) (__adl_empty): Remove. * include/bits/stl_iterator.h (disable_sized_sentinel): Specialize for reverse_iterator. * include/bits/stl_iterator_base_types.h (contiguous_iterator_tag): Define new struct for C++20. (iterator_traits<_Tp*>): Constrain partial specialization in C++20. * include/std/concepts (__is_class_or_enum): Move to __detail namespace. * testsuite/20_util/forward/c_neg.cc: Adjust dg-error line number. * testsuite/20_util/forward/f_neg.cc: Likewise. * testsuite/24_iterators/associated_types/incrementable.traits.cc: New test. * testsuite/24_iterators/associated_types/readable.traits.cc: New test. * testsuite/24_iterators/contiguous/concept.cc: New test. * testsuite/24_iterators/contiguous/tag.cc: New test. * testsuite/24_iterators/customization_points/iter_move.cc: New test. * testsuite/24_iterators/customization_points/iter_swap.cc: New test. * testsuite/24_iterators/headers/iterator/synopsis_c++20.cc: New test. * testsuite/24_iterators/range_operations/advance.cc: New test. * testsuite/24_iterators/range_operations/distance.cc: New test. * testsuite/24_iterators/range_operations/next.cc: New test. * testsuite/24_iterators/range_operations/prev.cc: New test. * testsuite/26_numerics/adjacent_difference/requirements/ explicit_instantiation/2.cc: Rename types that conflict with C++20 concepts. * testsuite/26_numerics/adjacent_difference/requirements/ explicit_instantiation/pod.cc: Likewise. * testsuite/26_numerics/partial_sum/requirements/ explicit_instantiation/2.cc: Likewise. * testsuite/26_numerics/partial_sum/requirements/ explicit_instantiation/pod.cc: Likewise. * testsuite/experimental/iterator/requirements.cc: Likewise. * testsuite/std/ranges/access/begin.cc: New test. * testsuite/std/ranges/access/cbegin.cc: New test. * testsuite/std/ranges/access/cdata.cc: New test. * testsuite/std/ranges/access/cend.cc: New test. * testsuite/std/ranges/access/crbegin.cc: New test. * testsuite/std/ranges/access/crend.cc: New test. * testsuite/std/ranges/access/data.cc: New test. * testsuite/std/ranges/access/empty.cc: New test. * testsuite/std/ranges/access/end.cc: New test. * testsuite/std/ranges/access/rbegin.cc: New test. * testsuite/std/ranges/access/rend.cc: New test. * testsuite/std/ranges/access/size.cc: New test. * testsuite/util/testsuite_iterators.h (contiguous_iterator_wrapper) (test_range, test_sized_range): New test utilities. From-SVN: r277579 --- libstdc++-v3/ChangeLog | 80 ++ libstdc++-v3/include/Makefile.am | 1 + libstdc++-v3/include/Makefile.in | 1 + libstdc++-v3/include/bits/iterator_concepts.h | 828 ++++++++++++++++++ libstdc++-v3/include/bits/move.h | 7 +- libstdc++-v3/include/bits/range_access.h | 750 +++++++++++++++- libstdc++-v3/include/bits/stl_iterator.h | 16 +- .../include/bits/stl_iterator_base_types.h | 37 +- libstdc++-v3/include/std/concepts | 15 +- .../testsuite/20_util/forward/c_neg.cc | 2 +- .../testsuite/20_util/forward/f_neg.cc | 2 +- .../associated_types/incrementable.traits.cc | 142 +++ .../associated_types/readable.traits.cc | 143 +++ .../24_iterators/contiguous/concept.cc | 36 + .../testsuite/24_iterators/contiguous/tag.cc | 34 + .../customization_points/iter_move.cc | 68 ++ .../customization_points/iter_swap.cc | 61 ++ .../headers/iterator/synopsis_c++20.cc | 95 ++ .../24_iterators/range_operations/advance.cc | 204 +++++ .../24_iterators/range_operations/distance.cc | 146 +++ .../24_iterators/range_operations/next.cc | 211 +++++ .../24_iterators/range_operations/prev.cc | 98 +++ .../requirements/explicit_instantiation/2.cc | 9 +- .../explicit_instantiation/pod.cc | 9 +- .../requirements/explicit_instantiation/2.cc | 7 +- .../explicit_instantiation/pod.cc | 7 +- .../experimental/iterator/requirements.cc | 2 + .../testsuite/std/ranges/access/begin.cc | 140 +++ .../testsuite/std/ranges/access/cbegin.cc | 91 ++ .../testsuite/std/ranges/access/cdata.cc | 73 ++ .../testsuite/std/ranges/access/cend.cc | 98 +++ .../testsuite/std/ranges/access/crbegin.cc | 73 ++ .../testsuite/std/ranges/access/crend.cc | 108 +++ .../testsuite/std/ranges/access/data.cc | 78 ++ .../testsuite/std/ranges/access/empty.cc | 76 ++ .../testsuite/std/ranges/access/end.cc | 145 +++ .../testsuite/std/ranges/access/rbegin.cc | 81 ++ .../testsuite/std/ranges/access/rend.cc | 105 +++ .../testsuite/std/ranges/access/size.cc | 116 +++ .../testsuite/util/testsuite_iterators.h | 144 ++- 40 files changed, 4262 insertions(+), 77 deletions(-) create mode 100644 libstdc++-v3/include/bits/iterator_concepts.h create mode 100644 libstdc++-v3/testsuite/24_iterators/associated_types/incrementable.traits.cc create mode 100644 libstdc++-v3/testsuite/24_iterators/associated_types/readable.traits.cc create mode 100644 libstdc++-v3/testsuite/24_iterators/contiguous/concept.cc create mode 100644 libstdc++-v3/testsuite/24_iterators/contiguous/tag.cc create mode 100644 libstdc++-v3/testsuite/24_iterators/customization_points/iter_move.cc create mode 100644 libstdc++-v3/testsuite/24_iterators/customization_points/iter_swap.cc create mode 100644 libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++20.cc create mode 100644 libstdc++-v3/testsuite/24_iterators/range_operations/advance.cc create mode 100644 libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc create mode 100644 libstdc++-v3/testsuite/24_iterators/range_operations/next.cc create mode 100644 libstdc++-v3/testsuite/24_iterators/range_operations/prev.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/access/begin.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/access/cbegin.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/access/cdata.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/access/cend.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/access/crbegin.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/access/crend.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/access/data.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/access/empty.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/access/end.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/access/rbegin.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/access/rend.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/access/size.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 0414f128e4a..ad595aa7a65 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,85 @@ 2019-10-29 Jonathan Wakely + * include/Makefile.am: Add new header. + * include/Makefile.in: Regenerate. + * include/bits/iterator_concepts.h: New header. + (contiguous_iterator_tag, iter_reference_t, ranges::iter_move) + (iter_rvalue_reference_t, incrementable_traits, iter_difference_t) + (readable_traits, iter_value_t, readable, iter_common_reference_t) + (writable, waekly_incrementable, incrementable) + (input_or_output_iterator, sentinel_for, disable_sized_sentinel) + (sized_sentinel_for, input_iterator, output_iterator) + (forward_iterator, bidirectional_iterator, random_access_iterator) + (contiguous_iterator, indirectly_unary_invocable) + (indirectly_regular_unary_invocable, indirect_unary_predicate) + (indirect_relation, indirect_strict_weak_order, indirect_result_t) + (projected, indirectly_movable, indirectly_movable_storable) + (indirectly_copyable, indirectly_copyable_storable, ranges::iter_swap) + (indirectly_swappable, indirectly_comparable, permutable, mergeable) + (sortable, unreachable_sentinel_t, unreachable_sentinel) + (default_sentinel_t, default_sentinel): Define. + (__detail::__cpp17_iterator, __detail::__cpp17_input_iterator) + (__detail::__cpp17_fwd_iterator, __detail::__cpp17_bidi_iterator) + (__detail::__cpp17_randacc_iterator): Define. + (__iterator_traits): Define constrained specializations. + * include/bits/move.h (move): Only use old concept check for C++98. + * include/bits/range_access.h (ranges::disable_sized_range) + (ranges::begin, ranges::end, ranges::cbegin, ranges::cend) + (ranges::rbegin, ranges::rend, ranges::crbegin, ranges::crend) + (ranges::size, ranges::empty, ranges::data, ranges::cdata): Define + new customization points for C++20. + (ranges::range, ranges::sized_range): Define new concepts for C++20. + (ranges::advance, ranges::distance, ranges::next, ranges::prev): + Define new functions for C++20. + (__adl_end, __adl_cdata, __adl_cbegin, __adl_cend, __adl_rbegin) + (__adl_rend, __adl_crbegin, __adl_crend, __adl_cdata, __adl_size) + (__adl_empty): Remove. + * include/bits/stl_iterator.h (disable_sized_sentinel): Specialize + for reverse_iterator. + * include/bits/stl_iterator_base_types.h (contiguous_iterator_tag): + Define new struct for C++20. + (iterator_traits<_Tp*>): Constrain partial specialization in C++20. + * include/std/concepts (__is_class_or_enum): Move to __detail + namespace. + * testsuite/20_util/forward/c_neg.cc: Adjust dg-error line number. + * testsuite/20_util/forward/f_neg.cc: Likewise. + * testsuite/24_iterators/associated_types/incrementable.traits.cc: New + test. + * testsuite/24_iterators/associated_types/readable.traits.cc: New test. + * testsuite/24_iterators/contiguous/concept.cc: New test. + * testsuite/24_iterators/contiguous/tag.cc: New test. + * testsuite/24_iterators/customization_points/iter_move.cc: New test. + * testsuite/24_iterators/customization_points/iter_swap.cc: New test. + * testsuite/24_iterators/headers/iterator/synopsis_c++20.cc: New test. + * testsuite/24_iterators/range_operations/advance.cc: New test. + * testsuite/24_iterators/range_operations/distance.cc: New test. + * testsuite/24_iterators/range_operations/next.cc: New test. + * testsuite/24_iterators/range_operations/prev.cc: New test. + * testsuite/26_numerics/adjacent_difference/requirements/ + explicit_instantiation/2.cc: Rename types that conflict with C++20 + concepts. + * testsuite/26_numerics/adjacent_difference/requirements/ + explicit_instantiation/pod.cc: Likewise. + * testsuite/26_numerics/partial_sum/requirements/ + explicit_instantiation/2.cc: Likewise. + * testsuite/26_numerics/partial_sum/requirements/ + explicit_instantiation/pod.cc: Likewise. + * testsuite/experimental/iterator/requirements.cc: Likewise. + * testsuite/std/ranges/access/begin.cc: New test. + * testsuite/std/ranges/access/cbegin.cc: New test. + * testsuite/std/ranges/access/cdata.cc: New test. + * testsuite/std/ranges/access/cend.cc: New test. + * testsuite/std/ranges/access/crbegin.cc: New test. + * testsuite/std/ranges/access/crend.cc: New test. + * testsuite/std/ranges/access/data.cc: New test. + * testsuite/std/ranges/access/empty.cc: New test. + * testsuite/std/ranges/access/end.cc: New test. + * testsuite/std/ranges/access/rbegin.cc: New test. + * testsuite/std/ranges/access/rend.cc: New test. + * testsuite/std/ranges/access/size.cc: New test. + * testsuite/util/testsuite_iterators.h (contiguous_iterator_wrapper) + (test_range, test_sized_range): New test utilities. + * testsuite/util/testsuite_iterators.h (BoundsContainer::size()): Add new member function. (WritableObject::operator=): Constrain with enable_if when available. diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 9ff12f10fb1..401c87ad103 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -129,6 +129,7 @@ bits_headers = \ ${bits_srcdir}/invoke.h \ ${bits_srcdir}/ios_base.h \ ${bits_srcdir}/istream.tcc \ + ${bits_srcdir}/iterator_concepts.h \ ${bits_srcdir}/list.tcc \ ${bits_srcdir}/locale_classes.h \ ${bits_srcdir}/locale_classes.tcc \ diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index 5dce01faeda..e0a74963547 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -473,6 +473,7 @@ bits_headers = \ ${bits_srcdir}/invoke.h \ ${bits_srcdir}/ios_base.h \ ${bits_srcdir}/istream.tcc \ + ${bits_srcdir}/iterator_concepts.h \ ${bits_srcdir}/list.tcc \ ${bits_srcdir}/locale_classes.h \ ${bits_srcdir}/locale_classes.tcc \ diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h new file mode 100644 index 00000000000..323689e63ea --- /dev/null +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -0,0 +1,828 @@ +// Concepts and traits for use with iterators -*- C++ -*- + +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/iterator_concepts.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{iterator} + */ + +#ifndef _ITERATOR_CONCEPTS_H +#define _ITERATOR_CONCEPTS_H 1 + +#pragma GCC system_header + +#include +#include // to_address +#include // identity, ranges::less + +#if __cpp_lib_concepts +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + struct input_iterator_tag; + struct output_iterator_tag; + struct forward_iterator_tag; + struct bidirectional_iterator_tag; + struct random_access_iterator_tag; + struct contiguous_iterator_tag; + + template + struct iterator_traits; + + template requires is_object_v<_Tp> + struct iterator_traits<_Tp*>; + + template + struct __iterator_traits; + + namespace __detail + { + template + using __with_ref = _Tp&; + + template + concept __can_reference = requires { typename __with_ref<_Tp>; }; + + template + concept __dereferenceable = requires(_Tp& __t) + { + { *__t } -> __can_reference; + }; + + // FIXME: needed due to PR c++/67704 + template<__detail::__dereferenceable _Tp> + struct __iter_ref + { + using type = decltype(*std::declval<_Tp&>()); + }; + } // namespace __detail + + template + using iter_reference_t = typename __detail::__iter_ref<_Tp>::type; + + namespace ranges + { + namespace __cust_imove + { + template + concept __adl_imove + = (std::__detail::__class_or_enum>) + && requires(_Tp&& __t) { iter_move(static_cast<_Tp&&>(__t)); }; + + struct _IMove + { + private: + template + static constexpr bool + _S_noexcept() + { + if constexpr (__adl_imove<_Tp>) + return noexcept(iter_move(std::declval<_Tp>())); + else + return noexcept(*std::declval<_Tp>()); + } + + public: + template + requires __adl_imove<_Tp> || requires(_Tp& __e) { *__e; } + constexpr decltype(auto) + operator()(_Tp&& __e) const + noexcept(_S_noexcept<_Tp>()) + { + if constexpr (__adl_imove<_Tp>) + return iter_move(static_cast<_Tp&&>(__e)); + else if constexpr (is_reference_v>) + return std::move(*__e); + else + return *__e; + } + }; + } // namespace __cust_imove + + inline namespace __cust + { + inline constexpr __cust_imove::_IMove iter_move{}; + } // inline namespace __cust + } // namespace ranges + + namespace __detail + { + // FIXME: needed due to PR c++/67704 + template<__detail::__dereferenceable _Tp> + struct __iter_rvalue_ref + { }; + + template<__detail::__dereferenceable _Tp> + requires requires(_Tp& __t) + { + { ranges::iter_move(__t) } -> __detail::__can_reference; + } + struct __iter_rvalue_ref<_Tp> + { using type = decltype(ranges::iter_move(std::declval<_Tp&>())); }; + + } // namespace __detail + + template + using iter_rvalue_reference_t + = typename __detail::__iter_rvalue_ref<_Tp>::type; + + template struct incrementable_traits { }; + + template requires is_object_v<_Tp> + struct incrementable_traits<_Tp*> + { using difference_type = ptrdiff_t; }; + + template + struct incrementable_traits + : incrementable_traits<_Iter> { }; + + template requires requires { typename _Tp::difference_type; } + struct incrementable_traits<_Tp> + { using difference_type = typename _Tp::difference_type; }; + + template + requires (!requires { typename _Tp::difference_type; } + && requires(const _Tp& __a, const _Tp& __b) + { + requires (!is_void_v>); // PR c++/78173 + { __a - __b } -> integral; + }) + struct incrementable_traits<_Tp> + { + using difference_type + = make_signed_t() - std::declval<_Tp>())>; + }; + + namespace __detail + { + // An iterator such that iterator_traits<_Iter> names a specialization + // generated from the primary template. + template + concept __primary_traits_iter + = __is_base_of(__iterator_traits<_Iter, void>, iterator_traits<_Iter>); + + template + struct __iter_traits_impl + { using type = iterator_traits<_Iter>; }; + + template + requires __primary_traits_iter<_Iter> + struct __iter_traits_impl<_Iter, _Tp> + { using type = _Tp; }; + + // ITER_TRAITS + template + using __iter_traits = typename __iter_traits_impl<_Iter, _Tp>::type; + } // namespace __detail + + template + using iter_difference_t = typename + __detail::__iter_traits<_Tp, incrementable_traits<_Tp>>::difference_type; + + namespace __detail + { + template struct __cond_value_type { }; + + template requires is_object_v<_Tp> + struct __cond_value_type<_Tp> + { using value_type = remove_cv_t<_Tp>; }; + } // namespace __detail + + template struct readable_traits { }; + + template + struct readable_traits<_Tp*> + : __detail::__cond_value_type<_Tp> + { }; + + template requires is_array_v<_Iter> + struct readable_traits<_Iter> + { using value_type = remove_cv_t>; }; + + template + struct readable_traits + : readable_traits<_Iter> + { }; + + template requires requires { typename _Tp::value_type; } + struct readable_traits<_Tp> + : __detail::__cond_value_type + { }; + + template requires requires { typename _Tp::element_type; } + struct readable_traits<_Tp> + : __detail::__cond_value_type + { }; + + template + using iter_value_t = typename + __detail::__iter_traits<_Tp, readable_traits<_Tp>>::value_type; + + namespace __detail + { + template + concept __cpp17_iterator = copyable<_Iter> + && requires(_Iter __it) + { + { *__it } -> __can_reference; + { ++__it } -> same_as<_Iter&>; + { *__it++ } -> __can_reference; + }; + + template + concept __cpp17_input_iterator = __cpp17_iterator<_Iter> + && equality_comparable<_Iter> + && requires(_Iter __it) + { + typename incrementable_traits<_Iter>::difference_type; + typename readable_traits<_Iter>::value_type; + typename common_reference_t&&, + typename readable_traits<_Iter>::value_type&>; + typename common_reference_t::value_type&>; + requires signed_integral::difference_type>; + }; + + template + concept __cpp17_fwd_iterator = __cpp17_input_iterator<_Iter> + && constructible_from<_Iter> + && is_lvalue_reference_v> + && same_as>, + typename readable_traits<_Iter>::value_type> + && requires(_Iter __it) + { + { __it++ } -> convertible_to; + { *__it++ } -> same_as>; + }; + + template + concept __cpp17_bidi_iterator = __cpp17_fwd_iterator<_Iter> + && requires(_Iter __it) + { + { --__it } -> same_as<_Iter&>; + { __it-- } -> convertible_to; + { *__it-- } -> same_as>; + }; + + template + concept __cpp17_randacc_iterator = __cpp17_bidi_iterator<_Iter> + && totally_ordered<_Iter> + && requires(_Iter __it, + typename incrementable_traits<_Iter>::difference_type __n) + { + { __it += __n } -> same_as<_Iter&>; + { __it -= __n } -> same_as<_Iter&>; + { __it + __n } -> same_as<_Iter>; + { __n + __it } -> same_as<_Iter>; + { __it - __n } -> same_as<_Iter>; + { __it - __it } -> same_as; + { __it[__n] } -> convertible_to>; + }; + + template + concept __iter_with_nested_types = requires { + typename _Iter::iterator_category; + typename _Iter::value_type; + typename _Iter::difference_type; + typename _Iter::reference; + }; + + // FIXME: needed due to PR c++/92102 + template + concept __iter_without_nested_types = !__iter_with_nested_types<_Iter>; + + template + struct __ptr + { using type = void; }; + + template requires requires { typename _Iter::pointer; } + struct __ptr<_Iter, true> + { using type = typename _Iter::pointer; }; + + template requires requires { typename _Iter::pointer; } + struct __ptr<_Iter, false> + { using type = typename _Iter::pointer; }; + + template + requires (!requires { typename _Iter::pointer; } + && requires(_Iter& __it) { __it.operator->(); }) + struct __ptr<_Iter, true> + { using type = decltype(std::declval<_Iter&>().operator->()); }; + + template + struct __ref + { using type = iter_reference_t<_Iter>; }; + + template requires requires { typename _Iter::reference; } + struct __ref<_Iter> + { using type = typename _Iter::reference; }; + + template + struct __cat + { using type = input_iterator_tag; }; + + template + requires requires { typename _Iter::iterator_category; } + struct __cat<_Iter> + { using type = typename _Iter::iterator_category; }; + + template + requires (!requires { typename _Iter::iterator_category; } + && __detail::__cpp17_randacc_iterator<_Iter>) + struct __cat<_Iter> + { using type = random_access_iterator_tag; }; + + template + requires (!requires { typename _Iter::iterator_category; } + && __detail::__cpp17_bidi_iterator<_Iter>) + struct __cat<_Iter> + { using type = bidirectional_iterator_tag; }; + + template + requires (!requires { typename _Iter::iterator_category; } + && __detail::__cpp17_fwd_iterator<_Iter>) + struct __cat<_Iter> + { using type = forward_iterator_tag; }; + + template + struct __diff + { using type = void; }; + + template + requires requires { + typename incrementable_traits<_Iter>::difference_type; + } + struct __diff<_Iter> + { + using type = typename incrementable_traits<_Iter>::difference_type; + }; + + } // namespace __detail + + template + requires __detail::__iter_with_nested_types<_Iterator> + struct __iterator_traits<_Iterator, void> + { + using iterator_category = typename _Iterator::iterator_category; + using value_type = typename _Iterator::value_type; + using difference_type = typename _Iterator::difference_type; + using pointer = typename __detail::__ptr<_Iterator>::type; + using reference = typename _Iterator::reference; + }; + + template + requires __detail::__iter_without_nested_types<_Iterator> + && __detail::__cpp17_input_iterator<_Iterator> + struct __iterator_traits<_Iterator, void> + { + using iterator_category = typename __detail::__cat<_Iterator>::type; + using value_type + = typename readable_traits<_Iterator>::value_type; + using difference_type + = typename incrementable_traits<_Iterator>::difference_type; + using pointer = typename __detail::__ptr<_Iterator, true>::type; + using reference = typename __detail::__ref<_Iterator>::type; + }; + + template + requires __detail::__iter_without_nested_types<_Iterator> + && __detail::__cpp17_iterator<_Iterator> + struct __iterator_traits<_Iterator, void> + { + using iterator_category = output_iterator_tag; + using value_type = void; + using difference_type = typename __detail::__diff<_Iterator>::type; + using pointer = void; + using reference = void; + }; + + namespace __detail + { + template + struct __iter_concept_impl + { }; + + template + requires requires { typename __iter_traits<_Iter>::iterator_concept; } + struct __iter_concept_impl<_Iter> + { using type = typename __iter_traits<_Iter>::iterator_concept; }; + + template + requires (!requires { typename __iter_traits<_Iter>::iterator_concept; } + && requires { typename __iter_traits<_Iter>::iterator_category; }) + struct __iter_concept_impl<_Iter> + { using type = typename __iter_traits<_Iter>::iterator_category; }; + + template + requires (!requires { typename __iter_traits<_Iter>::iterator_concept; } + && !requires { typename __iter_traits<_Iter>::iterator_category; } + && __primary_traits_iter<_Iter>) + struct __iter_concept_impl<_Iter> + { using type = random_access_iterator_tag; }; + + // ITER_TRAITS + template + using __iter_concept = typename __iter_concept_impl<_Iter>::type; + } // namespace __detail + + /// Requirements for types that are readable by applying operator*. + template + concept readable = requires + { + typename iter_value_t<_In>; + typename iter_reference_t<_In>; + typename iter_rvalue_reference_t<_In>; + } + && common_reference_with&&, iter_value_t<_In>&> + && common_reference_with&&, + iter_rvalue_reference_t<_In>&&> + && common_reference_with&&, + const iter_value_t<_In>&>; + + namespace __detail + { + // FIXME: needed due to PR c++/67704 + template + struct __iter_common_ref + : common_reference, iter_value_t<_Tp>&> + { }; + + // FIXME: needed due to PR c++/67704 + template + struct __indirect_result + { }; + + template + requires (readable<_Is> && ...) + && invocable<_Fn, iter_reference_t<_Is>...> + struct __indirect_result<_Fn, _Is...> + : invoke_result<_Fn, iter_reference_t<_Is>...> + { }; + } // namespace __detail + + template + using iter_common_reference_t + = typename __detail::__iter_common_ref<_Tp>::type; + + /// Requirements for writing a value into an iterator's referenced object. + template + concept writable = requires(_Out&& __o, _Tp&& __t) + { + *__o = std::forward<_Tp>(__t); + *std::forward<_Out>(__o) = std::forward<_Tp>(__t); + const_cast&&>(*__o) + = std::forward<_Tp>(__t); + const_cast&&>(*std::forward<_Out>(__o)) + = std::forward<_Tp>(__t); + }; + + /// Requirements on types that can be incremented with ++. + template + concept weakly_incrementable = default_constructible<_Iter> + && movable<_Iter> + && requires(_Iter __i) + { + typename iter_difference_t<_Iter>; + requires signed_integral>; + { ++__i } -> same_as<_Iter&>; + __i++; + }; + + template + concept incrementable = regular<_Iter> && weakly_incrementable<_Iter> + && requires(_Iter __i) { { __i++ } -> same_as<_Iter>; }; + + template + concept input_or_output_iterator + = requires(_Iter __i) { { *__i } -> __detail::__can_reference; } + && weakly_incrementable<_Iter>; + + template + concept sentinel_for = semiregular<_Sent> + && input_or_output_iterator<_Iter> + && __detail::__weakly_eq_cmp_with<_Sent, _Iter>; + + template + inline constexpr bool disable_sized_sentinel = false; + + template + concept sized_sentinel_for = sentinel_for<_Sent, _Iter> + && !disable_sized_sentinel, remove_cv_t<_Iter>> + && requires(const _Iter& __i, const _Sent& __s) + { + { __s - __i } -> same_as>; + { __i - __s } -> same_as>; + }; + + template + concept input_iterator = input_or_output_iterator<_Iter> + && readable<_Iter> + && requires { typename __detail::__iter_concept<_Iter>; } + && derived_from<__detail::__iter_concept<_Iter>, input_iterator_tag>; + + template + concept output_iterator = input_or_output_iterator<_Iter> + && writable<_Iter, _Tp> + && requires(_Iter __i, _Tp&& __t) { *__i++ = std::forward<_Tp>(__t); }; + + template + concept forward_iterator = input_iterator<_Iter> + && derived_from<__detail::__iter_concept<_Iter>, forward_iterator_tag> + && incrementable<_Iter> && sentinel_for<_Iter, _Iter>; + + template + concept bidirectional_iterator = forward_iterator<_Iter> + && derived_from<__detail::__iter_concept<_Iter>, + bidirectional_iterator_tag> + && requires(_Iter __i) + { + { --__i } -> same_as<_Iter&>; + { __i-- } -> same_as<_Iter>; + }; + + template + concept random_access_iterator = bidirectional_iterator<_Iter> + && derived_from<__detail::__iter_concept<_Iter>, + random_access_iterator_tag> + && totally_ordered<_Iter> && sized_sentinel_for<_Iter, _Iter> + && requires(_Iter __i, const _Iter __j, + const iter_difference_t<_Iter> __n) + { + { __i += __n } -> same_as<_Iter&>; + { __j + __n } -> same_as<_Iter>; + { __n + __j } -> same_as<_Iter>; + { __i -= __n } -> same_as<_Iter&>; + { __j - __n } -> same_as<_Iter>; + { __j[__n] } -> same_as>; + }; + + template + concept contiguous_iterator = random_access_iterator<_Iter> + && derived_from<__detail::__iter_concept<_Iter>, contiguous_iterator_tag> + && is_lvalue_reference_v> + && same_as, remove_cvref_t>> + && requires(const _Iter& __i) + { + { std::to_address(__i) } + -> same_as>>; + }; + + // [indirectcallable], indirect callable requirements + + // [indirectcallable.indirectinvocable], indirect callables + + template + concept indirectly_unary_invocable = readable<_Iter> + && copy_constructible<_Fn> && invocable<_Fn&, iter_value_t<_Iter>&> + && invocable<_Fn&, iter_reference_t<_Iter>> + && invocable<_Fn&, iter_common_reference_t<_Iter>> + && common_reference_with&>, + invoke_result_t<_Fn&, iter_reference_t<_Iter>>>; + + template + concept indirectly_regular_unary_invocable = readable<_Iter> + && copy_constructible<_Fn> + && regular_invocable<_Fn&, iter_value_t<_Iter>&> + && regular_invocable<_Fn&, iter_reference_t<_Iter>> + && regular_invocable<_Fn&, iter_common_reference_t<_Iter>> + && common_reference_with&>, + invoke_result_t<_Fn&, iter_reference_t<_Iter>>>; + + template + concept indirect_unary_predicate = readable<_Iter> + && copy_constructible<_Fn> && predicate<_Fn&, iter_value_t<_Iter>&> + && predicate<_Fn&, iter_reference_t<_Iter>> + && predicate<_Fn&, iter_common_reference_t<_Iter>>; + + template + concept indirect_relation = readable<_I1> && readable<_I2> + && copy_constructible<_Fn> + && relation<_Fn&, iter_value_t<_I1>&, iter_value_t<_I2>&> + && relation<_Fn&, iter_value_t<_I1>&, iter_reference_t<_I2>> + && relation<_Fn&, iter_reference_t<_I1>, iter_value_t<_I2>&> + && relation<_Fn&, iter_reference_t<_I1>, iter_reference_t<_I2>> + && relation<_Fn&, iter_common_reference_t<_I1>, + iter_common_reference_t<_I2>>; + + template + concept indirect_strict_weak_order = readable<_I1> && readable<_I2> + && copy_constructible<_Fn> + && strict_weak_order<_Fn&, iter_value_t<_I1>&, iter_value_t<_I2>&> + && strict_weak_order<_Fn&, iter_value_t<_I1>&, iter_reference_t<_I2>> + && strict_weak_order<_Fn&, iter_reference_t<_I1>, iter_value_t<_I2>&> + && strict_weak_order<_Fn&, iter_reference_t<_I1>, iter_reference_t<_I2>> + && strict_weak_order<_Fn&, iter_common_reference_t<_I1>, + iter_common_reference_t<_I2>>; + + template + using indirect_result_t = typename + __detail::__indirect_result<_Fn, iter_reference_t<_Is>...>::type; + + /// [projected], projected + template _Proj> + struct projected + { + using value_type = remove_cvref_t>; + indirect_result_t<_Proj&, _Iter> operator*() const; // not defined + }; + + template + struct incrementable_traits> + { using difference_type = iter_difference_t<_Iter>; }; + + // [alg.req], common algorithm requirements + + /// [alg.req.ind.move], concept `indirectly_movable` + + template + concept indirectly_movable = readable<_In> + && writable<_Out, iter_rvalue_reference_t<_In>>; + + template + concept indirectly_movable_storable = indirectly_movable<_In, _Out> + && writable<_Out, iter_value_t<_In>> && movable> + && constructible_from, iter_rvalue_reference_t<_In>> + && assignable_from&, iter_rvalue_reference_t<_In>>; + + /// [alg.req.ind.copy], concept `indirectly_copyable` + template + concept indirectly_copyable = readable<_In> + && writable<_Out, iter_reference_t<_In>>; + + template + concept indirectly_copyable_storable = indirectly_copyable<_In, _Out> + && writable<_Out, const iter_value_t<_In>&> + && copyable> + && constructible_from, iter_reference_t<_In>> + && assignable_from&, iter_reference_t<_In>>; + +namespace ranges +{ + namespace __cust_iswap + { + template + void iter_swap(_It1&, _It2&) = delete; + + template + concept __adl_iswap + = (std::__detail::__class_or_enum> + || std::__detail::__class_or_enum>) + && requires(_Tp&& __t, _Up&& __u) { + iter_swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); + }; + + template + constexpr iter_value_t> + __iter_exchange_move(_Xp&& __x, _Yp&& __y) + noexcept(noexcept(iter_value_t>(iter_move(__x))) + && noexcept(*__x = iter_move(__y))) + { + iter_value_t> __old_value(iter_move(__x)); + *__x = iter_move(__y); + return __old_value; + } + + struct _IterSwap + { + private: + template + static constexpr bool + _S_noexcept() + { + if constexpr (__adl_iswap<_Tp, _Up>) + return noexcept(iter_swap(std::declval<_Tp>(), + std::declval<_Up>())); + else if constexpr (readable<_Tp> && readable<_Up> + && swappable_with, iter_reference_t<_Up>>) + return noexcept(ranges::swap(*std::declval<_Tp>(), + *std::declval<_Up>())); + else + return noexcept(*std::declval<_Tp>() + = __iter_exchange_move(std::declval<_Up>(), + std::declval<_Tp>())); + } + + public: + template + requires __adl_iswap<_Tp, _Up> + || (readable<_Tp> && readable<_Up> + && swappable_with, iter_reference_t<_Up>>) + || (indirectly_movable_storable<_Tp, _Up> + && indirectly_movable_storable<_Up, _Tp>) + constexpr void + operator()(_Tp&& __e1, _Up&& __e2) const + noexcept(_S_noexcept<_Tp, _Up>()) + { + if constexpr (__adl_iswap<_Tp, _Up>) + iter_swap(static_cast<_Tp&&>(__e1), static_cast<_Up&&>(__e2)); + else if constexpr (readable<_Tp> && readable<_Up> + && swappable_with, iter_reference_t<_Up>>) + ranges::swap(*__e1, *__e2); + else + *__e1 = __iter_exchange_move(__e2, __e1); + } + }; + } // namespace __cust_iswap + + inline namespace __cust + { + inline constexpr __cust_iswap::_IterSwap iter_swap{}; + } // inline namespace __cust + +} // namespace ranges + + /// [alg.req.ind.swap], concept `indirectly_swappable` + template + concept indirectly_swappable = readable<_I1> && readable<_I2> + && requires(_I1& __i1, _I2& __i2) + { + ranges::iter_swap(__i1, __i1); + ranges::iter_swap(__i2, __i2); + ranges::iter_swap(__i1, __i2); + ranges::iter_swap(__i2, __i1); + }; + + /// [alg.req.ind.cmp], concept `indirectly_comparable` + template + concept indirectly_comparable + = indirect_relation<_Rel, projected<_I1, _P1>, projected<_I2, _P2>>; + + /// [alg.req.permutable], concept `permutable` + template + concept permutable = forward_iterator<_Iter> + && indirectly_movable_storable<_Iter, _Iter> + && indirectly_swappable<_Iter, _Iter>; + + /// [alg.req.mergeable], concept `mergeable` + template + concept mergeable = input_iterator<_I1> && input_iterator<_I2> + && weakly_incrementable<_Out> && indirectly_copyable<_I1, _Out> + && indirectly_copyable<_I2, _Out> + && indirect_strict_weak_order<_Rel, projected<_I1, _P1>, + projected<_I2, _P2>>; + + /// [alg.req.sortable], concept `sortable` + template + concept sortable = permutable<_Iter> + && indirect_strict_weak_order<_Rel, projected<_Iter, _Proj>>; + + struct unreachable_sentinel_t + { + template + friend constexpr bool + operator==(unreachable_sentinel_t, const _It&) noexcept + { return false; } + +#ifndef __cpp_lib_three_way_comparison + template + friend constexpr bool + operator!=(unreachable_sentinel_t, const _It&) noexcept + { return true; } + + template + friend constexpr bool + operator==(const _It&, unreachable_sentinel_t) noexcept + { return false; } + + template + friend constexpr bool + operator!=(const _It&, unreachable_sentinel_t) noexcept + { return true; } +#endif + }; + + inline constexpr unreachable_sentinel_t unreachable_sentinel{}; + + struct default_sentinel_t { }; + inline constexpr default_sentinel_t default_sentinel{}; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std +#endif // C++20 library concepts +#endif // _ITERATOR_CONCEPTS_H diff --git a/libstdc++-v3/include/bits/move.h b/libstdc++-v3/include/bits/move.h index d7c7068e29c..5d6541d193f 100644 --- a/libstdc++-v3/include/bits/move.h +++ b/libstdc++-v3/include/bits/move.h @@ -31,7 +31,9 @@ #define _MOVE_H 1 #include -#include +#if __cplusplus < 201103L +# include +#endif namespace std _GLIBCXX_VISIBILITY(default) { @@ -188,9 +190,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_NOEXCEPT_IF(__and_, is_nothrow_move_assignable<_Tp>>::value) { +#if __cplusplus < 201103L // concept requirements __glibcxx_function_requires(_SGIAssignableConcept<_Tp>) - +#endif _Tp __tmp = _GLIBCXX_MOVE(__a); __a = _GLIBCXX_MOVE(__b); __b = _GLIBCXX_MOVE(__tmp); diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h index bc137d7396e..3b6ed9aa66a 100644 --- a/libstdc++-v3/include/bits/range_access.h +++ b/libstdc++-v3/include/bits/range_access.h @@ -34,6 +34,8 @@ #if __cplusplus >= 201103L #include +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -344,60 +346,722 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template constexpr auto - __adl_end(_Container& __cont) noexcept(noexcept(end(__cont))) - { return end(__cont); } + __adl_data(_Container& __cont) noexcept(noexcept(data(__cont))) + { return data(__cont); } - template - constexpr auto - __adl_cbegin(_Container& __cont) noexcept(noexcept(cbegin(__cont))) - { return cbegin(__cont); } +namespace ranges +{ + template + inline constexpr bool disable_sized_range = false; - template - constexpr auto - __adl_cend(_Container& __cont) noexcept(noexcept(cend(__cont))) - { return cend(__cont); } + namespace __detail + { + using __max_diff_type = long long; + using __max_size_type = unsigned long long; - template - constexpr auto - __adl_rbegin(_Container& __cont) noexcept(noexcept(rbegin(__cont))) - { return rbegin(__cont); } + template + concept __is_integer_like = integral<_Tp> + || same_as<_Tp, __max_diff_type> || same_as<_Tp, __max_size_type>; - template - constexpr auto - __adl_rend(_Container& __cont) noexcept(noexcept(rend(__cont))) - { return rend(__cont); } + template + concept __is_signed_integer_like = signed_integral<_Tp> + || same_as<_Tp, __max_diff_type>; - template - constexpr auto - __adl_crbegin(_Container& __cont) noexcept(noexcept(crbegin(__cont))) - { return crbegin(__cont); } + template + constexpr make_unsigned_t<_Tp> + __to_unsigned_like(_Tp __t) noexcept + { return __t; } + } // namespace __detail - template - constexpr auto - __adl_crend(_Container& __cont) noexcept(noexcept(crend(__cont))) - { return crend(__cont); } + namespace __cust_access + { + template + constexpr decay_t<_Tp> + __decay_copy(_Tp&& __t) + noexcept(is_nothrow_convertible_v<_Tp, decay_t<_Tp>>) + { return std::forward<_Tp>(__t); } - template - constexpr auto - __adl_data(_Container& __cont) noexcept(noexcept(data(__cont))) - { return data(__cont); } + template + concept __member_begin = is_lvalue_reference_v<_Tp> + && requires(_Tp __t) + { { __decay_copy(__t.begin()) } -> input_or_output_iterator; }; - template - constexpr auto - __adl_cdata(_Container& __cont) noexcept(noexcept(cdata(__cont))) - { return cdata(__cont); } + template void begin(_Tp&&) = delete; + template void begin(initializer_list<_Tp>&&) = delete; - template - constexpr auto - __adl_size(_Container& __cont) noexcept(noexcept(size(__cont))) - { return size(__cont); } + template + concept __adl_begin = requires(_Tp&& __t) + { + { __decay_copy(begin(std::forward<_Tp>(__t))) } + -> input_or_output_iterator; + }; - template - constexpr auto - __adl_empty(_Container& __cont) noexcept(noexcept(empty(__cont))) - { return empty(__cont); } -#endif // C++20 + template + concept __complete_type = requires(_Tp* __p) { __p + 1; }; + + struct _Begin + { + private: + template + static constexpr bool + _S_noexcept() + { + if constexpr (__member_begin<_Tp>) + return noexcept(__decay_copy(std::declval<_Tp>().begin())); + else + return noexcept(__decay_copy(begin(std::declval<_Tp>()))); + } + + public: + template<__complete_type _Tp, size_t _Nm> + constexpr _Tp* + operator()(_Tp (&__e)[_Nm]) const noexcept + { return __e; } + + template requires __member_begin<_Tp> || __adl_begin<_Tp> + constexpr auto + operator()(_Tp&& __e) const noexcept(_S_noexcept<_Tp>()) + { + if constexpr (__member_begin<_Tp>) + return __e.begin(); + else + return begin(std::forward<_Tp>(__e)); + } + }; + + template + concept __member_end = is_lvalue_reference_v<_Tp> + && requires(_Tp __t) + { + { __decay_copy(__t.end()) } + -> sentinel_for; + }; + + template void end(_Tp&&) = delete; + template void end(initializer_list<_Tp>&&) = delete; + template + concept __adl_end = requires(_Tp&& __t) + { + { __decay_copy(end(std::forward<_Tp>(__t))) } + -> sentinel_for(__t)))>; + }; + + struct _End + { + private: + template + static constexpr bool + _S_noexcept() + { + if constexpr (__member_end<_Tp>) + return noexcept(__decay_copy(std::declval<_Tp>().end())); + else + return noexcept(__decay_copy(end(std::declval<_Tp>()))); + } + + public: + template<__complete_type _Tp, size_t _Nm> + constexpr _Tp* + operator()(_Tp (&__e)[_Nm]) const noexcept + { return __e + _Nm; } + + template requires __member_end<_Tp> || __adl_end<_Tp> + constexpr auto + operator()(_Tp&& __e) const noexcept(_S_noexcept<_Tp>()) + { + if constexpr (__member_end<_Tp>) + return __e.end(); + else + return end(std::forward<_Tp>(__e)); + } + }; + + template + constexpr decltype(auto) + __as_const(_Tp&& __t) noexcept + { + if constexpr (is_lvalue_reference_v<_Tp>) + return static_cast&>(__t); + else + return static_cast(__t); + } + + struct _CBegin + { + template + constexpr auto + operator()(_Tp&& __e) const + noexcept(noexcept(_Begin{}(__cust_access::__as_const((_Tp&&)__e)))) + requires requires { _Begin{}(__cust_access::__as_const((_Tp&&)__e)); } + { + return _Begin{}(__cust_access::__as_const(std::forward<_Tp>(__e))); + } + }; + + struct _CEnd + { + template + constexpr auto + operator()(_Tp&& __e) const + noexcept(noexcept(_End{}(__cust_access::__as_const((_Tp&&)__e)))) + requires requires { _End{}(__cust_access::__as_const((_Tp&&)__e)); } + { + return _End{}(__cust_access::__as_const(std::forward<_Tp>(__e))); + } + }; + + template + concept __member_rbegin = is_lvalue_reference_v<_Tp> + && requires(_Tp __t) + { { __decay_copy(__t.rbegin()) } -> input_or_output_iterator; }; + + template void rbegin(_Tp&&) = delete; + + template + concept __adl_rbegin = requires(_Tp&& __t) + { + { __decay_copy(rbegin(std::forward<_Tp>(__t))) } + -> input_or_output_iterator; + }; + + template + concept __reversable = requires(_Tp&& __t) + { + { _Begin{}(std::forward<_Tp>(__t)) } -> bidirectional_iterator; + { _End{}(std::forward<_Tp>(__t)) } + -> same_as(__t)))>; + }; + + struct _RBegin + { + private: + template + static constexpr bool + _S_noexcept() + { + if constexpr (__member_rbegin<_Tp>) + return noexcept(__decay_copy(std::declval<_Tp>().rbegin())); + else if constexpr (__adl_rbegin<_Tp>) + return noexcept(__decay_copy(rbegin(std::declval<_Tp>()))); + else if constexpr (noexcept(_End{}(std::declval<_Tp>()))) + { + using _It = decltype(_End{}(std::declval<_Tp>())); + // std::reverse_iterator copy-initializes its member. + return is_nothrow_copy_constructible_v<_It>; + } + else + return false; + } + + public: + template + requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> || __reversable<_Tp> + constexpr auto + operator()(_Tp&& __e) const + noexcept(_S_noexcept<_Tp>()) + { + if constexpr (__member_rbegin<_Tp>) + return __e.rbegin(); + else if constexpr (__adl_rbegin<_Tp>) + return rbegin(std::forward<_Tp>(__e)); + else + return std::make_reverse_iterator(_End{}(std::forward<_Tp>(__e))); + } + }; + + template + concept __member_rend = is_lvalue_reference_v<_Tp> + && requires(_Tp __t) + { + { __decay_copy(__t.rend()) } + -> sentinel_for; + }; + + template void rend(_Tp&&) = delete; + + template + concept __adl_rend = requires(_Tp&& __t) + { + { __decay_copy(rend(std::forward<_Tp>(__t))) } + -> sentinel_for(__t)))>; + }; + + struct _REnd + { + private: + template + static constexpr bool + _S_noexcept() + { + if constexpr (__member_rend<_Tp>) + return noexcept(__decay_copy(std::declval<_Tp>().rend())); + else if constexpr (__adl_rend<_Tp>) + return noexcept(__decay_copy(rend(std::declval<_Tp>()))); + else if constexpr (noexcept(_Begin{}(std::declval<_Tp>()))) + { + using _It = decltype(_Begin{}(std::declval<_Tp>())); + // std::reverse_iterator copy-initializes its member. + return is_nothrow_copy_constructible_v<_It>; + } + else + return false; + } + + public: + template + requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp> + constexpr auto + operator()(_Tp&& __e) const + noexcept(_S_noexcept<_Tp>()) + { + if constexpr (__member_rend<_Tp>) + return __e.rend(); + else if constexpr (__adl_rend<_Tp>) + return rend(std::forward<_Tp>(__e)); + else + return std::make_reverse_iterator(_Begin{}(std::forward<_Tp>(__e))); + } + }; + + struct _CRBegin + { + template + constexpr auto + operator()(_Tp&& __e) const + noexcept(noexcept(_RBegin{}(__cust_access::__as_const((_Tp&&)__e)))) + requires requires { _RBegin{}(__cust_access::__as_const((_Tp&&)__e)); } + { + return _RBegin{}(__cust_access::__as_const(std::forward<_Tp>(__e))); + } + }; + + struct _CREnd + { + template + constexpr auto + operator()(_Tp&& __e) const + noexcept(noexcept(_REnd{}(__cust_access::__as_const((_Tp&&)__e)))) + requires requires { _REnd{}(__cust_access::__as_const((_Tp&&)__e)); } + { + return _REnd{}(__cust_access::__as_const(std::forward<_Tp>(__e))); + } + }; + + template + concept __member_size = !disable_sized_range> + && requires(_Tp&& __t) + { + { __decay_copy(std::forward<_Tp>(__t).size()) } + -> __detail::__is_integer_like; + }; + + template void size(_Tp&&) = delete; + + template + concept __adl_size = !disable_sized_range> + && requires(_Tp&& __t) + { + { __decay_copy(size(std::forward<_Tp>(__t))) } + -> __detail::__is_integer_like; + }; + + // FIXME: needed due to PR c++/92268 + template _End> + requires requires (_It __it, _End __end) + { { __end - __it } -> __detail::__is_integer_like; } + void + __subtractable_fwd_iter(_It, _End) + { } + + template + concept __sizable = requires(_Tp&& __t) + { + __subtractable_fwd_iter(_Begin{}(std::forward<_Tp>(__t)), + _End{}(std::forward<_Tp>(__t))); + }; + + struct _Size + { + private: + template + static constexpr bool + _S_noexcept() + { + if constexpr (__member_size<_Tp>) + return noexcept(__decay_copy(std::declval<_Tp>().size())); + else if constexpr (__adl_size<_Tp>) + return noexcept(__decay_copy(size(std::declval<_Tp>()))); + else if constexpr (__sizable<_Tp>) + return noexcept(_End{}(std::declval<_Tp>()) + - _Begin{}(std::declval<_Tp>())); + } + + public: + template<__complete_type _Tp, size_t _Nm> + constexpr size_t + operator()(_Tp (&__e)[_Nm]) const noexcept + { return _Nm; } + + template + requires __member_size<_Tp> || __adl_size<_Tp> || __sizable<_Tp> + constexpr auto + operator()(_Tp&& __e) const noexcept(_S_noexcept<_Tp>()) + { + if constexpr (__member_size<_Tp>) + return std::forward<_Tp>(__e).size(); + else if constexpr (__adl_size<_Tp>) + return size(std::forward<_Tp>(__e)); + else if constexpr (__sizable<_Tp>) + return __detail::__to_unsigned_like( + _End{}(std::forward<_Tp>(__e)) + - _Begin{}(std::forward<_Tp>(__e))); + } + }; + + template + concept __member_empty = requires(_Tp&& __t) + { bool(std::forward<_Tp>(__t).empty()); }; + + template + concept __size0_empty = requires(_Tp&& __t) + { _Size{}(std::forward<_Tp>(__t)) == 0; }; + + template + concept __eq_iter_empty = requires(_Tp&& __t) + { + { _Begin{}(std::forward<_Tp>(__t)) } -> forward_iterator; + bool(_Begin{}(std::forward<_Tp>(__t)) + == _End{}(std::forward<_Tp>(__t))); + }; + + struct _Empty + { + private: + template + static constexpr bool + _S_noexcept() + { + if constexpr (__member_empty<_Tp>) + return noexcept(std::declval<_Tp>().empty()); + else if constexpr (__size0_empty<_Tp>) + return noexcept(_Size{}(std::declval<_Tp>()) == 0); + else + return noexcept(bool(_Begin{}(std::declval<_Tp>()) + == _End{}(std::declval<_Tp>()))); + } + + public: + template + requires __member_empty<_Tp> || __size0_empty<_Tp> + || __eq_iter_empty<_Tp> + constexpr auto + operator()(_Tp&& __e) const noexcept(_S_noexcept<_Tp>()) + { + if constexpr (__member_empty<_Tp>) + return bool(std::forward<_Tp>(__e).empty()); + else if constexpr (__size0_empty<_Tp>) + return _Size{}(std::forward<_Tp>(__e)) == 0; + else + return bool(_Begin{}(std::forward<_Tp>(__e)) + == _End{}(std::forward<_Tp>(__e))); + } + }; + + template + concept __pointer_to_object = is_pointer_v<_Tp> + && is_object_v>; + + template + concept __member_data = is_lvalue_reference_v<_Tp> + && requires(_Tp __t) { { __t.data() } -> __pointer_to_object; }; + + template + concept __begin_data = requires(_Tp&& __t) + { { _Begin{}(std::forward<_Tp>(__t)) } -> contiguous_iterator; }; + + struct _Data + { + private: + template + static constexpr bool + _S_noexcept() + { + if constexpr (__member_data<_Tp>) + return noexcept(__decay_copy(std::declval<_Tp>().data())); + else + return noexcept(_Begin{}(std::declval<_Tp>())); + } + + public: + template requires __member_data<_Tp> || __begin_data<_Tp> + constexpr auto + operator()(_Tp&& __e) const noexcept(_S_noexcept<_Tp>()) + { + if constexpr (__member_data<_Tp>) + return __e.data(); + else + return std::to_address(_Begin{}(std::forward<_Tp>(__e))); + } + }; + + struct _CData + { + template + constexpr auto + operator()(_Tp&& __e) const + noexcept(noexcept(_Data{}(__cust_access::__as_const((_Tp&&)__e)))) + requires requires { _Data{}(__cust_access::__as_const((_Tp&&)__e)); } + { + return _Data{}(__cust_access::__as_const(std::forward<_Tp>(__e))); + } + }; + + } // namespace __cust_access + + inline namespace __cust + { + inline constexpr __cust_access::_Begin begin{}; + inline constexpr __cust_access::_End end{}; + inline constexpr __cust_access::_CBegin cbegin{}; + inline constexpr __cust_access::_CEnd cend{}; + inline constexpr __cust_access::_RBegin rbegin{}; + inline constexpr __cust_access::_REnd rend{}; + inline constexpr __cust_access::_CRBegin crbegin{}; + inline constexpr __cust_access::_CREnd crend{}; + inline constexpr __cust_access::_Size size{}; + inline constexpr __cust_access::_Empty empty{}; + inline constexpr __cust_access::_Data data{}; + inline constexpr __cust_access::_CData cdata{}; + } + + namespace __detail + { + template + concept __range_impl = requires(_Tp&& __t) { + ranges::begin(std::forward<_Tp>(__t)); + ranges::end(std::forward<_Tp>(__t)); + }; + + } // namespace __detail + + /// [range.range] The range concept. + template + concept range = __detail::__range_impl<_Tp&>; + + /// [range.sized] The sized_range concept. + template + concept sized_range = range<_Tp> + && requires(_Tp& __t) { ranges::size(__t); }; + + // [range.iter.ops] range iterator operations + + template + constexpr void + advance(_It& __it, iter_difference_t<_It> __n) + { + if constexpr (random_access_iterator<_It>) + __it += __n; + else if constexpr (bidirectional_iterator<_It>) + { + if (__n > 0) + { + do + { + ++__it; + } + while (--__n); + } + else if (__n < 0) + { + do + { + --__it; + } + while (++__n); + } + } + else + { +#ifdef __cpp_lib_is_constant_evaluated + if (std::is_constant_evaluated() && __n < 0) + throw "attempt to decrement a non-bidirectional iterator"; +#endif + __glibcxx_assert(__n >= 0); + while (__n-- > 0) + ++__it; + } + } + + template _Sent> + constexpr void + advance(_It& __it, _Sent __bound) + { + if constexpr (assignable_from<_It&, _Sent>) + __it = std::move(__bound); + else if constexpr (sized_sentinel_for<_Sent, _It>) + ranges::advance(__it, __bound - __it); + else + { + while (__it != __bound) + ++__it; + } + } + + template _Sent> + constexpr iter_difference_t<_It> + advance(_It& __it, iter_difference_t<_It> __n, _Sent __bound) + { + if constexpr (sized_sentinel_for<_Sent, _It>) + { + const auto __diff = __bound - __it; +#ifdef __cpp_lib_is_constant_evaluated + if (std::is_constant_evaluated() + && !(__n == 0 || __diff == 0 || (__n < 0 == __diff < 0))) + throw "inconsistent directions for distance and bound"; +#endif + // n and bound must not lead in opposite directions: + __glibcxx_assert(__n == 0 || __diff == 0 || (__n < 0 == __diff < 0)); + const auto __absdiff = __diff < 0 ? -__diff : __diff; + const auto __absn = __n < 0 ? -__n : __n;; + if (__absn >= __absdiff) + { + ranges::advance(__it, __bound); + return __n - __diff; + } + else + { + ranges::advance(__it, __n); + return 0; + } + } + else if (__it == __bound || __n == 0) + return iter_difference_t<_It>(0); + else if (__n > 0) + { + iter_difference_t<_It> __m = 0; + do + { + ++__it; + ++__m; + } + while (__m != __n && __it != __bound); + return __n - __m; + } + else if constexpr (bidirectional_iterator<_It> && same_as<_It, _Sent>) + { + iter_difference_t<_It> __m = 0; + do + { + --__it; + --__m; + } + while (__m != __n && __it != __bound); + return __n - __m; + } + else + { +#ifdef __cpp_lib_is_constant_evaluated + if (std::is_constant_evaluated() && __n < 0) + throw "attempt to decrement a non-bidirectional iterator"; +#endif + __glibcxx_assert(__n >= 0); + return __n; + } + } + + template _Sent> + constexpr iter_difference_t<_It> + distance(_It __first, _Sent __last) + { + if constexpr (sized_sentinel_for<_Sent, _It>) + return __last - __first; + else + { + iter_difference_t<_It> __n = 0; + while (__first != __last) + { + ++__first; + ++__n; + } + return __n; + } + } + + template + using iterator_t = decltype(ranges::begin(std::declval<_Range&>())); + + template + using range_difference_t = iter_difference_t>; + + template + constexpr range_difference_t<_Range> + distance(_Range&& __r) + { + if constexpr (sized_range<_Range>) + return static_cast>(ranges::size(__r)); + else + return ranges::distance(ranges::begin(__r), ranges::end(__r)); + } + + template + constexpr _It + next(_It __x) + { + ++__x; + return __x; + } + + template + constexpr _It + next(_It __x, iter_difference_t<_It> __n) + { + ranges::advance(__x, __n); + return __x; + } + + template _Sent> + constexpr _It + next(_It __x, _Sent __bound) + { + ranges::advance(__x, __bound); + return __x; + } + + template _Sent> + constexpr _It + next(_It __x, iter_difference_t<_It> __n, _Sent __bound) + { + ranges::advance(__x, __n, __bound); + return __x; + } + + template + constexpr _It + prev(_It __x) + { + --__x; + return __x; + } + + template + constexpr _It + prev(_It __x, iter_difference_t<_It> __n) + { + ranges::advance(__x, -__n); + return __x; + } + + template + constexpr _It + prev(_It __x, iter_difference_t<_It> __n, _It __bound) + { + ranges::advance(__x, -__n, __bound); + return __x; + } + +} // namespace ranges +#endif // C++20 _GLIBCXX_END_NAMESPACE_VERSION } // namespace diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 420fea687b5..966087598f4 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -431,7 +431,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __make_reverse_iterator(_Iterator __i) { return reverse_iterator<_Iterator>(__i); } -# if __cplusplus > 201103L +# if __cplusplus >= 201402L # define __cpp_lib_make_reverse_iterator 201402 // _GLIBCXX_RESOLVE_LIB_DEFECTS @@ -441,10 +441,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline _GLIBCXX17_CONSTEXPR reverse_iterator<_Iterator> make_reverse_iterator(_Iterator __i) { return reverse_iterator<_Iterator>(__i); } -# endif -#endif -#if __cplusplus >= 201103L +# if __cplusplus > 201703L + template + requires (!sized_sentinel_for<_Iterator1, _Iterator2>) + inline constexpr bool disable_sized_sentinel, + reverse_iterator<_Iterator2>> + = true; +# endif // C++20 +# endif // C++14 + template _GLIBCXX20_CONSTEXPR auto @@ -463,7 +469,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __miter_base(reverse_iterator<_Iterator> __it) -> decltype(__make_reverse_iterator(__miter_base(__it.base()))) { return __make_reverse_iterator(__miter_base(__it.base())); } -#endif +#endif // C++11 // 24.4.2.2.1 back_insert_iterator /** diff --git a/libstdc++-v3/include/bits/stl_iterator_base_types.h b/libstdc++-v3/include/bits/stl_iterator_base_types.h index 951e704e468..3fad5869b40 100644 --- a/libstdc++-v3/include/bits/stl_iterator_base_types.h +++ b/libstdc++-v3/include/bits/stl_iterator_base_types.h @@ -67,6 +67,10 @@ # include // For __void_t, is_convertible #endif +#if __cplusplus > 201703L && __cpp_concepts +# include +#endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -101,6 +105,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Random-access iterators support a superset of bidirectional /// iterator operations. struct random_access_iterator_tag : public bidirectional_iterator_tag { }; + +#if __cplusplus > 201703L + /// Contiguous iterators point to objects stored contiguously in memory. + struct contiguous_iterator_tag : public random_access_iterator_tag { }; +#endif //@} /** @@ -137,12 +146,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * argument. Specialized versions for pointers and pointers-to-const * provide tighter, more correct semantics. */ + template + struct iterator_traits; + #if __cplusplus >= 201103L // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2408. SFINAE-friendly common_type/iterator_traits is missing in C++14 template> struct __iterator_traits { }; +#if ! __cpp_lib_concepts + template struct __iterator_traits<_Iterator, __void_t struct iterator_traits : public __iterator_traits<_Iterator> { }; -#else + +#else // ! C++11 template struct iterator_traits { @@ -171,8 +187,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef typename _Iterator::pointer pointer; typedef typename _Iterator::reference reference; }; -#endif +#endif // C++11 +#if __cplusplus > 201703L + /// Partial specialization for object pointer types. + template +#if __cpp_concepts + requires is_object_v<_Tp> +#endif + struct iterator_traits<_Tp*> + { + using iterator_concept = contiguous_iterator_tag; + using iterator_category = random_access_iterator_tag; + using value_type = remove_cv_t<_Tp>; + using difference_type = ptrdiff_t; + using pointer = _Tp*; + using reference = _Tp&; + }; +#else /// Partial specialization for pointer types. template struct iterator_traits<_Tp*> @@ -194,6 +226,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef const _Tp* pointer; typedef const _Tp& reference; }; +#endif /** * This function is not a part of the C++ standard but is syntactic diff --git a/libstdc++-v3/include/std/concepts b/libstdc++-v3/include/std/concepts index 6d740eb663c..68cbba9b8a7 100644 --- a/libstdc++-v3/include/std/concepts +++ b/libstdc++-v3/include/std/concepts @@ -114,6 +114,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { template using __cref = const remove_reference_t<_Tp>&; + + template + concept __class_or_enum + = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>; } // namespace __detail /// [concept.assignable], concept assignable_from @@ -159,14 +163,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { template void swap(_Tp&, _Tp&) = delete; - template - concept __class_or_enum - = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>; - template concept __adl_swap - = (__class_or_enum> - || __class_or_enum>) + = (__detail::__class_or_enum> + || __detail::__class_or_enum>) && requires(_Tp&& __t, _Up&& __u) { swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }; @@ -175,7 +175,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { template requires __adl_swap<_Tp, _Up> - constexpr void operator()(_Tp&& __t, _Up&& __u) const + constexpr void + operator()(_Tp&& __t, _Up&& __u) const noexcept(noexcept(swap(std::declval<_Tp>(), std::declval<_Up>()))) { swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); } diff --git a/libstdc++-v3/testsuite/20_util/forward/c_neg.cc b/libstdc++-v3/testsuite/20_util/forward/c_neg.cc index ecbac1fd2b8..6b719eb988f 100644 --- a/libstdc++-v3/testsuite/20_util/forward/c_neg.cc +++ b/libstdc++-v3/testsuite/20_util/forward/c_neg.cc @@ -17,7 +17,7 @@ // with this library; see the file COPYING3. If not see // . -// { dg-error "static assertion failed" "" { target *-*-* } 87 } +// { dg-error "static assertion failed" "" { target *-*-* } 89 } #include diff --git a/libstdc++-v3/testsuite/20_util/forward/f_neg.cc b/libstdc++-v3/testsuite/20_util/forward/f_neg.cc index a073adc7fb6..7161f47760c 100644 --- a/libstdc++-v3/testsuite/20_util/forward/f_neg.cc +++ b/libstdc++-v3/testsuite/20_util/forward/f_neg.cc @@ -17,7 +17,7 @@ // with this library; see the file COPYING3. If not see // . -// { dg-error "static assertion failed" "" { target *-*-* } 87 } +// { dg-error "static assertion failed" "" { target *-*-* } 89 } #include diff --git a/libstdc++-v3/testsuite/24_iterators/associated_types/incrementable.traits.cc b/libstdc++-v3/testsuite/24_iterators/associated_types/incrementable.traits.cc new file mode 100644 index 00000000000..929f0e4121f --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/associated_types/incrementable.traits.cc @@ -0,0 +1,142 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include + +struct none; + +template + concept has_inc_traits_type + = requires { typename std::incrementable_traits::difference_type; }; + +// Check std::incrementable_traits::difference_type is U (or doesn't exist). +template + concept check_inc_traits = (has_inc_traits_type != std::same_as); + +static_assert( check_inc_traits ); +static_assert( check_inc_traits ); +static_assert( check_inc_traits ); +static_assert( check_inc_traits ); + +static_assert( check_inc_traits ); +static_assert( check_inc_traits ); + +static_assert( check_inc_traits ); +static_assert( check_inc_traits ); +static_assert( check_inc_traits ); +static_assert( check_inc_traits ); + +struct A { using difference_type = int; }; +static_assert( check_inc_traits ); +static_assert( check_inc_traits ); +struct B : private A { }; +static_assert( check_inc_traits ); + +struct C { }; +short operator-(C, C) { return 0; } +static_assert( check_inc_traits ); +static_assert( check_inc_traits ); + +struct D { }; +unsigned short operator-(D, D) { return 0; } +static_assert( check_inc_traits ); +static_assert( check_inc_traits ); + +struct E { }; +template<> + struct std::incrementable_traits { using difference_type = long; }; +static_assert( check_inc_traits ); +static_assert( check_inc_traits ); + +template + concept has_alias = requires { typename std::iter_difference_t; }; + +// Check std::iter_difference_t is U (or doesn't exist). +template + concept check_alias = (has_alias != std::same_as); + +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); + +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); + +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); + +struct F { }; +template<> + struct std::iterator_traits { using difference_type = F; }; +// iterator_traits is specialized, so use its difference_type. +static_assert( check_alias::difference_type> ); + +struct G { }; +template<> + struct std::incrementable_traits { using difference_type = G; }; +template<> + struct std::iterator_traits { using difference_type = int; }; +// iterator_traits is specialized, so use its difference_type. +static_assert( check_alias::difference_type> ); + +struct H { }; +template<> + struct std::incrementable_traits { using difference_type = H; }; +template<> + struct std::iterator_traits + { + using iterator_category = input_iterator_tag; + using difference_type = int; + using value_type = char; + using reference = value_type&; + }; +// iterator_traits is specialized, so use its difference_type. +static_assert( check_alias::difference_type> ); + +struct I +{ + using difference_type = I; +}; +// iterator_traits is not specialized, and no standard specialization +// matches, so use incrementable_traits. +static_assert( check_alias::difference_type> ); + +struct J +{ + using iterator_category = std::input_iterator_tag; + using difference_type = int; + using value_type = char; + using reference = value_type&; +}; +// iterator_traits matches constrained specialization in the library, +// so use its difference_type. +static_assert( check_alias ); diff --git a/libstdc++-v3/testsuite/24_iterators/associated_types/readable.traits.cc b/libstdc++-v3/testsuite/24_iterators/associated_types/readable.traits.cc new file mode 100644 index 00000000000..b4678abc1bc --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/associated_types/readable.traits.cc @@ -0,0 +1,143 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include + +struct none; + +template + concept has_readable_traits_type + = requires { typename std::readable_traits::value_type; }; + +// Check std::readable_traits::value_type is U (or doesn't exist). +template + concept check_readable_traits + = (has_readable_traits_type != std::same_as); + +static_assert( check_readable_traits ); +static_assert( check_readable_traits ); +static_assert( check_readable_traits ); +static_assert( check_readable_traits ); + +static_assert( check_readable_traits ); +static_assert( check_readable_traits ); + +static_assert( check_readable_traits ); +static_assert( check_readable_traits ); +static_assert( check_readable_traits ); +static_assert( check_readable_traits ); + +struct A { using value_type = int; }; +static_assert( check_readable_traits ); +static_assert( check_readable_traits ); +struct B : private A { }; +static_assert( check_readable_traits ); + +struct C { }; +short operator-(C, C) { return 0; } +static_assert( check_readable_traits ); +static_assert( check_readable_traits ); + +struct D { long operator*() const { return 1L; } }; +unsigned short operator-(D, D) { return 0; } +static_assert( check_readable_traits ); +static_assert( check_readable_traits ); + +struct E { }; +template<> + struct std::readable_traits { using value_type = long; }; +static_assert( check_readable_traits ); +static_assert( check_readable_traits ); + +template + concept has_alias = requires { typename std::iter_value_t; }; + +// Check std::iter_value_t is U (or doesn't exist). +template + concept check_alias = (has_alias != std::same_as); + +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); + +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); + +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); +static_assert( check_alias ); + +struct F { }; +template<> + struct std::iterator_traits { using value_type = F; }; +// iterator_traits is specialized, so use its value_type. +static_assert( check_alias::value_type> ); + +struct G { }; +template<> + struct std::readable_traits { using value_type = G; }; +template<> + struct std::iterator_traits { using value_type = int; }; +// iterator_traits is specialized, so use its value_type. +static_assert( check_alias::value_type> ); + +struct H { }; +template<> + struct std::readable_traits { using value_type = H; }; +template<> + struct std::iterator_traits + { + using iterator_category = input_iterator_tag; + using difference_type = int; + using value_type = char; + using reference = value_type&; + }; +// iterator_traits is specialized, so use its value_type. +static_assert( check_alias::value_type> ); + +struct I +{ + using value_type = I; +}; +// iterator_traits is not specialized, and no standard specialization +// matches, so use readable_traits. +static_assert( check_alias::value_type> ); + +struct J +{ + using iterator_category = std::input_iterator_tag; + using difference_type = int; + using value_type = char; + using reference = value_type&; +}; +// iterator_traits matches constrained specialization in the library, +// so use its value_type. +static_assert( check_alias ); diff --git a/libstdc++-v3/testsuite/24_iterators/contiguous/concept.cc b/libstdc++-v3/testsuite/24_iterators/contiguous/concept.cc new file mode 100644 index 00000000000..a9bb42e023f --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/contiguous/concept.cc @@ -0,0 +1,36 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include + +static_assert( std::contiguous_iterator ); +static_assert( std::contiguous_iterator ); +static_assert( std::contiguous_iterator ); + +static_assert( ! std::contiguous_iterator ); +static_assert( ! std::contiguous_iterator ); +static_assert( ! std::contiguous_iterator ); + +static_assert( ! std::contiguous_iterator ); +static_assert( ! std::contiguous_iterator ); + +struct A; +static_assert( ! std::contiguous_iterator ); +static_assert( ! std::contiguous_iterator ); diff --git a/libstdc++-v3/testsuite/24_iterators/contiguous/tag.cc b/libstdc++-v3/testsuite/24_iterators/contiguous/tag.cc new file mode 100644 index 00000000000..7673131f215 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/contiguous/tag.cc @@ -0,0 +1,34 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include + +static_assert( std::is_empty_v ); +static_assert( std::is_trivially_copy_constructible_v ); + +static_assert( std::is_base_of_v ); +static_assert( std::is_convertible_v ); + +static_assert( ! std::is_same_v::iterator_category, + std::contiguous_iterator_tag> ); +static_assert( std::is_same_v::iterator_concept, + std::contiguous_iterator_tag> ); diff --git a/libstdc++-v3/testsuite/24_iterators/customization_points/iter_move.cc b/libstdc++-v3/testsuite/24_iterators/customization_points/iter_move.cc new file mode 100644 index 00000000000..d32dee39f3a --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/customization_points/iter_move.cc @@ -0,0 +1,68 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +struct X +{ + int value; + + constexpr X(int i) : value(i) { } + + X(const X&) = default; + X& operator=(const X&) = default; + + constexpr X(X&& x) + : value(x.value) + { + x.value = -2; + } + + constexpr X& operator=(X&& x) + { + value = x.value; + x.value = -1; + return *this; + } +}; + +constexpr bool +test_X(int i, int j) +{ + X x1{i}, x2{j}; + std::ranges::iter_move(&x1); // no-op + x1 = std::ranges::iter_move(&x2); + return x1.value == j && x2.value == -1; +} + +static_assert( test_X(1, 2) ); + +void +test01() +{ + VERIFY( test_X(3, 4) ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/24_iterators/customization_points/iter_swap.cc b/libstdc++-v3/testsuite/24_iterators/customization_points/iter_swap.cc new file mode 100644 index 00000000000..4243a162fc6 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/customization_points/iter_swap.cc @@ -0,0 +1,61 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +struct X +{ + int value; + + constexpr X(int i) : value(i) { } + + X(const X&) = default; + X& operator=(const X&) = default; + + constexpr X& operator=(X&& x) + { + value = x.value; + x.value = -1; + return *this; + } +}; + +constexpr bool +test_X(int i, int j) +{ + X x1{i}, x2{j}; + std::ranges::iter_swap(&x1, &x2); + return x1.value == j && x2.value == i; +} + +static_assert( test_X(1, 2) ); + +void +test01() +{ + VERIFY( test_X(3, 4) ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++20.cc b/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++20.cc new file mode 100644 index 00000000000..2dbfb767fdb --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++20.cc @@ -0,0 +1,95 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } +// { dg-require-normal-namespace "" } + +#include +#include "./synopsis_c++17.cc" + +namespace std +{ + template struct incrementable_traits; + template struct readable_traits; + + struct contiguous_iterator_tag; + + namespace ranges + { + template S> + constexpr iter_difference_t distance(I first, S last); + template + constexpr range_difference_t distance(R&& r); + + template + constexpr I next(I x); + template + constexpr I next(I x, iter_difference_t n); + template S> + constexpr I next(I x, S bound); + template S> + constexpr I next(I x, iter_difference_t n, S bound); + + template + constexpr I prev(I x); + template + constexpr I prev(I x, iter_difference_t n); + template + constexpr I prev(I x, iter_difference_t n, I bound); + } + + template class move_sentinel; + + template S> + requires (!same_as) + class common_iterator; + + template + struct incrementable_traits>; + + template + struct iterator_traits>; + + struct default_sentinel_t; + + template class counted_iterator; + + template + struct incrementable_traits>; + + template + struct iterator_traits>; + + struct unreachable_sentinel_t; +} + +namespace __gnu_test +{ + // customization points + constexpr auto* iter_move = &std::ranges::iter_move; + constexpr auto* iter_swap = &std::ranges::iter_swap; + // sized sentinels + constexpr bool const* disable_sized_sentinel + = &std::disable_sized_sentinel; + // default sentinels + constexpr std::default_sentinel_t const* default_sentinel + = &std::default_sentinel; + // unreachable sentinels + constexpr std::unreachable_sentinel_t const* unreachable_sentinel + = &std::unreachable_sentinel; +} diff --git a/libstdc++-v3/testsuite/24_iterators/range_operations/advance.cc b/libstdc++-v3/testsuite/24_iterators/range_operations/advance.cc new file mode 100644 index 00000000000..7f77eca1c4b --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/range_operations/advance.cc @@ -0,0 +1,204 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::random_access_iterator_wrapper; +using __gnu_test::bidirectional_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; + +void +test01() +{ + int a[2] = { }; + test_range r(a); + auto iter = r.begin(); + std::ranges::advance(iter, 1); + VERIFY( iter != r.begin() ); + VERIFY( iter != r.end() ); + std::ranges::advance(iter, 1); + VERIFY( iter == r.end() ); + std::ranges::advance(iter, -2); + VERIFY( iter == r.begin() ); + + std::ranges::advance(iter, r.begin() + 1); + VERIFY( iter != r.begin() ); + VERIFY( iter != r.end() ); + std::ranges::advance(iter, r.begin()); + VERIFY( iter == r.begin() ); + + std::ranges::advance(iter, 99, r.end()); + VERIFY( iter == r.end() ); + std::ranges::advance(iter, -222, r.begin()); + VERIFY( iter == r.begin() ); +} + +void +test02() +{ + int a[2] = { }; + test_range r(a); + auto iter = r.begin(); + std::ranges::advance(iter, 1); + VERIFY( iter != r.begin() ); + VERIFY( iter != r.end() ); + std::ranges::advance(iter, 1); + VERIFY( iter == r.end() ); + std::ranges::advance(iter, -2); + VERIFY( iter == r.begin() ); + + auto iter1 = r.begin(); + ++iter1; + std::ranges::advance(iter, iter1); + VERIFY( iter != r.begin() ); + VERIFY( iter != r.end() ); + std::ranges::advance(iter, r.begin()); + VERIFY( iter == r.begin() ); + + std::ranges::advance(iter, 99, r.end()); + VERIFY( iter == r.end() ); + std::ranges::advance(iter, -222, r.begin()); + VERIFY( iter == r.begin() ); +} + +void +test03() +{ + int a[2] = { }; + test_range r(a); + auto iter = r.begin(); + std::ranges::advance(iter, 1); + VERIFY( iter != r.begin() ); + VERIFY( iter != r.end() ); + std::ranges::advance(iter, 1); + std::ranges::advance(iter, 0); + VERIFY( iter == r.end() ); + std::ranges::advance(iter, 0); + VERIFY( iter == r.end() ); + + auto iter1 = r.begin(); + ++iter1; + std::ranges::advance(iter, iter1); + VERIFY( iter != r.begin() ); + VERIFY( iter != r.end() ); + std::ranges::advance(iter, r.end()); + VERIFY( iter == r.end() ); + std::ranges::advance(iter, r.end()); + VERIFY( iter == r.end() ); + + std::ranges::advance(iter, 99, r.end()); + VERIFY( iter == r.end() ); + std::ranges::advance(iter, 99, r.end()); + VERIFY( iter == r.end() ); + iter = r.begin(); + std::ranges::advance(iter, 99, r.end()); + VERIFY( iter == r.end() ); + std::ranges::advance(iter, 99, r.end()); + VERIFY( iter == r.end() ); +} + +void +test04() +{ + int a[2] = { }; + test_range r(a); + auto iter = r.begin(); + std::ranges::advance(iter, 1); + VERIFY( iter != r.end() ); + std::ranges::advance(iter, 1); + std::ranges::advance(iter, 0); + VERIFY( iter == r.end() ); + std::ranges::advance(iter, 0); + VERIFY( iter == r.end() ); + + test_range r2(a); + iter = r2.begin(); + ++iter; + const auto iter1 = iter; + std::ranges::advance(iter, iter1); + VERIFY( iter == iter1 ); + VERIFY( iter != r2.end() ); + std::ranges::advance(iter, r2.end()); + VERIFY( iter == r2.end() ); + std::ranges::advance(iter, r2.end()); + VERIFY( iter == r2.end() ); + + std::ranges::advance(iter, 99, r2.end()); + VERIFY( iter == r2.end() ); + std::ranges::advance(iter, 99, r2.end()); + VERIFY( iter == r2.end() ); + + test_range r3(a); + iter = r3.begin(); + std::ranges::advance(iter, 99, r3.end()); + VERIFY( iter == r3.end() ); + std::ranges::advance(iter, 99, r3.end()); + VERIFY( iter == r3.end() ); +} + +void +test05() +{ + int a[2] = { }; + test_range r(a); + auto iter = r.begin(); + std::ranges::advance(iter, 1); + VERIFY( iter != r.end() ); + std::ranges::advance(iter, 1); + std::ranges::advance(iter, 0); + VERIFY( iter == r.end() ); + std::ranges::advance(iter, 0); + VERIFY( iter == r.end() ); + + test_range r2(a); + iter = r2.begin(); + ++iter; + std::ranges::advance(iter, r2.end()); + VERIFY( iter == r2.end() ); + std::ranges::advance(iter, r2.end()); + VERIFY( iter == r2.end() ); + + std::ranges::advance(iter, 99, r2.end()); + VERIFY( iter == r2.end() ); + std::ranges::advance(iter, 99, r2.end()); + VERIFY( iter == r2.end() ); + + test_range r3(a); + iter = r3.begin(); + std::ranges::advance(iter, 99, r3.end()); + VERIFY( iter == r3.end() ); + std::ranges::advance(iter, 99, r3.end()); + VERIFY( iter == r3.end() ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); +} diff --git a/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc b/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc new file mode 100644 index 00000000000..4aa095ff3d7 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc @@ -0,0 +1,146 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::test_sized_range; +using __gnu_test::random_access_iterator_wrapper; +using __gnu_test::bidirectional_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; + +void +test01() +{ + int a[10] = { }; + VERIFY( std::ranges::distance(a) == 10 ); + + test_range c(a); + VERIFY( std::ranges::distance(c) == 10 ); + + auto b = c.begin(), e = c.end(); + VERIFY( std::ranges::distance(b, e) == 10 ); + VERIFY( std::ranges::distance(e, b) == -10 ); + + const auto cb = b, ce = e; + VERIFY( std::ranges::distance(cb, ce) == 10 ); + VERIFY( std::ranges::distance(ce, cb) == -10 ); + + test_sized_range c2(a); + VERIFY( std::ranges::distance(c2) == 10 ); +} + +void +test02() +{ + int a[2] = { }; + VERIFY( std::ranges::distance(a) == 2 ); + + test_range c(a); + VERIFY( std::ranges::distance(c) == 2 ); + + auto b = c.begin(), e = c.end(); + VERIFY( std::ranges::distance(b, e) == 2 ); + + const auto cb = b, ce = e; + VERIFY( std::ranges::distance(cb, ce) == 2 ); + + test_sized_range c2(a); + VERIFY( std::ranges::distance(c2) == 2 ); +} + +void +test03() +{ + int a[3] = { }; + test_range c(a); + VERIFY( std::ranges::distance(c) == 3 ); + + auto b = c.begin(), e = c.end(); + VERIFY( std::ranges::distance(b, e) == 3 ); + + const auto cb = b, ce = e; + VERIFY( std::ranges::distance(cb, ce) == 3 ); + + test_sized_range c2(a); + VERIFY( std::ranges::distance(c2) == 3 ); +} + +void +test04() +{ + int a[4] = { }; + test_range c(a); + static_assert( std::ranges::range ); + + VERIFY( std::ranges::distance(c) == 4 ); + // first call to distance has traversed the range: + VERIFY( std::ranges::distance(c) == 0 ); + + c = test_range(a); + auto b = c.begin(), e = c.end(); + VERIFY( std::ranges::distance(b, e) == 4 ); + + test_range c2(a); + const auto cb = c2.begin(), ce = c2.end(); + VERIFY( std::ranges::distance(cb, ce) == 4 ); + + test_sized_range c3(a); + VERIFY( std::ranges::distance(c3) == 4 ); + // first call to distance just called size() without affecting the range: + VERIFY( std::ranges::distance(c3) == 4 ); +} + +void +test05() +{ + int a[5] = { }; + test_range c(a); + VERIFY( std::ranges::distance(c) == 5 ); + + test_range c2(a); + auto b = c2.begin(); + auto e = c2.end(); + VERIFY( std::ranges::distance(b, e) == 5 ); + + test_range c3(a); + const auto cb = c3.begin(); + const auto ce = c3.end(); + VERIFY( std::ranges::distance(cb, ce) == 5 ); + + test_sized_range c4(a); + VERIFY( std::ranges::distance(c4) == 5 ); + // first call to distance just called size() without affecting the range: + VERIFY( std::ranges::distance(c4) == 5 ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); +} diff --git a/libstdc++-v3/testsuite/24_iterators/range_operations/next.cc b/libstdc++-v3/testsuite/24_iterators/range_operations/next.cc new file mode 100644 index 00000000000..7f04cb23b3c --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/range_operations/next.cc @@ -0,0 +1,211 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::random_access_iterator_wrapper; +using __gnu_test::bidirectional_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; + +void +test01() +{ + int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + test_range r(a); + auto begin = r.begin(); + auto end = r.end(); + VERIFY( *std::ranges::next(begin) == 1 ); + VERIFY( std::ranges::next(begin, 0) == begin ); + VERIFY( *std::ranges::next(begin, 1) == 1 ); + VERIFY( *std::ranges::next(begin, 3) == 3 ); + VERIFY( *std::ranges::next(end, -4) == 6 ); + VERIFY( std::ranges::next(begin, begin) == begin ); + VERIFY( std::ranges::next(begin, end) == end ); + VERIFY( std::ranges::next(end, end) == end ); + VERIFY( std::ranges::next(end, begin) == begin ); + VERIFY( std::ranges::next(begin, 0, begin) == begin ); + VERIFY( std::ranges::next(begin, 5, begin) == begin ); + VERIFY( std::ranges::next(begin, -5, begin) == begin ); + VERIFY( std::ranges::next(begin, 0, end) == begin ); + VERIFY( *std::ranges::next(begin, 5, end) == 5 ); + VERIFY( std::ranges::next(begin, 55, end) == end ); + VERIFY( std::ranges::next(end, 0, end) == end ); + VERIFY( std::ranges::next(end, -5, end) == end ); + VERIFY( std::ranges::next(end, -55, end) == end ); + VERIFY( std::ranges::next(end, 0, begin) == end ); + VERIFY( *std::ranges::next(end, -5, begin) == 5 ); + VERIFY( std::ranges::next(end, -55, begin) == begin ); +} + +void +test02() +{ + int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + test_range r(a); + auto begin = r.begin(); + auto end = r.end(); + VERIFY( *std::ranges::next(begin) == 1 ); + VERIFY( std::ranges::next(begin, 0) == begin ); + VERIFY( *std::ranges::next(begin, 1) == 1 ); + VERIFY( *std::ranges::next(begin, 3) == 3 ); + VERIFY( *std::ranges::next(end, -4) == 6 ); + VERIFY( std::ranges::next(begin, begin) == begin ); + VERIFY( std::ranges::next(begin, end) == end ); + VERIFY( std::ranges::next(end, end) == end ); + VERIFY( std::ranges::next(end, begin) == begin ); + VERIFY( std::ranges::next(begin, 0, begin) == begin ); + VERIFY( std::ranges::next(begin, 5, begin) == begin ); + VERIFY( std::ranges::next(begin, -5, begin) == begin ); + VERIFY( std::ranges::next(begin, 0, end) == begin ); + VERIFY( *std::ranges::next(begin, 5, end) == 5 ); + VERIFY( std::ranges::next(begin, 55, end) == end ); + VERIFY( std::ranges::next(end, 0, end) == end ); + VERIFY( std::ranges::next(end, -5, end) == end ); + VERIFY( std::ranges::next(end, -55, end) == end ); + VERIFY( std::ranges::next(end, 0, begin) == end ); + VERIFY( *std::ranges::next(end, -5, begin) == 5 ); + VERIFY( std::ranges::next(end, -55, begin) == begin ); +} + +void +test03() +{ + int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + test_range r(a); + auto begin = r.begin(); + auto end = r.end(); + VERIFY( *std::ranges::next(begin) == 1 ); + VERIFY( std::ranges::next(begin, 0) == begin ); + VERIFY( *std::ranges::next(begin, 1) == 1 ); + VERIFY( *std::ranges::next(begin, 3) == 3 ); + VERIFY( std::ranges::next(begin, begin) == begin ); + VERIFY( std::ranges::next(begin, end) == end ); + VERIFY( std::ranges::next(end, end) == end ); + VERIFY( std::ranges::next(begin, 0, begin) == begin ); + VERIFY( std::ranges::next(begin, 5, begin) == begin ); + VERIFY( std::ranges::next(begin, -5, begin) == begin ); + VERIFY( std::ranges::next(begin, 0, end) == begin ); + VERIFY( *std::ranges::next(begin, 5, end) == 5 ); + VERIFY( std::ranges::next(begin, 55, end) == end ); + VERIFY( std::ranges::next(end, 0, end) == end ); + VERIFY( std::ranges::next(end, 5, end) == end ); + VERIFY( std::ranges::next(end, 55, end) == end ); + VERIFY( std::ranges::next(end, 0, begin) == end ); +} + +void +test04() +{ + int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + test_range r(a); + auto begin = r.begin(); + auto end = r.end(); + auto iter = std::ranges::next(begin); + VERIFY( *iter == 1 ); + iter = std::ranges::next(iter, 0); + VERIFY( *iter == 1 ); + iter = std::ranges::next(iter, 1); + VERIFY( *iter == 2 ); + iter = std::ranges::next(iter, 4); + VERIFY( *iter == 6 ); + + iter = std::ranges::next(iter, iter); + VERIFY( *iter == 6 ); + iter = std::ranges::next(iter, end); + VERIFY( iter == end ); + iter = std::ranges::next(iter, end); + VERIFY( iter == end ); + + test_range r2(a); + begin = r2.begin(); + end = r2.end(); + iter = std::ranges::next(begin, 0, begin); + VERIFY( *iter == 0 ); + iter = std::ranges::next(begin, 5, begin); + VERIFY( *iter == 0 ); + iter = std::ranges::next(begin, -5, begin); + VERIFY( *iter == 0 ); + iter = std::ranges::next(begin, 0, end); + VERIFY( *iter == 0 ); + iter = std::ranges::next(end, 0, begin); + VERIFY( iter == end ); + iter = std::ranges::next(begin, 5, end); // invalidates begin + VERIFY( *iter == 5 ); + iter = std::ranges::next(iter, 55, end); + VERIFY( iter == end ); + iter = std::ranges::next(end, 0, end); + VERIFY( iter == end ); + iter = std::ranges::next(end, 5, end); + VERIFY( iter == end ); +} + +void +test05() +{ + int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + test_range r(a); + auto iter = r.begin(); + auto end = r.end(); // sentinel, !same_as + + iter = std::ranges::next(iter); + *iter = 10; + VERIFY( a[1] == 10 ); + iter = std::ranges::next(iter, 0); + iter = std::ranges::next(iter, 1); + *iter = 20; + VERIFY( a[2] == 20 ); + iter = std::ranges::next(iter, 4); + iter = std::ranges::next(iter, 0); + *iter = 60; + VERIFY( a[6] == 60 ); + + iter = std::ranges::next(iter, end); + VERIFY( iter == end ); + iter = std::ranges::next(iter, end); + VERIFY( iter == end ); + + test_range r2(a); + iter = std::ranges::next(r2.begin(), 5); + end = r2.end(); + + iter = std::ranges::next(iter, 0, end); + *iter = 50; + VERIFY( a[5] == 50 ); + iter = std::ranges::next(iter, 2, end); + *iter = 70; + VERIFY( a[7] == 70 ); + iter = std::ranges::next(iter, 5, end); + VERIFY( iter == end ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); +} diff --git a/libstdc++-v3/testsuite/24_iterators/range_operations/prev.cc b/libstdc++-v3/testsuite/24_iterators/range_operations/prev.cc new file mode 100644 index 00000000000..944c02a6052 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/range_operations/prev.cc @@ -0,0 +1,98 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::random_access_iterator_wrapper; +using __gnu_test::bidirectional_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; + +void +test01() +{ + int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + test_range r(a); + auto begin = r.begin(); + auto end = r.end(); + VERIFY( *std::ranges::prev(end) == 9 ); + VERIFY( std::ranges::prev(begin, 0) == begin ); + VERIFY( *std::ranges::prev(end, 1) == 9 ); + VERIFY( *std::ranges::prev(end, 3) == 7 ); + VERIFY( *std::ranges::prev(begin, -4) == 4 ); + VERIFY( std::ranges::prev(begin, 0, begin) == begin ); + VERIFY( std::ranges::prev(begin, 5, begin) == begin ); + VERIFY( std::ranges::prev(begin, -5, begin) == begin ); + VERIFY( std::ranges::prev(begin, 0, end) == begin ); + VERIFY( *std::ranges::prev(end, 5, begin) == 5 ); + VERIFY( std::ranges::prev(end, 55, begin) == begin ); + VERIFY( std::ranges::prev(end, 0, end) == end ); + VERIFY( std::ranges::prev(end, -5, end) == end ); + VERIFY( std::ranges::prev(end, -55, end) == end ); + VERIFY( std::ranges::prev(end, 0, begin) == end ); + VERIFY( *std::ranges::prev(begin, -5, end) == 5 ); + VERIFY( std::ranges::prev(begin, -55, end) == end ); +} + +void +test02() +{ + int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + test_range r(a); + auto begin = r.begin(); + auto end = r.end(); + VERIFY( *std::ranges::prev(end) == 9 ); + VERIFY( std::ranges::prev(begin, 0) == begin ); + VERIFY( *std::ranges::prev(end, 1) == 9 ); + VERIFY( *std::ranges::prev(end, 3) == 7 ); + VERIFY( *std::ranges::prev(begin, -4) == 4 ); + VERIFY( std::ranges::prev(begin, 0, begin) == begin ); + VERIFY( std::ranges::prev(begin, 5, begin) == begin ); + VERIFY( std::ranges::prev(begin, -5, begin) == begin ); + VERIFY( std::ranges::prev(begin, 0, end) == begin ); + VERIFY( *std::ranges::prev(end, 5, begin) == 5 ); + VERIFY( std::ranges::prev(end, 55, begin) == begin ); + VERIFY( std::ranges::prev(end, 0, end) == end ); + VERIFY( std::ranges::prev(end, -5, end) == end ); + VERIFY( std::ranges::prev(end, -55, end) == end ); + VERIFY( std::ranges::prev(end, 0, begin) == end ); + VERIFY( *std::ranges::prev(begin, -5, end) == 5 ); + VERIFY( std::ranges::prev(begin, -55, end) == end ); +} + +template + concept can_prev = requires(T& t) { std::ranges::prev(t); } + || requires(T& t) { std::ranges::prev(t, 1); } + || requires(T& t) { std::ranges::prev(t, 1, t); }; + +static_assert( !can_prev> ); +static_assert( !can_prev> ); +static_assert( !can_prev> ); + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/26_numerics/adjacent_difference/requirements/explicit_instantiation/2.cc b/libstdc++-v3/testsuite/26_numerics/adjacent_difference/requirements/explicit_instantiation/2.cc index 83bd8bc7eb6..1d44c316086 100644 --- a/libstdc++-v3/testsuite/26_numerics/adjacent_difference/requirements/explicit_instantiation/2.cc +++ b/libstdc++-v3/testsuite/26_numerics/adjacent_difference/requirements/explicit_instantiation/2.cc @@ -28,9 +28,10 @@ namespace std using __gnu_test::NonDefaultConstructible; typedef NonDefaultConstructible value_type; - typedef value_type* input_iterator; - typedef value_type* output_iterator; + typedef value_type* input_iterator_type; + typedef value_type* output_iterator_type; - template - output_iterator adjacent_difference(input_iterator, input_iterator, output_iterator); + template output_iterator_type + adjacent_difference(input_iterator_type, input_iterator_type, + output_iterator_type); } diff --git a/libstdc++-v3/testsuite/26_numerics/adjacent_difference/requirements/explicit_instantiation/pod.cc b/libstdc++-v3/testsuite/26_numerics/adjacent_difference/requirements/explicit_instantiation/pod.cc index dd8b7dc6494..f7c82ece908 100644 --- a/libstdc++-v3/testsuite/26_numerics/adjacent_difference/requirements/explicit_instantiation/pod.cc +++ b/libstdc++-v3/testsuite/26_numerics/adjacent_difference/requirements/explicit_instantiation/pod.cc @@ -28,9 +28,10 @@ namespace std using __gnu_test::pod_int; typedef pod_int value_type; - typedef value_type* input_iterator; - typedef value_type* output_iterator; + typedef value_type* input_iterator_type; + typedef value_type* output_iterator_type; - template - output_iterator adjacent_difference(input_iterator, input_iterator, output_iterator); + template output_iterator_type + adjacent_difference(input_iterator_type, input_iterator_type, + output_iterator_type); } diff --git a/libstdc++-v3/testsuite/26_numerics/partial_sum/requirements/explicit_instantiation/2.cc b/libstdc++-v3/testsuite/26_numerics/partial_sum/requirements/explicit_instantiation/2.cc index 707de2f37fc..763d2d1ebe5 100644 --- a/libstdc++-v3/testsuite/26_numerics/partial_sum/requirements/explicit_instantiation/2.cc +++ b/libstdc++-v3/testsuite/26_numerics/partial_sum/requirements/explicit_instantiation/2.cc @@ -28,8 +28,9 @@ namespace std using __gnu_test::NonDefaultConstructible; typedef NonDefaultConstructible value_type; - typedef value_type* input_iterator; - typedef value_type* output_iterator; + typedef value_type* input_iterator_type; + typedef value_type* output_iterator_type; - template output_iterator partial_sum(input_iterator, input_iterator, output_iterator); + template output_iterator_type + partial_sum(input_iterator_type, input_iterator_type, output_iterator_type); } diff --git a/libstdc++-v3/testsuite/26_numerics/partial_sum/requirements/explicit_instantiation/pod.cc b/libstdc++-v3/testsuite/26_numerics/partial_sum/requirements/explicit_instantiation/pod.cc index 89c2bd9718b..a5b7a688ccb 100644 --- a/libstdc++-v3/testsuite/26_numerics/partial_sum/requirements/explicit_instantiation/pod.cc +++ b/libstdc++-v3/testsuite/26_numerics/partial_sum/requirements/explicit_instantiation/pod.cc @@ -28,8 +28,9 @@ namespace std using __gnu_test::pod_int; typedef pod_int value_type; - typedef value_type* input_iterator; - typedef value_type* output_iterator; + typedef value_type* input_iterator_type; + typedef value_type* output_iterator_type; - template output_iterator partial_sum(input_iterator, input_iterator, output_iterator); + template output_iterator_type + partial_sum(input_iterator_type, input_iterator_type, output_iterator_type); } diff --git a/libstdc++-v3/testsuite/experimental/iterator/requirements.cc b/libstdc++-v3/testsuite/experimental/iterator/requirements.cc index c11857e34a7..734cc170e9e 100644 --- a/libstdc++-v3/testsuite/experimental/iterator/requirements.cc +++ b/libstdc++-v3/testsuite/experimental/iterator/requirements.cc @@ -64,4 +64,6 @@ std::move_iterator mi; std::istream_iterator isi; std::ostream_iterator osi(os()); std::istreambuf_iterator isbi; + +#include std::ostreambuf_iterator osbi(os()); diff --git a/libstdc++-v3/testsuite/std/ranges/access/begin.cc b/libstdc++-v3/testsuite/std/ranges/access/begin.cc new file mode 100644 index 00000000000..1d7db46b68a --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/access/begin.cc @@ -0,0 +1,140 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include // N.B. should be +#include +#include + +using std::same_as; + +void +test01() +{ + int a[2] = {}; + + static_assert(same_as); + static_assert(noexcept(std::ranges::begin(a))); + VERIFY( std::ranges::begin(a) == (a + 0) ); + + constexpr long b[2] = { }; + static_assert( std::ranges::begin(b) == (b + 0) ); +} + +void +test02() +{ + using __gnu_test::test_range; + using __gnu_test::random_access_iterator_wrapper; + using __gnu_test::input_iterator_wrapper; + using __gnu_test::output_iterator_wrapper; + + int a[] = { 0, 1 }; + + test_range r(a); + static_assert(same_as); + VERIFY( std::ranges::begin(r) == r.begin() ); + + test_range i(a); + static_assert(same_as); + VERIFY( std::ranges::begin(i) == i.begin() ); + + test_range o(a); + static_assert(same_as); + *std::ranges::begin(o) = 99; + VERIFY( a[0] == 99 ); +} + +struct R +{ + int a[4] = { 0, 1, 2, 3 }; + + friend int* begin(R& r) { return r.a + 0; } + friend int* begin(R&& r) { return r.a + 1; } + friend const int* begin(const R& r) noexcept { return r.a + 2; } + friend const int* begin(const R&& r) noexcept { return r.a + 3; } +}; + +void +test03() +{ + R r; + const R& c = r; + + static_assert(same_as); + static_assert(!noexcept(std::ranges::begin(r))); + VERIFY( std::ranges::begin(r) == begin(r) ); + + static_assert(same_as); + static_assert(!noexcept(std::ranges::begin(std::move(r)))); + VERIFY( std::ranges::begin(std::move(r)) == begin(std::move(r)) ); + + + static_assert(same_as); + static_assert(noexcept(std::ranges::begin(c))); + VERIFY( std::ranges::begin(c) == begin(c) ); + + static_assert(same_as); + static_assert(noexcept(std::ranges::begin(std::move(c)))); + VERIFY( std::ranges::begin(std::move(c)) == begin(std::move(c)) ); +} + +struct RR +{ + short s = 0; + long l = 0; + int a[4] = { 0, 1, 2, 3 }; + + short* begin() noexcept { return &s; } + const long* begin() const { return &l; } + + friend int* begin(RR& r) { return r.a + 0; } + friend int* begin(RR&& r) { return r.a + 1; } + friend const int* begin(const RR& r) { return r.a + 2; } + friend const int* begin(const RR&& r) noexcept { return r.a + 3; } +}; + +void +test04() +{ + RR r; + const RR& c = r; + VERIFY( std::ranges::begin(r) == &r.s ); + static_assert(noexcept(std::ranges::begin(r))); + + VERIFY( std::ranges::begin(std::move(r)) == r.a + 1 ); + static_assert(!noexcept(std::ranges::begin(std::move(r)))); + + VERIFY( std::ranges::begin(c) == &r.l ); + static_assert(!noexcept(std::ranges::begin(c))); + + VERIFY( std::ranges::begin(std::move(c)) == r.a + 3 ); + static_assert(noexcept(std::ranges::begin(std::move(c)))); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc new file mode 100644 index 00000000000..34dd7fec3c6 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc @@ -0,0 +1,91 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include // N.B. should be +#include +using std::same_as; + +void +test01() +{ + int a[2] = {}; + + static_assert(same_as); + static_assert(noexcept(std::ranges::cbegin(a))); + VERIFY( std::ranges::cbegin(a) == (a + 0) ); + + constexpr long b[2] = {}; + static_assert( std::ranges::cbegin(b) == (b + 0) ); +} + +struct R +{ + int a[4] = { 0, 1, 2, 3 }; + + friend int* begin(R& r) { return r.a + 0; } + friend int* begin(R&& r) { return r.a + 1; } + friend const int* begin(const R& r) noexcept { return r.a + 2; } + friend const int* begin(const R&& r) noexcept { return r.a + 3; } +}; + +void +test03() +{ + R r; + const R& c = r; + VERIFY(std::ranges::cbegin(r) == std::ranges::begin(c)); + VERIFY(std::ranges::cbegin(std::move(r)) == std::ranges::begin(std::move(c))); + VERIFY(std::ranges::cbegin(c) == std::ranges::begin(c)); + VERIFY(std::ranges::cbegin(std::move(c)) == std::ranges::begin(std::move(c))); +} + +struct RR +{ + short s = 0; + long l = 0; + int a[4] = { 0, 1, 2, 3 }; + + short* begin() noexcept { return &s; } + const long* begin() const { return &l; } + + friend int* begin(RR& r) { return r.a + 0; } + friend int* begin(RR&& r) { return r.a + 1; } + friend const int* begin(const RR& r) { return r.a + 2; } + friend const int* begin(const RR&& r) noexcept { return r.a + 3; } +}; + +void +test04() +{ + RR r; + const RR& c = r; + VERIFY(std::ranges::cbegin(r) == std::ranges::begin(c)); + VERIFY(std::ranges::cbegin(std::move(r)) == std::ranges::begin(std::move(c))); + VERIFY(std::ranges::cbegin(c) == std::ranges::begin(c)); + VERIFY(std::ranges::cbegin(std::move(c)) == std::ranges::begin(std::move(c))); +} + +int +main() +{ + test01(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc new file mode 100644 index 00000000000..9a1ab5b9607 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc @@ -0,0 +1,73 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +void +test01() +{ + struct R + { + int i = 0; + int j = 0; + int* data() { return &j; } + const R* data() const noexcept { return nullptr; } + }; + R r; + const R& c = r; + VERIFY( std::ranges::cdata(r) == (R*)nullptr ); + static_assert( noexcept(std::ranges::cdata(r)) ); + VERIFY( std::ranges::cdata(c) == (R*)nullptr ); + static_assert( noexcept(std::ranges::cdata(c)) ); +} + +void +test02() +{ + int a[] = { 0, 1 }; + VERIFY( std::ranges::cdata(a) == a + 0 ); +} + +struct R +{ + long l = 0; + + int* data() const { return nullptr; } + friend long* begin(R&& r) { return &r.l; } + friend const long* begin(const R&& r) { return &r.l + 1; } +}; + +void +test03() +{ + R r; + const R& c = r; + VERIFY( std::ranges::cdata(std::move(r)) == std::ranges::data(std::move(c)) ); + VERIFY( std::ranges::cdata(std::move(c)) == std::ranges::data(std::move(c)) ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/access/cend.cc b/libstdc++-v3/testsuite/std/ranges/access/cend.cc new file mode 100644 index 00000000000..789c6ca3837 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/access/cend.cc @@ -0,0 +1,98 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include // N.B. should be +#include + +using std::same_as; + +void +test01() +{ + int a[2] = {}; + + static_assert(same_as); + static_assert(noexcept(std::ranges::cend(a))); + VERIFY( std::ranges::cend(a) == (a + 2) ); +} + +struct R +{ + int a[4] = { 0, 1, 2, 3 }; + + const int* begin() const { return nullptr; } + friend const int* begin(const R&& r) noexcept { return nullptr; } + + // Should be ignored because it doesn't return a sentinel for int* + const long* end() const { return nullptr; } + + friend int* end(R& r) { return r.a + 0; } + friend int* end(R&& r) { return r.a + 1; } + friend const int* end(const R& r) noexcept { return r.a + 2; } + friend const int* end(const R&& r) noexcept { return r.a + 3; } +}; + +void +test03() +{ + R r; + const R& c = r; + VERIFY( std::ranges::cend(r) == std::ranges::end(c) ); + VERIFY( std::ranges::cend(std::move(r)) == std::ranges::end(std::move(c)) ); + VERIFY( std::ranges::cend(c) == std::ranges::end(c) ); + VERIFY( std::ranges::cend(std::move(c)) == std::ranges::end(std::move(c)) ); +} + +struct RR +{ + short s = 0; + long l = 0; + int a[4] = { 0, 1, 2, 3 }; + + const void* begin() const { return nullptr; } + friend const void* begin(const RR&&) noexcept { return nullptr; } + + short* end() noexcept { return &s; } + const long* end() const { return &l; } + + friend int* end(RR&) { throw 1; } + friend int* end(RR&& r) { return r.a + 1; } + friend const int* end(const RR&) { throw 1; } + friend const int* end(const RR&& r) noexcept { return r.a + 3; } +}; + +void +test04() +{ + RR r; + const RR& c = r; + VERIFY( std::ranges::cend(r) == std::ranges::end(c) ); + VERIFY( std::ranges::cend(std::move(r)) == std::ranges::end(std::move(c)) ); + VERIFY( std::ranges::cend(c) == std::ranges::end(c) ); + VERIFY( std::ranges::cend(std::move(c)) == std::ranges::end(std::move(c)) ); +} + +int +main() +{ + test01(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc new file mode 100644 index 00000000000..24939ac658e --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc @@ -0,0 +1,73 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +struct R1 +{ + int i = 0; + int j = 0; + + const int* rbegin() const { return &i; } + friend const int* rbegin(const R1&& r) { return &r.j; } +}; + +void +test01() +{ + R1 r; + const R1& c = r; + VERIFY( std::ranges::crbegin(r) == std::ranges::rbegin(c) ); + VERIFY( std::ranges::crbegin(std::move(r)) == std::ranges::rbegin(std::move(c)) ); + VERIFY( std::ranges::crbegin(c) == std::ranges::rbegin(c) ); + VERIFY( std::ranges::crbegin(std::move(c)) == std::ranges::rbegin(std::move(c)) ); +} + +struct R2 +{ + int a[2] = { }; + long l[2] = { }; + + const int* begin() const { return a; } + const int* end() const { return a + 2; } + + friend const long* begin(const R2&& r) { return r.l; } + friend const long* end(const R2&& r) { return r.l + 2; } +}; + +void +test02() +{ + R2 r; + const R2& c = r; + VERIFY( std::ranges::crbegin(r) == std::ranges::rbegin(c) ); + VERIFY( std::ranges::crbegin(std::move(r)) == std::ranges::rbegin(std::move(c)) ); + VERIFY( std::ranges::crbegin(c) == std::ranges::rbegin(c) ); + VERIFY( std::ranges::crbegin(std::move(c)) == std::ranges::rbegin(std::move(c)) ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/access/crend.cc b/libstdc++-v3/testsuite/std/ranges/access/crend.cc new file mode 100644 index 00000000000..ef0fb0e6b09 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/access/crend.cc @@ -0,0 +1,108 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +struct R1 +{ + int i = 0; + int j = 0; + + constexpr const int* rbegin() const { return &i; } + constexpr const int* rend() const { return &i + 1; } + friend constexpr const int* rbegin(const R1&& r) { return &r.j; } + friend constexpr const int* rend(const R1&& r) { return &r.j + 1; } +}; + +void +test01() +{ + R1 r; + const R1& c = r; + VERIFY( std::ranges::crend(r) == std::ranges::rend(c) ); + VERIFY( std::ranges::crend(std::move(r)) == std::ranges::rend(std::move(c)) ); + VERIFY( std::ranges::crend(c) == std::ranges::rend(c) ); + VERIFY( std::ranges::crend(std::move(c)) == std::ranges::rend(std::move(c)) ); +} + +struct R2 +{ + int a[2] = { }; + long l[2] = { }; + + const int* begin() const { return a; } + const int* end() const { return a + 2; } + + friend const long* begin(const R2&& r) { return r.l; } + friend const long* end(const R2&& r) { return r.l + 2; } +}; + +void +test02() +{ + R2 r; + const R2& c = r; + VERIFY( std::ranges::crend(r) == std::ranges::rend(c) ); + VERIFY( std::ranges::crend(std::move(r)) == std::ranges::rend(std::move(c)) ); + VERIFY( std::ranges::crend(c) == std::ranges::rend(c) ); + VERIFY( std::ranges::crend(std::move(c)) == std::ranges::rend(std::move(c)) ); +} + +struct R3 +{ + int i = 0; + + const int* rbegin() const noexcept { return &i + 1; } + const long* rend() const noexcept { return nullptr; } // not a sentinel for rbegin() + + friend const long* rbegin(const R3&) noexcept { return nullptr; } + friend const int* rend(const R3& r) { return &r.i; } +}; + +void +test03() +{ + R3 r; + const R3& c = r; + VERIFY( std::ranges::crend(r) == std::ranges::rend(c) ); + static_assert( !noexcept(std::ranges::crend(r)) ); + VERIFY( std::ranges::crend(c) == std::ranges::rend(c) ); + static_assert( !noexcept(std::ranges::crend(c)) ); +} + +void +test04() +{ + int a[2] = { }; + const auto& c = a; + VERIFY( std::ranges::crend(a) == std::ranges::rend(c) ); + VERIFY( std::ranges::crend(c) == std::ranges::rend(c) ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/access/data.cc b/libstdc++-v3/testsuite/std/ranges/access/data.cc new file mode 100644 index 00000000000..d9129d055fc --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/access/data.cc @@ -0,0 +1,78 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +void +test01() +{ + struct R + { + int i = 0; + int j = 0; + int* data() { return &j; } + const R* data() const noexcept { return nullptr; } + }; + R r; + const R& c = r; + VERIFY( std::ranges::data(r) == &r.j ); + static_assert( !noexcept(std::ranges::data(r)) ); + VERIFY( std::ranges::data(c) == (R*)nullptr ); + static_assert( noexcept(std::ranges::data(c)) ); +} + + +void +test02() +{ + int a[] = { 0, 1 }; + VERIFY( std::ranges::data(a) == a + 0 ); + + __gnu_test::test_range r(a); + VERIFY( std::ranges::data(r) == std::to_address(std::ranges::begin(r)) ); +} + +struct R3 +{ + long l = 0; + + int* data() const { return nullptr; } + friend long* begin(R3&& r) { return &r.l; } + friend const long* begin(const R3&& r) { return &r.l + 1; } +}; + +void +test03() +{ + R3 r; + const R3& c = r; + VERIFY( std::ranges::data(std::move(r)) == std::to_address(std::ranges::begin(std::move(r))) ); + VERIFY( std::ranges::data(std::move(c)) == std::to_address(std::ranges::begin(std::move(c))) ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/access/empty.cc b/libstdc++-v3/testsuite/std/ranges/access/empty.cc new file mode 100644 index 00000000000..64b1e1b5e1b --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/access/empty.cc @@ -0,0 +1,76 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include // N.B. should be +#include +#include + +using std::same_as; + +void +test01() +{ + struct R + { + constexpr int empty() const & { return 0; } + constexpr const void* empty() const && { return this; } + }; + constexpr R r; + static_assert( !std::ranges::empty(r) ); + static_assert( same_as ); + static_assert( std::ranges::empty(std::move(r)) ); + static_assert( same_as ); +} + +void +test02() +{ + using __gnu_test::test_range; + using __gnu_test::test_sized_range; + using __gnu_test::random_access_iterator_wrapper; + using __gnu_test::forward_iterator_wrapper; + using __gnu_test::input_iterator_wrapper; + using __gnu_test::output_iterator_wrapper; + + int a[] = { 0, 1 }; + VERIFY( !std::ranges::empty(a) ); + + test_range r(a); + VERIFY( !std::ranges::empty(r) ); + + test_range i(a); + VERIFY( !std::ranges::empty(i) ); + + test_sized_range sr(a); + VERIFY( !std::ranges::empty(sr) ); + + test_sized_range si(a); + VERIFY( !std::ranges::empty(si) ); + + test_sized_range so(a); + VERIFY( !std::ranges::empty(so) ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/access/end.cc b/libstdc++-v3/testsuite/std/ranges/access/end.cc new file mode 100644 index 00000000000..7f09cc2a4ab --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/access/end.cc @@ -0,0 +1,145 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include // N.B. should be +#include +#include + +using std::same_as; + +void +test01() +{ + int a[2] = {}; + + static_assert(same_as); + static_assert(noexcept(std::ranges::end(a))); + VERIFY( std::ranges::end(a) == (a + 2) ); +} + +void +test02() +{ + using __gnu_test::test_range; + using __gnu_test::random_access_iterator_wrapper; + using __gnu_test::input_iterator_wrapper; + using __gnu_test::output_iterator_wrapper; + + int a[] = { 0, 1 }; + + test_range r(a); + static_assert(same_as); + VERIFY( std::ranges::end(r) == r.end() ); + + test_range i(a); + static_assert(same_as); + VERIFY( std::ranges::end(i) == i.end() ); + + test_range o(a); + static_assert(same_as); + VERIFY( std::ranges::end(o) == std::ranges::next(o.begin(), 2) ); +} + +struct R +{ + int a[4] = { 0, 1, 2, 3 }; + + const int* begin() const { return nullptr; } + friend const int* begin(const R&& r) noexcept { return nullptr; } + + // Should be ignored because it doesn't return a sentinel for int* + const long* end() const { return nullptr; } + + friend int* end(R& r) { return r.a + 0; } + friend int* end(R&& r) { return r.a + 1; } + friend const int* end(const R& r) noexcept { return r.a + 2; } + friend const int* end(const R&& r) noexcept { return r.a + 3; } +}; + +void +test03() +{ + R r; + const R& c = r; + + static_assert(same_as); + static_assert(!noexcept(std::ranges::end(r))); + VERIFY( std::ranges::end(r) == end(r) ); + + static_assert(same_as); + static_assert(!noexcept(std::ranges::end(std::move(r)))); + VERIFY( std::ranges::end(std::move(r)) == end(std::move(r)) ); + + + static_assert(same_as); + static_assert(noexcept(std::ranges::end(c))); + VERIFY( std::ranges::end(c) == end(c) ); + + static_assert(same_as); + static_assert(noexcept(std::ranges::end(std::move(c)))); + VERIFY( std::ranges::end(std::move(c)) == end(std::move(c)) ); +} + +struct RR +{ + short s = 0; + long l = 0; + int a[4] = { 0, 1, 2, 3 }; + + const void* begin() const { return nullptr; } + friend const void* begin(const RR&&) noexcept { return nullptr; } + + short* end() noexcept { return &s; } + const long* end() const { return &l; } + + friend int* end(RR&) { throw 1; } + friend int* end(RR&& r) { return r.a + 1; } + friend const int* end(const RR&) { throw 1; } + friend const int* end(const RR&& r) noexcept { return r.a + 3; } +}; + +void +test04() +{ + RR r; + const RR& c = r; + VERIFY( std::ranges::end(r) == &r.s ); + static_assert(noexcept(std::ranges::end(r))); + + VERIFY( std::ranges::end(std::move(r)) == r.a + 1 ); + static_assert(!noexcept(std::ranges::end(std::move(r)))); + + VERIFY( std::ranges::end(c) == &r.l ); + static_assert(!noexcept(std::ranges::end(c))); + + VERIFY( std::ranges::end(std::move(c)) == r.a + 3 ); + static_assert(noexcept(std::ranges::end(std::move(c)))); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc new file mode 100644 index 00000000000..6cfc1a38122 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc @@ -0,0 +1,81 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +struct R1 +{ + int i = 0; + int j = 0; + + constexpr const int* rbegin() const { return &i; } + friend constexpr const int* rbegin(const R1&& r) { return &r.j; } +}; + +void +test01() +{ + constexpr R1 r; + static_assert( std::ranges::rbegin(r) == &r.i ); + static_assert( std::ranges::rbegin(std::move(r)) == &r.j ); +} + +struct R2 +{ + int a[2] = { }; + long l[2] = { }; + + constexpr const int* begin() const { return a; } + constexpr const int* end() const { return a + 2; } + + friend constexpr const long* begin(const R2&& r) { return r.l; } + friend constexpr const long* end(const R2&& r) { return r.l + 2; } +}; + +void +test02() +{ + constexpr R2 r; + static_assert( std::ranges::rbegin(r) + == std::make_reverse_iterator(std::ranges::end(r)) ); + static_assert( std::ranges::rbegin(std::move(r)) + == std::make_reverse_iterator(std::ranges::end(std::move(r))) ); +} + +void +test03() +{ + using __gnu_test::test_range; + using __gnu_test::bidirectional_iterator_wrapper; + + int a[2] = { }; + test_range r(a); + VERIFY( std::ranges::rbegin(r) == std::make_reverse_iterator(std::ranges::end(r)) ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/access/rend.cc b/libstdc++-v3/testsuite/std/ranges/access/rend.cc new file mode 100644 index 00000000000..2192825708a --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/access/rend.cc @@ -0,0 +1,105 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +struct R1 +{ + int i = 0; + int j = 0; + + constexpr const int* rbegin() const { return &i; } + constexpr const int* rend() const { return &i + 1; } + friend constexpr const int* rbegin(const R1&& r) { return &r.j; } + friend constexpr const int* rend(const R1&& r) { return &r.j + 1; } +}; + +void +test01() +{ + constexpr R1 r; + static_assert( std::ranges::rend(r) == &r.i + 1 ); + static_assert( std::ranges::rend(std::move(r)) == &r.j + 1 ); +} + +struct R2 +{ + int a[2] = { }; + long l[2] = { }; + + constexpr const int* begin() const { return a; } + constexpr const int* end() const { return a + 2; } + + friend constexpr const long* begin(const R2&& r) { return r.l; } + friend constexpr const long* end(const R2&& r) { return r.l + 2; } +}; + +void +test02() +{ + constexpr R2 r; + static_assert( std::ranges::rend(r) + == std::make_reverse_iterator(std::ranges::begin(r)) ); + static_assert( std::ranges::rend(std::move(r)) + == std::make_reverse_iterator(std::ranges::begin(std::move(r))) ); +} + +struct R3 +{ + int i = 0; + + int* rbegin() noexcept { return &i + 1; } + long* rend() noexcept { return nullptr; } // not a sentinel for rbegin() + + friend long* rbegin(R3&) noexcept { return nullptr; } + friend int* rend(R3& r) { return &r.i; } +}; + +void +test03() +{ + R3 r; + auto i1 = std::ranges::rbegin(r); + auto i2 = rend(r); + static_assert( std::sentinel_for ); + // VERIFY( std::ranges::rend(r) == r.i ); + // static_assert( !noexcept(std::ranges::rend(r)) ); +} + +void +test04() +{ + using __gnu_test::test_range; + using __gnu_test::bidirectional_iterator_wrapper; + + int a[2] = { }; + test_range r(a); + VERIFY( std::ranges::rend(r) == std::make_reverse_iterator(std::ranges::begin(r)) ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/access/size.cc b/libstdc++-v3/testsuite/std/ranges/access/size.cc new file mode 100644 index 00000000000..b92e5d50449 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/access/size.cc @@ -0,0 +1,116 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +void +test01() +{ + constexpr int a[10] = { }; + static_assert( std::ranges::size(a) == 10 ); + static_assert( noexcept(std::ranges::size(a)) ); + + int a2[2]; + VERIFY( std::ranges::size(a2) == 2); + static_assert( noexcept(std::ranges::size(a2)) ); +} + +void +test02() +{ + struct R + { + int size() { return 1; } + long size() const noexcept { return 2; } + }; + R r; + const R& c = r; + VERIFY( std::ranges::size(r) == 1 ); + static_assert( !noexcept(std::ranges::size(r)) ); + VERIFY( std::ranges::size(c) == 2L ); + static_assert( noexcept(std::ranges::size(c)) ); + + int a[3] = { }; + __gnu_test::test_sized_range ri(a); + VERIFY( std::ranges::size(ri) == 3 ); + static_assert( noexcept(std::ranges::size(ri)) ); +} + +struct R3 +{ + int* size() { return nullptr; } + friend int size(R3&) noexcept { return 1; } + friend long size(const R3&) { return 2L; } + friend unsigned int size(R3&&) { return 3U; } + friend unsigned long size(const R3&&) noexcept { return 4UL; } +}; + +void +test03() +{ + R3 r; + const R3& c = r; + VERIFY( std::ranges::size(r) == 1 ); + static_assert( noexcept(std::ranges::size(r)) ); + VERIFY( std::ranges::size(std::move(r)) == 3U ); + static_assert( !noexcept(std::ranges::size(std::move(r))) ); + VERIFY( std::ranges::size(c) == 2L ); + static_assert( !noexcept(std::ranges::size(c)) ); + VERIFY( std::ranges::size(std::move(c)) == 4UL ); + static_assert( noexcept(std::ranges::size(std::move(c))) ); +} + +void +test04() +{ + int a[] = { 0, 1 }; + __gnu_test::test_range r(a); + auto& rr = r; + VERIFY( std::ranges::size(r) == (std::ranges::end(r) - std::ranges::begin(r)) ); +} + +struct R5 +{ + int size() const noexcept { return 0; } + R5* begin() { return this; } + R5* end() { return this + 1; } +}; + +template<> +constexpr bool std::ranges::disable_sized_range = true; + +void +test05() +{ + R5 r; + VERIFY( std::ranges::size(r) == 1 ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); +} diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h index 974490b1b6c..70c1f9b6689 100644 --- a/libstdc++-v3/testsuite/util/testsuite_iterators.h +++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h @@ -590,5 +590,145 @@ namespace __gnu_test size() const { return bounds.size(); } }; -} -#endif + +#if __cplusplus > 201703L + template + struct contiguous_iterator_wrapper + : random_access_iterator_wrapper + { + using random_access_iterator_wrapper::random_access_iterator_wrapper; + + using iterator_concept = std::contiguous_iterator_tag; + + contiguous_iterator_wrapper& + operator++() + { + random_access_iterator_wrapper::operator++(); + return *this; + } + + contiguous_iterator_wrapper& + operator--() + { + random_access_iterator_wrapper::operator--(); + return *this; + } + + contiguous_iterator_wrapper + operator++(int) + { + auto tmp = *this; + ++*this; + return tmp; + } + + contiguous_iterator_wrapper + operator--(int) + { + auto tmp = *this; + --*this; + return tmp; + } + + contiguous_iterator_wrapper& + operator+=(std::ptrdiff_t n) + { + random_access_iterator_wrapper::operator+=(n); + return *this; + } + + friend contiguous_iterator_wrapper + operator+(contiguous_iterator_wrapper iter, std::ptrdiff_t n) + { return iter += n; } + + friend contiguous_iterator_wrapper + operator+(std::ptrdiff_t n, contiguous_iterator_wrapper iter) + { return iter += n; } + + contiguous_iterator_wrapper& + operator-=(std::ptrdiff_t n) + { return *this += -n; } + + friend contiguous_iterator_wrapper + operator-(contiguous_iterator_wrapper iter, std::ptrdiff_t n) + { return iter -= n; } + }; + + // A type meeting the minimum std::range requirements + template class Iter> + class test_range + { + // Adds default constructor to Iter if needed + struct iterator : Iter + { + using Iter::Iter; + + iterator() : Iter(nullptr, nullptr) { } + + using Iter::operator++; + + iterator& operator++() { Iter::operator++(); return *this; } + }; + + template + struct sentinel + { + T* end; + + friend bool operator==(const sentinel& s, const I& i) + { return s.end == i.ptr; } + + friend bool operator!=(const sentinel& s, const I& i) + { return !(s == i); } + + friend bool operator==(const I& i, const sentinel& s) + { return s == i; } + + friend bool operator!=(const I& i, const sentinel& s) + { return !(s == i); } + }; + + auto + get_iterator(T* p) + { + if constexpr (std::default_constructible>) + return Iter(p, &bounds); + else + return iterator(p, &bounds); + } + + public: + test_range(T* first, T* last) : bounds(first, last) + { } + + template + explicit + test_range(T (&arr)[N]) : test_range(arr, arr+N) + { } + + auto begin() & { return get_iterator(bounds.first); } + + auto end() & + { + using I = decltype(get_iterator(bounds.last)); + if constexpr (std::sentinel_for) + return get_iterator(bounds.last); + else + return sentinel{bounds.last}; + } + + typename Iter::ContainerType bounds; + }; + + // A type meeting the minimum std::sized_range requirements + template class Iter> + struct test_sized_range : test_range + { + using test_range::test_range; + + std::size_t size() const noexcept + { return this->bounds.size(); } + }; +#endif // C++20 +} // namespace __gnu_test +#endif // _TESTSUITE_ITERATORS -- 2.30.2