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

Implements parts of:
    - P0896R4 The One Ranges Proposal

Depends on D99041

Differential Revision: https://reviews.llvm.org/D99141
This commit is contained in:
Christopher Di Bella 2021-03-23 03:55:52 +00:00
parent 7dbb4274ef
commit fe31f11cc8
4 changed files with 306 additions and 1 deletions

View File

@ -61,7 +61,7 @@
"`P0608R3 <https://wg21.link/P0608R3>`__","LWG","A sane variant converting constructor","San Diego","|Complete|","9.0"
"`P0655R1 <https://wg21.link/P0655R1>`__","LWG","visit<R>: Explicit Return Type for visit","San Diego","|Complete|","12.0"
"`P0771R1 <https://wg21.link/P0771R1>`__","LWG","std::function move constructor should be noexcept","San Diego","|Complete|","6.0"
"`P0896R4 <https://wg21.link/P0896R4>`__","LWG","The One Ranges Proposal","San Diego","* *",""
"`P0896R4 <https://wg21.link/P0896R4>`__","LWG","The One Ranges Proposal","San Diego","|In Progress|",""
"`P0899R1 <https://wg21.link/P0899R1>`__","LWG","P0899R1 - LWG 3016 is not a defect","San Diego","|Nothing To Do|",""
"`P0919R3 <https://wg21.link/P0919R3>`__","LWG","Heterogeneous lookup for unordered containers","San Diego","|Complete|","12.0"
"`P0972R0 <https://wg21.link/P0972R0>`__","LWG","<chrono> ``zero()``\ , ``min()``\ , and ``max()``\ should be noexcept","San Diego","|Complete|","8.0"

1 Paper # Group Paper Name Meeting Status First released version
61 `P0608R3 <https://wg21.link/P0608R3>`__ LWG A sane variant converting constructor San Diego |Complete| 9.0
62 `P0655R1 <https://wg21.link/P0655R1>`__ LWG visit<R>: Explicit Return Type for visit San Diego |Complete| 12.0
63 `P0771R1 <https://wg21.link/P0771R1>`__ LWG std::function move constructor should be noexcept San Diego |Complete| 6.0
64 `P0896R4 <https://wg21.link/P0896R4>`__ LWG The One Ranges Proposal San Diego * * |In Progress|
65 `P0899R1 <https://wg21.link/P0899R1>`__ LWG P0899R1 - LWG 3016 is not a defect San Diego |Nothing To Do|
66 `P0919R3 <https://wg21.link/P0919R3>`__ LWG Heterogeneous lookup for unordered containers San Diego |Complete| 12.0
67 `P0972R0 <https://wg21.link/P0972R0>`__ LWG <chrono> ``zero()``\ , ``min()``\ , and ``max()``\ should be noexcept San Diego |Complete| 8.0

View File

@ -848,6 +848,10 @@ typedef unsigned int char32_t;
#define _LIBCPP_HAS_NO_CONCEPTS
#endif
#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_HAS_NO_CONCEPTS)
#define _LIBCPP_HAS_NO_RANGES
#endif
#ifdef _LIBCPP_CXX03_LANG
# define _LIBCPP_DEFAULT {}
#else

View File

