diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -18,7 +18,12 @@ namespace std { template<class> struct incrementable_traits; // since C++20 +template<class T> + using iter_difference_t = see below; // since C++20 + template<class> struct indirectly_readable_traits; // since C++20 +template<class T> + using iter_value_t = see below; // since C++20 template<class Iterator> struct iterator_traits; @@ -428,6 +433,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template <class _Iter> +struct _LIBCPP_TEMPLATE_VIS iterator_traits; + #if !defined(_LIBCPP_HAS_NO_RANGES) template<class _Tp> @@ -475,7 +483,15 @@ using difference_type = make_signed_t<decltype(declval<_Tp>() - declval<_Tp>())>; }; -// TODO(cjdb): add iter_difference_t once iterator_traits is cleaned up. +// Let `RI` be `remove_Âcvref_Ât<I>`. The type `iter_Âdifference_Ât<I>` denotes +// `incrementable_Âtraits<RI>::difference_Âtype` if `iterator_Âtraits<RI>` names a specialization +// generated from the primary template, and `iterator_Âtraits<R[I]>::difference_Âtype` otherwise. +template <class _Ip> +using iter_difference_t = + typename conditional_t< + __is_primary_template<iterator_traits<remove_cvref_t<_Ip>>>::value, + incrementable_traits<remove_cvref_t<_Ip>>, + iterator_traits<remove_cvref_t<_Ip>>>::difference_type; // [readable.traits] template<class> struct __cond_value_type {}; @@ -523,14 +539,21 @@ struct indirectly_readable_traits<_Tp> : __cond_value_type<typename _Tp::value_type> {}; +// Let `RI` be `remove_Âcvref_Ât<I>`. The type `iter_Âvalue_Ât<I>` denotes +// `indirectly_Âreadable_Âtraits<RI>::value_Âtype` if `iterator_Âtraits<RI>` names a specialization +// generated from the primary template, and `iterator_Âtraits<RI>::value_Âtype` otherwise. +template<class _Ip> +using iter_value_t = + typename conditional_t< + __is_primary_template<iterator_traits<remove_cvref_t<_Ip>>>::value, + indirectly_readable_traits<remove_cvref_t<_Ip>>, + iterator_traits<remove_cvref_t<_Ip>>>::value_type; + // [iterator.traits] template<__dereferenceable _Tp> using iter_reference_t = decltype(*declval<_Tp&>()); #endif // !defined(_LIBCPP_HAS_NO_RANGES) -template <class _Iter> -struct _LIBCPP_TEMPLATE_VIS iterator_traits; - struct _LIBCPP_TEMPLATE_VIS input_iterator_tag {}; struct _LIBCPP_TEMPLATE_VIS output_iterator_tag {}; struct _LIBCPP_TEMPLATE_VIS forward_iterator_tag : public input_iterator_tag {}; diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/iter_difference_t.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/iter_difference_t.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/iter_difference_t.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: gcc-10 + +// template<class T> +// using iter_difference_t; + +#include <iterator> + +#include <concepts> +#include <vector> + +template <class T, class Expected> +[[nodiscard]] constexpr bool check_iter_difference_t() { + constexpr bool result = std::same_as<std::iter_difference_t<T>, Expected>; + static_assert(std::same_as<std::iter_difference_t<T const>, Expected> == result); + static_assert(std::same_as<std::iter_difference_t<T volatile>, Expected> == result); + static_assert(std::same_as<std::iter_difference_t<T const volatile>, Expected> == result); + static_assert(std::same_as<std::iter_difference_t<T const&>, Expected> == result); + static_assert(std::same_as<std::iter_difference_t<T volatile&>, Expected> == result); + static_assert(std::same_as<std::iter_difference_t<T const volatile&>, Expected> == result); + static_assert(std::same_as<std::iter_difference_t<T const&&>, Expected> == result); + static_assert(std::same_as<std::iter_difference_t<T volatile&&>, Expected> == result); + static_assert(std::same_as<std::iter_difference_t<T const volatile&&>, Expected> == result); + + return result; +} + +static_assert(check_iter_difference_t<int, int>()); +static_assert(check_iter_difference_t<int*, std::ptrdiff_t>()); +static_assert(check_iter_difference_t<std::vector<int>::iterator, std::vector<int>::iterator::difference_type>()); + +struct int_subtraction { + friend int operator-(int_subtraction, int_subtraction) noexcept; +}; +static_assert(check_iter_difference_t<int_subtraction, int>()); + +// clang-format off +template <class T> +requires requires { typename std::iter_difference_t<T>; } +[[nodiscard]] constexpr bool check_no_iter_difference_t() { + return false; +} +// clang-format on + +template <class T> +[[nodiscard]] constexpr bool check_no_iter_difference_t() { + return true; +} + +static_assert(check_no_iter_difference_t<void>()); +static_assert(check_no_iter_difference_t<double>()); + +struct S {}; +static_assert(check_no_iter_difference_t<S>()); + +struct void_subtraction { + friend void operator-(void_subtraction, void_subtraction); +}; +static_assert(check_no_iter_difference_t<void_subtraction>()); + +int main(int, char**) { return 0; } diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/iter_value_t.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/iter_value_t.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/iter_value_t.pass.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: gcc-10 + +// template<class T> +// using iter_value_t; + +#include <iterator> + +#include <concepts> +#include <memory> +#include <vector> + +template <class T, class Expected> +[[nodiscard]] constexpr bool check_iter_value_t() { + constexpr bool result = std::same_as<std::iter_value_t<T>, Expected>; + static_assert(std::same_as<std::iter_value_t<T const>, Expected> == result); + static_assert(std::same_as<std::iter_value_t<T volatile>, Expected> == result); + static_assert(std::same_as<std::iter_value_t<T const volatile>, Expected> == result); + static_assert(std::same_as<std::iter_value_t<T const&>, Expected> == result); + static_assert(std::same_as<std::iter_value_t<T volatile&>, Expected> == result); + static_assert(std::same_as<std::iter_value_t<T const volatile&>, Expected> == result); + static_assert(std::same_as<std::iter_value_t<T const&&>, Expected> == result); + static_assert(std::same_as<std::iter_value_t<T volatile&&>, Expected> == result); + static_assert(std::same_as<std::iter_value_t<T const volatile&&>, Expected> == result); + + return result; +} + +static_assert(check_iter_value_t<int*, int>()); +static_assert(check_iter_value_t<int[], int>()); +static_assert(check_iter_value_t<int[10], int>()); +static_assert(check_iter_value_t<std::vector<int>::iterator, std::vector<int>::iterator::value_type>()); +static_assert(check_iter_value_t<std::shared_ptr<int>, std::shared_ptr<int>::element_type>()); + +struct both_members { + using value_type = double; + using element_type = double; +}; +static_assert(check_iter_value_t<both_members, double>()); + +// clang-format off +template <class T> +requires requires { typename std::iter_value_t<T>; } +[[nodiscard]] constexpr bool check_no_iter_value_t() { + return false; +} +// clang-format on + +template <class T> +[[nodiscard]] constexpr bool check_no_iter_value_t() { + return true; +} + +static_assert(check_no_iter_value_t<void>()); +static_assert(check_no_iter_value_t<double>()); + +struct S {}; +static_assert(check_no_iter_value_t<S>()); + +struct different_value_element_members { + using value_type = int; + using element_type = long; +}; +static_assert(check_no_iter_value_t<different_value_element_members>()); + +int main(int, char**) { return 0; }