1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 // UNSUPPORTED: libcpp-no-concepts
11 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
12 
13 // template<class I1, class I2, class Out,
14 //     class R = ranges::less, class P1 = identity, class P2 = identity>
15 //   concept mergeable = see below;                           // since C++20
16 
17 #include <iterator>
18 
19 #include <functional>
20 
21 #include "test_iterators.h"
22 #include "test_macros.h"
23 
24 using CompDefault = std::ranges::less;
25 using CompInt = bool(*)(int, int);
26 using ProjDefault = std::identity;
27 
28 using Input = cpp20_input_iterator<int*>;
29 static_assert( std::input_iterator<Input>);
30 using InputLong = cpp20_input_iterator<long*>;
31 static_assert( std::input_iterator<InputLong>);
32 
33 using Output = cpp17_output_iterator<int*>;
34 static_assert( std::weakly_incrementable<Output>);
35 
36 static_assert( std::indirectly_copyable<Input, Output>);
37 static_assert( std::indirectly_copyable<InputLong, Output>);
38 static_assert( std::indirect_strict_weak_order<CompDefault, Input, Input>);
39 static_assert( std::indirect_strict_weak_order<CompInt, Input, Input>);
40 static_assert( std::indirect_strict_weak_order<CompDefault, Input, InputLong>);
41 static_assert( std::indirect_strict_weak_order<CompInt, Input, InputLong>);
42 
43 // All requirements satisfied.
44 static_assert( std::mergeable<Input, Input, Output>);
45 static_assert( std::mergeable<Input, Input, Output, CompInt>);
46 static_assert( std::mergeable<Input, Input, Output, CompInt, ProjDefault>);
47 
48 // Non-default projections.
49 struct Foo {};
50 using ProjFooToInt = int(*)(Foo);
51 using ProjFooToLong = long(*)(Foo);
52 static_assert( std::indirect_strict_weak_order<CompDefault,
53     std::projected<Foo*, ProjFooToInt>, std::projected<Foo*, ProjFooToLong>>);
54 static_assert( std::mergeable<Foo*, Foo*, Foo*, CompDefault, ProjFooToInt, ProjFooToLong>);
55 static_assert( std::indirect_strict_weak_order<CompInt,
56     std::projected<Foo*, ProjFooToInt>, std::projected<Foo*, ProjFooToLong>>);
57 static_assert( std::mergeable<Foo*, Foo*, Foo*, CompInt, ProjFooToInt, ProjFooToLong>);
58 
59 // I1 or I2 is not an input iterator.
60 static_assert(!std::input_iterator<Output>);
61 static_assert(!std::mergeable<Output, Input, Output>);
62 static_assert(!std::mergeable<Input, Output, Output>);
63 
64 // O is not weakly incrementable.
65 struct NotWeaklyIncrementable {
66   int& operator*() const;
67 };
68 
69 static_assert(!std::weakly_incrementable<NotWeaklyIncrementable>);
70 static_assert( std::indirectly_copyable<Input, NotWeaklyIncrementable>);
71 static_assert( std::indirect_strict_weak_order<CompDefault, Input, Input>);
72 static_assert(!std::mergeable<Input, Input, NotWeaklyIncrementable>);
73 
74 // I1 or I2 is not indirectly copyable into O.
75 struct AssignableOnlyFromInt {
76   AssignableOnlyFromInt& operator=(int);
77   template <class T>
78   AssignableOnlyFromInt& operator=(T) = delete;
79 };
80 using OutputOnlyInt = cpp17_output_iterator<AssignableOnlyFromInt*>;
81 static_assert( std::weakly_incrementable<OutputOnlyInt>);
82 
83 static_assert( std::indirectly_copyable<Input, OutputOnlyInt>);
84 static_assert(!std::indirectly_copyable<InputLong, OutputOnlyInt>);
85 static_assert( std::indirect_strict_weak_order<CompDefault, Input, InputLong>);
86 static_assert( std::mergeable<Input, Input, OutputOnlyInt>);
87 static_assert(!std::mergeable<Input, InputLong, OutputOnlyInt>);
88 static_assert(!std::mergeable<InputLong, Input, OutputOnlyInt>);
89 
90 // No indirect strict weak order between I1 and I2 (bad comparison functor).
91 using GoodComp = bool(*)(int, int);
92 static_assert( std::indirect_strict_weak_order<GoodComp, Input, Input>);
93 static_assert( std::mergeable<Input, Input, Output, GoodComp>);
94 using BadComp = bool(*)(int*, int*);
95 static_assert(!std::indirect_strict_weak_order<BadComp, Input, Input>);
96 static_assert(!std::mergeable<Input, Input, Output, BadComp>);
97 
98 // No indirect strict weak order between I1 and I2 (bad projection).
99 using ToInt = int(*)(int);
100 using ToPtr = int*(*)(int);
101 static_assert( std::mergeable<Input, Input, Output, GoodComp, std::identity, std::identity>);
102 static_assert( std::mergeable<Input, Input, Output, GoodComp, ToInt, ToInt>);
103 static_assert(!std::mergeable<Input, Input, Output, GoodComp, ToPtr, ToInt>);
104 static_assert(!std::mergeable<Input, Input, Output, GoodComp, ToInt, ToPtr>);
105 static_assert(!std::mergeable<Input, Input, Output, bool(*)(int*, int), ToPtr, ToInt>);
106 static_assert(!std::mergeable<Input, Input, Output, bool(*)(int, int*), ToInt, ToPtr>);
107 
108 // A projection that only supports non-const references and has a non-const `operator()` still has to work.
109 struct ProjectionOnlyMutable {
110   int operator()(int&);
111   int operator()(int&&) const = delete;
112 };
113 static_assert( std::mergeable<Input, Input, Output, CompDefault, ProjectionOnlyMutable, ProjectionOnlyMutable>);
114 
115 // The output is weakly incrementable but not an output iterator.
116 struct WeaklyIncrementable {
117   using value_type = int;
118   using difference_type = int;
119 
120   int& operator*() const;
121   WeaklyIncrementable& operator++();
122   // `output_iterator` requires `i++` to return an iterator,
123   // while `weakly_incrementable` requires only that `i++` be well-formed.
124   void operator++(int);
125 };
126 static_assert( std::weakly_incrementable<WeaklyIncrementable>);
127 static_assert( std::indirectly_copyable<int*, WeaklyIncrementable>);
128 static_assert(!std::output_iterator<WeaklyIncrementable, int>);
129 static_assert( std::mergeable<Input, Input, WeaklyIncrementable>);
130