diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2019-10-29 17:44:18 +0000 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2019-10-29 17:44:18 +0000 |
commit | 6d0dff49ca1539e14647c04cc1bb035ef4c2780b (patch) | |
tree | e438e2b4a9d49f1cc15e751a889a0ed890cfd287 /libstdc++-v3/include | |
parent | 9921ac3db381106b66b70d8bf99136b265ec07c3 (diff) | |
download | gcc-6d0dff49ca1539e14647c04cc1bb035ef4c2780b.zip gcc-6d0dff49ca1539e14647c04cc1bb035ef4c2780b.tar.gz gcc-6d0dff49ca1539e14647c04cc1bb035ef4c2780b.tar.bz2 |
Add iterator concepts and range access customization points for C++20
This adds most of the new C++20 features to <iterator>, as well as a few
initial pieces of <ranges> (but no actual <ranges> header just yet).
* include/Makefile.am: Add new header.
* include/Makefile.in: Regenerate.
* include/bits/iterator_concepts.h: New header.
(contiguous_iterator_tag, iter_reference_t, ranges::iter_move)
(iter_rvalue_reference_t, incrementable_traits, iter_difference_t)
(readable_traits, iter_value_t, readable, iter_common_reference_t)
(writable, waekly_incrementable, incrementable)
(input_or_output_iterator, sentinel_for, disable_sized_sentinel)
(sized_sentinel_for, input_iterator, output_iterator)
(forward_iterator, bidirectional_iterator, random_access_iterator)
(contiguous_iterator, indirectly_unary_invocable)
(indirectly_regular_unary_invocable, indirect_unary_predicate)
(indirect_relation, indirect_strict_weak_order, indirect_result_t)
(projected, indirectly_movable, indirectly_movable_storable)
(indirectly_copyable, indirectly_copyable_storable, ranges::iter_swap)
(indirectly_swappable, indirectly_comparable, permutable, mergeable)
(sortable, unreachable_sentinel_t, unreachable_sentinel)
(default_sentinel_t, default_sentinel): Define.
(__detail::__cpp17_iterator, __detail::__cpp17_input_iterator)
(__detail::__cpp17_fwd_iterator, __detail::__cpp17_bidi_iterator)
(__detail::__cpp17_randacc_iterator): Define.
(__iterator_traits): Define constrained specializations.
* include/bits/move.h (move): Only use old concept check for C++98.
* include/bits/range_access.h (ranges::disable_sized_range)
(ranges::begin, ranges::end, ranges::cbegin, ranges::cend)
(ranges::rbegin, ranges::rend, ranges::crbegin, ranges::crend)
(ranges::size, ranges::empty, ranges::data, ranges::cdata): Define
new customization points for C++20.
(ranges::range, ranges::sized_range): Define new concepts for C++20.
(ranges::advance, ranges::distance, ranges::next, ranges::prev):
Define new functions for C++20.
(__adl_end, __adl_cdata, __adl_cbegin, __adl_cend, __adl_rbegin)
(__adl_rend, __adl_crbegin, __adl_crend, __adl_cdata, __adl_size)
(__adl_empty): Remove.
* include/bits/stl_iterator.h (disable_sized_sentinel): Specialize
for reverse_iterator.
* include/bits/stl_iterator_base_types.h (contiguous_iterator_tag):
Define new struct for C++20.
(iterator_traits<_Tp*>): Constrain partial specialization in C++20.
* include/std/concepts (__is_class_or_enum): Move to __detail
namespace.
* testsuite/20_util/forward/c_neg.cc: Adjust dg-error line number.
* testsuite/20_util/forward/f_neg.cc: Likewise.
* testsuite/24_iterators/associated_types/incrementable.traits.cc: New
test.
* testsuite/24_iterators/associated_types/readable.traits.cc: New test.
* testsuite/24_iterators/contiguous/concept.cc: New test.
* testsuite/24_iterators/contiguous/tag.cc: New test.
* testsuite/24_iterators/customization_points/iter_move.cc: New test.
* testsuite/24_iterators/customization_points/iter_swap.cc: New test.
* testsuite/24_iterators/headers/iterator/synopsis_c++20.cc: New test.
* testsuite/24_iterators/range_operations/advance.cc: New test.
* testsuite/24_iterators/range_operations/distance.cc: New test.
* testsuite/24_iterators/range_operations/next.cc: New test.
* testsuite/24_iterators/range_operations/prev.cc: New test.
* testsuite/26_numerics/adjacent_difference/requirements/
explicit_instantiation/2.cc: Rename types that conflict with C++20
concepts.
* testsuite/26_numerics/adjacent_difference/requirements/
explicit_instantiation/pod.cc: Likewise.
* testsuite/26_numerics/partial_sum/requirements/
explicit_instantiation/2.cc: Likewise.
* testsuite/26_numerics/partial_sum/requirements/
explicit_instantiation/pod.cc: Likewise.
* testsuite/experimental/iterator/requirements.cc: Likewise.
* testsuite/std/ranges/access/begin.cc: New test.
* testsuite/std/ranges/access/cbegin.cc: New test.
* testsuite/std/ranges/access/cdata.cc: New test.
* testsuite/std/ranges/access/cend.cc: New test.
* testsuite/std/ranges/access/crbegin.cc: New test.
* testsuite/std/ranges/access/crend.cc: New test.
* testsuite/std/ranges/access/data.cc: New test.
* testsuite/std/ranges/access/empty.cc: New test.
* testsuite/std/ranges/access/end.cc: New test.
* testsuite/std/ranges/access/rbegin.cc: New test.
* testsuite/std/ranges/access/rend.cc: New test.
* testsuite/std/ranges/access/size.cc: New test.
* testsuite/util/testsuite_iterators.h (contiguous_iterator_wrapper)
(test_range, test_sized_range): New test utilities.
From-SVN: r277579
Diffstat (limited to 'libstdc++-v3/include')
-rw-r--r-- | libstdc++-v3/include/Makefile.am | 1 | ||||
-rw-r--r-- | libstdc++-v3/include/Makefile.in | 1 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/iterator_concepts.h | 828 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/move.h | 7 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/range_access.h | 750 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/stl_iterator.h | 16 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/stl_iterator_base_types.h | 37 | ||||
-rw-r--r-- | libstdc++-v3/include/std/concepts | 15 |
8 files changed, 1596 insertions, 59 deletions
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)); } |