[libcxx] adds `std::indirectly_readable_traits` to <iterator>

Implements parts of:
    * P0896R4 The One Ranges Proposal
    * LWG3446 `indirectly_readable_traits` ambiguity for types with both `value_type` and `element_type`

Depends on D99141.

Differential Revision: https://reviews.llvm.org/D99461

GitOrigin-RevId: f280505aa08432f5d4c4296122c6ff728b753398
diff --git a/include/iterator b/include/iterator
index 4e1077f..cc2b264 100644
--- a/include/iterator
+++ b/include/iterator
@@ -17,7 +17,8 @@
 
 namespace std
 {
-template<class> struct incrementable_traits; // since C++20
+template<class> struct incrementable_traits;       // since C++20
+template<class> struct indirectly_readable_traits; // since C++20
 
 template<class Iterator>
 struct iterator_traits
@@ -472,6 +473,53 @@
 };
 
 // TODO(cjdb): add iter_difference_t once iterator_traits is cleaned up.
+
+// [readable.traits]
+template<class> struct __cond_value_type {};
+
+template<class _Tp>
+requires is_object_v<_Tp>
+struct __cond_value_type<_Tp> { using value_type = remove_cv_t<_Tp>; };
+
+template<class _Tp>
+concept __has_member_value_type = requires { typename _Tp::value_type; };
+
+template<class _Tp>
+concept __has_member_element_type = requires { typename _Tp::element_type; };
+
+template<class> struct indirectly_readable_traits {};
+
+template<class _Ip>
+requires is_array_v<_Ip>
+struct indirectly_readable_traits<_Ip> {
+  using value_type = remove_cv_t<remove_extent_t<_Ip>>;
+};
+
+template<class _Ip>
+struct indirectly_readable_traits<const _Ip> : indirectly_readable_traits<_Ip> {};
+
+template<class _Tp>
+struct indirectly_readable_traits<_Tp*> : __cond_value_type<_Tp> {};
+
+template<__has_member_value_type _Tp>
+struct indirectly_readable_traits<_Tp>
+  : __cond_value_type<typename _Tp::value_type> {};
+
+template<__has_member_element_type _Tp>
+struct indirectly_readable_traits<_Tp>
+  : __cond_value_type<typename _Tp::element_type> {};
+
+// Pre-emptively applies LWG3541
+template<__has_member_value_type _Tp>
+requires __has_member_element_type<_Tp>
+struct indirectly_readable_traits<_Tp> {};
+template<__has_member_value_type _Tp>
+requires __has_member_element_type<_Tp> &&
+         same_as<remove_cv_t<typename _Tp::element_type>,
+                 remove_cv_t<typename _Tp::value_type>>
+struct indirectly_readable_traits<_Tp>
+  : __cond_value_type<typename _Tp::value_type> {};
+
 #endif // !defined(_LIBCPP_HAS_NO_RANGES)
 
 template <class _Iter>