[libcxx] adds `iter_difference_t` and `iter_value_t`
authorChristopher Di Bella <cjdb@google.com>
Tue, 20 Apr 2021 18:56:08 +0000 (18:56 +0000)
committerChristopher Di Bella <cjdb@google.com>
Tue, 20 Apr 2021 19:02:07 +0000 (19:02 +0000)
Implements parts of:
    * P0896R4 The One Ranges Proposal

Depends on D99855.

Reviewed By: ldionne, #libc

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

libcxx/docs/OneRangesProposalStatus.csv
libcxx/include/__iterator/incrementable_traits.h
libcxx/include/__iterator/readable_traits.h
libcxx/include/iterator
libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/iter_difference_t.pass.cpp [new file with mode: 0644]
libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/iter_value_t.pass.cpp [new file with mode: 0644]

index 645047d..822b09c 100644 (file)
@@ -3,13 +3,13 @@ Section,Description,Dependencies,Assignee,Patch,Complete
 [tuple.helper],Update <tuple> includes.,,,,
 [function.objects],"Comparison functions: equal_to, less, etc.",[concepts],Zoe Carver,`D100429 <https://reviews.llvm.org/D100429>`_,
 [memory.syn],Add specializations for uninitialized_* and destroy_*. ,"[concepts], [readable.traits]: iter_value_t",,,
-[readable.traits]: indirectly_readable_traits,indirectly_readable_traits only. ,[concepts],Christopher Di Bella,`D99461 <https://reviews.llvm.org/D99461>`_,
-[iterator.traits],Mainly updates to iterator_traits.,"[readable.traits]: indirectly_readable_traits, [concepts]",Christopher Di Bella,"`D99854 <https://reviews.llvm.org/D99854>`_, `D99855 <https://reviews.llvm.org/D99855>`_",
-[readable.traits]: iter_value_t,Finish implementing readable.traits.,"[readable.traits]: indirectly_readable_traits, [concepts], [iterator.traits]",Christopher Di Bella,`D99863 <https://reviews.llvm.org/D99863>`_,
+[readable.traits]: indirectly_readable_traits,indirectly_readable_traits only. ,[concepts],Christopher Di Bella,`D99461 <https://reviews.llvm.org/D99461>`_,
+[iterator.traits],Mainly updates to iterator_traits.,"[readable.traits]: indirectly_readable_traits, [concepts]",Christopher Di Bella,"`D99854 <https://reviews.llvm.org/D99854>`_, `D99855 <https://reviews.llvm.org/D99855>`_",
+[readable.traits]: iter_value_t,Finish implementing readable.traits.,"[readable.traits]: indirectly_readable_traits, [concepts], [iterator.traits]",Christopher Di Bella,`D99863 <https://reviews.llvm.org/D99863>`_,
 [specialized.algorithms],NOT FINISHED,NOT FINISHED,,,
 [strings],Adds begin/end and updates const_iterator.,[iterator.concepts],,,
 [views.span],Same as [strings],[iterator.concepts],,,
-[incrementable.traits],,[concepts],Christopher Di Bella,"`D99141 <https://reviews.llvm.org/D99141>`_, `D99863 <https://reviews.llvm.org/D99863>`_",1/2
+[incrementable.traits],,[concepts],Christopher Di Bella,"`D99141 <https://reviews.llvm.org/D99141>`_, `D99863 <https://reviews.llvm.org/D99863>`_",
 [iterator.cust.move],Implement iter_move.,,Christopher Di Bella,`D99873 <https://reviews.llvm.org/D99873>`_,
 [iterator.cust.swap],Implement iter_swap.,"[concepts], [readable.traits]: iter_value_t",,,
 [iterator.concepts],"indirectly_readable, indirectly_writable, weakly_incrementable, incrementable, input_or_output_iterator, sentinel_for, sized_sentinel_for, input_iterator, output_iterator, forward_iterator, bidirectional_iterator, random_access_iterator, and contiguous_iterator.","[concepts], [readable.traits]: iter_value_t, [iterator.traits]",Christopher Di Bella,"indirectly_readable: `D100073 <https://reviews.llvm.org/D100073>`_
index 2a7dff8..2acabba 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <__config>
 #include <__iterator/concepts.h>
+#include <type_traits>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
@@ -56,6 +57,17 @@ struct incrementable_traits<_Tp> {
   using difference_type = make_signed_t<decltype(declval<_Tp>() - declval<_Tp>())>;
 };
 
+template <class>
+struct iterator_traits;
+
+// 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<RI>::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;
+
 #endif // !defined(_LIBCPP_HAS_NO_RANGES)
 
 _LIBCPP_END_NAMESPACE_STD
index c2a78e7..8566f86 100644 (file)
@@ -70,6 +70,17 @@ requires __has_member_element_type<_Tp> &&
 struct indirectly_readable_traits<_Tp>
   : __cond_value_type<typename _Tp::value_type> {};
 
+template <class>
+struct iterator_traits;
+
+// 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;
+
 #endif // !defined(_LIBCPP_HAS_NO_RANGES)
 
 _LIBCPP_END_NAMESPACE_STD
index a1e492a..2785fec 100644 (file)
 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;
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 (file)
index 0000000..05a0690
--- /dev/null
@@ -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 (file)
index 0000000..8b459b2
--- /dev/null
@@ -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; }