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/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h --- a/libcxx/include/__ranges/concepts.h +++ b/libcxx/include/__ranges/concepts.h @@ -69,6 +69,10 @@ template concept random_access_range = bidirectional_range<_Tp> && random_access_iterator >; + + template + concept contiguous_range = + random_access_range<_Tp> && contiguous_iterator >; } // namespace ranges #endif // !defined(_LIBCPP_HAS_NO_RANGES) 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 @@ -25,8 +25,10 @@ static_assert(stdr::common_range); static_assert(stdr::bidirectional_range); static_assert(stdr::random_access_range); +static_assert(stdr::contiguous_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); static_assert(stdr::bidirectional_range); static_assert(stdr::random_access_range); +static_assert(stdr::contiguous_range); 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,274 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// 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 >); +// TODO: are we adding cxx20_iterators? +// static_assert( std::random_access_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/ranges/range.refinements/contiguous_range.compile.pass.cpp b/libcxx/test/std/ranges/range.refinements/contiguous_range.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.refinements/contiguous_range.compile.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// template +// concept contiguous_range; + +#include + +#include "test_range.h" +#include "test_iterators.h" + +namespace ranges = std::ranges; + +template