[libcxx-commits] [libcxx] 6624fcb - [libc++] Add _ITER_CONCEPT and _ITER_TRAITS implementations from C++20

Eric Fiselier via libcxx-commits libcxx-commits at lists.llvm.org
Sat Nov 16 17:27:02 PST 2019


Author: Eric Fiselier
Date: 2019-11-16T20:26:35-05:00
New Revision: 6624fcba43be88fd357c74435a4d6462858c8fed

URL: https://github.com/llvm/llvm-project/commit/6624fcba43be88fd357c74435a4d6462858c8fed
DIFF: https://github.com/llvm/llvm-project/commit/6624fcba43be88fd357c74435a4d6462858c8fed.diff

LOG: [libc++] Add _ITER_CONCEPT and _ITER_TRAITS implementations from C++20

These traits are currently unused because we don't implement ranges.
However, their addition is part of ongoing work to allow libc++
to optimize on user-provided contiguous iterators.

Added: 
    libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_concepts.pass.cpp
    libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_traits.pass.cpp

Modified: 
    libcxx/include/iterator
    libcxx/include/type_traits

Removed: 
    


################################################################################
diff  --git a/libcxx/include/iterator b/libcxx/include/iterator
index 6a9a08241b64..13329e1473d3 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -434,6 +434,8 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
 #endif
 
 _LIBCPP_BEGIN_NAMESPACE_STD
+template <class _Iter>
+struct _LIBCPP_TEMPLATE_VIS iterator_traits;
 
 struct _LIBCPP_TEMPLATE_VIS input_iterator_tag {};
 struct _LIBCPP_TEMPLATE_VIS output_iterator_tag {};
@@ -446,6 +448,52 @@ struct _LIBCPP_TEMPLATE_VIS random_access_iterator_tag : public bidirectional_it
 struct _LIBCPP_TEMPLATE_VIS contiguous_iterator_tag: public random_access_iterator_tag { };
 #endif
 
+template <class _Iter>
+struct __iter_traits_cache {
+  using type = _If<
+    __is_primary_template<iterator_traits<_Iter> >::value,
+    _Iter,
+    iterator_traits<_Iter>
+  >;
+};
+template <class _Iter>
+using _ITER_TRAITS = typename __iter_traits_cache<_Iter>::type;
+
+struct __iter_concept_concept_test {
+  template <class _Iter>
+  using _Apply = typename _ITER_TRAITS<_Iter>::iterator_concept;
+};
+struct __iter_concept_category_test {
+  template <class _Iter>
+  using _Apply = typename _ITER_TRAITS<_Iter>::iterator_category;
+};
+struct __iter_concept_random_fallback {
+  template <class _Iter>
+  using _Apply = _EnableIf<
+                          __is_primary_template<iterator_traits<_Iter> >::value,
+                          random_access_iterator_tag
+                        >;
+};
+
+template <class _Iter, class _Tester> struct __test_iter_concept
+    : _IsValidExpansion<_Tester::template _Apply, _Iter>,
+      _Tester
+{
+};
+
+template <class _Iter>
+struct __iter_concept_cache {
+  using type = _Or<
+    __test_iter_concept<_Iter, __iter_concept_concept_test>,
+    __test_iter_concept<_Iter, __iter_concept_category_test>,
+    __test_iter_concept<_Iter, __iter_concept_random_fallback>
+  >;
+};
+
+template <class _Iter>
+using _ITER_CONCEPT = typename __iter_concept_cache<_Iter>::type::template _Apply<_Iter>;
+
+
 template <class _Tp>
 struct __has_iterator_typedefs
 {
@@ -505,7 +553,10 @@ struct __iterator_traits<_Iter, true>
 
 template <class _Iter>
 struct _LIBCPP_TEMPLATE_VIS iterator_traits
-    : __iterator_traits<_Iter, __has_iterator_typedefs<_Iter>::value> {};
+    : __iterator_traits<_Iter, __has_iterator_typedefs<_Iter>::value> {
+
+  using __primary_template = iterator_traits;
+};
 
 template<class _Tp>
 struct _LIBCPP_TEMPLATE_VIS iterator_traits<_Tp*>

diff  --git a/libcxx/include/type_traits b/libcxx/include/type_traits
index cd0aff96680a..c0c3934afccc 100644
--- a/libcxx/include/type_traits
+++ b/libcxx/include/type_traits
@@ -525,6 +525,7 @@ struct __identity { typedef _Tp type; };
 template <class _Tp, bool>
 struct _LIBCPP_TEMPLATE_VIS __dependent_type : public _Tp {};
 
+
 template <bool _Bp, class _If, class _Then>
     struct _LIBCPP_TEMPLATE_VIS conditional {typedef _If type;};
 template <class _If, class _Then>
@@ -570,6 +571,16 @@ using _IsNotSame = _BoolConstant<
 #endif
 >;
 
+
+template <class _Tp>
+using __test_for_primary_template = _EnableIf<
+    _IsSame<_Tp, typename _Tp::__primary_template>::value
+  >;
+template <class _Tp>
+using __is_primary_template = _IsValidExpansion<
+    __test_for_primary_template, _Tp
+  >;
+
 // addressof
 #ifndef _LIBCPP_HAS_NO_BUILTIN_ADDRESSOF
 

diff  --git a/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_concepts.pass.cpp b/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_concepts.pass.cpp
new file mode 100644
index 000000000000..1fbba0263cda
--- /dev/null
+++ b/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_concepts.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// ITER_TRAITS(I)
+
+// -- If the qualified-id ITER_TRAITS(I)::iterator_concept is valid and names a
+//   type, then ITER_CONCEPT(I) denotes that type.
+// (1.2) -- Otherwise, if the qualified-id ITER_TRAITS(I)::iterator_category is
+// valid and names a type, then ITER_CONCEPT(I) denotes that type.
+// (1.3) -- Otherwise, if iterator_traits<I> names a specialization generated
+// from the primary template, then ITER_CONCEPT(I) denotes
+// random_access_iterator_tag.
+// (1.4) -- Otherwise, ITER_CONCEPT(I) does not denote a type.
+
+#include "test_macros.h"
+
+#include <iterator>
+struct OtherTag : std::input_iterator_tag {};
+struct OtherTagTwo : std::output_iterator_tag {};
+struct MyIter : std::iterator<std::random_access_iterator_tag, char> {
+  using iterator_concept = int;
+};
+struct MyIter2 : std::iterator<OtherTag, char> {
+
+};
+struct MyIter3 {};
+
+struct Empty {};
+struct EmptyWithSpecial {};
+namespace std {
+template <>
+struct iterator_traits<MyIter3>
+    : std::iterator<OtherTagTwo, char> {};
+
+template <>
+struct iterator_traits<EmptyWithSpecial> {
+  // empty non-default.
+};
+} // namespace std
+
+int main(int, char**) {
+  // If the qualified-id ITER_TRAITS(I)::iterator_concept is valid and names a type,
+  // then ITER_CONCEPT(I) denotes that type.
+  {
+#if TEST_STD_VER > 17
+    ASSERT_SAME_TYPE(std::_ITER_CONCEPT<char*>, std::contiguous_iterator_tag);
+#endif
+    ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter>, int);
+  }
+  // Otherwise, if the qualified-id ITER_TRAITS(I)::iterator_category is valid
+  // and names a type, then ITER_CONCEPT(I) denotes that type.
+  {
+    ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter2>, OtherTag);
+    ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter3>, OtherTagTwo);
+  }
+  // FIXME - This requirement makes no sense to me. Why does an empty type with
+  // an empty default iterator_traits get a category of random?
+  {
+    ASSERT_SAME_TYPE(std::_ITER_CONCEPT<Empty>, std::random_access_iterator_tag);
+  }
+  {
+    static_assert(!std::_IsValidExpansion<std::_ITER_CONCEPT, EmptyWithSpecial>::value, "");
+  }
+
+  return 0;
+}

