[libcxx-commits] [libcxx] eea3d90 - [libc++][ranges] Implement `std::mergeable`.

Konstantin Varlamov via libcxx-commits libcxx-commits at lists.llvm.org
Thu Feb 17 20:12:40 PST 2022


Author: Konstantin Varlamov
Date: 2022-02-17T20:12:04-08:00
New Revision: eea3d90af181fdb66e583af53401e80ddfcc8cd1

URL: https://github.com/llvm/llvm-project/commit/eea3d90af181fdb66e583af53401e80ddfcc8cd1
DIFF: https://github.com/llvm/llvm-project/commit/eea3d90af181fdb66e583af53401e80ddfcc8cd1.diff

LOG: [libc++][ranges] Implement `std::mergeable`.

Differential Revision: https://reviews.llvm.org/D119489

Added: 
    libcxx/include/__iterator/mergeable.h
    libcxx/test/libcxx/diagnostics/detail.headers/iterator/mergeable.module.verify.cpp
    libcxx/test/std/iterators/iterator.requirements/alg.req.mergeable/mergeable.compile.pass.cpp
    libcxx/test/std/iterators/iterator.requirements/alg.req.mergeable/mergeable.subsumption.compile.pass.cpp

Modified: 
    libcxx/docs/Status/RangesPaper.csv
    libcxx/include/CMakeLists.txt
    libcxx/include/iterator
    libcxx/include/module.modulemap

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv
index 3e7be37614ad1..e67abd35873dc 100644
--- a/libcxx/docs/Status/RangesPaper.csv
+++ b/libcxx/docs/Status/RangesPaper.csv
@@ -65,7 +65,7 @@ Section,Description,Dependencies,Assignee,Complete
 | [iterator.cust.swap]",Zoe Carver,✅
 `[alg.req] <https://wg21.link/alg.req>`_: pt. 3,`indirectly_comparable <https://llvm.org/D116268>`_,[projected],Nikolas Klauser,✅
 `[alg.req] <https://wg21.link/alg.req>`_: pt. 4,"| `permutable <https://llvm.org/D119222>`_
-| mergeable
+| `mergeable <https://llvm.org/D119489>`_
 | sortable",[iterator.concepts],Konstantin Varlamov,In progress
 `[std.iterator.tags] <https://wg21.link/std.iterator.tags>`_,"| `contiguous_iterator_tag <https://llvm.org/rG45d048c20440989df2b4e1be1f9343225e7741ab>`_
 | `iterator_concept specialization for pointers <https://llvm.org/rG45d048c20440989df2b4e1be1f9343225e7741ab>`_

diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 1e5299f00c2e5..0858a90fe2a6d 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -243,6 +243,7 @@ set(files
   __iterator/iter_swap.h
   __iterator/iterator.h
   __iterator/iterator_traits.h
+  __iterator/mergeable.h
   __iterator/move_iterator.h
   __iterator/next.h
   __iterator/ostream_iterator.h

diff  --git a/libcxx/include/__iterator/mergeable.h b/libcxx/include/__iterator/mergeable.h
new file mode 100644
index 0000000000000..08022aab6d272
--- /dev/null
+++ b/libcxx/include/__iterator/mergeable.h
@@ -0,0 +1,41 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ITERATOR_MERGEABLE_H
+#define _LIBCPP___ITERATOR_MERGEABLE_H
+
+#include <__config>
+#include <__functional/identity.h>
+#include <__functional/ranges_operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/projected.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
+
+template <class _Input1, class _Input2, class _Output,
+          class _Comp = ranges::less, class _Proj1 = identity, class _Proj2 = identity>
+concept mergeable =
+    input_iterator<_Input1> &&
+    input_iterator<_Input2> &&
+    weakly_incrementable<_Output> &&
+    indirectly_copyable<_Input1, _Output> &&
+    indirectly_copyable<_Input2, _Output> &&
+    indirect_strict_weak_order<_Comp, projected<_Input1, _Proj1>, projected<_Input2, _Proj2>>;
+
+#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___ITERATOR_MERGEABLE_H

diff  --git a/libcxx/include/iterator b/libcxx/include/iterator
index fe91d15e6bc31..1668be3a60c8e 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -147,15 +147,20 @@ template<class In, class Out>
 template<class I1, class I2 = I1>
   concept indirectly_swappable = see below;                // since C++20
 
-// [alg.req.permutable], concept permutable                // since C++20
-template<class I>
-  concept permutable = see below;
-
 template<class I1, class I2, class R, class P1 = identity,
          class P2 = identity>
   concept indirectly_comparable =
     indirect_binary_predicate<R, projected<I1, P1>, projected<I2, P2>>; // since C++20
 
+// [alg.req.permutable], concept permutable                // since C++20
+template<class I>
+  concept permutable = see below;
+
+ // [alg.req.mergeable], concept mergeable
+template<class I1, class I2, class Out,
+    class R = ranges::less, class P1 = identity, class P2 = identity>
+  concept mergeable = see below;                           // since C++20
+
 template<input_or_output_iterator I, sentinel_for<I> S>
   requires (!same_as<I, S> && copyable<I>)
 class common_iterator;                                     // since C++20
@@ -623,6 +628,7 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
 #include <__iterator/iter_swap.h>
 #include <__iterator/iterator.h>
 #include <__iterator/iterator_traits.h>
+#include <__iterator/mergeable.h>
 #include <__iterator/move_iterator.h>
 #include <__iterator/next.h>
 #include <__iterator/ostream_iterator.h>

diff  --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index a44493968db7e..ea050751d9ca7 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -628,6 +628,7 @@ module std [system] {
       module iter_swap             { private header "__iterator/iter_swap.h" }
       module iterator              { private header "__iterator/iterator.h" }
       module iterator_traits       { private header "__iterator/iterator_traits.h" }
+      module mergeable             { private header "__iterator/mergeable.h" }
       module move_iterator         { private header "__iterator/move_iterator.h" }
       module next                  { private header "__iterator/next.h" }
       module ostream_iterator      { private header "__iterator/ostream_iterator.h" }

diff  --git a/libcxx/test/libcxx/diagnostics/detail.headers/iterator/mergeable.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/iterator/mergeable.module.verify.cpp
new file mode 100644
index 0000000000000..b8f15dcbd6d1e
--- /dev/null
+++ b/libcxx/test/libcxx/diagnostics/detail.headers/iterator/mergeable.module.verify.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: modules-build
+
+// WARNING: This test was generated by 'generate_private_header_tests.py'
+// and should not be edited manually.
+
+// expected-error@*:* {{use of private header from outside its module: '__iterator/mergeable.h'}}
+#include <__iterator/mergeable.h>

diff  --git a/libcxx/test/std/iterators/iterator.requirements/alg.req.mergeable/mergeable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/alg.req.mergeable/mergeable.compile.pass.cpp
new file mode 100644
index 0000000000000..21dc0c204cec3
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/alg.req.mergeable/mergeable.compile.pass.cpp
@@ -0,0 +1,129 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: libcpp-has-no-incomplete-ranges
+
+// template<class I1, class I2, class Out,
+//     class R = ranges::less, class P1 = identity, class P2 = identity>
+//   concept mergeable = see below;                           // since C++20
+
+#include <iterator>
+
+#include <functional>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+using CompDefault = std::ranges::less;
+using CompInt = bool(*)(int, int);
+using ProjDefault = std::identity;
+
+using Input = cpp20_input_iterator<int*>;
+static_assert( std::input_iterator<Input>);
+using InputLong = cpp20_input_iterator<long*>;
+static_assert( std::input_iterator<InputLong>);
+
+using Output = cpp17_output_iterator<int*>;
+static_assert( std::weakly_incrementable<Output>);
+
+static_assert( std::indirectly_copyable<Input, Output>);
+static_assert( std::indirectly_copyable<InputLong, Output>);
+static_assert( std::indirect_strict_weak_order<CompDefault, Input, Input>);
+static_assert( std::indirect_strict_weak_order<CompInt, Input, Input>);
+static_assert( std::indirect_strict_weak_order<CompDefault, Input, InputLong>);
+static_assert( std::indirect_strict_weak_order<CompInt, Input, InputLong>);
+
+// All requirements satisfied.
+static_assert( std::mergeable<Input, Input, Output>);
+static_assert( std::mergeable<Input, Input, Output, CompInt>);
+static_assert( std::mergeable<Input, Input, Output, CompInt, ProjDefault>);
+
+// Non-default projections.
+struct Foo {};
+using ProjFooToInt = int(*)(Foo);
+using ProjFooToLong = long(*)(Foo);
+static_assert( std::indirect_strict_weak_order<CompDefault,
+    std::projected<Foo*, ProjFooToInt>, std::projected<Foo*, ProjFooToLong>>);
+static_assert( std::mergeable<Foo*, Foo*, Foo*, CompDefault, ProjFooToInt, ProjFooToLong>);
+static_assert( std::indirect_strict_weak_order<CompInt,
+    std::projected<Foo*, ProjFooToInt>, std::projected<Foo*, ProjFooToLong>>);
+static_assert( std::mergeable<Foo*, Foo*, Foo*, CompInt, ProjFooToInt, ProjFooToLong>);
+
+// I1 or I2 is not an input iterator.
+static_assert(!std::input_iterator<Output>);
+static_assert(!std::mergeable<Output, Input, Output>);
+static_assert(!std::mergeable<Input, Output, Output>);
+
+// O is not weakly incrementable.
+struct NotWeaklyIncrementable {
+  int& operator*() const;
+};
+
+static_assert(!std::weakly_incrementable<NotWeaklyIncrementable>);
+static_assert( std::indirectly_copyable<Input, NotWeaklyIncrementable>);
+static_assert( std::indirect_strict_weak_order<CompDefault, Input, Input>);
+static_assert(!std::mergeable<Input, Input, NotWeaklyIncrementable>);
+
+// I1 or I2 is not indirectly copyable into O.
+struct AssignableOnlyFromInt {
+  AssignableOnlyFromInt& operator=(int);
+  template <class T>
+  AssignableOnlyFromInt& operator=(T) = delete;
+};
+using OutputOnlyInt = cpp17_output_iterator<AssignableOnlyFromInt*>;
+static_assert( std::weakly_incrementable<OutputOnlyInt>);
+
+static_assert( std::indirectly_copyable<Input, OutputOnlyInt>);
+static_assert(!std::indirectly_copyable<InputLong, OutputOnlyInt>);
+static_assert( std::indirect_strict_weak_order<CompDefault, Input, InputLong>);
+static_assert( std::mergeable<Input, Input, OutputOnlyInt>);
+static_assert(!std::mergeable<Input, InputLong, OutputOnlyInt>);
+static_assert(!std::mergeable<InputLong, Input, OutputOnlyInt>);
+
+// No indirect strict weak order between I1 and I2 (bad comparison functor).
+using GoodComp = bool(*)(int, int);
+static_assert( std::indirect_strict_weak_order<GoodComp, Input, Input>);
+static_assert( std::mergeable<Input, Input, Output, GoodComp>);
+using BadComp = bool(*)(int*, int*);
+static_assert(!std::indirect_strict_weak_order<BadComp, Input, Input>);
+static_assert(!std::mergeable<Input, Input, Output, BadComp>);
+
+// No indirect strict weak order between I1 and I2 (bad projection).
+using ToInt = int(*)(int);
+using ToPtr = int*(*)(int);
+static_assert( std::mergeable<Input, Input, Output, GoodComp, std::identity, std::identity>);
+static_assert( std::mergeable<Input, Input, Output, GoodComp, ToInt, ToInt>);
+static_assert(!std::mergeable<Input, Input, Output, GoodComp, ToPtr, ToInt>);
+static_assert(!std::mergeable<Input, Input, Output, GoodComp, ToInt, ToPtr>);
+static_assert(!std::mergeable<Input, Input, Output, bool(*)(int*, int), ToPtr, ToInt>);
+static_assert(!std::mergeable<Input, Input, Output, bool(*)(int, int*), ToInt, ToPtr>);
+
+// A projection that only supports non-const references and has a non-const `operator()` still has to work.
+struct ProjectionOnlyMutable {
+  int operator()(int&);
+  int operator()(int&&) const = delete;
+};
+static_assert( std::mergeable<Input, Input, Output, CompDefault, ProjectionOnlyMutable, ProjectionOnlyMutable>);
+
+// The output is weakly incrementable but not an output iterator.
+struct WeaklyIncrementable {
+  using value_type = int;
+  using 
diff erence_type = int;
+
+  int& operator*() const;
+  WeaklyIncrementable& operator++();
+  // `output_iterator` requires `i++` to return an iterator,
+  // while `weakly_incrementable` requires only that `i++` be well-formed.
+  void operator++(int);
+};
+static_assert( std::weakly_incrementable<WeaklyIncrementable>);
+static_assert( std::indirectly_copyable<int*, WeaklyIncrementable>);
+static_assert(!std::output_iterator<WeaklyIncrementable, int>);
+static_assert( std::mergeable<Input, Input, WeaklyIncrementable>);

diff  --git a/libcxx/test/std/iterators/iterator.requirements/alg.req.mergeable/mergeable.subsumption.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/alg.req.mergeable/mergeable.subsumption.compile.pass.cpp
new file mode 100644
index 0000000000000..a17a523e6aeab
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/alg.req.mergeable/mergeable.subsumption.compile.pass.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: libcpp-has-no-incomplete-ranges
+
+// template<class I1, class I2, class Out,
+//     class R = ranges::less, class P1 = identity, class P2 = identity>
+//   concept mergeable = see below;                           // since C++20
+
+#include <iterator>
+
+#include "test_macros.h"
+
+template <class I1, class I2, class O>
+void test_subsumption() requires std::input_iterator<I1> && std::input_iterator<I2>;
+
+template <class I1, class I2, class O>
+void test_subsumption() requires std::weakly_incrementable<O>;
+
+template <class I1, class I2, class O>
+void test_subsumption() requires std::indirectly_copyable<I1, O> && std::indirectly_copyable<I2, O>;
+
+template <class I1, class I2, class O>
+void test_subsumption() requires std::indirect_strict_weak_order<I1, I2>;
+
+template <class I1, class I2, class O>
+constexpr bool test_subsumption() requires std::mergeable<I1, I2, O> {
+  return true;
+}
+
+static_assert(test_subsumption<int*, int*, int*>());


        


More information about the libcxx-commits mailing list