From: Eric Fiselier Date: Sun, 17 Nov 2019 01:24:39 +0000 (-0500) Subject: [libc++] Add _ITER_CONCEPT and _ITER_TRAITS implementations from C++20 X-Git-Tag: llvmorg-11-init~4098 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6624fcba43be88fd357c74435a4d6462858c8fed;p=platform%2Fupstream%2Fllvm.git [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. --- diff --git a/libcxx/include/iterator b/libcxx/include/iterator index 6a9a082..13329e1 100644 --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -434,6 +434,8 @@ template constexpr const E* data(initializer_list il) noexcept; #endif _LIBCPP_BEGIN_NAMESPACE_STD +template +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 +struct __iter_traits_cache { + using type = _If< + __is_primary_template >::value, + _Iter, + iterator_traits<_Iter> + >; +}; +template +using _ITER_TRAITS = typename __iter_traits_cache<_Iter>::type; + +struct __iter_concept_concept_test { + template + using _Apply = typename _ITER_TRAITS<_Iter>::iterator_concept; +}; +struct __iter_concept_category_test { + template + using _Apply = typename _ITER_TRAITS<_Iter>::iterator_category; +}; +struct __iter_concept_random_fallback { + template + using _Apply = _EnableIf< + __is_primary_template >::value, + random_access_iterator_tag + >; +}; + +template struct __test_iter_concept + : _IsValidExpansion<_Tester::template _Apply, _Iter>, + _Tester +{ +}; + +template +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 +using _ITER_CONCEPT = typename __iter_concept_cache<_Iter>::type::template _Apply<_Iter>; + + template struct __has_iterator_typedefs { @@ -505,7 +553,10 @@ struct __iterator_traits<_Iter, true> template 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 struct _LIBCPP_TEMPLATE_VIS iterator_traits<_Tp*> diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits index cd0aff9..c0c3934 100644 --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -525,6 +525,7 @@ struct __identity { typedef _Tp type; }; template struct _LIBCPP_TEMPLATE_VIS __dependent_type : public _Tp {}; + template struct _LIBCPP_TEMPLATE_VIS conditional {typedef _If type;}; template @@ -570,6 +571,16 @@ using _IsNotSame = _BoolConstant< #endif >; + +template +using __test_for_primary_template = _EnableIf< + _IsSame<_Tp, typename _Tp::__primary_template>::value + >; +template +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 0000000..1fbba026 --- /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 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 +struct OtherTag : std::input_iterator_tag {}; +struct OtherTagTwo : std::output_iterator_tag {}; +struct MyIter : std::iterator { + using iterator_concept = int; +}; +struct MyIter2 : std::iterator { + +}; +struct MyIter3 {}; + +struct Empty {}; +struct EmptyWithSpecial {}; +namespace std { +template <> +struct iterator_traits + : std::iterator {}; + +template <> +struct iterator_traits { + // 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, std::contiguous_iterator_tag); +#endif + ASSERT_SAME_TYPE(std::_ITER_CONCEPT, 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, OtherTag); + ASSERT_SAME_TYPE(std::_ITER_CONCEPT, 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, std::random_access_iterator_tag); + } + { + static_assert(!std::_IsValidExpansion::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 0000000..1d72bb7 --- /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 names +// a specialization generated from the primary template. Otherwise, +// ITER_TRAITS(I) denotes iterator_traits. + +#include "test_macros.h" + +#include + +struct MyIter : std::iterator {}; +struct MyIter2 : std::iterator {}; +struct MyIter3 : std::iterator {}; + +namespace std { +template <> +struct iterator_traits + : iterator_traits > {}; +template <> +struct iterator_traits + : std::iterator {}; + +} // namespace std + +int main(int, char**) { + ASSERT_SAME_TYPE(std::_ITER_TRAITS, std::iterator_traits); + { + using ClassIter = std::reverse_iterator; + ASSERT_SAME_TYPE(std::_ITER_TRAITS, ClassIter); + ASSERT_SAME_TYPE(std::_ITER_TRAITS, MyIter3); + } + { + ASSERT_SAME_TYPE(std::_ITER_TRAITS, std::iterator_traits); + ASSERT_SAME_TYPE(std::_ITER_TRAITS, std::iterator_traits); + } + return 0; +}