[libcxx] adds `cpp17-.*iterator` concepts for iterator_traits
The `iterator_traits` patch became too large for a concise review, so
the "bloat" —as it were— was moved into this patch. Also tests most
C++[98,17] iterator types to confirm backwards compatibility is
successful (regex iterators are intentionally not present, but directory
iterators are due to a peculiar error encountered while patching
`iterator_traits`).
Depends on D99461.
Differential Revision: https://reviews.llvm.org/D99854
GitOrigin-RevId: 0148b653727592279e1e399129f9c623cd83bb38
diff --git a/include/iterator b/include/iterator
index cc2b264..5e9e822 100644
--- a/include/iterator
+++ b/include/iterator
@@ -40,6 +40,9 @@
typedef random_access_iterator_tag iterator_category;
};
+template<dereferenceable T>
+ using iter_reference_t = decltype(*declval<T&>());
+
template<class Category, class T, class Distance = ptrdiff_t,
class Pointer = T*, class Reference = T&>
struct iterator
@@ -429,7 +432,6 @@
#include <__memory/addressof.h>
#include <__memory/pointer_traits.h>
#include <version>
-#include <concepts>
#include <__debug>
@@ -440,6 +442,20 @@
_LIBCPP_BEGIN_NAMESPACE_STD
#if !defined(_LIBCPP_HAS_NO_RANGES)
+
+template<class _Tp>
+using __with_reference = _Tp&;
+
+template<class _Tp>
+concept __referenceable = requires {
+ typename __with_reference<_Tp>;
+};
+
+template<class _Tp>
+concept __dereferenceable = requires(_Tp& __t) {
+ { *__t } -> __referenceable; // not required to be equality-preserving
+};
+
// [incrementable.traits]
template<class> struct incrementable_traits {};
@@ -520,6 +536,9 @@
struct indirectly_readable_traits<_Tp>
: __cond_value_type<typename _Tp::value_type> {};
+// [iterator.traits]
+template<__dereferenceable _Tp>
+using iter_reference_t = decltype(*declval<_Tp&>());
#endif // !defined(_LIBCPP_HAS_NO_RANGES)
template <class _Iter>
@@ -630,6 +649,71 @@
typedef typename _Iter::iterator_category iterator_category;
};
+#if !defined(_LIBCPP_HAS_NO_RANGES)
+
+// The `cpp17-*-iterator` exposition-only concepts are easily confused with the Cpp17*Iterator tables,
+// so they've been banished to a namespace that makes it obvious they have a niche use-case.
+namespace __iterator_traits_detail {
+template<class _Ip>
+concept __cpp17_iterator =
+ requires(_Ip __i) {
+ { *__i } -> __referenceable;
+ { ++__i } -> same_as<_Ip&>;
+ { *__i++ } -> __referenceable;
+ } &&
+ copyable<_Ip>;
+
+template<class _Ip>
+concept __cpp17_input_iterator =
+ __cpp17_iterator<_Ip> &&
+ equality_comparable<_Ip> &&
+ requires(_Ip __i) {
+ typename incrementable_traits<_Ip>::difference_type;
+ typename indirectly_readable_traits<_Ip>::value_type;
+ typename common_reference_t<iter_reference_t<_Ip>&&,
+ typename indirectly_readable_traits<_Ip>::value_type&>;
+ typename common_reference_t<decltype(*__i++)&&,
+ typename indirectly_readable_traits<_Ip>::value_type&>;
+ requires signed_integral<typename incrementable_traits<_Ip>::difference_type>;
+ };
+
+template<class _Ip>
+concept __cpp17_forward_iterator =
+ __cpp17_input_iterator<_Ip> &&
+ constructible_from<_Ip> &&
+ is_lvalue_reference_v<iter_reference_t<_Ip>> &&
+ same_as<remove_cvref_t<iter_reference_t<_Ip>>,
+ typename indirectly_readable_traits<_Ip>::value_type> &&
+ requires(_Ip __i) {
+ { __i++ } -> convertible_to<_Ip const&>;
+ { *__i++ } -> same_as<iter_reference_t<_Ip>>;
+ };
+
+template<class _Ip>
+concept __cpp17_bidirectional_iterator =
+ __cpp17_forward_iterator<_Ip> &&
+ requires(_Ip __i) {
+ { --__i } -> same_as<_Ip&>;
+ { __i-- } -> convertible_to<_Ip const&>;
+ { *__i-- } -> same_as<iter_reference_t<_Ip>>;
+ };
+
+template<class _Ip>
+concept __cpp17_random_access_iterator =
+ __cpp17_bidirectional_iterator<_Ip> and
+ totally_ordered<_Ip> and
+ requires(_Ip __i, typename incrementable_traits<_Ip>::difference_type __n) {
+ { __i += __n } -> same_as<_Ip&>;
+ { __i -= __n } -> same_as<_Ip&>;
+ { __i + __n } -> same_as<_Ip>;
+ { __n + __i } -> same_as<_Ip>;
+ { __i - __n } -> same_as<_Ip>;
+ { __i - __i } -> same_as<decltype(__n)>;
+ { __i[__n] } -> convertible_to<iter_reference_t<_Ip>>;
+ };
+} // namespace __iterator_traits_detail
+#endif // !defined(_LIBCPP_HAS_NO_RANGES)
+
template <class _Iter, bool> struct __iterator_traits {};
template <class _Iter>