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 @@ -11,6 +11,7 @@ #include <__config> #include <__ranges/access.h> +#include #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -50,6 +51,11 @@ template using range_rvalue_reference_t = iter_rvalue_reference_t >; + +// [range.refinements] +template +concept input_range = range<_Tp>&& input_iterator >; + } // namespace ranges #endif // !defined(_LIBCPP_HAS_NO_RANGES) diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -84,6 +84,10 @@ template concept sentinel_for = see below; // since C++20 +// [iterator.concept.input], concept input_­iterator +template + concept input_iterator = see below; // since C++20 + template struct iterator @@ -2599,6 +2603,14 @@ input_or_output_iterator<_Ip> && __weakly_equality_comparable_with<_Sp, _Ip>; +// [iterator.concept.input] +template +concept input_iterator = + input_or_output_iterator<_Ip> && + indirectly_readable<_Ip> && + requires { typename _ITER_CONCEPT<_Ip>; } && + derived_from<_ITER_CONCEPT<_Ip>, input_iterator_tag>; + #undef _LIBCPP_NOEXCEPT_RETURN #endif // !defined(_LIBCPP_HAS_NO_RANGES) diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -38,6 +38,10 @@ // using range_reference_t = iter_reference_t>; // template // using range_rvalue_reference_t = iter_rvalue_reference_t>; +// +// // [range.refinements], other range refinements +// template +// concept input_range = see below; // } #ifndef _LIBCPP_RANGES diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.input/input_iterator.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.input/input_iterator.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.input/input_iterator.compile.pass.cpp @@ -0,0 +1,252 @@ +//===----------------------------------------------------------------------===// +// +// 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 input_iterator; + +#include + +#include +#include +#include +#ifndef _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_iterators.h" + +static_assert(!std::copyable && + std::input_iterator); +static_assert(std::input_iterator::iterator> >); + +struct no_explicit_iter_concept { + using value_type = int; + using difference_type = std::ptrdiff_t; + + no_explicit_iter_concept() = default; + + no_explicit_iter_concept(no_explicit_iter_concept&&) = default; + no_explicit_iter_concept& operator=(no_explicit_iter_concept&&) = default; + + no_explicit_iter_concept(no_explicit_iter_concept const&) = delete; + no_explicit_iter_concept& operator=(no_explicit_iter_concept const&) = delete; + + value_type operator*() const; + + no_explicit_iter_concept& operator++(); + void operator++(int); +}; +// ITER-CONCEPT is `random_access_iterator_tag` >:( +static_assert(std::input_iterator); + +namespace standard_types { +static_assert(std::input_iterator); +static_assert(std::input_iterator); +static_assert(std::input_iterator); +static_assert(std::input_iterator); + +// +static_assert(std::input_iterator::iterator>); +static_assert(std::input_iterator::const_iterator>); +static_assert(std::input_iterator::reverse_iterator>); +static_assert(std::input_iterator::const_reverse_iterator>); + +// +static_assert(std::input_iterator::iterator>); +static_assert(std::input_iterator::const_iterator>); +static_assert(std::input_iterator::reverse_iterator>); +static_assert(std::input_iterator::const_reverse_iterator>); + +// +#ifndef _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY +static_assert(std::input_iterator); +static_assert( + std::input_iterator); +#endif + +// +static_assert(std::input_iterator::iterator>); +static_assert(std::input_iterator::const_iterator>); + +// +static_assert( + !std::input_iterator > >); +static_assert( + !std::input_iterator > >); +static_assert(!std::input_iterator > >); +static_assert( + std::input_iterator::iterator> >); + +// +static_assert(std::input_iterator::iterator>); +static_assert(std::input_iterator::const_iterator>); +static_assert(std::input_iterator::reverse_iterator>); +static_assert(std::input_iterator::const_reverse_iterator>); + +// +static_assert(std::input_iterator::iterator>); +static_assert(std::input_iterator::const_iterator>); +static_assert(std::input_iterator::reverse_iterator>); +static_assert(std::input_iterator::const_reverse_iterator>); + +static_assert(std::input_iterator::iterator>); +static_assert(std::input_iterator::const_iterator>); +static_assert(std::input_iterator::reverse_iterator>); +static_assert( + std::input_iterator::const_reverse_iterator>); + +// +static_assert(!std::input_iterator >); +static_assert(!std::input_iterator >); +static_assert(!std::input_iterator >); +static_assert(!std::input_iterator >); + +// +static_assert(!std::input_iterator >); + +// +static_assert(std::input_iterator::iterator>); +static_assert(std::input_iterator::const_iterator>); +static_assert(std::input_iterator::reverse_iterator>); +static_assert(std::input_iterator::const_reverse_iterator>); + +static_assert(std::input_iterator::iterator>); +static_assert(std::input_iterator::const_iterator>); +static_assert(std::input_iterator::reverse_iterator>); +static_assert(std::input_iterator::const_reverse_iterator>); + +// +static_assert(std::input_iterator); +static_assert(std::input_iterator); +static_assert(std::input_iterator); +static_assert(std::input_iterator); + +// +static_assert(std::input_iterator); +static_assert(std::input_iterator); +static_assert(std::input_iterator); +static_assert(std::input_iterator); + +// +static_assert(std::input_iterator::iterator>); +static_assert( + std::input_iterator::const_iterator>); + +static_assert(std::input_iterator::iterator>); +static_assert( + std::input_iterator::const_iterator>); + +// +static_assert(std::input_iterator::iterator>); +static_assert(std::input_iterator::const_iterator>); + +static_assert(std::input_iterator::iterator>); +static_assert( + std::input_iterator::const_iterator>); + +// +static_assert(std::input_iterator::iterator>); +static_assert(std::input_iterator::const_iterator>); +static_assert(std::input_iterator::reverse_iterator>); +static_assert(std::input_iterator::const_reverse_iterator>); +static_assert(!std::input_iterator >); +} // namespace standard_types + +struct not_weakly_incrementable { + using difference_type = std::ptrdiff_t; + using iterator_concept = std::input_iterator_tag; + + not_weakly_incrementable() = default; + + not_weakly_incrementable(not_weakly_incrementable&&) = default; + not_weakly_incrementable& operator=(not_weakly_incrementable&&) = default; + + not_weakly_incrementable(not_weakly_incrementable const&) = delete; + not_weakly_incrementable& operator=(not_weakly_incrementable const&) = delete; + + int operator*() const; + + not_weakly_incrementable& operator++(); +}; +static_assert(!std::input_or_output_iterator && + !std::input_iterator); + +struct not_indirectly_readable { + using difference_type = std::ptrdiff_t; + using iterator_concept = std::input_iterator_tag; + + not_indirectly_readable() = default; + + not_indirectly_readable(not_indirectly_readable&&) = default; + not_indirectly_readable& operator=(not_indirectly_readable&&) = default; + + not_indirectly_readable(not_indirectly_readable const&) = delete; + not_indirectly_readable& operator=(not_indirectly_readable const&) = delete; + + int operator*() const; + + not_indirectly_readable& operator++(); + void operator++(int); +}; +static_assert(!std::indirectly_readable && + !std::input_iterator); + +struct bad_iterator_category { + using value_type = int; + using difference_type = std::ptrdiff_t; + using iterator_category = void; + + bad_iterator_category() = default; + + bad_iterator_category(bad_iterator_category&&) = default; + bad_iterator_category& operator=(bad_iterator_category&&) = default; + + bad_iterator_category(bad_iterator_category const&) = delete; + bad_iterator_category& operator=(bad_iterator_category const&) = delete; + + value_type operator*() const; + + bad_iterator_category& operator++(); + void operator++(int); +}; +static_assert(!std::input_iterator); + +struct bad_iterator_concept { + using value_type = int; + using difference_type = std::ptrdiff_t; + using iterator_concept = void*; + + bad_iterator_concept() = default; + + bad_iterator_concept(bad_iterator_concept&&) = default; + bad_iterator_concept& operator=(bad_iterator_concept&&) = default; + + bad_iterator_concept(bad_iterator_concept const&) = delete; + bad_iterator_concept& operator=(bad_iterator_concept const&) = delete; + + value_type operator*() const; + + bad_iterator_concept& operator++(); + void operator++(int); +}; +static_assert(!std::input_iterator); diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.input/subsumption.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.input/subsumption.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.input/subsumption.compile.pass.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 input_iterator; + +#include + +#include + +// clang-format off +template +requires std::indirectly_readable && + std::derived_from, std::input_iterator_tag> +[[nodiscard]] constexpr bool check_subsumption() { + return false; +} + +template +[[nodiscard]] constexpr bool check_subsumption() { + return true; +} +// clang-format on + +static_assert(check_subsumption()); diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/locale_dependent.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/locale_dependent.compile.pass.cpp --- a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/locale_dependent.compile.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/locale_dependent.compile.pass.cpp @@ -28,17 +28,21 @@ static_assert(std::input_or_output_iterator >); static_assert(std::sentinel_for, std::istream_iterator >); +static_assert(std::input_iterator >); static_assert(std::input_or_output_iterator >); static_assert(std::sentinel_for, std::istreambuf_iterator >); +static_assert(std::input_iterator >); static_assert( !std::input_or_output_iterator >); static_assert(!std::sentinel_for, std::ostream_iterator >); +static_assert(!std::input_iterator >); static_assert( !std::input_or_output_iterator >); static_assert(!std::sentinel_for, std::ostreambuf_iterator >); +static_assert(!std::input_iterator >); diff --git a/libcxx/test/std/ranges/range.refinements/input_range.compile.pass.cpp b/libcxx/test/std/ranges/range.refinements/input_range.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.refinements/input_range.compile.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// 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 input_range; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_range.h" + +namespace stdr = std::ranges; + +static_assert(stdr::input_range >); +static_assert(stdr::input_range >); +static_assert(stdr::input_range >); +static_assert(stdr::input_range >); +static_assert(stdr::input_range >); +static_assert(stdr::input_range >); +static_assert(stdr::input_range >); +static_assert(stdr::input_range >); +static_assert(stdr::input_range); +static_assert(stdr::input_range); +static_assert(stdr::input_range >); +static_assert(stdr::input_range >); +static_assert(stdr::input_range >); +static_assert(stdr::input_range >); +static_assert(stdr::input_range >); + +static_assert(stdr::input_range > >); +static_assert(stdr::input_range > >); +static_assert(stdr::input_range > >); +static_assert(stdr::input_range > >); +static_assert(stdr::input_range > >); +static_assert(stdr::input_range > >); +static_assert(stdr::input_range > >); +static_assert(stdr::input_range > >); +static_assert(stdr::input_range >); +static_assert(stdr::input_range >); +static_assert(stdr::input_range > >); +static_assert( + stdr::input_range > >); +static_assert(stdr::input_range > >); +static_assert(stdr::input_range > >); +static_assert(stdr::input_range > >); diff --git a/libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp b/libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// 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 input_iterator; + +#include + +#include +#include + +// clang-format off +template +[[nodiscard]] constexpr bool check_input_range_subsumption() { + return false; +} + +template +[[nodiscard]] constexpr bool check_input_range_subsumption() { + return true; +} +// clang-format on + +static_assert(check_input_range_subsumption >()); diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -632,6 +632,26 @@ bool operator!= (const NonThrowingIterator& a, const NonThrowingIterator& b) TEST_NOEXCEPT { return !a.operator==(b); } +struct noncopyable_input_iterator { + using value_type = int; + using difference_type = std::ptrdiff_t; + using iterator_concept = std::input_iterator_tag; + + noncopyable_input_iterator() = default; + + noncopyable_input_iterator(noncopyable_input_iterator&&) = default; + noncopyable_input_iterator& operator=(noncopyable_input_iterator&&) = default; + + noncopyable_input_iterator(noncopyable_input_iterator const&) = delete; + noncopyable_input_iterator& + operator=(noncopyable_input_iterator const&) = delete; + + value_type operator*() const; + + noncopyable_input_iterator& operator++(); + void operator++(int); +}; + #undef DELETE_FUNCTION #endif // ITERATORS_H diff --git a/libcxx/test/support/test_range.h b/libcxx/test/support/test_range.h --- a/libcxx/test/support/test_range.h +++ b/libcxx/test/support/test_range.h @@ -10,6 +10,8 @@ #include +#include "test_iterators.h" + #ifdef _LIBCPP_HAS_NO_RANGES #error "test/suppoort/test_range.h" can only be included in builds supporting ranges #endif @@ -26,4 +28,12 @@ sentinel end() const; }; +template +struct input_range { + input_iterator > begin(); + input_iterator > begin() const; + sentinel end(); + sentinel end() const; +}; + #endif // LIBCXX_TEST_SUPPORT_TEST_RANGE_H