[libcxx-commits] [libcxx] fe31f11 - [libcxx] adds `std::incrementable_traits` to <iterator>
Christopher Di Bella via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Apr 12 22:02:50 PDT 2021
Author: Christopher Di Bella
Date: 2021-04-13T05:01:45Z
New Revision: fe31f11cc82135a9f612300a66fd6b80cc3245c3
URL: https://github.com/llvm/llvm-project/commit/fe31f11cc82135a9f612300a66fd6b80cc3245c3
DIFF: https://github.com/llvm/llvm-project/commit/fe31f11cc82135a9f612300a66fd6b80cc3245c3.diff
LOG: [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
Added:
libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/incrementable_traits.compile.pass.cpp
Modified:
libcxx/docs/Cxx2aStatusPaperStatus.csv
libcxx/include/__config
libcxx/include/iterator
Removed:
################################################################################
diff --git a/libcxx/docs/Cxx2aStatusPaperStatus.csv b/libcxx/docs/Cxx2aStatusPaperStatus.csv
index 696a16c09c191..2e36ab1e8d26b 100644
--- a/libcxx/docs/Cxx2aStatusPaperStatus.csv
+++ b/libcxx/docs/Cxx2aStatusPaperStatus.csv
@@ -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"
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 7b6a08c2202af..ebef56833cbe5 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -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
diff --git a/libcxx/include/iterator b/libcxx/include/iterator
index 54ea2aab1325f..c45a1e542f910 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -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
diff erence_type = ptr
diff _t;
+};
+
+template<class _Ip>
+struct incrementable_traits<const _Ip> : incrementable_traits<_Ip> {};
+
+template<class _Tp>
+concept __has_member_
diff erence_type = requires { typename _Tp::
diff erence_type; };
+
+template<__has_member_
diff erence_type _Tp>
+struct incrementable_traits<_Tp> {
+ using
diff erence_type = typename _Tp::
diff erence_type;
+};
+
+template<class _Tp>
+concept __has_integral_minus =
+ !__has_member_
diff erence_type<_Tp> &&
+ requires(const _Tp& __x, const _Tp& __y) {
+ { __x - __y } -> integral;
+ };
+
+template<__has_integral_minus _Tp>
+struct incrementable_traits<_Tp> {
+ using
diff erence_type = make_signed_t<decltype(declval<_Tp>() - declval<_Tp>())>;
+};
+
+// TODO(cjdb): add iter_
diff erence_t once iterator_traits is cleaned up.
+#endif // !defined(_LIBCPP_HAS_NO_RANGES)
+
template <class _Iter>
struct _LIBCPP_TEMPLATE_VIS iterator_traits;
diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/incrementable_traits.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/incrementable_traits.compile.pass.cpp
new file mode 100644
index 0000000000000..7316991a4987b
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/incrementable_traits.compile.pass.cpp
@@ -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_
diff erence_type = requires {
+ typename std::incrementable_traits<T>::
diff erence_type;
+};
+
+template <class T, class Expected>
+concept check_
diff erence_type_matches =
+ check_has_
diff erence_type<T> &&
+ std::same_as<typename std::incrementable_traits<T>::
diff erence_type, Expected>;
+// clang-format on
+
+template <class T, class Expected>
+[[nodiscard]] constexpr bool check_incrementable_traits() noexcept {
+ constexpr bool result = check_
diff erence_type_matches<T, Expected>;
+ static_assert(check_
diff erence_type_matches<T const, Expected> == result);
+ return result;
+}
+
+static_assert(check_incrementable_traits<float*, std::ptr
diff _t>());
+static_assert(check_incrementable_traits<float const*, std::ptr
diff _t>());
+static_assert(check_incrementable_traits<float volatile*, std::ptr
diff _t>());
+static_assert(
+ check_incrementable_traits<float const volatile*, std::ptr
diff _t>());
+static_assert(check_incrementable_traits<float**, std::ptr
diff _t>());
+
+static_assert(check_incrementable_traits<int[], std::ptr
diff _t>());
+static_assert(check_incrementable_traits<int[10], std::ptr
diff _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::ptr
diff _t>());
+
+struct integral_
diff erence_type {
+ using
diff erence_type = int;
+};
+static_assert(check_incrementable_traits<integral_
diff erence_type, int>());
+
+struct non_integral_
diff erence_type {
+ using
diff erence_type = void;
+};
+static_assert(check_incrementable_traits<non_integral_
diff erence_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
diff erence_type = int;
+};
+} // namespace std
+static_assert(
+ check_incrementable_traits<specialised_incrementable_traits, int>());
+
+static_assert(!check_has_
diff erence_type<void>);
+static_assert(!check_has_
diff erence_type<float>);
+static_assert(!check_has_
diff erence_type<double>);
+static_assert(!check_has_
diff erence_type<long double>);
+static_assert(!check_has_
diff erence_type<float&>);
+static_assert(!check_has_
diff erence_type<float const&>);
+
+static_assert(!check_has_
diff erence_type<void*>);
+static_assert(!check_has_
diff erence_type<std::nullptr_t>);
+static_assert(!check_has_
diff erence_type<int()>);
+static_assert(!check_has_
diff erence_type<int() noexcept>);
+static_assert(!check_has_
diff erence_type<int (*)()>);
+static_assert(!check_has_
diff erence_type<int (*)() noexcept>);
+static_assert(!check_has_
diff erence_type<int (&)()>);
+static_assert(!check_has_
diff erence_type<int (&)() noexcept>);
+
+#define TEST_POINTER_TO_MEMBER_FUNCTION(type, cv_qualifier) \
+ static_assert(!check_has_
diff erence_type<int (type::*)() cv_qualifier>); \
+ static_assert( \
+ !check_has_
diff erence_type<int (type::*)() cv_qualifier noexcept>); \
+ static_assert(!check_has_
diff erence_type<int (type::*)() cv_qualifier&>); \
+ static_assert( \
+ !check_has_
diff erence_type<int (type::*)() cv_qualifier & noexcept>); \
+ static_assert(!check_has_
diff erence_type<int (type::*)() cv_qualifier&&>); \
+ static_assert(!check_has_
diff erence_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_
diff erence_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_
diff erence_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&&);
More information about the libcxx-commits
mailing list