[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