diff options
40 files changed, 4262 insertions, 77 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 0414f12..ad595aa 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,85 @@ 2019-10-29 Jonathan Wakely <jwakely@redhat.com> + * 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 9ff12f1..401c87a 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 5dce01f..e0a7496 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 0000000..323689e --- /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 +// <http://www.gnu.org/licenses/>. + +/** @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 <concepts> +#include <bits/ptr_traits.h> // to_address +#include <bits/range_cmp.h> // 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<typename _Iterator> + struct iterator_traits; + + template<typename _Tp> requires is_object_v<_Tp> + struct iterator_traits<_Tp*>; + + template<typename _Iterator, typename> + struct __iterator_traits; + + namespace __detail + { + template<typename _Tp> + using __with_ref = _Tp&; + + template<typename _Tp> + concept __can_reference = requires { typename __with_ref<_Tp>; }; + + template<typename _Tp> + 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<typename _Tp> + using iter_reference_t = typename __detail::__iter_ref<_Tp>::type; + + namespace ranges + { + namespace __cust_imove + { + template<typename _Tp> + concept __adl_imove + = (std::__detail::__class_or_enum<remove_reference_t<_Tp>>) + && requires(_Tp&& __t) { iter_move(static_cast<_Tp&&>(__t)); }; + + struct _IMove + { + private: + template<typename _Tp> + 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<typename _Tp> + 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<iter_reference_t<_Tp>>) + 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<typename _Tp> + using iter_rvalue_reference_t + = typename __detail::__iter_rvalue_ref<_Tp>::type; + + template<typename> struct incrementable_traits { }; + + template<typename _Tp> requires is_object_v<_Tp> + struct incrementable_traits<_Tp*> + { using difference_type = ptrdiff_t; }; + + template<typename _Iter> + struct incrementable_traits<const _Iter> + : incrementable_traits<_Iter> { }; + + template<typename _Tp> requires requires { typename _Tp::difference_type; } + struct incrementable_traits<_Tp> + { using difference_type = typename _Tp::difference_type; }; + + template<typename _Tp> + requires (!requires { typename _Tp::difference_type; } + && requires(const _Tp& __a, const _Tp& __b) + { + requires (!is_void_v<remove_pointer_t<_Tp>>); // PR c++/78173 + { __a - __b } -> integral; + }) + struct incrementable_traits<_Tp> + { + using difference_type + = make_signed_t<decltype(std::declval<_Tp>() - std::declval<_Tp>())>; + }; + + namespace __detail + { + // An iterator such that iterator_traits<_Iter> names a specialization + // generated from the primary template. + template<typename _Iter> + concept __primary_traits_iter + = __is_base_of(__iterator_traits<_Iter, void>, iterator_traits<_Iter>); + + template<typename _Iter, typename _Tp> + struct __iter_traits_impl + { using type = iterator_traits<_Iter>; }; + + template<typename _Iter, typename _Tp> + requires __primary_traits_iter<_Iter> + struct __iter_traits_impl<_Iter, _Tp> + { using type = _Tp; }; + + // ITER_TRAITS + template<typename _Iter, typename _Tp = _Iter> + using __iter_traits = typename __iter_traits_impl<_Iter, _Tp>::type; + } // namespace __detail + + template<typename _Tp> + using iter_difference_t = typename + __detail::__iter_traits<_Tp, incrementable_traits<_Tp>>::difference_type; + + namespace __detail + { + template<typename> struct __cond_value_type { }; + + template<typename _Tp> requires is_object_v<_Tp> + struct __cond_value_type<_Tp> + { using value_type = remove_cv_t<_Tp>; }; + } // namespace __detail + + template<typename> struct readable_traits { }; + + template<typename _Tp> + struct readable_traits<_Tp*> + : __detail::__cond_value_type<_Tp> + { }; + + template<typename _Iter> requires is_array_v<_Iter> + struct readable_traits<_Iter> + { using value_type = remove_cv_t<remove_extent_t<_Iter>>; }; + + template<typename _Iter> + struct readable_traits<const _Iter> + : readable_traits<_Iter> + { }; + + template<typename _Tp> requires requires { typename _Tp::value_type; } + struct readable_traits<_Tp> + : __detail::__cond_value_type<typename _Tp::value_type> + { }; + + template<typename _Tp> requires requires { typename _Tp::element_type; } + struct readable_traits<_Tp> + : __detail::__cond_value_type<typename _Tp::element_type> + { }; + + template<typename _Tp> + using iter_value_t = typename + __detail::__iter_traits<_Tp, readable_traits<_Tp>>::value_type; + + namespace __detail + { + template<typename _Iter> + concept __cpp17_iterator = copyable<_Iter> + && requires(_Iter __it) + { + { *__it } -> __can_reference; + { ++__it } -> same_as<_Iter&>; + { *__it++ } -> __can_reference; + }; + + template<typename _Iter> + 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<iter_reference_t<_Iter>&&, + typename readable_traits<_Iter>::value_type&>; + typename common_reference_t<decltype(*__it++)&&, + typename readable_traits<_Iter>::value_type&>; + requires signed_integral<typename incrementable_traits<_Iter>::difference_type>; + }; + + template<typename _Iter> + concept __cpp17_fwd_iterator = __cpp17_input_iterator<_Iter> + && constructible_from<_Iter> + && is_lvalue_reference_v<iter_reference_t<_Iter>> + && same_as<remove_cvref_t<iter_reference_t<_Iter>>, + typename readable_traits<_Iter>::value_type> + && requires(_Iter __it) + { + { __it++ } -> convertible_to<const _Iter&>; + { *__it++ } -> same_as<iter_reference_t<_Iter>>; + }; + + template<typename _Iter> + concept __cpp17_bidi_iterator = __cpp17_fwd_iterator<_Iter> + && requires(_Iter __it) + { + { --__it } -> same_as<_Iter&>; + { __it-- } -> convertible_to<const _Iter&>; + { *__it-- } -> same_as<iter_reference_t<_Iter>>; + }; + + template<typename _Iter> + 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<decltype(__n)>; + { __it[__n] } -> convertible_to<iter_reference_t<_Iter>>; + }; + + template<typename _Iter> + 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<typename _Iter> + concept __iter_without_nested_types = !__iter_with_nested_types<_Iter>; + + template<typename _Iter, bool __use_arrow = false> + struct __ptr + { using type = void; }; + + template<typename _Iter> requires requires { typename _Iter::pointer; } + struct __ptr<_Iter, true> + { using type = typename _Iter::pointer; }; + + template<typename _Iter> requires requires { typename _Iter::pointer; } + struct __ptr<_Iter, false> + { using type = typename _Iter::pointer; }; + + template<typename _Iter> + requires (!requires { typename _Iter::pointer; } + && requires(_Iter& __it) { __it.operator->(); }) + struct __ptr<_Iter, true> + { using type = decltype(std::declval<_Iter&>().operator->()); }; + + template<typename _Iter> + struct __ref + { using type = iter_reference_t<_Iter>; }; + + template<typename _Iter> requires requires { typename _Iter::reference; } + struct __ref<_Iter> + { using type = typename _Iter::reference; }; + + template<typename _Iter> + struct __cat + { using type = input_iterator_tag; }; + + template<typename _Iter> + requires requires { typename _Iter::iterator_category; } + struct __cat<_Iter> + { using type = typename _Iter::iterator_category; }; + + template<typename _Iter> + requires (!requires { typename _Iter::iterator_category; } + && __detail::__cpp17_randacc_iterator<_Iter>) + struct __cat<_Iter> + { using type = random_access_iterator_tag; }; + + template<typename _Iter> + requires (!requires { typename _Iter::iterator_category; } + && __detail::__cpp17_bidi_iterator<_Iter>) + struct __cat<_Iter> + { using type = bidirectional_iterator_tag; }; + + template<typename _Iter> + requires (!requires { typename _Iter::iterator_category; } + && __detail::__cpp17_fwd_iterator<_Iter>) + struct __cat<_Iter> + { using type = forward_iterator_tag; }; + + template<typename _Iter> + struct __diff + { using type = void; }; + + template<typename _Iter> + requires requires { + typename incrementable_traits<_Iter>::difference_type; + } + struct __diff<_Iter> + { + using type = typename incrementable_traits<_Iter>::difference_type; + }; + + } // namespace __detail + + template<typename _Iterator> + 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<typename _Iterator> + 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<typename _Iterator> + 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<typename _Iter> + struct __iter_concept_impl + { }; + + template<typename _Iter> + requires requires { typename __iter_traits<_Iter>::iterator_concept; } + struct __iter_concept_impl<_Iter> + { using type = typename __iter_traits<_Iter>::iterator_concept; }; + + template<typename _Iter> + 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<typename _Iter> + 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<typename _Iter> + using __iter_concept = typename __iter_concept_impl<_Iter>::type; + } // namespace __detail + + /// Requirements for types that are readable by applying operator*. + template<typename _In> + concept readable = requires + { + typename iter_value_t<_In>; + typename iter_reference_t<_In>; + typename iter_rvalue_reference_t<_In>; + } + && common_reference_with<iter_reference_t<_In>&&, iter_value_t<_In>&> + && common_reference_with<iter_reference_t<_In>&&, + iter_rvalue_reference_t<_In>&&> + && common_reference_with<iter_rvalue_reference_t<_In>&&, + const iter_value_t<_In>&>; + + namespace __detail + { + // FIXME: needed due to PR c++/67704 + template<readable _Tp> + struct __iter_common_ref + : common_reference<iter_reference_t<_Tp>, iter_value_t<_Tp>&> + { }; + + // FIXME: needed due to PR c++/67704 + template<typename _Fn, typename... _Is> + struct __indirect_result + { }; + + template<typename _Fn, typename... _Is> + requires (readable<_Is> && ...) + && invocable<_Fn, iter_reference_t<_Is>...> + struct __indirect_result<_Fn, _Is...> + : invoke_result<_Fn, iter_reference_t<_Is>...> + { }; + } // namespace __detail + + template<typename _Tp> + using iter_common_reference_t + = typename __detail::__iter_common_ref<_Tp>::type; + + /// Requirements for writing a value into an iterator's referenced object. + template<typename _Out, typename _Tp> + concept writable = requires(_Out&& __o, _Tp&& __t) + { + *__o = std::forward<_Tp>(__t); + *std::forward<_Out>(__o) = std::forward<_Tp>(__t); + const_cast<const iter_reference_t<_Out>&&>(*__o) + = std::forward<_Tp>(__t); + const_cast<const iter_reference_t<_Out>&&>(*std::forward<_Out>(__o)) + = std::forward<_Tp>(__t); + }; + + /// Requirements on types that can be incremented with ++. + template<typename _Iter> + concept weakly_incrementable = default_constructible<_Iter> + && movable<_Iter> + && requires(_Iter __i) + { + typename iter_difference_t<_Iter>; + requires signed_integral<iter_difference_t<_Iter>>; + { ++__i } -> same_as<_Iter&>; + __i++; + }; + + template<typename _Iter> + concept incrementable = regular<_Iter> && weakly_incrementable<_Iter> + && requires(_Iter __i) { { __i++ } -> same_as<_Iter>; }; + + template<typename _Iter> + concept input_or_output_iterator + = requires(_Iter __i) { { *__i } -> __detail::__can_reference; } + && weakly_incrementable<_Iter>; + + template<typename _Sent, typename _Iter> + concept sentinel_for = semiregular<_Sent> + && input_or_output_iterator<_Iter> + && __detail::__weakly_eq_cmp_with<_Sent, _Iter>; + + template<typename _Sent, typename _Iter> + inline constexpr bool disable_sized_sentinel = false; + + template<typename _Sent, typename _Iter> + concept sized_sentinel_for = sentinel_for<_Sent, _Iter> + && !disable_sized_sentinel<remove_cv_t<_Sent>, remove_cv_t<_Iter>> + && requires(const _Iter& __i, const _Sent& __s) + { + { __s - __i } -> same_as<iter_difference_t<_Iter>>; + { __i - __s } -> same_as<iter_difference_t<_Iter>>; + }; + + template<typename _Iter> + 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<typename _Iter, typename _Tp> + concept output_iterator = input_or_output_iterator<_Iter> + && writable<_Iter, _Tp> + && requires(_Iter __i, _Tp&& __t) { *__i++ = std::forward<_Tp>(__t); }; + + template<typename _Iter> + concept forward_iterator = input_iterator<_Iter> + && derived_from<__detail::__iter_concept<_Iter>, forward_iterator_tag> + && incrementable<_Iter> && sentinel_for<_Iter, _Iter>; + + template<typename _Iter> + 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<typename _Iter> + 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<iter_reference_t<_Iter>>; + }; + + template<typename _Iter> + concept contiguous_iterator = random_access_iterator<_Iter> + && derived_from<__detail::__iter_concept<_Iter>, contiguous_iterator_tag> + && is_lvalue_reference_v<iter_reference_t<_Iter>> + && same_as<iter_value_t<_Iter>, remove_cvref_t<iter_reference_t<_Iter>>> + && requires(const _Iter& __i) + { + { std::to_address(__i) } + -> same_as<add_pointer_t<iter_reference_t<_Iter>>>; + }; + + // [indirectcallable], indirect callable requirements + + // [indirectcallable.indirectinvocable], indirect callables + + template<typename _Fn, typename _Iter> + 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_value_t<_Iter>&>, + invoke_result_t<_Fn&, iter_reference_t<_Iter>>>; + + template<typename _Fn, typename _Iter> + 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_value_t<_Iter>&>, + invoke_result_t<_Fn&, iter_reference_t<_Iter>>>; + + template<typename _Fn, typename _Iter> + 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<typename _Fn, typename _I1, typename _I2 = _I1> + 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<typename _Fn, typename _I1, typename _I2 = _I1> + 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<typename _Fn, typename... _Is> + using indirect_result_t = typename + __detail::__indirect_result<_Fn, iter_reference_t<_Is>...>::type; + + /// [projected], projected + template<readable _Iter, indirectly_regular_unary_invocable<_Iter> _Proj> + struct projected + { + using value_type = remove_cvref_t<indirect_result_t<_Proj&, _Iter>>; + indirect_result_t<_Proj&, _Iter> operator*() const; // not defined + }; + + template<weakly_incrementable _Iter, typename _Proj> + struct incrementable_traits<projected<_Iter, _Proj>> + { using difference_type = iter_difference_t<_Iter>; }; + + // [alg.req], common algorithm requirements + + /// [alg.req.ind.move], concept `indirectly_movable` + + template<typename _In, typename _Out> + concept indirectly_movable = readable<_In> + && writable<_Out, iter_rvalue_reference_t<_In>>; + + template<typename _In, typename _Out> + concept indirectly_movable_storable = indirectly_movable<_In, _Out> + && writable<_Out, iter_value_t<_In>> && movable<iter_value_t<_In>> + && constructible_from<iter_value_t<_In>, iter_rvalue_reference_t<_In>> + && assignable_from<iter_value_t<_In>&, iter_rvalue_reference_t<_In>>; + + /// [alg.req.ind.copy], concept `indirectly_copyable` + template<typename _In, typename _Out> + concept indirectly_copyable = readable<_In> + && writable<_Out, iter_reference_t<_In>>; + + template<typename _In, typename _Out> + concept indirectly_copyable_storable = indirectly_copyable<_In, _Out> + && writable<_Out, const iter_value_t<_In>&> + && copyable<iter_value_t<_In>> + && constructible_from<iter_value_t<_In>, iter_reference_t<_In>> + && assignable_from<iter_value_t<_In>&, iter_reference_t<_In>>; + +namespace ranges +{ + namespace __cust_iswap + { + template<typename _It1, typename _It2> + void iter_swap(_It1&, _It2&) = delete; + + template<typename _Tp, typename _Up> + concept __adl_iswap + = (std::__detail::__class_or_enum<remove_reference_t<_Tp>> + || std::__detail::__class_or_enum<remove_reference_t<_Up>>) + && requires(_Tp&& __t, _Up&& __u) { + iter_swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); + }; + + template<typename _Xp, typename _Yp> + constexpr iter_value_t<remove_reference_t<_Xp>> + __iter_exchange_move(_Xp&& __x, _Yp&& __y) + noexcept(noexcept(iter_value_t<remove_reference_t<_Xp>>(iter_move(__x))) + && noexcept(*__x = iter_move(__y))) + { + iter_value_t<remove_reference_t<_Xp>> __old_value(iter_move(__x)); + *__x = iter_move(__y); + return __old_value; + } + + struct _IterSwap + { + private: + template<typename _Tp, typename _Up> + 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<_Tp>, 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<typename _Tp, typename _Up> + requires __adl_iswap<_Tp, _Up> + || (readable<_Tp> && readable<_Up> + && swappable_with<iter_reference_t<_Tp>, 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<_Tp>, 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<typename _I1, typename _I2 = _I1> + 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<typename _I1, typename _I2, typename _Rel, typename _P1 = identity, + typename _P2 = identity> + concept indirectly_comparable + = indirect_relation<_Rel, projected<_I1, _P1>, projected<_I2, _P2>>; + + /// [alg.req.permutable], concept `permutable` + template<typename _Iter> + concept permutable = forward_iterator<_Iter> + && indirectly_movable_storable<_Iter, _Iter> + && indirectly_swappable<_Iter, _Iter>; + + /// [alg.req.mergeable], concept `mergeable` + template<typename _I1, typename _I2, typename _Out, + typename _Rel = ranges::less, typename _P1 = identity, + typename _P2 = identity> + 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<typename _Iter, typename _Rel = ranges::less, + typename _Proj = identity> + concept sortable = permutable<_Iter> + && indirect_strict_weak_order<_Rel, projected<_Iter, _Proj>>; + + struct unreachable_sentinel_t + { + template<weakly_incrementable _It> + friend constexpr bool + operator==(unreachable_sentinel_t, const _It&) noexcept + { return false; } + +#ifndef __cpp_lib_three_way_comparison + template<weakly_incrementable _It> + friend constexpr bool + operator!=(unreachable_sentinel_t, const _It&) noexcept + { return true; } + + template<weakly_incrementable _It> + friend constexpr bool + operator==(const _It&, unreachable_sentinel_t) noexcept + { return false; } + + template<weakly_incrementable _It> + 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 d7c7068..5d6541d 100644 --- a/libstdc++-v3/include/bits/move.h +++ b/libstdc++-v3/include/bits/move.h @@ -31,7 +31,9 @@ #define _MOVE_H 1 #include <bits/c++config.h> -#include <bits/concept_check.h> +#if __cplusplus < 201103L +# include <bits/concept_check.h> +#endif namespace std _GLIBCXX_VISIBILITY(default) { @@ -188,9 +190,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_NOEXCEPT_IF(__and_<is_nothrow_move_constructible<_Tp>, 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 bc137d7..3b6ed9a 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 <initializer_list> +#include <bits/iterator_concepts.h> + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -344,60 +346,722 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template <typename _Container> 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 <typename _Container> - constexpr auto - __adl_cbegin(_Container& __cont) noexcept(noexcept(cbegin(__cont))) - { return cbegin(__cont); } +namespace ranges +{ + template<typename> + inline constexpr bool disable_sized_range = false; - template <typename _Container> - 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 <typename _Container> - constexpr auto - __adl_rbegin(_Container& __cont) noexcept(noexcept(rbegin(__cont))) - { return rbegin(__cont); } + template<typename _Tp> + concept __is_integer_like = integral<_Tp> + || same_as<_Tp, __max_diff_type> || same_as<_Tp, __max_size_type>; - template <typename _Container> - constexpr auto - __adl_rend(_Container& __cont) noexcept(noexcept(rend(__cont))) - { return rend(__cont); } + template<typename _Tp> + concept __is_signed_integer_like = signed_integral<_Tp> + || same_as<_Tp, __max_diff_type>; - template <typename _Container> - constexpr auto - __adl_crbegin(_Container& __cont) noexcept(noexcept(crbegin(__cont))) - { return crbegin(__cont); } + template<integral _Tp> + constexpr make_unsigned_t<_Tp> + __to_unsigned_like(_Tp __t) noexcept + { return __t; } + } // namespace __detail - template <typename _Container> - constexpr auto - __adl_crend(_Container& __cont) noexcept(noexcept(crend(__cont))) - { return crend(__cont); } + namespace __cust_access + { + template<typename _Tp> + constexpr decay_t<_Tp> + __decay_copy(_Tp&& __t) + noexcept(is_nothrow_convertible_v<_Tp, decay_t<_Tp>>) + { return std::forward<_Tp>(__t); } - template <typename _Container> - constexpr auto - __adl_data(_Container& __cont) noexcept(noexcept(data(__cont))) - { return data(__cont); } + template<typename _Tp> + concept __member_begin = is_lvalue_reference_v<_Tp> + && requires(_Tp __t) + { { __decay_copy(__t.begin()) } -> input_or_output_iterator; }; - template <typename _Container> - constexpr auto - __adl_cdata(_Container& __cont) noexcept(noexcept(cdata(__cont))) - { return cdata(__cont); } + template<typename _Tp> void begin(_Tp&&) = delete; + template<typename _Tp> void begin(initializer_list<_Tp>&&) = delete; - template <typename _Container> - constexpr auto - __adl_size(_Container& __cont) noexcept(noexcept(size(__cont))) - { return size(__cont); } + template<typename _Tp> + concept __adl_begin = requires(_Tp&& __t) + { + { __decay_copy(begin(std::forward<_Tp>(__t))) } + -> input_or_output_iterator; + }; - template <typename _Container> - constexpr auto - __adl_empty(_Container& __cont) noexcept(noexcept(empty(__cont))) - { return empty(__cont); } -#endif // C++20 + template<typename _Tp> + concept __complete_type = requires(_Tp* __p) { __p + 1; }; + + struct _Begin + { + private: + template<typename _Tp> + 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<typename _Tp> 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<typename _Tp> + concept __member_end = is_lvalue_reference_v<_Tp> + && requires(_Tp __t) + { + { __decay_copy(__t.end()) } + -> sentinel_for<decltype(_Begin{}(__t))>; + }; + + template<typename _Tp> void end(_Tp&&) = delete; + template<typename _Tp> void end(initializer_list<_Tp>&&) = delete; + template<typename _Tp> + concept __adl_end = requires(_Tp&& __t) + { + { __decay_copy(end(std::forward<_Tp>(__t))) } + -> sentinel_for<decltype(_Begin{}(std::forward<_Tp>(__t)))>; + }; + + struct _End + { + private: + template<typename _Tp> + 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<typename _Tp> 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<typename _Tp> + constexpr decltype(auto) + __as_const(_Tp&& __t) noexcept + { + if constexpr (is_lvalue_reference_v<_Tp>) + return static_cast<const remove_reference_t<_Tp>&>(__t); + else + return static_cast<const _Tp&&>(__t); + } + + struct _CBegin + { + template<typename _Tp> + 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<typename _Tp> + 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<typename _Tp> + concept __member_rbegin = is_lvalue_reference_v<_Tp> + && requires(_Tp __t) + { { __decay_copy(__t.rbegin()) } -> input_or_output_iterator; }; + + template<typename _Tp> void rbegin(_Tp&&) = delete; + + template<typename _Tp> + concept __adl_rbegin = requires(_Tp&& __t) + { + { __decay_copy(rbegin(std::forward<_Tp>(__t))) } + -> input_or_output_iterator; + }; + + template<typename _Tp> + concept __reversable = requires(_Tp&& __t) + { + { _Begin{}(std::forward<_Tp>(__t)) } -> bidirectional_iterator; + { _End{}(std::forward<_Tp>(__t)) } + -> same_as<decltype(_Begin{}(std::forward<_Tp>(__t)))>; + }; + + struct _RBegin + { + private: + template<typename _Tp> + 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<typename _Tp> + 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<typename _Tp> + concept __member_rend = is_lvalue_reference_v<_Tp> + && requires(_Tp __t) + { + { __decay_copy(__t.rend()) } + -> sentinel_for<decltype(_RBegin{}(__t))>; + }; + + template<typename _Tp> void rend(_Tp&&) = delete; + + template<typename _Tp> + concept __adl_rend = requires(_Tp&& __t) + { + { __decay_copy(rend(std::forward<_Tp>(__t))) } + -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>; + }; + + struct _REnd + { + private: + template<typename _Tp> + 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<typename _Tp> + 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<typename _Tp> + 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<typename _Tp> + 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<typename _Tp> + concept __member_size = !disable_sized_range<remove_cvref_t<_Tp>> + && requires(_Tp&& __t) + { + { __decay_copy(std::forward<_Tp>(__t).size()) } + -> __detail::__is_integer_like; + }; + + template<typename _Tp> void size(_Tp&&) = delete; + + template<typename _Tp> + concept __adl_size = !disable_sized_range<remove_cvref_t<_Tp>> + && requires(_Tp&& __t) + { + { __decay_copy(size(std::forward<_Tp>(__t))) } + -> __detail::__is_integer_like; + }; + + // FIXME: needed due to PR c++/92268 + template<forward_iterator _It, sized_sentinel_for<_It> _End> + requires requires (_It __it, _End __end) + { { __end - __it } -> __detail::__is_integer_like; } + void + __subtractable_fwd_iter(_It, _End) + { } + + template<typename _Tp> + concept __sizable = requires(_Tp&& __t) + { + __subtractable_fwd_iter(_Begin{}(std::forward<_Tp>(__t)), + _End{}(std::forward<_Tp>(__t))); + }; + + struct _Size + { + private: + template<typename _Tp> + 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<typename _Tp> + 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<typename _Tp> + concept __member_empty = requires(_Tp&& __t) + { bool(std::forward<_Tp>(__t).empty()); }; + + template<typename _Tp> + concept __size0_empty = requires(_Tp&& __t) + { _Size{}(std::forward<_Tp>(__t)) == 0; }; + + template<typename _Tp> + 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<typename _Tp> + 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<typename _Tp> + 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<typename _Tp> + concept __pointer_to_object = is_pointer_v<_Tp> + && is_object_v<remove_pointer_t<_Tp>>; + + template<typename _Tp> + concept __member_data = is_lvalue_reference_v<_Tp> + && requires(_Tp __t) { { __t.data() } -> __pointer_to_object; }; + + template<typename _Tp> + concept __begin_data = requires(_Tp&& __t) + { { _Begin{}(std::forward<_Tp>(__t)) } -> contiguous_iterator; }; + + struct _Data + { + private: + template<typename _Tp> + 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<typename _Tp> 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<typename _Tp> + 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<typename _Tp> + 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<typename _Tp> + concept range = __detail::__range_impl<_Tp&>; + + /// [range.sized] The sized_range concept. + template<typename _Tp> + concept sized_range = range<_Tp> + && requires(_Tp& __t) { ranges::size(__t); }; + + // [range.iter.ops] range iterator operations + + template<input_or_output_iterator _It> + 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<input_or_output_iterator _It, sentinel_for<_It> _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<input_or_output_iterator _It, sentinel_for<_It> _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<input_or_output_iterator _It, sentinel_for<_It> _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<range _Range> + using iterator_t = decltype(ranges::begin(std::declval<_Range&>())); + + template<range _Range> + using range_difference_t = iter_difference_t<iterator_t<_Range>>; + + template<range _Range> + constexpr range_difference_t<_Range> + distance(_Range&& __r) + { + if constexpr (sized_range<_Range>) + return static_cast<range_difference_t<_Range>>(ranges::size(__r)); + else + return ranges::distance(ranges::begin(__r), ranges::end(__r)); + } + + template<input_or_output_iterator _It> + constexpr _It + next(_It __x) + { + ++__x; + return __x; + } + + template<input_or_output_iterator _It> + constexpr _It + next(_It __x, iter_difference_t<_It> __n) + { + ranges::advance(__x, __n); + return __x; + } + + template<input_or_output_iterator _It, sentinel_for<_It> _Sent> + constexpr _It + next(_It __x, _Sent __bound) + { + ranges::advance(__x, __bound); + return __x; + } + + template<input_or_output_iterator _It, sentinel_for<_It> _Sent> + constexpr _It + next(_It __x, iter_difference_t<_It> __n, _Sent __bound) + { + ranges::advance(__x, __n, __bound); + return __x; + } + + template<bidirectional_iterator _It> + constexpr _It + prev(_It __x) + { + --__x; + return __x; + } + + template<bidirectional_iterator _It> + constexpr _It + prev(_It __x, iter_difference_t<_It> __n) + { + ranges::advance(__x, -__n); + return __x; + } + + template<bidirectional_iterator _It> + 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 420fea6..9660875 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<typename _Iterator1, typename _Iterator2> + requires (!sized_sentinel_for<_Iterator1, _Iterator2>) + inline constexpr bool disable_sized_sentinel<reverse_iterator<_Iterator1>, + reverse_iterator<_Iterator2>> + = true; +# endif // C++20 +# endif // C++14 + template<typename _Iterator> _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 951e704..3fad586 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 <type_traits> // For __void_t, is_convertible #endif +#if __cplusplus > 201703L && __cpp_concepts +# include <bits/iterator_concepts.h> +#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<typename _Iterator> + struct iterator_traits; + #if __cplusplus >= 201103L // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2408. SFINAE-friendly common_type/iterator_traits is missing in C++14 template<typename _Iterator, typename = __void_t<>> struct __iterator_traits { }; +#if ! __cpp_lib_concepts + template<typename _Iterator> struct __iterator_traits<_Iterator, __void_t<typename _Iterator::iterator_category, @@ -157,11 +171,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef typename _Iterator::pointer pointer; typedef typename _Iterator::reference reference; }; +#endif // ! concepts template<typename _Iterator> struct iterator_traits : public __iterator_traits<_Iterator> { }; -#else + +#else // ! C++11 template<typename _Iterator> 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<typename _Tp> +#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<typename _Tp> 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 6d740eb..68cbba9 100644 --- a/libstdc++-v3/include/std/concepts +++ b/libstdc++-v3/include/std/concepts @@ -114,6 +114,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { template<typename _Tp> using __cref = const remove_reference_t<_Tp>&; + + template<typename _Tp> + 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<typename _Tp> void swap(_Tp&, _Tp&) = delete; - template<typename _Tp> - concept __class_or_enum - = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>; - template<typename _Tp, typename _Up> concept __adl_swap - = (__class_or_enum<remove_cvref_t<_Tp>> - || __class_or_enum<remove_cvref_t<_Up>>) + = (__detail::__class_or_enum<remove_reference_t<_Tp>> + || __detail::__class_or_enum<remove_reference_t<_Up>>) && requires(_Tp&& __t, _Up&& __u) { swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }; @@ -175,7 +175,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { template<typename _Tp, typename _Up> 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 ecbac1f..6b719eb 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 // <http://www.gnu.org/licenses/>. -// { dg-error "static assertion failed" "" { target *-*-* } 87 } +// { dg-error "static assertion failed" "" { target *-*-* } 89 } #include <list> diff --git a/libstdc++-v3/testsuite/20_util/forward/f_neg.cc b/libstdc++-v3/testsuite/20_util/forward/f_neg.cc index a073adc..7161f47 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 // <http://www.gnu.org/licenses/>. -// { dg-error "static assertion failed" "" { target *-*-* } 87 } +// { dg-error "static assertion failed" "" { target *-*-* } 89 } #include <utility> 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 0000000..929f0e4 --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include <iterator> + +struct none; + +template<typename T> + concept has_inc_traits_type + = requires { typename std::incrementable_traits<T>::difference_type; }; + +// Check std::incrementable_traits<T>::difference_type is U (or doesn't exist). +template<typename T, typename U> + concept check_inc_traits = (has_inc_traits_type<T> != std::same_as<U, none>); + +static_assert( check_inc_traits<void, none> ); +static_assert( check_inc_traits<const void, none> ); +static_assert( check_inc_traits<void*, none> ); +static_assert( check_inc_traits<const void*, none> ); + +static_assert( check_inc_traits<int, int> ); +static_assert( check_inc_traits<const int, int> ); + +static_assert( check_inc_traits<int*, std::ptrdiff_t> ); +static_assert( check_inc_traits<const int*, std::ptrdiff_t> ); +static_assert( check_inc_traits<int[2], std::ptrdiff_t> ); +static_assert( check_inc_traits<const int[2], std::ptrdiff_t> ); + +struct A { using difference_type = int; }; +static_assert( check_inc_traits<A, int> ); +static_assert( check_inc_traits<const A, int> ); +struct B : private A { }; +static_assert( check_inc_traits<B, none> ); + +struct C { }; +short operator-(C, C) { return 0; } +static_assert( check_inc_traits<C, short> ); +static_assert( check_inc_traits<const C, short> ); + +struct D { }; +unsigned short operator-(D, D) { return 0; } +static_assert( check_inc_traits<D, short> ); +static_assert( check_inc_traits<const D, short> ); + +struct E { }; +template<> + struct std::incrementable_traits<E> { using difference_type = long; }; +static_assert( check_inc_traits<E, long> ); +static_assert( check_inc_traits<const E, long> ); + +template<typename T> + concept has_alias = requires { typename std::iter_difference_t<T>; }; + +// Check std::iter_difference_t<T> is U (or doesn't exist). +template<typename T, typename U> + concept check_alias = (has_alias<T> != std::same_as<U, none>); + +static_assert( check_alias<void, none> ); +static_assert( check_alias<const void, none> ); +static_assert( check_alias<void*, none> ); +static_assert( check_alias<const void*, none> ); + +static_assert( check_alias<int, int> ); +static_assert( check_alias<const int, int> ); +static_assert( check_alias<int*, std::ptrdiff_t> ); +static_assert( check_alias<const int*, std::ptrdiff_t> ); +static_assert( check_alias<int[2], std::ptrdiff_t> ); +static_assert( check_alias<const int[2], std::ptrdiff_t> ); + +static_assert( check_alias<A, int> ); +static_assert( check_alias<const A, int> ); +static_assert( check_alias<B, none> ); +static_assert( check_alias<C, short> ); +static_assert( check_alias<const C, short> ); +static_assert( check_alias<D, short> ); +static_assert( check_alias<const D, short> ); +static_assert( check_alias<E, long> ); +static_assert( check_alias<const E, long> ); + +struct F { }; +template<> + struct std::iterator_traits<F> { using difference_type = F; }; +// iterator_traits<F> is specialized, so use its difference_type. +static_assert( check_alias<F, std::iterator_traits<F>::difference_type> ); + +struct G { }; +template<> + struct std::incrementable_traits<G> { using difference_type = G; }; +template<> + struct std::iterator_traits<G> { using difference_type = int; }; +// iterator_traits<G> is specialized, so use its difference_type. +static_assert( check_alias<G, std::iterator_traits<G>::difference_type> ); + +struct H { }; +template<> + struct std::incrementable_traits<H> { using difference_type = H; }; +template<> + struct std::iterator_traits<H> + { + using iterator_category = input_iterator_tag; + using difference_type = int; + using value_type = char; + using reference = value_type&; + }; +// iterator_traits<H> is specialized, so use its difference_type. +static_assert( check_alias<H, std::iterator_traits<H>::difference_type> ); + +struct I +{ + using difference_type = I; +}; +// iterator_traits<I> is not specialized, and no standard specialization +// matches, so use incrementable_traits. +static_assert( check_alias<I, std::incrementable_traits<I>::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<J> matches constrained specialization in the library, +// so use its difference_type. +static_assert( check_alias<J, int> ); 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 0000000..b4678ab --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include <iterator> + +struct none; + +template<typename T> + concept has_readable_traits_type + = requires { typename std::readable_traits<T>::value_type; }; + +// Check std::readable_traits<T>::value_type is U (or doesn't exist). +template<typename T, typename U> + concept check_readable_traits + = (has_readable_traits_type<T> != std::same_as<U, none>); + +static_assert( check_readable_traits<void, none> ); +static_assert( check_readable_traits<const void, none> ); +static_assert( check_readable_traits<void*, none> ); +static_assert( check_readable_traits<const void*, none> ); + +static_assert( check_readable_traits<int, none> ); +static_assert( check_readable_traits<const int, none> ); + +static_assert( check_readable_traits<int*, int> ); +static_assert( check_readable_traits<const int*, int> ); +static_assert( check_readable_traits<int[2], int> ); +static_assert( check_readable_traits<const int[2], int> ); + +struct A { using value_type = int; }; +static_assert( check_readable_traits<A, int> ); +static_assert( check_readable_traits<const A, int> ); +struct B : private A { }; +static_assert( check_readable_traits<B, none> ); + +struct C { }; +short operator-(C, C) { return 0; } +static_assert( check_readable_traits<C, none> ); +static_assert( check_readable_traits<const C, none> ); + +struct D { long operator*() const { return 1L; } }; +unsigned short operator-(D, D) { return 0; } +static_assert( check_readable_traits<D, none> ); +static_assert( check_readable_traits<const D, none> ); + +struct E { }; +template<> + struct std::readable_traits<E> { using value_type = long; }; +static_assert( check_readable_traits<E, long> ); +static_assert( check_readable_traits<const E, long> ); + +template<typename T> + concept has_alias = requires { typename std::iter_value_t<T>; }; + +// Check std::iter_value_t<T> is U (or doesn't exist). +template<typename T, typename U> + concept check_alias = (has_alias<T> != std::same_as<U, none>); + +static_assert( check_alias<void, none> ); +static_assert( check_alias<const void, none> ); +static_assert( check_alias<void*, none> ); +static_assert( check_alias<const void*, none> ); + +static_assert( check_alias<int, none> ); +static_assert( check_alias<const int, none> ); +static_assert( check_alias<int*, std::ptrdiff_t> ); +static_assert( check_alias<const int*, std::ptrdiff_t> ); +static_assert( check_alias<int[2], std::ptrdiff_t> ); +static_assert( check_alias<const int[2], std::ptrdiff_t> ); + +static_assert( check_alias<A, int> ); +static_assert( check_alias<const A, int> ); +static_assert( check_alias<B, none> ); +static_assert( check_alias<C, none> ); +static_assert( check_alias<const C, none> ); +static_assert( check_alias<D, none> ); +static_assert( check_alias<const D, none> ); +static_assert( check_alias<E, long> ); +static_assert( check_alias<const E, long> ); + +struct F { }; +template<> + struct std::iterator_traits<F> { using value_type = F; }; +// iterator_traits<F> is specialized, so use its value_type. +static_assert( check_alias<F, std::iterator_traits<F>::value_type> ); + +struct G { }; +template<> + struct std::readable_traits<G> { using value_type = G; }; +template<> + struct std::iterator_traits<G> { using value_type = int; }; +// iterator_traits<G> is specialized, so use its value_type. +static_assert( check_alias<G, std::iterator_traits<G>::value_type> ); + +struct H { }; +template<> + struct std::readable_traits<H> { using value_type = H; }; +template<> + struct std::iterator_traits<H> + { + using iterator_category = input_iterator_tag; + using difference_type = int; + using value_type = char; + using reference = value_type&; + }; +// iterator_traits<H> is specialized, so use its value_type. +static_assert( check_alias<H, std::iterator_traits<H>::value_type> ); + +struct I +{ + using value_type = I; +}; +// iterator_traits<I> is not specialized, and no standard specialization +// matches, so use readable_traits. +static_assert( check_alias<I, std::readable_traits<I>::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<J> matches constrained specialization in the library, +// so use its value_type. +static_assert( check_alias<J, int> ); 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 0000000..a9bb42e --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include <iterator> + +static_assert( std::contiguous_iterator<int*> ); +static_assert( std::contiguous_iterator<const int*> ); +static_assert( std::contiguous_iterator<void**> ); + +static_assert( ! std::contiguous_iterator<void*> ); +static_assert( ! std::contiguous_iterator<const void*> ); +static_assert( ! std::contiguous_iterator<volatile void*> ); + +static_assert( ! std::contiguous_iterator<void(*)()> ); +static_assert( ! std::contiguous_iterator<void(*)()> ); + +struct A; +static_assert( ! std::contiguous_iterator<void(A::*)()> ); +static_assert( ! std::contiguous_iterator<int A::*> ); 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 0000000..7673131 --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include <iterator> + +static_assert( std::is_empty_v<std::contiguous_iterator_tag> ); +static_assert( std::is_trivially_copy_constructible_v<std::contiguous_iterator_tag> ); + +static_assert( std::is_base_of_v<std::random_access_iterator_tag, + std::contiguous_iterator_tag> ); +static_assert( std::is_convertible_v<std::contiguous_iterator_tag*, + std::random_access_iterator_tag*> ); + +static_assert( ! std::is_same_v<std::iterator_traits<int*>::iterator_category, + std::contiguous_iterator_tag> ); +static_assert( std::is_same_v<std::iterator_traits<int*>::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 0000000..d32dee3 --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> +#include <testsuite_hooks.h> + +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 0000000..4243a16 --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> +#include <testsuite_hooks.h> + +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 0000000..2dbfb76 --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } +// { dg-require-normal-namespace "" } + +#include <iterator> +#include "./synopsis_c++17.cc" + +namespace std +{ + template<class> struct incrementable_traits; + template<class> struct readable_traits; + + struct contiguous_iterator_tag; + + namespace ranges + { + template<input_or_output_iterator I, sentinel_for<I> S> + constexpr iter_difference_t<I> distance(I first, S last); + template<range R> + constexpr range_difference_t<R> distance(R&& r); + + template<input_or_output_iterator I> + constexpr I next(I x); + template<input_or_output_iterator I> + constexpr I next(I x, iter_difference_t<I> n); + template<input_or_output_iterator I, sentinel_for<I> S> + constexpr I next(I x, S bound); + template<input_or_output_iterator I, sentinel_for<I> S> + constexpr I next(I x, iter_difference_t<I> n, S bound); + + template<bidirectional_iterator I> + constexpr I prev(I x); + template<bidirectional_iterator I> + constexpr I prev(I x, iter_difference_t<I> n); + template<bidirectional_iterator I> + constexpr I prev(I x, iter_difference_t<I> n, I bound); + } + + template<semiregular S> class move_sentinel; + + template<input_or_output_iterator I, sentinel_for<I> S> + requires (!same_as<I, S>) + class common_iterator; + + template<class I, class S> + struct incrementable_traits<common_iterator<I, S>>; + + template<input_iterator I, class S> + struct iterator_traits<common_iterator<I, S>>; + + struct default_sentinel_t; + + template<input_or_output_iterator I> class counted_iterator; + + template<class I> + struct incrementable_traits<counted_iterator<I>>; + + template<input_iterator I> + struct iterator_traits<counted_iterator<I>>; + + 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<void, void>; + // 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 0000000..7f77eca --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +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<int, random_access_iterator_wrapper> 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<int, bidirectional_iterator_wrapper> 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<int, forward_iterator_wrapper> 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<int, input_iterator_wrapper> 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<int, input_iterator_wrapper> 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<int, input_iterator_wrapper> 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<int, output_iterator_wrapper> 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<int, output_iterator_wrapper> 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<int, output_iterator_wrapper> 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 0000000..4aa095f --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +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<int, random_access_iterator_wrapper> 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<int, random_access_iterator_wrapper> c2(a); + VERIFY( std::ranges::distance(c2) == 10 ); +} + +void +test02() +{ + int a[2] = { }; + VERIFY( std::ranges::distance(a) == 2 ); + + test_range<int, bidirectional_iterator_wrapper> 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<int, bidirectional_iterator_wrapper> c2(a); + VERIFY( std::ranges::distance(c2) == 2 ); +} + +void +test03() +{ + int a[3] = { }; + test_range<int, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> c2(a); + VERIFY( std::ranges::distance(c2) == 3 ); +} + +void +test04() +{ + int a[4] = { }; + test_range<int, input_iterator_wrapper> c(a); + static_assert( std::ranges::range<decltype(c)> ); + + VERIFY( std::ranges::distance(c) == 4 ); + // first call to distance has traversed the range: + VERIFY( std::ranges::distance(c) == 0 ); + + c = test_range<int, input_iterator_wrapper>(a); + auto b = c.begin(), e = c.end(); + VERIFY( std::ranges::distance(b, e) == 4 ); + + test_range<int, input_iterator_wrapper> c2(a); + const auto cb = c2.begin(), ce = c2.end(); + VERIFY( std::ranges::distance(cb, ce) == 4 ); + + test_sized_range<int, input_iterator_wrapper> 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<int, output_iterator_wrapper> c(a); + VERIFY( std::ranges::distance(c) == 5 ); + + test_range<int, output_iterator_wrapper> c2(a); + auto b = c2.begin(); + auto e = c2.end(); + VERIFY( std::ranges::distance(b, e) == 5 ); + + test_range<int, output_iterator_wrapper> c3(a); + const auto cb = c3.begin(); + const auto ce = c3.end(); + VERIFY( std::ranges::distance(cb, ce) == 5 ); + + test_sized_range<int, output_iterator_wrapper> 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 0000000..7f04cb2 --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +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<int, random_access_iterator_wrapper> 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<int, bidirectional_iterator_wrapper> 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<int, forward_iterator_wrapper> 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<int, input_iterator_wrapper> 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<int, input_iterator_wrapper> 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<int, output_iterator_wrapper> r(a); + auto iter = r.begin(); + auto end = r.end(); // sentinel, !same_as<decltype(iter), decltype(end)> + + 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<int, output_iterator_wrapper> 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 0000000..944c02a --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +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<int, random_access_iterator_wrapper> 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<int, bidirectional_iterator_wrapper> 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<typename T> + 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<forward_iterator_wrapper<int>> ); +static_assert( !can_prev<input_iterator_wrapper<int>> ); +static_assert( !can_prev<output_iterator_wrapper<int>> ); + +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 83bd8bc..1d44c31 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 dd8b7dc..f7c82ec 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 707de2f..763d2d1 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 89c2bd9..a5b7a68 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 c11857e..734cc17 100644 --- a/libstdc++-v3/testsuite/experimental/iterator/requirements.cc +++ b/libstdc++-v3/testsuite/experimental/iterator/requirements.cc @@ -64,4 +64,6 @@ std::move_iterator<int*> mi; std::istream_iterator<int> isi; std::ostream_iterator<int> osi(os()); std::istreambuf_iterator<char> isbi; + +#include <ostream> std::ostreambuf_iterator<char> 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 0000000..1d7db46 --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> // N.B. should be <ranges> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +using std::same_as; + +void +test01() +{ + int a[2] = {}; + + static_assert(same_as<decltype(std::ranges::begin(a)), decltype(a + 0)>); + 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<int, random_access_iterator_wrapper> r(a); + static_assert(same_as<decltype(std::ranges::begin(r)), decltype(r.begin())>); + VERIFY( std::ranges::begin(r) == r.begin() ); + + test_range<int, input_iterator_wrapper> i(a); + static_assert(same_as<decltype(std::ranges::begin(i)), decltype(i.begin())>); + VERIFY( std::ranges::begin(i) == i.begin() ); + + test_range<int, output_iterator_wrapper> o(a); + static_assert(same_as<decltype(std::ranges::begin(o)), decltype(o.begin())>); + *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<decltype(std::ranges::begin(r)), decltype(begin(r))>); + static_assert(!noexcept(std::ranges::begin(r))); + VERIFY( std::ranges::begin(r) == begin(r) ); + + static_assert(same_as<decltype(std::ranges::begin(std::move(r))), + decltype(begin(std::move(r)))>); + static_assert(!noexcept(std::ranges::begin(std::move(r)))); + VERIFY( std::ranges::begin(std::move(r)) == begin(std::move(r)) ); + + + static_assert(same_as<decltype(std::ranges::begin(c)), decltype(begin(c))>); + static_assert(noexcept(std::ranges::begin(c))); + VERIFY( std::ranges::begin(c) == begin(c) ); + + static_assert(same_as<decltype(std::ranges::begin(std::move(c))), + decltype(begin(std::move(c)))>); + 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 0000000..34dd7fec --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> // N.B. should be <ranges> +#include <testsuite_hooks.h> +using std::same_as; + +void +test01() +{ + int a[2] = {}; + + static_assert(same_as<decltype(std::ranges::cbegin(a)), const int*>); + 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 0000000..9a1ab5b --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> +#include <testsuite_hooks.h> + +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 0000000..789c6ca --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> // N.B. should be <ranges> +#include <testsuite_hooks.h> + +using std::same_as; + +void +test01() +{ + int a[2] = {}; + + static_assert(same_as<decltype(std::ranges::cend(a)), const int*>); + 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 0000000..24939ac --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +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 0000000..ef0fb0e --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +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 0000000..d9129d0 --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +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<int, __gnu_test::contiguous_iterator_wrapper> 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 0000000..64b1e1b --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> // N.B. should be <ranges> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +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<decltype(std::ranges::empty(r)), bool> ); + static_assert( std::ranges::empty(std::move(r)) ); + static_assert( same_as<decltype(std::ranges::empty(std::move(r))), bool> ); +} + +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<int, random_access_iterator_wrapper> r(a); + VERIFY( !std::ranges::empty(r) ); + + test_range<int, forward_iterator_wrapper> i(a); + VERIFY( !std::ranges::empty(i) ); + + test_sized_range<int, random_access_iterator_wrapper> sr(a); + VERIFY( !std::ranges::empty(sr) ); + + test_sized_range<int, input_iterator_wrapper> si(a); + VERIFY( !std::ranges::empty(si) ); + + test_sized_range<int, output_iterator_wrapper> 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 0000000..7f09cc2 --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> // N.B. should be <ranges> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +using std::same_as; + +void +test01() +{ + int a[2] = {}; + + static_assert(same_as<decltype(std::ranges::end(a)), decltype(a + 2)>); + 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<int, random_access_iterator_wrapper> r(a); + static_assert(same_as<decltype(std::ranges::end(r)), decltype(r.end())>); + VERIFY( std::ranges::end(r) == r.end() ); + + test_range<int, input_iterator_wrapper> i(a); + static_assert(same_as<decltype(std::ranges::end(i)), decltype(i.end())>); + VERIFY( std::ranges::end(i) == i.end() ); + + test_range<int, output_iterator_wrapper> o(a); + static_assert(same_as<decltype(std::ranges::end(o)), decltype(o.end())>); + 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<decltype(std::ranges::end(r)), decltype(end(r))>); + static_assert(!noexcept(std::ranges::end(r))); + VERIFY( std::ranges::end(r) == end(r) ); + + static_assert(same_as<decltype(std::ranges::end(std::move(r))), + decltype(end(std::move(r)))>); + static_assert(!noexcept(std::ranges::end(std::move(r)))); + VERIFY( std::ranges::end(std::move(r)) == end(std::move(r)) ); + + + static_assert(same_as<decltype(std::ranges::end(c)), decltype(end(c))>); + static_assert(noexcept(std::ranges::end(c))); + VERIFY( std::ranges::end(c) == end(c) ); + + static_assert(same_as<decltype(std::ranges::end(std::move(c))), + decltype(end(std::move(c)))>); + 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 0000000..6cfc1a3 --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +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<int, bidirectional_iterator_wrapper> 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 0000000..2192825 --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +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<decltype(i2), decltype(i1)> ); + // 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<int, bidirectional_iterator_wrapper> 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 0000000..b92e5d5 --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <iterator> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +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<int, __gnu_test::input_iterator_wrapper> 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<int, __gnu_test::random_access_iterator_wrapper> 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<R5> = 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 974490b..70c1f9b 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<typename T> + struct contiguous_iterator_wrapper + : random_access_iterator_wrapper<T> + { + using random_access_iterator_wrapper<T>::random_access_iterator_wrapper; + + using iterator_concept = std::contiguous_iterator_tag; + + contiguous_iterator_wrapper& + operator++() + { + random_access_iterator_wrapper<T>::operator++(); + return *this; + } + + contiguous_iterator_wrapper& + operator--() + { + random_access_iterator_wrapper<T>::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<T>::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<typename T, template<typename> class Iter> + class test_range + { + // Adds default constructor to Iter<T> if needed + struct iterator : Iter<T> + { + using Iter<T>::Iter; + + iterator() : Iter<T>(nullptr, nullptr) { } + + using Iter<T>::operator++; + + iterator& operator++() { Iter<T>::operator++(); return *this; } + }; + + template<typename I> + 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<Iter<T>>) + return Iter<T>(p, &bounds); + else + return iterator(p, &bounds); + } + + public: + test_range(T* first, T* last) : bounds(first, last) + { } + + template<std::size_t N> + 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<I, I>) + return get_iterator(bounds.last); + else + return sentinel<I>{bounds.last}; + } + + typename Iter<T>::ContainerType bounds; + }; + + // A type meeting the minimum std::sized_range requirements + template<typename T, template<typename> class Iter> + struct test_sized_range : test_range<T, Iter> + { + using test_range<T, Iter>::test_range; + + std::size_t size() const noexcept + { return this->bounds.size(); } + }; +#endif // C++20 +} // namespace __gnu_test +#endif // _TESTSUITE_ITERATORS |