[libcxx] adds `std::incrementable_traits` to <iterator>
authorChristopher Di Bella <cjdb@google.com>
Tue, 23 Mar 2021 03:55:52 +0000 (03:55 +0000)
committerChristopher Di Bella <cjdb@google.com>
Tue, 13 Apr 2021 05:01:45 +0000 (05:01 +0000)
Implements parts of:
    - P0896R4 The One Ranges Proposal

Depends on D99041

Differential Revision: https://reviews.llvm.org/D99141

libcxx/docs/Cxx2aStatusPaperStatus.csv
libcxx/include/__config
libcxx/include/iterator
libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/incrementable_traits.compile.pass.cpp [new file with mode: 0644]

index 696a16c..2e36ab1 100644 (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"
index 7b6a08c..ebef568 100644 (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
index 54ea2aa..c45a1e5 100644 (file)
 /*
     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;
 
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 (file)
index 0000000..7316991
--- /dev/null
@@ -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&&);