diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv --- a/libcxx/docs/Status/RangesPaper.csv +++ b/libcxx/docs/Status/RangesPaper.csv @@ -44,11 +44,11 @@ | `sentinel_for `_ | `sized_sentinel_for `_ | `input_iterator `_ -| output_iterator +| `output_iterator `_ | `forward_iterator `_ | `bidirectional_iterator `_ | `random_access_iterator `_ -| `contiguous_iterator `_",iter_value_t,Christopher Di Bella,In progress +| `contiguous_iterator `_",,Various,✅ `[indirectcallable.indirectinvocable] `_,"| indirectly_unary_invocable | `indirectly_regular_unary_invocable `_ | `indirectly_unary_predicate `_ @@ -120,7 +120,7 @@ | `ranges::random_access_range `_ | ranges::contiguous_range | `ranges::common_range `_",[range.range],Christopher Di Bella,✅ -`[range.refinements]`_,`ranges::viewable_range `_,[range.range],Louis Dionne,✅ +`[range.refinements]`_,`ranges::viewable_range `_,[range.range],Louis Dionne,✅ `[range.utility.helpers] `_,"| *simple-view* | *has-arrow* | *not-same-as*","| [range.range] @@ -141,7 +141,7 @@ `[range.iota] `_,iota_view,[range.all],Louis Dionne,Not started `[range.take] `_,take_view,[range.all],Zoe Carver,In Progress `[range.join] `_,join_view,[range.all],Christopher Di Bella,Not started -`[range.empty] `_,`empty_view `_,[view.interface],Zoe Carver,✅ +`[range.empty] `_,`empty_view `_,[view.interface],Zoe Carver,✅ `[range.single] `_,single_view,[view.interface],Zoe Carver,In Progress `[range.split] `_,split_view,[range.all],Unassigned,Not started `[range.counted] `_,view::counted,[range.subrange],Zoe Carver,Not started 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 @@ -124,6 +124,15 @@ requires { typename _ITER_CONCEPT<_Ip>; } && derived_from<_ITER_CONCEPT<_Ip>, input_iterator_tag>; +// [iterator.concept.output] +template +concept output_iterator = + input_or_output_iterator<_Ip> && + indirectly_writable<_Ip, _Tp> && + requires (_Ip __it, _Tp&& __t) { + *__it++ = _VSTD::forward<_Tp>(__t); // not required to be equality-preserving + }; + // [iterator.concept.forward] template concept forward_iterator = 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 @@ -92,6 +92,9 @@ same_as, iterator_t>; // [range.refinements], other range refinements + template + concept output_range = range<_Rp> && output_iterator, _Tp>; + template concept input_range = range<_Tp> && input_iterator>; diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -83,6 +83,10 @@ template concept input_iterator = see below; // since C++20 +// [iterator.concept.output], concept output_iterator +template + concept output_iterator = see below; // since C++20 + // [iterator.concept.forward], concept forward_iterator template concept forward_iterator = see below; // since C++20 diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -67,6 +67,9 @@ concept view = ...; // [range.refinements], other range refinements + template + concept output_range = see below; + template concept input_range = see below; diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.output/output_iterator.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.output/output_iterator.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.output/output_iterator.compile.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// 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 output_iterator; + +#include + +#include +#include "test_iterators.h" + +struct T { }; +struct DerivedFromT : T { }; + +static_assert( std::output_iterator, int>); +static_assert( std::output_iterator, short>); +static_assert( std::output_iterator, long>); +static_assert( std::output_iterator, T>); +static_assert(!std::output_iterator, T>); +static_assert( std::output_iterator, T const>); +static_assert( std::output_iterator, DerivedFromT>); +static_assert(!std::output_iterator, T>); + +// Not satisfied when the iterator is not an input_or_output_iterator +static_assert(!std::output_iterator); +static_assert(!std::output_iterator); +static_assert(!std::output_iterator); +static_assert(!std::output_iterator); + +// Not satisfied when we can't assign a T to the result of *it++ +struct WrongPostIncrement { + using difference_type = std::ptrdiff_t; + T const* operator++(int); + WrongPostIncrement& operator++(); + T& operator*(); +}; +static_assert( std::input_or_output_iterator); +static_assert( std::indirectly_writable); +static_assert(!std::output_iterator); + +// Not satisfied when we can't assign a T to the result of *it (i.e. not indirectly_writable) +struct NotIndirectlyWritable { + using difference_type = std::ptrdiff_t; + T* operator++(int); + NotIndirectlyWritable& operator++(); + T const& operator*(); // const so we can't write to it +}; +static_assert( std::input_or_output_iterator); +static_assert(!std::indirectly_writable); +static_assert(!std::output_iterator); diff --git a/libcxx/test/std/ranges/range.req/range.refinements/output_range.compile.pass.cpp b/libcxx/test/std/ranges/range.req/range.refinements/output_range.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.req/range.refinements/output_range.compile.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// 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 output_range; + +#include + +#include +#include "test_iterators.h" +#include "test_range.h" + +struct T { }; + +// Satisfied when it's a range and has the right iterator +struct GoodRange { + output_iterator begin(); + sentinel end(); +}; +static_assert(std::ranges::range); +static_assert(std::output_iterator, T>); +static_assert(std::ranges::output_range); + +// Not satisfied when it's not a range +struct NotRange { + output_iterator begin(); +}; +static_assert(!std::ranges::range); +static_assert( std::output_iterator, T>); +static_assert(!std::ranges::output_range); + +// Not satisfied when the iterator is not an output_iterator +struct RangeWithBadIterator { + cpp17_input_iterator begin(); + sentinel end(); +}; +static_assert( std::ranges::range); +static_assert(!std::output_iterator, T>); +static_assert(!std::ranges::output_range);