[libcxx-commits] [libcxx] 7b28c5d - [libc++] Implement the output_iterator and output_range concepts
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jul 26 12:05:29 PDT 2021
Author: Louis Dionne
Date: 2021-07-26T15:05:17-04:00
New Revision: 7b28c5d3765c5f48a1502693331b22330d609f88
URL: https://github.com/llvm/llvm-project/commit/7b28c5d3765c5f48a1502693331b22330d609f88
DIFF: https://github.com/llvm/llvm-project/commit/7b28c5d3765c5f48a1502693331b22330d609f88.diff
LOG: [libc++] Implement the output_iterator and output_range concepts
Differential Revision: https://reviews.llvm.org/D106704
Added:
libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.output/output_iterator.compile.pass.cpp
libcxx/test/std/ranges/range.req/range.refinements/output_range.compile.pass.cpp
Modified:
libcxx/docs/Status/RangesPaper.csv
libcxx/include/__iterator/concepts.h
libcxx/include/__ranges/concepts.h
libcxx/include/iterator
libcxx/include/ranges
Removed:
################################################################################
diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv
index 3595d29aa05d4..024a5e4462bee 100644
--- a/libcxx/docs/Status/RangesPaper.csv
+++ b/libcxx/docs/Status/RangesPaper.csv
@@ -44,11 +44,11 @@ Section,Description,Dependencies,Assignee,Complete
| `sentinel_for <https://llvm.org/D100160>`_
| `sized_sentinel_for <https://llvm.org/D101371>`_
| `input_iterator <https://llvm.org/D100271>`_
-| output_iterator
+| `output_iterator <https://llvm.org/D106704>`_
| `forward_iterator <https://llvm.org/D100275>`_
| `bidirectional_iterator <https://llvm.org/D100278>`_
| `random_access_iterator <https://llvm.org/D101316>`_
-| `contiguous_iterator <https://llvm.org/D101396>`_",iter_value_t,Christopher Di Bella,In progress
+| `contiguous_iterator <https://llvm.org/D101396>`_",,Various,✅
`[indirectcallable.indirectinvocable] <http://wg21.link/indirectcallable.indirectinvocable>`_,"| indirectly_unary_invocable
| `indirectly_regular_unary_invocable <https://llvm.org/D101277>`_
| `indirectly_unary_predicate <https://llvm.org/D101277>`_
@@ -120,7 +120,7 @@ Section,Description,Dependencies,Assignee,Complete
| `ranges::random_access_range <https://llvm.org/D101316>`_
| ranges::contiguous_range
| `ranges::common_range <https://llvm.org/D100269>`_",[range.range],Christopher Di Bella,✅
-`[range.refinements]`_,`ranges::viewable_range <https://reviews.llvm.org/D105816>`_,[range.range],Louis Dionne,✅
+`[range.refinements]`_,`ranges::viewable_range <https://llvm.org/D105816>`_,[range.range],Louis Dionne,✅
`[range.utility.helpers] <http://wg21.link/range.utility.helpers>`_,"| *simple-view*
| *has-arrow*
| *not-same-as*","| [range.range]
@@ -141,7 +141,7 @@ Section,Description,Dependencies,Assignee,Complete
`[range.iota] <http://wg21.link/range.iota>`_,iota_view,[range.all],Louis Dionne,Not started
`[range.take] <http://wg21.link/range.take>`_,take_view,[range.all],Zoe Carver,In Progress
`[range.join] <http://wg21.link/range.join>`_,join_view,[range.all],Christopher Di Bella,Not started
-`[range.empty] <http://wg21.link/range.empty>`_,`empty_view <https://reviews.llvm.org/D103208>`_,[view.interface],Zoe Carver,✅
+`[range.empty] <http://wg21.link/range.empty>`_,`empty_view <https://llvm.org/D103208>`_,[view.interface],Zoe Carver,✅
`[range.single] <http://wg21.link/range.single>`_,single_view,[view.interface],Zoe Carver,In Progress
`[range.split] <http://wg21.link/range.split>`_,split_view,[range.all],Unassigned,Not started
`[range.counted] <http://wg21.link/range.counted>`_,view::counted,[range.subrange],Zoe Carver,Not started
diff --git a/libcxx/include/__iterator/concepts.h b/libcxx/include/__iterator/concepts.h
index f577bd944c283..6eb4aef10528a 100644
--- a/libcxx/include/__iterator/concepts.h
+++ b/libcxx/include/__iterator/concepts.h
@@ -124,6 +124,15 @@ concept input_iterator =
requires { typename _ITER_CONCEPT<_Ip>; } &&
derived_from<_ITER_CONCEPT<_Ip>, input_iterator_tag>;
+// [iterator.concept.output]
+template<class _Ip, class _Tp>
+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<class _Ip>
concept forward_iterator =
diff --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h
index 6493f81e1dbab..2f912c2841e84 100644
--- a/libcxx/include/__ranges/concepts.h
+++ b/libcxx/include/__ranges/concepts.h
@@ -92,6 +92,9 @@ namespace ranges {
same_as<sentinel_t<_Range>, iterator_t<const _Range>>;
// [range.refinements], other range refinements
+ template <class _Rp, class _Tp>
+ concept output_range = range<_Rp> && output_iterator<iterator_t<_Rp>, _Tp>;
+
template <class _Tp>
concept input_range = range<_Tp> && input_iterator<iterator_t<_Tp>>;
diff --git a/libcxx/include/iterator b/libcxx/include/iterator
index 80f3827b72034..a9f794c7e2bfa 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -83,6 +83,10 @@ template<class S, class I>
template<class I>
concept input_iterator = see below; // since C++20
+// [iterator.concept.output], concept output_iterator
+template<class I, class T>
+ concept output_iterator = see below; // since C++20
+
// [iterator.concept.forward], concept forward_iterator
template<class I>
concept forward_iterator = see below; // since C++20
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index 682dd6e094290..e97e5659f5c0e 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -67,6 +67,9 @@ namespace std::ranges {
concept view = ...;
// [range.refinements], other range refinements
+ template<class R, class T>
+ concept output_range = see below;
+
template<class T>
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
index 0000000000000..899e0c1e52a08
--- /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<class It, class T>
+// concept output_iterator;
+
+#include <iterator>
+
+#include <cstddef>
+#include "test_iterators.h"
+
+struct T { };
+struct DerivedFromT : T { };
+
+static_assert( std::output_iterator<output_iterator<int*>, int>);
+static_assert( std::output_iterator<output_iterator<int*>, short>);
+static_assert( std::output_iterator<output_iterator<int*>, long>);
+static_assert( std::output_iterator<output_iterator<T*>, T>);
+static_assert(!std::output_iterator<output_iterator<T const*>, T>);
+static_assert( std::output_iterator<output_iterator<T*>, T const>);
+static_assert( std::output_iterator<output_iterator<T*>, DerivedFromT>);
+static_assert(!std::output_iterator<output_iterator<DerivedFromT*>, T>);
+
+// Not satisfied when the iterator is not an input_or_output_iterator
+static_assert(!std::output_iterator<void, int>);
+static_assert(!std::output_iterator<void (*)(), int>);
+static_assert(!std::output_iterator<int&, int>);
+static_assert(!std::output_iterator<T, int>);
+
+// Not satisfied when we can't assign a T to the result of *it++
+struct WrongPostIncrement {
+ using
diff erence_type = std::ptr
diff _t;
+ T const* operator++(int);
+ WrongPostIncrement& operator++();
+ T& operator*();
+};
+static_assert( std::input_or_output_iterator<WrongPostIncrement>);
+static_assert( std::indirectly_writable<WrongPostIncrement, T>);
+static_assert(!std::output_iterator<WrongPostIncrement, T>);
+
+// Not satisfied when we can't assign a T to the result of *it (i.e. not indirectly_writable)
+struct NotIndirectlyWritable {
+ using
diff erence_type = std::ptr
diff _t;
+ T* operator++(int);
+ NotIndirectlyWritable& operator++();
+ T const& operator*(); // const so we can't write to it
+};
+static_assert( std::input_or_output_iterator<NotIndirectlyWritable>);
+static_assert(!std::indirectly_writable<NotIndirectlyWritable, T>);
+static_assert(!std::output_iterator<NotIndirectlyWritable, T>);
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
index 0000000000000..d3c58081d6e7c
--- /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<class R, class T>
+// concept output_range;
+
+#include <ranges>
+
+#include <iterator>
+#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<T*> begin();
+ sentinel end();
+};
+static_assert(std::ranges::range<GoodRange>);
+static_assert(std::output_iterator<std::ranges::iterator_t<GoodRange>, T>);
+static_assert(std::ranges::output_range<GoodRange, T>);
+
+// Not satisfied when it's not a range
+struct NotRange {
+ output_iterator<T*> begin();
+};
+static_assert(!std::ranges::range<NotRange>);
+static_assert( std::output_iterator<std::ranges::iterator_t<NotRange>, T>);
+static_assert(!std::ranges::output_range<NotRange, T>);
+
+// Not satisfied when the iterator is not an output_iterator
+struct RangeWithBadIterator {
+ cpp17_input_iterator<T const*> begin();
+ sentinel end();
+};
+static_assert( std::ranges::range<RangeWithBadIterator>);
+static_assert(!std::output_iterator<std::ranges::iterator_t<RangeWithBadIterator>, T>);
+static_assert(!std::ranges::output_range<RangeWithBadIterator, T>);
More information about the libcxx-commits
mailing list