diff --git a/libcxx/docs/Cxx2aStatusPaperStatus.csv b/libcxx/docs/Cxx2aStatusPaperStatus.csv --- a/libcxx/docs/Cxx2aStatusPaperStatus.csv +++ b/libcxx/docs/Cxx2aStatusPaperStatus.csv @@ -61,7 +61,7 @@ "`P0608R3 `__","LWG","A sane variant converting constructor","San Diego","|Complete|","9.0" "`P0655R1 `__","LWG","visit: Explicit Return Type for visit","San Diego","|Complete|","12.0" "`P0771R1 `__","LWG","std::function move constructor should be noexcept","San Diego","|Complete|","6.0" -"`P0896R4 `__","LWG","The One Ranges Proposal","San Diego","* *","" +"`P0896R4 `__","LWG","The One Ranges Proposal","San Diego","|In Progress|","" "`P0899R1 `__","LWG","P0899R1 - LWG 3016 is not a defect","San Diego","|Nothing To Do|","" "`P0919R3 `__","LWG","Heterogeneous lookup for unordered containers","San Diego","|Complete|","12.0" "`P0972R0 `__","LWG"," ``zero()``\ , ``min()``\ , and ``max()``\ should be noexcept","San Diego","|Complete|","8.0" diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -13,8 +13,11 @@ /* iterator synopsis +#include + namespace std { +template struct incrementable_traits; // since C++20 template struct iterator_traits @@ -423,6 +426,7 @@ #include <__memory/base.h> #include <__memory/pointer_traits.h> #include +#include #include <__debug> @@ -431,6 +435,43 @@ #endif _LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 +// [incrementable.traits] +template struct incrementable_traits {}; + +template +requires is_object_v<_Tp> +struct incrementable_traits<_Tp*> { + using difference_type = ptrdiff_t; +}; + +template +struct incrementable_traits : incrementable_traits<_Ip> {}; + +template +concept __has_member_difference_type = requires { typename _Tp::difference_type; }; + +template +concept __has_integral_minus = + !__has_member_difference_type<_Tp> && + requires(const _Tp& __x, const _Tp& __y) { + { __x - __y } -> integral; + }; + +template<__has_member_difference_type _Tp> +struct incrementable_traits<_Tp> { + using difference_type = typename _Tp::difference_type; +}; + +template<__has_integral_minus _Tp> +struct incrementable_traits<_Tp> { + using difference_type = make_signed_t() - declval<_Tp>())>; +}; + +// TODO(cjdb): add iter_difference_t once iterator_traits is cleaned up. +#endif // _LIBCPP_STD_VER > 17 + template struct _LIBCPP_TEMPLATE_VIS iterator_traits; diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/incrementable_traits.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/incrementable_traits.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/incrementable_traits.pass.cpp @@ -0,0 +1,224 @@ +//===----------------------------------------------------------------------===// +// +// 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 incrementable_traits; + +#include + +#include + +// clang-format off +template +concept incrementable_traits_has_difference_type = requires { + typename std::incrementable_traits::difference_type; +}; + +template +concept difference_type_matches = + incrementable_traits_has_difference_type && + std::same_as::difference_type, Expected>; +// clang-format on + +template +[[nodiscard]] constexpr bool check_incrementable_traits() noexcept { + constexpr bool result = difference_type_matches; + static_assert(difference_type_matches == result); + return result; +} + +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert( + check_incrementable_traits()); +static_assert(check_incrementable_traits()); + +static_assert(check_incrementable_traits()); + +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); + +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); + +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); + +struct integral_difference_type { + using difference_type = int; +}; +static_assert(check_incrementable_traits()); + +struct non_integral_difference_type { + using difference_type = void; +}; +static_assert(check_incrementable_traits()); + +struct int_subtraction { + friend int operator-(int_subtraction, int_subtraction) noexcept; +}; +static_assert(check_incrementable_traits()); +static_assert(!check_incrementable_traits()); +static_assert( + !check_incrementable_traits()); + +struct char_subtraction { + friend char operator-(char_subtraction, char_subtraction) noexcept; +}; +static_assert(check_incrementable_traits()); + +struct unsigned_int_subtraction_with_cv { + friend unsigned int + operator-(unsigned_int_subtraction_with_cv const&, + unsigned_int_subtraction_with_cv const&) noexcept; + friend unsigned int + operator-(unsigned_int_subtraction_with_cv const volatile&, + unsigned_int_subtraction_with_cv const volatile&) noexcept; +}; +static_assert( + check_incrementable_traits()); +static_assert(check_incrementable_traits< + unsigned_int_subtraction_with_cv volatile&, int>()); +static_assert(check_incrementable_traits< + unsigned_int_subtraction_with_cv const volatile&, int>()); + +struct specialised_incrementable_traits {}; +namespace std { +template <> +struct incrementable_traits { + using difference_type = int; +}; +} // namespace std +static_assert( + check_incrementable_traits()); + +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); + +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); + +struct empty {}; +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); +static_assert( + !incrementable_traits_has_difference_type); +static_assert( + !incrementable_traits_has_difference_type); +static_assert( + !incrementable_traits_has_difference_type); +static_assert( + !incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type< + int (empty::*)() volatile noexcept>); +static_assert( + !incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type< + int (empty::*)() const volatile noexcept>); +static_assert(!incrementable_traits_has_difference_type); +static_assert( + !incrementable_traits_has_difference_type); +static_assert( + !incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type); +static_assert( + !incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type< + int (empty::*)() volatile & noexcept>); +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type< + int (empty::*)() const volatile & noexcept>); +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type < int (empty::*)() && + noexcept >); +static_assert( + !incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type < + int (empty::*)() const&& noexcept >); +static_assert( + !incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type < + int (empty::*)() volatile&& noexcept >); +static_assert(!incrementable_traits_has_difference_type); +static_assert(!incrementable_traits_has_difference_type < + int (empty::*)() const volatile&& noexcept >); + +struct void_subtraction { + friend void operator-(void_subtraction, void_subtraction) noexcept; +}; +static_assert(!incrementable_traits_has_difference_type); + +struct rvalue_ref_subtraction_can_throw { + friend int operator-(rvalue_ref_subtraction_can_throw&&, + rvalue_ref_subtraction_can_throw&&); +}; +static_assert(!incrementable_traits_has_difference_type< + rvalue_ref_subtraction_can_throw>); + +struct rvalue_ref_subtraction { + friend int operator-(rvalue_ref_subtraction&&, + rvalue_ref_subtraction&&) noexcept; +}; +static_assert( + !incrementable_traits_has_difference_type); + +struct rvalue_ref_const_subtraction { + friend int operator-(rvalue_ref_const_subtraction const&&, + rvalue_ref_const_subtraction const&&) noexcept; +}; +static_assert(!incrementable_traits_has_difference_type< + rvalue_ref_const_subtraction const>); + +struct rvalue_ref_volatile_subtraction { + friend int operator-(rvalue_ref_volatile_subtraction volatile&&, + rvalue_ref_volatile_subtraction volatile&&) noexcept; +}; +static_assert(!incrementable_traits_has_difference_type< + rvalue_ref_volatile_subtraction volatile>); + +struct rvalue_ref_cv_subtraction { + friend int operator-(rvalue_ref_cv_subtraction const volatile&&, + rvalue_ref_cv_subtraction const volatile&&) noexcept; +}; +static_assert(!incrementable_traits_has_difference_type< + rvalue_ref_cv_subtraction const volatile>); + +int main(int, char**) { return 0; }