diff  --git a/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_traits.pass.cpp b/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_traits.pass.cpp
new file mode 100644
index 000000000000..1d72bb7fb607
--- /dev/null
+++ b/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_traits.pass.cpp
@@ -0,0 +1,47 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// ITER_TRAITS(I)
+
+// For a type I, let ITER_TRAITS(I) denote the type I if iterator_traits<I> names
+// a specialization generated from the primary template. Otherwise,
+// ITER_TRAITS(I) denotes iterator_traits<I>.
+
+#include "test_macros.h"
+
+#include <iterator>
+
+struct MyIter : std::iterator<std::random_access_iterator_tag, char> {};
+struct MyIter2 : std::iterator<std::random_access_iterator_tag, char> {};
+struct MyIter3 : std::iterator<std::random_access_iterator_tag, char> {};
+
+namespace std {
+template <>
+struct iterator_traits<MyIter>
+    : iterator_traits<std::iterator<std::random_access_iterator_tag, char> > {};
+template <>
+struct iterator_traits<MyIter2>
+    : std::iterator<std::random_access_iterator_tag, char> {};
+
+} // namespace std
+
+int main(int, char**) {
+  ASSERT_SAME_TYPE(std::_ITER_TRAITS<char*>, std::iterator_traits<char*>);
+  {
+    using ClassIter = std::reverse_iterator<char*>;
+    ASSERT_SAME_TYPE(std::_ITER_TRAITS<ClassIter>, ClassIter);
+    ASSERT_SAME_TYPE(std::_ITER_TRAITS<MyIter3>, MyIter3);
+  }
+  {
+    ASSERT_SAME_TYPE(std::_ITER_TRAITS<MyIter>, std::iterator_traits<MyIter>);
+    ASSERT_SAME_TYPE(std::_ITER_TRAITS<MyIter2>, std::iterator_traits<MyIter2>);
+  }
+  return 0;
+}


        


More information about the libcxx-commits mailing list