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