diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -15,7 +15,8 @@ namespace std { -template struct incrementable_traits; // since C++20 +template struct incrementable_traits; // since C++20 +template struct indirectly_readable_traits; // since C++20 template struct iterator_traits @@ -468,6 +469,54 @@ }; // TODO(cjdb): add iter_difference_t once iterator_traits is cleaned up. + +// [readable.traits] +template struct indirectly_readable_traits {}; + +template +requires is_array_v<_Ip> +struct indirectly_readable_traits<_Ip> { + using value_type = remove_cv_t>; +}; + +template +struct indirectly_readable_traits : indirectly_readable_traits<_Ip> {}; + +template struct __cond_value_type {}; + +template +requires is_object_v<_Tp> +struct __cond_value_type<_Tp> { using value_type = remove_cv_t<_Tp>; }; + +template +struct indirectly_readable_traits<_Tp*> : __cond_value_type<_Tp> {}; + +template +concept __has_member_value_type = requires { typename _Tp::value_type; }; + +template<__has_member_value_type _Tp> +struct indirectly_readable_traits<_Tp> + : __cond_value_type {}; + +template +concept __has_member_element_type = requires { typename _Tp::element_type; }; + +template<__has_member_element_type _Tp> +struct indirectly_readable_traits<_Tp> + : __cond_value_type {}; + +template +concept __has_members_value_type_and_element_type = + __has_member_value_type<_Tp> && + __has_member_element_type<_Tp> && + same_as, + remove_cv_t>; + +template<__has_members_value_type_and_element_type _Tp> +struct indirectly_readable_traits<_Tp> + : __cond_value_type {}; + +// TODO(cjdb): add iter_value_t once iterator_traits is cleaned up. #endif // _LIBCPP_STD_VER > 17 template diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/indirectly_readable_traits.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/indirectly_readable_traits.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/indirectly_readable_traits.pass.cpp @@ -0,0 +1,150 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// template +// struct indirectly_readable_traits; + +#include + +#include +#include +#include +#include + +template +concept check_has_value_type = requires { + typename std::indirectly_readable_traits::value_type; +}; + +template +concept check_value_type_matches = check_has_value_type&& std::same_as< + typename std::indirectly_readable_traits::value_type, Expected>; + +template +constexpr bool check_pointer() { + constexpr bool result = check_value_type_matches; + static_assert(check_value_type_matches == result); + static_assert(check_value_type_matches == result); + static_assert(check_value_type_matches == result); + + static_assert(check_value_type_matches == result); + static_assert(check_value_type_matches == result); + static_assert(check_value_type_matches == result); + static_assert(check_value_type_matches == result); + + return result; +} + +static_assert(!check_pointer()); +static_assert(check_pointer()); +static_assert(check_pointer()); +static_assert(check_pointer()); +static_assert(check_pointer()); + +struct S {}; +static_assert(check_pointer()); + +template +constexpr bool check_array() { + constexpr bool result = check_value_type_matches; + static_assert(check_value_type_matches == result); + static_assert(check_value_type_matches == result); + static_assert(check_value_type_matches == result); + static_assert(check_value_type_matches == result); + static_assert(check_value_type_matches == result); + static_assert(check_value_type_matches == result); + static_assert(check_value_type_matches == result); + return result; +} + +static_assert(check_array()); +static_assert(check_array()); +static_assert(check_array()); +static_assert(check_array()); +static_assert(check_array()); + +template +constexpr bool check_explicit_member() { + constexpr bool result = check_value_type_matches; + return result == check_value_type_matches; +} + +struct has_value_type { + using value_type = int; +}; +static_assert(check_explicit_member()); +static_assert(check_explicit_member::iterator, int>()); + +struct has_element_type { + using element_type = S; +}; +static_assert(check_explicit_member()); + +struct has_same_value_and_element_type { + using value_type = int; + using element_type = int; +}; +static_assert(check_explicit_member()); +static_assert(check_explicit_member, long>()); +static_assert(check_explicit_member, long>()); + +struct S2 {}; +namespace std { +template <> +struct indirectly_readable_traits { + using value_type = int; +}; +} // namespace std +static_assert(check_value_type_matches); +static_assert(check_value_type_matches, int>); +static_assert(check_value_type_matches, int>); + +template +constexpr bool check_ref() { + struct ref_value { + using value_type = T&; + }; + constexpr bool result = check_has_value_type; + + struct ref_element { + using element_type = T&; + }; + static_assert(check_has_value_type == result); + + return result; +} + +static_assert(!check_ref()); +static_assert(!check_ref()); +static_assert(!check_ref >()); + +static_assert(!check_has_value_type); +static_assert(!check_has_value_type); +static_assert(!check_has_value_type); +static_assert(!check_has_value_type); + +struct has_different_value_and_element_type { + using value_type = int; + using element_type = long; +}; +static_assert(!check_has_value_type); + +struct void_value { + using value_type = void; +}; +static_assert(!check_has_value_type); + +struct void_element { + using element_type = void; +}; +static_assert(!check_has_value_type); + +int main(int, char**) { return 0; }