diff --git a/libcxx/include/__iterator/concepts.h b/libcxx/include/__iterator/concepts.h --- a/libcxx/include/__iterator/concepts.h +++ b/libcxx/include/__iterator/concepts.h @@ -16,6 +16,7 @@ #include <__iterator/incrementable_traits.h> #include <__iterator/iterator_traits.h> #include <__iterator/readable_traits.h> +#include <__memory/pointer_traits.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -152,6 +153,19 @@ { __j[__n] } -> same_as>; }; +template +concept contiguous_iterator = + random_access_iterator<_Ip> && + derived_from<_ITER_CONCEPT<_Ip>, contiguous_iterator_tag> && + is_lvalue_reference_v> && + same_as, remove_cvref_t>> && + // This condition isn't required, but allows `contiguous_iterator` to be SFINAE friendly + // which improves the QoI. + (is_pointer_v<_Ip> || requires { sizeof(__pointer_traits_element_type<_Ip>); }) && + requires(const _Ip& __i) { + { _VSTD::to_address(__i) } -> same_as>>; + }; + // clang-format on #endif // !defined(_LIBCPP_HAS_NO_RANGES) diff --git a/libcxx/include/__memory/pointer_traits.h b/libcxx/include/__memory/pointer_traits.h --- a/libcxx/include/__memory/pointer_traits.h +++ b/libcxx/include/__memory/pointer_traits.h @@ -198,7 +198,7 @@ template <> struct __to_address_helper { template - using __return_type = typename pointer_traits<_Pointer>::element_type*; + using __return_type = decltype( _VSTD::__to_address(declval().operator->())); template _LIBCPP_CONSTEXPR diff --git a/libcxx/test/std/containers/sequences/array/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/array/iterator_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/array/iterator_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/iterator_concept_conformance.compile.pass.cpp @@ -21,7 +21,7 @@ using reverse_iterator = std::array::reverse_iterator; using const_reverse_iterator = std::array::const_reverse_iterator; -static_assert(std::random_access_iterator); +static_assert(std::contiguous_iterator); static_assert(std::indirectly_writable); static_assert(std::sentinel_for); static_assert(std::sentinel_for); @@ -32,7 +32,7 @@ static_assert(!std::sized_sentinel_for); static_assert(!std::sized_sentinel_for); -static_assert(std::random_access_iterator); +static_assert(std::contiguous_iterator); static_assert(!std::indirectly_writable); static_assert(std::sentinel_for); static_assert(std::sentinel_for); diff --git a/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp @@ -24,9 +24,11 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); static_assert(stdr::random_access_range); +static_assert(stdr::contiguous_range); static_assert(!stdr::view); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); static_assert(stdr::random_access_range); +static_assert(stdr::contiguous_range); diff --git a/libcxx/test/std/containers/sequences/deque/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/deque/iterator_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/deque/iterator_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/deque/iterator_concept_conformance.compile.pass.cpp @@ -23,6 +23,7 @@ using value_type = int; static_assert(std::random_access_iterator); +static_assert(!std::contiguous_iterator); static_assert(std::indirectly_writable); static_assert(std::sentinel_for); static_assert(std::sentinel_for); @@ -34,6 +35,7 @@ static_assert(!std::sized_sentinel_for); static_assert(std::random_access_iterator); +static_assert(!std::contiguous_iterator); static_assert(!std::indirectly_writable); static_assert(std::sentinel_for); static_assert(std::sentinel_for); diff --git a/libcxx/test/std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp @@ -22,8 +22,8 @@ using const_reverse_iterator = std::vector::const_reverse_iterator; using value_type = bool; -static_assert(std::random_access_iterator); -static_assert(std::random_access_iterator); +static_assert(std::contiguous_iterator); +static_assert(!std::contiguous_iterator); static_assert(!std::indirectly_writable); static_assert(std::sentinel_for); static_assert(std::sentinel_for); @@ -34,8 +34,8 @@ static_assert(!std::sized_sentinel_for); static_assert(!std::sized_sentinel_for); -static_assert(std::random_access_iterator); -static_assert(std::random_access_iterator); +static_assert(std::contiguous_iterator); +static_assert(!std::contiguous_iterator); static_assert(!std::indirectly_writable); static_assert(std::sentinel_for); static_assert(std::sentinel_for); diff --git a/libcxx/test/std/containers/sequences/vector/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector/iterator_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/iterator_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/iterator_concept_conformance.compile.pass.cpp @@ -22,8 +22,8 @@ using const_reverse_iterator = std::vector::const_reverse_iterator; using value_type = int; -static_assert(std::random_access_iterator); -static_assert(std::random_access_iterator); +static_assert(std::contiguous_iterator); +static_assert(!std::contiguous_iterator); static_assert(std::indirectly_writable); static_assert(std::sentinel_for); static_assert(std::sentinel_for); @@ -34,8 +34,8 @@ static_assert(!std::sized_sentinel_for); static_assert(!std::sized_sentinel_for); -static_assert(std::random_access_iterator); -static_assert(std::random_access_iterator); +static_assert(std::contiguous_iterator); +static_assert(!std::contiguous_iterator); static_assert(!std::indirectly_writable); static_assert(std::sentinel_for); static_assert(std::sentinel_for); diff --git a/libcxx/test/std/containers/views/span.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/views/span.iterators/iterator_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/views/span.iterators/iterator_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/views/span.iterators/iterator_concept_conformance.compile.pass.cpp @@ -20,7 +20,7 @@ using reverse_iterator = std::span::reverse_iterator; using value_type = int; -static_assert(std::random_access_iterator); +static_assert(std::contiguous_iterator); static_assert(std::indirectly_writable); static_assert(std::sentinel_for); static_assert(!std::sentinel_for); diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.random.access/contiguous_iterator.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.random.access/contiguous_iterator.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.random.access/contiguous_iterator.compile.pass.cpp @@ -0,0 +1,267 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// concept random_access_iterator; + +#include + +#include "test_iterators.h" + +static_assert(!std::contiguous_iterator >); +static_assert(!std::contiguous_iterator >); +static_assert(!std::contiguous_iterator >); +static_assert(!std::contiguous_iterator >); +static_assert(std::contiguous_iterator >); + +static_assert(std::contiguous_iterator); +static_assert(std::contiguous_iterator); +static_assert(std::contiguous_iterator); +static_assert(std::contiguous_iterator); + +struct simple_contiguous_iterator { + typedef std::contiguous_iterator_tag iterator_category; + typedef int value_type; + typedef int element_type; + typedef std::ptrdiff_t difference_type; + typedef int* pointer; + typedef int& reference; + typedef simple_contiguous_iterator self; + + simple_contiguous_iterator(); + + reference operator*() const; + pointer operator->() const; + friend bool operator==(const self, const self y); + friend bool operator< (const self, const self y); + friend bool operator<=(const self, const self y); + friend bool operator> (const self, const self y); + friend bool operator>=(const self, const self y); + + self& operator++(); + self operator++(int); + + self& operator--(); + self operator--(int); + + self& operator+=(difference_type n); + self operator+(difference_type n) const; + friend self operator+(difference_type n, self x); + + self& operator-=(difference_type n); + self operator-(difference_type n) const; + difference_type operator-(const self n) const; + + reference operator[](difference_type n) const; +}; + +static_assert(std::random_access_iterator); +static_assert(std::contiguous_iterator); + +struct missmatch_value_iter_ref_t { + typedef std::contiguous_iterator_tag iterator_category; + typedef short value_type; + typedef std::ptrdiff_t difference_type; + typedef int* pointer; + typedef int& reference; + typedef missmatch_value_iter_ref_t self; + + missmatch_value_iter_ref_t(); + + reference operator*() const; + pointer operator->() const; + friend bool operator==(const self, const self y); + friend bool operator< (const self, const self y); + friend bool operator<=(const self, const self y); + friend bool operator> (const self, const self y); + friend bool operator>=(const self, const self y); + + self& operator++(); + self operator++(int); + + self& operator--(); + self operator--(int); + + self& operator+=(difference_type n); + self operator+(difference_type n) const; + friend self operator+(difference_type n, self x); + + self& operator-=(difference_type n); + self operator-(difference_type n) const; + difference_type operator-(const self n) const; + + reference operator[](difference_type n) const; +}; + +static_assert(std::random_access_iterator); +static_assert(!std::contiguous_iterator); + +struct wrong_iter_reference_t { + typedef std::contiguous_iterator_tag iterator_category; + typedef short value_type; + typedef std::ptrdiff_t difference_type; + typedef int* pointer; + typedef short& reference; + typedef wrong_iter_reference_t self; + + wrong_iter_reference_t(); + + reference operator*() const; + pointer operator->() const; + friend bool operator==(const self, const self y); + friend bool operator< (const self, const self y); + friend bool operator<=(const self, const self y); + friend bool operator> (const self, const self y); + friend bool operator>=(const self, const self y); + + self& operator++(); + self operator++(int); + + self& operator--(); + self operator--(int); + + self& operator+=(difference_type n); + self operator+(difference_type n) const; + friend self operator+(difference_type n, self x); + + self& operator-=(difference_type n); + self operator-(difference_type n) const; + difference_type operator-(const self n) const; + + reference operator[](difference_type n) const; +}; + +static_assert(std::random_access_iterator); +static_assert(!std::contiguous_iterator); + +struct no_element_type { + typedef std::contiguous_iterator_tag iterator_category; + typedef int value_type; + typedef std::ptrdiff_t difference_type; + typedef int* pointer; + typedef int& reference; + typedef no_element_type self; + + no_element_type(); + + reference operator*() const; + pointer operator->() const; + friend bool operator==(const self, const self y); + friend bool operator< (const self, const self y); + friend bool operator<=(const self, const self y); + friend bool operator> (const self, const self y); + friend bool operator>=(const self, const self y); + + self& operator++(); + self operator++(int); + + self& operator--(); + self operator--(int); + + self& operator+=(difference_type n); + self operator+(difference_type n) const; + friend self operator+(difference_type n, self x); + + self& operator-=(difference_type n); + self operator-(difference_type n) const; + difference_type operator-(const self n) const; + + reference operator[](difference_type n) const; +}; + +static_assert(std::random_access_iterator); +static_assert(!std::contiguous_iterator); + +struct to_address_wrong_return_type { + typedef std::contiguous_iterator_tag iterator_category; + typedef int value_type; + typedef int element_type; + typedef std::ptrdiff_t difference_type; + typedef int* pointer; + typedef int& reference; + typedef to_address_wrong_return_type self; + + to_address_wrong_return_type(); + + reference operator*() const; + pointer operator->() const; + friend bool operator==(const self, const self y); + friend bool operator< (const self, const self y); + friend bool operator<=(const self, const self y); + friend bool operator> (const self, const self y); + friend bool operator>=(const self, const self y); + + self& operator++(); + self operator++(int); + + self& operator--(); + self operator--(int); + + self& operator+=(difference_type n); + self operator+(difference_type n) const; + friend self operator+(difference_type n, self x); + + self& operator-=(difference_type n); + self operator-(difference_type n) const; + difference_type operator-(const self n) const; + + reference operator[](difference_type n) const; +}; + +template<> +struct std::pointer_traits { + typedef void element_type; + void *to_address(to_address_wrong_return_type const&); +}; + +static_assert(std::random_access_iterator); +static_assert(!std::contiguous_iterator); + +template +struct template_and_no_element_type { + typedef std::contiguous_iterator_tag iterator_category; + typedef int value_type; + typedef std::ptrdiff_t difference_type; + typedef int* pointer; + typedef int& reference; + typedef template_and_no_element_type self; + + template_and_no_element_type(); + + reference operator*() const; + pointer operator->() const; + friend bool operator==(const self, const self y); + friend bool operator< (const self, const self y); + friend bool operator<=(const self, const self y); + friend bool operator> (const self, const self y); + friend bool operator>=(const self, const self y); + + self& operator++(); + self operator++(int); + + self& operator--(); + self operator--(int); + + self& operator+=(difference_type n); + self operator+(difference_type n) const; + friend self operator+(difference_type n, self x); + + self& operator-=(difference_type n); + self operator-(difference_type n) const; + difference_type operator-(const self n) const; + + reference operator[](difference_type n) const; +}; + +// Template param is used instead of element_type. +static_assert(std::random_access_iterator>); +static_assert(std::contiguous_iterator>); diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp @@ -34,9 +34,10 @@ using reverse_random_access_iterator = std::reverse_iterator>; static_assert(common_reverse_iterator_checks()); static_assert(std::random_access_iterator); +static_assert(!std::contiguous_iterator); static_assert(std::sized_sentinel_for); using reverse_contiguous_iterator = std::reverse_iterator>; static_assert(common_reverse_iterator_checks()); -static_assert(std::random_access_iterator); +static_assert(!std::contiguous_iterator); static_assert(std::sized_sentinel_for); diff --git a/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp @@ -22,7 +22,7 @@ using const_reverse_iterator = std::string::const_reverse_iterator; using value_type = char; -static_assert(std::random_access_iterator); +static_assert(std::contiguous_iterator); static_assert(std::indirectly_writable); static_assert(std::sentinel_for); static_assert(std::sentinel_for); @@ -33,7 +33,7 @@ static_assert(!std::sized_sentinel_for); static_assert(!std::sized_sentinel_for); -static_assert(std::random_access_iterator); +static_assert(std::contiguous_iterator); static_assert(!std::indirectly_writable); static_assert(std::sentinel_for); static_assert(std::sentinel_for); diff --git a/libcxx/test/std/strings/string.view/string.view.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/string.view/string.view.iterators/iterator_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/strings/string.view/string.view.iterators/iterator_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/strings/string.view/string.view.iterators/iterator_concept_conformance.compile.pass.cpp @@ -21,7 +21,7 @@ using reverse_iterator = std::string_view::reverse_iterator; using const_reverse_iterator = std::string_view::const_reverse_iterator; -static_assert(std::random_access_iterator); +static_assert(std::contiguous_iterator); static_assert(!std::indirectly_writable); static_assert(std::sentinel_for); static_assert(std::sentinel_for); @@ -32,7 +32,7 @@ static_assert(!std::sized_sentinel_for); static_assert(!std::sized_sentinel_for); -static_assert(std::random_access_iterator); +static_assert(std::contiguous_iterator); static_assert(!std::indirectly_writable); static_assert(std::sentinel_for); static_assert(std::sentinel_for);