1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
13 // template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
14 // sentinel_for<I2> S2, class Proj1 = identity, class Proj2 = identity,
15 // indirect_equivalence_relation<projected<I1, Proj1>,
16 // projected<I2, Proj2>> Pred = ranges::equal_to>
17 // constexpr bool ranges::is_permutation(I1 first1, S1 last1, I2 first2, S2 last2,
19 // Proj1 proj1 = {}, Proj2 proj2 = {}); // Since C++20
21 // template<forward_range R1, forward_range R2,
22 // class Proj1 = identity, class Proj2 = identity,
23 // indirect_equivalence_relation<projected<iterator_t<R1>, Proj1>,
24 // projected<iterator_t<R2>, Proj2>> Pred = ranges::equal_to>
25 // constexpr bool ranges::is_permutation(R1&& r1, R2&& r2, Pred pred = {},
26 // Proj1 proj1 = {}, Proj2 proj2 = {}); // Since C++20
34 #include "almost_satisfies_types.h"
35 #include "counting_predicates.h"
36 #include "counting_projection.h"
37 #include "test_iterators.h"
39 template <class Iter1
, class Sent1
= int*, class Iter2
= int*, class Sent2
= int*>
40 concept HasIsPermutationIt
= requires(Iter1 first1
, Sent1 last1
, Iter2 first2
, Sent2 last2
) {
41 std::ranges::is_permutation(first1
, last1
, first2
, last2
);
44 template <class Range1
, class Range2
= UncheckedRange
<int*>>
45 concept HasIsPermutationR
= requires(Range1 range1
, Range2 range2
) {
46 std::ranges::is_permutation(range1
, range2
);
49 static_assert(HasIsPermutationIt
<int*>);
50 static_assert(!HasIsPermutationIt
<ForwardIteratorNotDerivedFrom
>);
51 static_assert(!HasIsPermutationIt
<ForwardIteratorNotIncrementable
>);
52 static_assert(!HasIsPermutationIt
<int*, SentinelForNotSemiregular
>);
53 static_assert(!HasIsPermutationIt
<int*, SentinelForNotWeaklyEqualityComparableWith
>);
54 static_assert(!HasIsPermutationIt
<int*, int*, ForwardIteratorNotDerivedFrom
>);
55 static_assert(!HasIsPermutationIt
<int*, int*, ForwardIteratorNotIncrementable
>);
56 static_assert(!HasIsPermutationIt
<int*, int*, int*, SentinelForNotSemiregular
>);
57 static_assert(!HasIsPermutationIt
<int*, int*, int*, SentinelForNotWeaklyEqualityComparableWith
>);
58 // !indirect_equivalence_relation<Pred, projected<I1, Proj1>, projected<I2, Proj2>>;
59 static_assert(!HasIsPermutationIt
<int*, int*, int**, int**>);
61 static_assert(HasIsPermutationR
<UncheckedRange
<int*>>);
62 static_assert(!HasIsPermutationR
<ForwardRangeNotDerivedFrom
>);
63 static_assert(!HasIsPermutationR
<ForwardRangeNotIncrementable
>);
64 static_assert(!HasIsPermutationR
<int*, ForwardRangeNotSentinelSemiregular
>);
65 static_assert(!HasIsPermutationR
<int*, ForwardRangeNotSentinelEqualityComparableWith
>);
66 static_assert(!HasIsPermutationR
<UncheckedRange
<int*>, ForwardRangeNotDerivedFrom
>);
67 static_assert(!HasIsPermutationR
<UncheckedRange
<int*>, ForwardRangeNotIncrementable
>);
68 static_assert(!HasIsPermutationR
<UncheckedRange
<int*>, ForwardRangeNotSentinelSemiregular
>);
69 static_assert(!HasIsPermutationR
<UncheckedRange
<int*>, ForwardRangeNotSentinelEqualityComparableWith
>);
70 // !indirect_equivalence_relation<Pred, projected<iterator_t<I1>, Proj1>, projected<iterator_t<I2>, Proj2>>;
71 static_assert(!HasIsPermutationIt
<UncheckedRange
<int*>, UncheckedRange
<int**>>);
73 template <int N
, int M
>
75 std::array
<int, N
> input1
;
76 std::array
<int, M
> input2
;
80 template <class Iter1
, class Sent1
, class Iter2
, class Sent2
, int N
, int M
>
81 constexpr void test(Data
<N
, M
> d
) {
83 std::same_as
<bool> decltype(auto) ret
= std::ranges::is_permutation(Iter1(d
.input1
.data()),
84 Sent1(Iter1(d
.input1
.data() + N
)),
85 Iter1(d
.input2
.data()),
86 Sent1(Iter1(d
.input2
.data() + M
)));
87 assert(ret
== d
.expected
);
90 auto range1
= std::ranges::subrange(Iter1(d
.input1
.data()), Sent1(Iter1(d
.input1
.data() + N
)));
91 auto range2
= std::ranges::subrange(Iter1(d
.input2
.data()), Sent1(Iter1(d
.input2
.data() + M
)));
92 std::same_as
<bool> decltype(auto) ret
= std::ranges::is_permutation(range1
, range2
);
93 assert(ret
== d
.expected
);
97 template <class Iter1
, class Sent1
, class Iter2
, class Sent2
= Iter2
>
98 constexpr void test_iterators() {
99 // Ranges are identical.
100 test
<Iter1
, Sent1
, Iter2
, Sent2
, 4, 4>({.input1
= {1, 2, 3, 4}, .input2
= {1, 2, 3, 4}, .expected
= true});
102 // Ranges are reversed.
103 test
<Iter1
, Sent1
, Iter2
, Sent2
, 4, 4>({.input1
= {1, 2, 3, 4}, .input2
= {4, 3, 2, 1}, .expected
= true});
105 // Two elements are swapped.
106 test
<Iter1
, Sent1
, Iter2
, Sent2
, 4, 4>({.input1
= {4, 2, 3, 1}, .input2
= {1, 2, 3, 4}, .expected
= true});
108 // The first range is shorter.
109 test
<Iter1
, Sent1
, Iter2
, Sent2
, 4, 5>({.input1
= {4, 2, 3, 1}, .input2
= {4, 3, 2, 1, 5}, .expected
= false});
111 // The first range is longer.
112 test
<Iter1
, Sent1
, Iter2
, Sent2
, 5, 4>({.input1
= {4, 2, 3, 1, 5}, .input2
= {4, 3, 2, 1}, .expected
= false});
114 // The first range is empty.
115 test
<Iter1
, Sent1
, Iter2
, Sent2
, 0, 4>({.input1
= {}, .input2
= {4, 3, 2, 1}, .expected
= false});
117 // The second range is empty.
118 test
<Iter1
, Sent1
, Iter2
, Sent2
, 5, 0>({.input1
= {4, 2, 3, 1, 5}, .input2
= {}, .expected
= false});
120 // Both ranges are empty.
121 test
<Iter1
, Sent1
, Iter2
, Sent2
, 0, 0>({.input1
= {}, .input2
= {}, .expected
= true});
123 // 1-element range, same value.
124 test
<Iter1
, Sent1
, Iter2
, Sent2
, 1, 1>({.input1
= {1}, .input2
= {1}, .expected
= true});
126 // 1-element range, different values.
127 test
<Iter1
, Sent1
, Iter2
, Sent2
, 1, 1>({.input1
= {1}, .input2
= {2}, .expected
= false});
130 template <class Iter1
, class Sent1
= Iter1
>
131 constexpr void test_iterators1() {
132 test_iterators
<Iter1
, Sent1
, forward_iterator
<int*>, sentinel_wrapper
<forward_iterator
<int*>>>();
133 test_iterators
<Iter1
, Sent1
, forward_iterator
<int*>>();
134 test_iterators
<Iter1
, Sent1
, bidirectional_iterator
<int*>>();
135 test_iterators
<Iter1
, Sent1
, random_access_iterator
<int*>>();
136 test_iterators
<Iter1
, Sent1
, contiguous_iterator
<int*>>();
137 test_iterators
<Iter1
, Sent1
, int*>();
138 test_iterators
<Iter1
, Sent1
, const int*>();
141 constexpr bool test() {
142 test_iterators1
<forward_iterator
<int*>, sentinel_wrapper
<forward_iterator
<int*>>>();
143 test_iterators1
<forward_iterator
<int*>>();
144 test_iterators1
<bidirectional_iterator
<int*>>();
145 test_iterators1
<random_access_iterator
<int*>>();
146 test_iterators1
<contiguous_iterator
<int*>>();
147 test_iterators1
<int*>();
148 test_iterators1
<const int*>();
150 { // A custom comparator works.
153 constexpr bool pred(const A
& rhs
) const { return a
== rhs
.a
; }
156 std::array in1
= {A
{2}, A
{3}, A
{1}};
157 std::array in2
= {A
{1}, A
{2}, A
{3}};
160 auto ret
= std::ranges::is_permutation(in1
.begin(), in1
.end(), in2
.begin(), in2
.end(), &A::pred
);
165 auto ret
= std::ranges::is_permutation(in1
, in2
, &A::pred
);
170 { // A custom projection works.
174 constexpr bool operator==(const A
&) const = default;
176 constexpr A
x2() const { return A
{a
* 2}; }
177 constexpr A
div2() const { return A
{a
/ 2}; }
180 std::array in1
= {A
{1}, A
{2}, A
{3}}; // [2, 4, 6] after applying `x2`.
181 std::array in2
= {A
{4}, A
{8}, A
{12}}; // [2, 4, 6] after applying `div2`.
184 auto ret
= std::ranges::is_permutation(
185 in1
.begin(), in1
.end(), in2
.begin(), in2
.end(), {}, &A::x2
, &A::div2
);
190 auto ret
= std::ranges::is_permutation(in1
, in2
, {}, &A::x2
, &A::div2
);
196 { // Check that complexity requirements are met.
200 auto reset_counters
= [&] {
201 predCount
= proj1Count
= proj2Count
= 0;
204 counting_predicate
pred(std::ranges::equal_to
{}, predCount
);
205 counting_projection
<> proj1(proj1Count
);
206 counting_projection
<> proj2(proj2Count
);
209 // 1. No applications of the corresponding predicate if `ForwardIterator1` and `ForwardIterator2` meet the
210 // requirements of random access iterators and `last1 - first1 != last2 - first2`.
211 int a
[] = {1, 2, 3, 4, 5};
212 int b
[] = {1, 2, 3, 4};
213 // Make sure that the iterators have different types.
214 auto b_begin
= random_access_iterator
<int*>(std::begin(b
));
215 auto b_end
= random_access_iterator
<int*>(std::end(b
));
218 auto ret
= std::ranges::is_permutation(a
, a
+ 5, b_begin
, b_end
, pred
, proj1
, proj2
);
221 assert(predCount
== 0);
222 assert(proj1Count
== 0);
223 assert(proj2Count
== 0);
228 auto ret
= std::ranges::is_permutation(a
, std::ranges::subrange(b_begin
, b_end
), pred
, proj1
, proj2
);
231 assert(predCount
== 0);
232 assert(proj1Count
== 0);
233 assert(proj2Count
== 0);
238 // 2. Otherwise, exactly last1 - first1 applications of the corresponding predicate if
239 // `equal(first1, last1, first2, last2, pred)` would return true.
241 int a
[] = {1, 2, 3, 4, 5};
242 int b
[] = {1, 2, 3, 4, 5};
246 auto ret
= std::ranges::is_permutation(a
, a
+ 5, b
, b
+ 5, pred
, proj1
, proj2
);
249 assert(predCount
== expected
);
250 assert(proj1Count
== expected
);
251 assert(proj2Count
== expected
);
256 auto ret
= std::ranges::is_permutation(a
, b
, pred
, proj1
, proj2
);
259 assert(predCount
== expected
);
260 assert(proj1Count
== expected
);
261 assert(proj2Count
== expected
);
266 // Note: we currently don't have the setup to test big-O complexity, but copying the requirement for completeness'
268 // 3. Otherwise, at worst `O(N^2)`, where `N` has the value `last1 - first1`.
275 int main(int, char**) {
277 static_assert(test());