@ -13,8 +13,11 @@
/*
iterator synopsis
#include <concepts>
namespace std
{
template<class> struct incrementable_traits; // since C++20
template<class Iterator>
struct iterator_traits
@ -425,6 +428,7 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
#include <__memory/base.h>
#include <__memory/pointer_traits.h>
#include <version>
#include <concepts>
#include <__debug>
@ -433,6 +437,43 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#if !defined(_LIBCPP_HAS_NO_RANGES)
// [incrementable.traits]
template<class> struct incrementable_traits {};
template<class _Tp>
requires is_object_v<_Tp>
struct incrementable_traits<_Tp*> {
using difference_type = ptrdiff_t;
};
template<class _Ip>
struct incrementable_traits<const _Ip> : incrementable_traits<_Ip> {};
template<class _Tp>
concept __has_member_difference_type = requires { typename _Tp::difference_type; };
template<__has_member_difference_type _Tp>
struct incrementable_traits<_Tp> {
using difference_type = typename _Tp::difference_type;
};
template<class _Tp>
concept __has_integral_minus =
!__has_member_difference_type<_Tp> &&
requires(const _Tp& __x, const _Tp& __y) {
{ __x - __y } -> integral;
};
template<__has_integral_minus _Tp>
struct incrementable_traits<_Tp> {
using difference_type = make_signed_t<decltype(declval<_Tp>() - declval<_Tp>())>;
};
// TODO(cjdb): add iter_difference_t once iterator_traits is cleaned up.
#endif // !defined(_LIBCPP_HAS_NO_RANGES)
template <class _Iter>
struct _LIBCPP_TEMPLATE_VIS iterator_traits;

View File

@ -0,0 +1,260 @@
//===----------------------------------------------------------------------===//
//
// 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>
// struct incrementable_traits;
#include <iterator>
#include <concepts>
#include "test_macros.h"
// clang-format off
template <class T>
concept check_has_difference_type = requires {
typename std::incrementable_traits<T>::difference_type;
};
template <class T, class Expected>
concept check_difference_type_matches =
check_has_difference_type<T> &&
std::same_as<typename std::incrementable_traits<T>::difference_type, Expected>;
// clang-format on
template <class T, class Expected>
[[nodiscard]] constexpr bool check_incrementable_traits() noexcept {
constexpr bool result = check_difference_type_matches<T, Expected>;
static_assert(check_difference_type_matches<T const, Expected> == result);
return result;
}
static_assert(check_incrementable_traits<float*, std::ptrdiff_t>());
static_assert(check_incrementable_traits<float const*, std::ptrdiff_t>());
static_assert(check_incrementable_traits<float volatile*, std::ptrdiff_t>());
static_assert(
check_incrementable_traits<float const volatile*, std::ptrdiff_t>());
static_assert(check_incrementable_traits<float**, std::ptrdiff_t>());
static_assert(check_incrementable_traits<int[], std::ptrdiff_t>());
static_assert(check_incrementable_traits<int[10], std::ptrdiff_t>());
static_assert(check_incrementable_traits<char, int>());
static_assert(check_incrementable_traits<signed char, int>());
static_assert(check_incrementable_traits<unsigned char, int>());
static_assert(check_incrementable_traits<short, int>());
static_assert(check_incrementable_traits<unsigned short, int>());
static_assert(check_incrementable_traits<int, int>());
static_assert(check_incrementable_traits<unsigned int, int>());
static_assert(check_incrementable_traits<long, long>());
static_assert(check_incrementable_traits<unsigned long, long>());
static_assert(check_incrementable_traits<long long, long long>());
static_assert(check_incrementable_traits<unsigned long long, long long>());
static_assert(check_incrementable_traits<int&, int>());
static_assert(check_incrementable_traits<int const&, int>());
static_assert(check_incrementable_traits<int volatile&, int>());
static_assert(check_incrementable_traits<int const volatile&, int>());
static_assert(check_incrementable_traits<int&&, int>());
static_assert(check_incrementable_traits<int const&&, int>());
static_assert(check_incrementable_traits<int volatile&&, int>());
static_assert(check_incrementable_traits<int const volatile&&, int>());
static_assert(check_incrementable_traits<int volatile, int>());
static_assert(check_incrementable_traits<int* volatile, std::ptrdiff_t>());
struct integral_difference_type {
using difference_type = int;
};
static_assert(check_incrementable_traits<integral_difference_type, int>());
struct non_integral_difference_type {
using difference_type = void;
};
static_assert(check_incrementable_traits<non_integral_difference_type, void>());
struct int_subtraction {
friend int operator-(int_subtraction, int_subtraction) noexcept;
};
static_assert(check_incrementable_traits<int_subtraction, int>());
static_assert(!check_incrementable_traits<int_subtraction volatile&, int>());
static_assert(
!check_incrementable_traits<int_subtraction const volatile&, int>());
struct char_subtraction {
friend char operator-(char_subtraction, char_subtraction) noexcept;
};
static_assert(check_incrementable_traits<char_subtraction, signed char>());
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<unsigned_int_subtraction_with_cv, int>());
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<specialised_incrementable_traits> {
using difference_type = int;
};
} // namespace std
static_assert(
check_incrementable_traits<specialised_incrementable_traits, int>());
static_assert(!check_has_difference_type<void>);
static_assert(!check_has_difference_type<float>);
static_assert(!check_has_difference_type<double>);
static_assert(!check_has_difference_type<long double>);
static_assert(!check_has_difference_type<float&>);
static_assert(!check_has_difference_type<float const&>);
static_assert(!check_has_difference_type<void*>);
static_assert(!check_has_difference_type<std::nullptr_t>);
static_assert(!check_has_difference_type<int()>);
static_assert(!check_has_difference_type<int() noexcept>);
static_assert(!check_has_difference_type<int (*)()>);
static_assert(!check_has_difference_type<int (*)() noexcept>);
static_assert(!check_has_difference_type<int (&)()>);
static_assert(!check_has_difference_type<int (&)() noexcept>);
#define TEST_POINTER_TO_MEMBER_FUNCTION(type, cv_qualifier) \
static_assert(!check_has_difference_type<int (type::*)() cv_qualifier>); \
static_assert( \
!check_has_difference_type<int (type::*)() cv_qualifier noexcept>); \
static_assert(!check_has_difference_type<int (type::*)() cv_qualifier&>); \
static_assert( \
!check_has_difference_type<int (type::*)() cv_qualifier & noexcept>); \
static_assert(!check_has_difference_type<int (type::*)() cv_qualifier&&>); \
static_assert(!check_has_difference_type < int (type::*)() \
cv_qualifier&& noexcept >); \
/**/
struct empty {};
#define NO_QUALIFIER
TEST_POINTER_TO_MEMBER_FUNCTION(empty, NO_QUALIFIER);
TEST_POINTER_TO_MEMBER_FUNCTION(empty, const);
TEST_POINTER_TO_MEMBER_FUNCTION(empty, volatile);
TEST_POINTER_TO_MEMBER_FUNCTION(empty, const volatile);
struct void_subtraction {
friend void operator-(void_subtraction, void_subtraction) noexcept;
};
static_assert(!check_has_difference_type<void_subtraction>);
#define TEST_NOT_DIFFERENCE_TYPE(qual1, qual2) \
struct TEST_CONCAT(test_subtraction_, __LINE__) { \
friend int operator-(TEST_CONCAT(test_subtraction_, __LINE__) qual1, \
TEST_CONCAT(test_subtraction_, __LINE__) qual2); \
}; \
static_assert(!check_has_difference_type<TEST_CONCAT(test_subtraction_, \
__LINE__)>) /**/
TEST_NOT_DIFFERENCE_TYPE(&, &);
TEST_NOT_DIFFERENCE_TYPE(&, const&);
TEST_NOT_DIFFERENCE_TYPE(&, volatile&);
TEST_NOT_DIFFERENCE_TYPE(&, const volatile&);
TEST_NOT_DIFFERENCE_TYPE(&, &&);
TEST_NOT_DIFFERENCE_TYPE(&, const&&);
TEST_NOT_DIFFERENCE_TYPE(&, volatile&&);
TEST_NOT_DIFFERENCE_TYPE(&, const volatile&&);
TEST_NOT_DIFFERENCE_TYPE(const&, &);
// TEST_NOT_DIFFERENCE_TYPE(const&, const&); // == true
TEST_NOT_DIFFERENCE_TYPE(const&, volatile&);
// TEST_NOT_DIFFERENCE_TYPE(const&, const volatile&); // invalid
TEST_NOT_DIFFERENCE_TYPE(const&, &&);
TEST_NOT_DIFFERENCE_TYPE(const&, const&&);
TEST_NOT_DIFFERENCE_TYPE(const&, volatile&&);
TEST_NOT_DIFFERENCE_TYPE(const&, const volatile&&);
TEST_NOT_DIFFERENCE_TYPE(volatile&, &);
TEST_NOT_DIFFERENCE_TYPE(volatile&, const&);
TEST_NOT_DIFFERENCE_TYPE(volatile&, volatile&);
TEST_NOT_DIFFERENCE_TYPE(volatile&, const volatile&);
TEST_NOT_DIFFERENCE_TYPE(volatile&, &&);
TEST_NOT_DIFFERENCE_TYPE(volatile&, const&&);
TEST_NOT_DIFFERENCE_TYPE(volatile&, volatile&&);
TEST_NOT_DIFFERENCE_TYPE(volatile&, const volatile&&);
TEST_NOT_DIFFERENCE_TYPE(const volatile&, &);
// TEST_NOT_DIFFERENCE_TYPE(const volatile&, const&); // invalid
TEST_NOT_DIFFERENCE_TYPE(const volatile&, volatile&);
// TEST_NOT_DIFFERENCE_TYPE(const volatile&, const volatile&); // invalid
TEST_NOT_DIFFERENCE_TYPE(const volatile&, &&);
TEST_NOT_DIFFERENCE_TYPE(const volatile&, const&&);
TEST_NOT_DIFFERENCE_TYPE(const volatile&, volatile&&);
TEST_NOT_DIFFERENCE_TYPE(const volatile&, const volatile&&);
TEST_NOT_DIFFERENCE_TYPE(&&, &);
TEST_NOT_DIFFERENCE_TYPE(&&, const&);
TEST_NOT_DIFFERENCE_TYPE(&&, volatile&);
TEST_NOT_DIFFERENCE_TYPE(&&, const volatile&);
TEST_NOT_DIFFERENCE_TYPE(&&, &&);
TEST_NOT_DIFFERENCE_TYPE(&&, const&&);
TEST_NOT_DIFFERENCE_TYPE(&&, volatile&&);
TEST_NOT_DIFFERENCE_TYPE(&&, const volatile&&);
TEST_NOT_DIFFERENCE_TYPE(const&&, &);
TEST_NOT_DIFFERENCE_TYPE(const&&, const&);
TEST_NOT_DIFFERENCE_TYPE(const&&, volatile&);
TEST_NOT_DIFFERENCE_TYPE(const&&, const volatile&);
TEST_NOT_DIFFERENCE_TYPE(const&&, &&);
TEST_NOT_DIFFERENCE_TYPE(const&&, const&&);
TEST_NOT_DIFFERENCE_TYPE(const&&, volatile&&);
TEST_NOT_DIFFERENCE_TYPE(const&&, const volatile&&);
TEST_NOT_DIFFERENCE_TYPE(volatile&&, &);
TEST_NOT_DIFFERENCE_TYPE(volatile&&, const&);
TEST_NOT_DIFFERENCE_TYPE(volatile&&, volatile&);
TEST_NOT_DIFFERENCE_TYPE(volatile&&, const volatile&);
TEST_NOT_DIFFERENCE_TYPE(volatile&&, &&);
TEST_NOT_DIFFERENCE_TYPE(volatile&&, const&&);
TEST_NOT_DIFFERENCE_TYPE(volatile&&, volatile&&);
TEST_NOT_DIFFERENCE_TYPE(volatile&&, const volatile&&);
TEST_NOT_DIFFERENCE_TYPE(const volatile&&, &);
TEST_NOT_DIFFERENCE_TYPE(const volatile&&, const&);
TEST_NOT_DIFFERENCE_TYPE(const volatile&&, volatile&);
TEST_NOT_DIFFERENCE_TYPE(const volatile&&, const volatile&);
TEST_NOT_DIFFERENCE_TYPE(const volatile&&, &&);
TEST_NOT_DIFFERENCE_TYPE(const volatile&&, const&&);
TEST_NOT_DIFFERENCE_TYPE(const volatile&&, volatile&&);
TEST_NOT_DIFFERENCE_TYPE(const volatile&&, const volatile&&);
TEST_NOT_DIFFERENCE_TYPE(&, NO_QUALIFIER);
// TEST_NOT_DIFFERENCE_TYPE(const&, NO_QUALIFIER); // == true
TEST_NOT_DIFFERENCE_TYPE(volatile&, NO_QUALIFIER);
// TEST_NOT_DIFFERENCE_TYPE(const volatile&, NO_QUALIFIER); // invalid
TEST_NOT_DIFFERENCE_TYPE(&&, NO_QUALIFIER);
TEST_NOT_DIFFERENCE_TYPE(const&&, NO_QUALIFIER);
TEST_NOT_DIFFERENCE_TYPE(volatile&&, NO_QUALIFIER);
TEST_NOT_DIFFERENCE_TYPE(const volatile&&, NO_QUALIFIER);
TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, &);
// TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, const&); // == true
TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, volatile&);
// TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, const volatile&); // invalid
TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, &&);
TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, const&&);
TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, volatile&&);
TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, const volatile&&);