diff --git a/libcxx/include/__iterator/iterator_traits.h b/libcxx/include/__iterator/iterator_traits.h --- a/libcxx/include/__iterator/iterator_traits.h +++ b/libcxx/include/__iterator/iterator_traits.h @@ -428,19 +428,18 @@ template >::value> struct __has_iterator_category_convertible_to - : _BoolConstant::iterator_category, _Up>::value> + : is_convertible::iterator_category, _Up> {}; template struct __has_iterator_category_convertible_to<_Tp, _Up, false> : false_type {}; -template ::value> -struct __has_iterator_concept_convertible_to - : _BoolConstant::value> -{}; +template +struct __has_iterator_concept_convertible_to : false_type {}; template -struct __has_iterator_concept_convertible_to<_Tp, _Up, false> : false_type {}; +struct __has_iterator_concept_convertible_to<_Tp, _Up, typename __void_t<_ITER_CONCEPT<_Tp> >::type> + : is_convertible<_ITER_CONCEPT<_Tp>, _Up> {}; template struct __is_cpp17_input_iterator : public __has_iterator_category_convertible_to<_Tp, input_iterator_tag> {}; @@ -454,10 +453,11 @@ template struct __is_cpp17_random_access_iterator : public __has_iterator_category_convertible_to<_Tp, random_access_iterator_tag> {}; -// __is_cpp17_contiguous_iterator determines if an iterator is contiguous, -// either because it advertises itself as such (in C++20) or because it -// is a pointer type or a known trivial wrapper around a pointer type, -// such as __wrap_iter. +// __is_cpp17_contiguous_iterator determines if an iterator is known by +// libc++ to be contiguous, either because it advertises itself as such +// (in C++20) or because it is a pointer type or a known trivial wrapper +// around a pointer type, such as __wrap_iter. Such iterators receive +// special "contiguous" optimizations in std::copy and std::sort. // #if _LIBCPP_STD_VER > 17 template @@ -466,15 +466,10 @@ __has_iterator_concept_convertible_to<_Tp, contiguous_iterator_tag> > {}; #else -template -struct __is_cpp17_contiguous_iterator : false_type {}; +template struct __is_cpp17_contiguous_iterator : false_type {}; +template struct __is_cpp17_contiguous_iterator<_Up*> : true_type {}; #endif -// Any native pointer which is an iterator is also a contiguous iterator. -template -struct __is_cpp17_contiguous_iterator<_Up*> : true_type {}; - - template struct __is_exactly_cpp17_input_iterator : public integral_constant #include <__iterator/iterator_traits.h> #include <__iterator/readable_traits.h> -#include <__iterator/concepts.h> #include <__memory/addressof.h> #include <__memory/pointer_traits.h> #include @@ -1272,6 +1271,16 @@ template class __wrap_iter { + // Prior to C++20, there was no "standard" way to mark a type as a fancy pointer; + // after C++20, we would prefer all fancy pointers to have contiguous_iterator_tag, + // but we can't assume that they will, because of legacy code. + // Since C++03, every fancy pointer should at least advertise itself as a + // random-access iterator. But we can't assume fancy pointers satisfy any particular + // C++20 concept (e.g. std::contiguous_iterator), again because legacy code exists. + // + static_assert(__is_cpp17_random_access_iterator<_Iter>::value, + "__wrap_iter cannot wrap anything but a fancy pointer"); + public: typedef _Iter iterator_type; typedef typename iterator_traits::value_type value_type; @@ -1280,9 +1289,11 @@ typedef typename iterator_traits::reference reference; typedef typename iterator_traits::iterator_category iterator_category; #if _LIBCPP_STD_VER > 17 - typedef _If<__is_cpp17_contiguous_iterator<_Iter>::value, - contiguous_iterator_tag, iterator_category> iterator_concept; + typedef contiguous_iterator_tag iterator_concept; #endif + typedef typename remove_reference< + typename iterator_traits::reference + >::type element_type; private: iterator_type __i; @@ -1464,15 +1475,15 @@ #if _LIBCPP_STD_VER <= 17 template -struct __is_cpp17_contiguous_iterator<__wrap_iter<_It> > : __is_cpp17_contiguous_iterator<_It> {}; -#endif +struct __is_cpp17_contiguous_iterator<__wrap_iter<_It> > : true_type {}; template _LIBCPP_CONSTEXPR -_EnableIf<__is_cpp17_contiguous_iterator<_Iter>::value, decltype(_VSTD::__to_address(declval<_Iter>()))> +decltype(_VSTD::__to_address(declval<_Iter>())) __to_address(__wrap_iter<_Iter> __w) _NOEXCEPT { return _VSTD::__to_address(__w.base()); } +#endif template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG diff --git a/libcxx/test/libcxx/iterators/contiguous_iterators.pass.cpp b/libcxx/test/libcxx/iterators/contiguous_iterators.pass.cpp --- a/libcxx/test/libcxx/iterators/contiguous_iterators.pass.cpp +++ b/libcxx/test/libcxx/iterators/contiguous_iterators.pass.cpp @@ -138,6 +138,21 @@ }; #endif +struct fake_deque_iterator : std::deque::iterator { + using element_type = int; +}; +static_assert(std::__is_cpp17_random_access_iterator::value, ""); +static_assert(!std::__is_cpp17_contiguous_iterator::value, ""); + +#if TEST_STD_VER >= 20 +struct fake2_deque_iterator : std::deque::iterator { + using iterator_concept = std::contiguous_iterator_tag; + using element_type = int; +}; +static_assert(std::__is_cpp17_random_access_iterator::value, ""); +static_assert(std::__is_cpp17_contiguous_iterator::value, ""); +#endif + int main(int, char**) { // basic tests @@ -178,16 +193,13 @@ static_assert(( std::__is_cpp17_contiguous_iterator >::value), ""); static_assert(( std::__is_cpp17_contiguous_iterator > >::value), ""); - static_assert((!std::__is_cpp17_contiguous_iterator > >::value), ""); - static_assert((!std::__is_cpp17_contiguous_iterator >::value), ""); - static_assert((!std::__is_cpp17_contiguous_iterator > >::value), ""); - static_assert((!std::__is_cpp17_contiguous_iterator > >::value), ""); + static_assert(( std::__is_cpp17_contiguous_iterator >::value), ""); + static_assert(( std::__is_cpp17_contiguous_iterator > >::value), ""); #if TEST_STD_VER >= 20 static_assert(( std::__is_cpp17_contiguous_iterator >::value), ""); static_assert(( std::__is_cpp17_contiguous_iterator > >::value), ""); - static_assert((!std::__is_cpp17_contiguous_iterator > >::value), ""); #endif // iterators in the libc++ test suite @@ -228,14 +240,12 @@ static_assert((!std::__is_cpp17_contiguous_iterator::const_iterator> ::value), ""); static_assert((!std::__is_cpp17_contiguous_iterator::reverse_iterator> ::value), ""); static_assert((!std::__is_cpp17_contiguous_iterator::const_reverse_iterator> ::value), ""); - static_assert((!std::__is_cpp17_contiguous_iterator::iterator> >::value), ""); // vector is random-access but not contiguous static_assert((!std::__is_cpp17_contiguous_iterator::iterator> ::value), ""); static_assert((!std::__is_cpp17_contiguous_iterator::const_iterator> ::value), ""); static_assert((!std::__is_cpp17_contiguous_iterator::reverse_iterator> ::value), ""); static_assert((!std::__is_cpp17_contiguous_iterator::const_reverse_iterator> ::value), ""); - static_assert((!std::__is_cpp17_contiguous_iterator::iterator> >::value), ""); #if TEST_STD_VER >= 11 static_assert(( std::__is_cpp17_contiguous_iterator::iterator> ::value), ""); diff --git a/libcxx/test/std/utilities/memory/pointer.conversion/to_address_std_iterators.pass.cpp b/libcxx/test/std/utilities/memory/pointer.conversion/to_address_std_iterators.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/pointer.conversion/to_address_std_iterators.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template constexpr T* to_address(T* p) noexcept; +// template constexpr auto to_address(const Ptr& p) noexcept; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include "test_macros.h" + +template +void test_container_iterators(C c) +{ + const C& cc = c; + assert(std::to_address(c.begin()) == c.data()); + assert(std::to_address(c.end()) == c.data() + c.size()); + assert(std::to_address(cc.begin()) == cc.data()); + assert(std::to_address(cc.end()) == cc.data() + cc.size()); +} + +void test_valarray_iterators() +{ + std::valarray v(100); + int *p = std::to_address(std::begin(v)); + int *q = std::to_address(std::end(v)); + assert(q - p == 100); +} + +int main(int, char**) { + test_container_iterators(std::array()); + test_container_iterators(std::vector(3)); + test_container_iterators(std::string("abc")); + test_container_iterators(std::string_view("abc")); + test_container_iterators(std::span("abc")); + test_valarray_iterators(); + + return 0; +} diff --git a/libcxx/test/std/utilities/memory/pointer.traits/std_iterators.pass.cpp b/libcxx/test/std/utilities/memory/pointer.traits/std_iterators.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/pointer.traits/std_iterators.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// template +// struct pointer_traits +// { +// using element_type = see below; +// ... +// }; + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) +{ + ASSERT_SAME_TYPE(typename std::pointer_traits::iterator>::element_type, int); + ASSERT_SAME_TYPE(typename std::pointer_traits::const_iterator>::element_type, const int); + +#if TEST_STD_VER >= 20 + ASSERT_SAME_TYPE(typename std::pointer_traits::iterator>::element_type, int); + ASSERT_SAME_TYPE(typename std::pointer_traits::iterator>::element_type, const int); +#endif + + ASSERT_SAME_TYPE(typename std::pointer_traits::element_type, char); + ASSERT_SAME_TYPE(typename std::pointer_traits::element_type, const char); + +#if TEST_STD_VER >= 17 + ASSERT_SAME_TYPE(typename std::pointer_traits::element_type, const char); + ASSERT_SAME_TYPE(typename std::pointer_traits::element_type, const char); +#endif + +#if TEST_STD_VER >= 11 + { + std::valarray v; + auto it = std::begin(v); + ASSERT_SAME_TYPE(typename std::pointer_traits::element_type, int); + const std::valarray& cv = v; + auto cit = std::begin(cv); + ASSERT_SAME_TYPE(typename std::pointer_traits::element_type, const int); + } +#endif + + ASSERT_SAME_TYPE(typename std::pointer_traits::iterator>::element_type, int); + ASSERT_SAME_TYPE(typename std::pointer_traits::const_iterator>::element_type, const int); + + return 0; +}