1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPP___ITERATOR_READABLE_TRAITS_H
11#define _LIBCPP___ITERATOR_READABLE_TRAITS_H
12
13#include <__config>
14#include <concepts>
15#include <type_traits>
16
17#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
18#pragma GCC system_header
19#endif
20
21_LIBCPP_PUSH_MACROS
22#include <__undef_macros>
23
24_LIBCPP_BEGIN_NAMESPACE_STD
25
26#if !defined(_LIBCPP_HAS_NO_RANGES)
27
28// [readable.traits]
29template<class> struct __cond_value_type {};
30
31template<class _Tp>
32requires is_object_v<_Tp>
33struct __cond_value_type<_Tp> { using value_type = remove_cv_t<_Tp>; };
34
35template<class _Tp>
36concept __has_member_value_type = requires { typename _Tp::value_type; };
37
38template<class _Tp>
39concept __has_member_element_type = requires { typename _Tp::element_type; };
40
41template<class> struct indirectly_readable_traits {};
42
43template<class _Ip>
44requires is_array_v<_Ip>
45struct indirectly_readable_traits<_Ip> {
46  using value_type = remove_cv_t<remove_extent_t<_Ip>>;
47};
48
49template<class _Ip>
50struct indirectly_readable_traits<const _Ip> : indirectly_readable_traits<_Ip> {};
51
52template<class _Tp>
53struct indirectly_readable_traits<_Tp*> : __cond_value_type<_Tp> {};
54
55template<__has_member_value_type _Tp>
56struct indirectly_readable_traits<_Tp>
57  : __cond_value_type<typename _Tp::value_type> {};
58
59template<__has_member_element_type _Tp>
60struct indirectly_readable_traits<_Tp>
61  : __cond_value_type<typename _Tp::element_type> {};
62
63// Pre-emptively applies LWG3541
64template<__has_member_value_type _Tp>
65requires __has_member_element_type<_Tp>
66struct indirectly_readable_traits<_Tp> {};
67template<__has_member_value_type _Tp>
68requires __has_member_element_type<_Tp> &&
69         same_as<remove_cv_t<typename _Tp::element_type>,
70                 remove_cv_t<typename _Tp::value_type>>
71struct indirectly_readable_traits<_Tp>
72  : __cond_value_type<typename _Tp::value_type> {};
73
74template <class>
75struct iterator_traits;
76
77// Let `RI` be `remove_cvref_t<I>`. The type `iter_value_t<I>` denotes
78// `indirectly_readable_traits<RI>::value_type` if `iterator_traits<RI>` names a specialization
79// generated from the primary template, and `iterator_traits<RI>::value_type` otherwise.
80template <class _Ip>
81using iter_value_t = typename conditional_t<__is_primary_template<iterator_traits<remove_cvref_t<_Ip> > >::value,
82                                            indirectly_readable_traits<remove_cvref_t<_Ip> >,
83                                            iterator_traits<remove_cvref_t<_Ip> > >::value_type;
84
85#endif // !defined(_LIBCPP_HAS_NO_RANGES)
86
87_LIBCPP_END_NAMESPACE_STD
88
89_LIBCPP_POP_MACROS
90
91#endif // _LIBCPP___ITERATOR_READABLE_TRAITS_H
92