|
11 | 11 | #define _LIBCPP___ALGORITHM_IS_PERMUTATION_H
|
12 | 12 |
|
13 | 13 | #include <__algorithm/comp.h>
|
| 14 | +#include <__algorithm/iterator_operations.h> |
14 | 15 | #include <__config>
|
| 16 | +#include <__functional/identity.h> |
| 17 | +#include <__functional/invoke.h> |
| 18 | +#include <__iterator/concepts.h> |
15 | 19 | #include <__iterator/distance.h>
|
16 | 20 | #include <__iterator/iterator_traits.h>
|
17 | 21 | #include <__iterator/next.h>
|
| 22 | +#include <__utility/move.h> |
| 23 | +#include <type_traits> |
18 | 24 |
|
19 | 25 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
20 | 26 | # pragma GCC system_header
|
21 | 27 | #endif
|
22 | 28 |
|
23 | 29 | _LIBCPP_BEGIN_NAMESPACE_STD
|
24 | 30 |
|
25 |
| -template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate> |
26 |
| -_LIBCPP_NODISCARD_EXT _LIBCPP_CONSTEXPR_AFTER_CXX17 bool |
27 |
| -is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, |
28 |
| - _BinaryPredicate __pred) { |
29 |
| - // shorten sequences as much as possible by lopping of any equal prefix |
30 |
| - for (; __first1 != __last1; ++__first1, (void)++__first2) |
31 |
| - if (!__pred(*__first1, *__first2)) |
32 |
| - break; |
33 |
| - if (__first1 == __last1) |
34 |
| - return true; |
| 31 | +template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class = void> |
| 32 | +struct _ConstTimeDistance : false_type {}; |
35 | 33 |
|
36 |
| - // __first1 != __last1 && *__first1 != *__first2 |
37 |
| - typedef typename iterator_traits<_ForwardIterator1>::difference_type _D1; |
38 |
| - _D1 __l1 = _VSTD::distance(__first1, __last1); |
39 |
| - if (__l1 == _D1(1)) |
40 |
| - return false; |
41 |
| - _ForwardIterator2 __last2 = _VSTD::next(__first2, __l1); |
42 |
| - // For each element in [f1, l1) see if there are the same number of |
43 |
| - // equal elements in [f2, l2) |
44 |
| - for (_ForwardIterator1 __i = __first1; __i != __last1; ++__i) { |
| 34 | +#if _LIBCPP_STD_VER > 17 |
| 35 | + |
| 36 | +template <class _Iter1, class _Sent1, class _Iter2, class _Sent2> |
| 37 | +struct _ConstTimeDistance<_Iter1, _Sent1, _Iter2, _Sent2, __enable_if_t< |
| 38 | + sized_sentinel_for<_Sent1, _Iter1> && |
| 39 | + sized_sentinel_for<_Sent2, _Iter2> |
| 40 | +>> : true_type {}; |
| 41 | + |
| 42 | +#else |
| 43 | + |
| 44 | +template <class _Iter1, class _Iter2> |
| 45 | +struct _ConstTimeDistance<_Iter1, _Iter1, _Iter2, _Iter2, __enable_if_t< |
| 46 | + is_same<typename iterator_traits<_Iter1>::iterator_category, random_access_iterator_tag>::value && |
| 47 | + is_same<typename iterator_traits<_Iter2>::iterator_category, random_access_iterator_tag>::value |
| 48 | +> > : true_type {}; |
| 49 | + |
| 50 | +#endif // _LIBCPP_STD_VER > 17 |
| 51 | + |
| 52 | +// Internal functions |
| 53 | + |
| 54 | +// For each element in [f1, l1) see if there are the same number of equal elements in [f2, l2) |
| 55 | +template <class _AlgPolicy, |
| 56 | + class _Iter1, class _Sent1, class _Iter2, class _Sent2, |
| 57 | + class _Proj1, class _Proj2, class _Pred> |
| 58 | +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool |
| 59 | +__is_permutation_impl(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, |
| 60 | + _Pred&& __pred, _Proj1&& __proj1, _Proj2&& __proj2) { |
| 61 | + using _D1 = __iter_diff_t<_Iter1>; |
| 62 | + |
| 63 | + for (auto __i = __first1; __i != __last1; ++__i) { |
45 | 64 | // Have we already counted the number of *__i in [f1, l1)?
|
46 |
| - _ForwardIterator1 __match = __first1; |
47 |
| - for (; __match != __i; ++__match) |
48 |
| - if (__pred(*__match, *__i)) |
| 65 | + auto __match = __first1; |
| 66 | + for (; __match != __i; ++__match) { |
| 67 | + if (std::__invoke(__pred, std::__invoke(__proj1, *__match), std::__invoke(__proj1, *__i))) |
49 | 68 | break;
|
| 69 | + } |
| 70 | + |
50 | 71 | if (__match == __i) {
|
51 | 72 | // Count number of *__i in [f2, l2)
|
52 | 73 | _D1 __c2 = 0;
|
53 |
| - for (_ForwardIterator2 __j = __first2; __j != __last2; ++__j) |
54 |
| - if (__pred(*__i, *__j)) |
| 74 | + for (auto __j = __first2; __j != __last2; ++__j) { |
| 75 | + if (std::__invoke(__pred, std::__invoke(__proj1, *__i), std::__invoke(__proj2, *__j))) |
55 | 76 | ++__c2;
|
| 77 | + } |
56 | 78 | if (__c2 == 0)
|
57 | 79 | return false;
|
| 80 | + |
58 | 81 | // Count number of *__i in [__i, l1) (we can start with 1)
|
59 | 82 | _D1 __c1 = 1;
|
60 |
| - for (_ForwardIterator1 __j = _VSTD::next(__i); __j != __last1; ++__j) |
61 |
| - if (__pred(*__i, *__j)) |
| 83 | + for (auto __j = _IterOps<_AlgPolicy>::next(__i); __j != __last1; ++__j) { |
| 84 | + if (std::__invoke(__pred, std::__invoke(__proj1, *__i), std::__invoke(__proj1, *__j))) |
62 | 85 | ++__c1;
|
| 86 | + } |
63 | 87 | if (__c1 != __c2)
|
64 | 88 | return false;
|
65 | 89 | }
|
66 | 90 | }
|
| 91 | + |
67 | 92 | return true;
|
68 | 93 | }
|
69 | 94 |
|
70 |
| -template <class _ForwardIterator1, class _ForwardIterator2> |
71 |
| -_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool |
72 |
| -is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) { |
73 |
| - typedef typename iterator_traits<_ForwardIterator1>::value_type __v1; |
74 |
| - typedef typename iterator_traits<_ForwardIterator2>::value_type __v2; |
75 |
| - return _VSTD::is_permutation(__first1, __last1, __first2, __equal_to<__v1, __v2>()); |
| 95 | +// 2+1 iterators, predicate. Not used by range algorithms. |
| 96 | +template <class _AlgPolicy, class _ForwardIterator1, class _Sentinel1, class _ForwardIterator2, class _BinaryPredicate> |
| 97 | +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool |
| 98 | +__is_permutation(_ForwardIterator1 __first1, _Sentinel1 __last1, _ForwardIterator2 __first2, |
| 99 | + _BinaryPredicate&& __pred) { |
| 100 | + // Shorten sequences as much as possible by lopping of any equal prefix. |
| 101 | + for (; __first1 != __last1; ++__first1, (void)++__first2) { |
| 102 | + if (!__pred(*__first1, *__first2)) |
| 103 | + break; |
| 104 | + } |
| 105 | + |
| 106 | + if (__first1 == __last1) |
| 107 | + return true; |
| 108 | + |
| 109 | + // __first1 != __last1 && *__first1 != *__first2 |
| 110 | + using _D1 = __iter_diff_t<_ForwardIterator1>; |
| 111 | + _D1 __l1 = _IterOps<_AlgPolicy>::distance(__first1, __last1); |
| 112 | + if (__l1 == _D1(1)) |
| 113 | + return false; |
| 114 | + auto __last2 = _IterOps<_AlgPolicy>::next(__first2, __l1); |
| 115 | + |
| 116 | + return std::__is_permutation_impl<_AlgPolicy>( |
| 117 | + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), |
| 118 | + __pred, __identity(), __identity()); |
76 | 119 | }
|
77 | 120 |
|
78 |
| -#if _LIBCPP_STD_VER > 11 |
79 |
| -template <class _BinaryPredicate, class _ForwardIterator1, class _ForwardIterator2> |
80 |
| -_LIBCPP_CONSTEXPR_AFTER_CXX17 bool |
81 |
| -__is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, |
82 |
| - _ForwardIterator2 __last2, _BinaryPredicate __pred, forward_iterator_tag, forward_iterator_tag) { |
83 |
| - // shorten sequences as much as possible by lopping of any equal prefix |
84 |
| - for (; __first1 != __last1 && __first2 != __last2; ++__first1, (void)++__first2) |
85 |
| - if (!__pred(*__first1, *__first2)) |
| 121 | +// 2+2 iterators, predicate, non-constant time `distance`. |
| 122 | +template <class _AlgPolicy, |
| 123 | + class _Iter1, class _Sent1, class _Iter2, class _Sent2, |
| 124 | + class _Proj1, class _Proj2, class _Pred> |
| 125 | +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool |
| 126 | +__is_permutation(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, |
| 127 | + _Pred&& __pred, _Proj1&& __proj1, _Proj2&& __proj2, |
| 128 | + /*_ConstTimeDistance=*/false_type) { |
| 129 | + // Shorten sequences as much as possible by lopping of any equal prefix. |
| 130 | + while (__first1 != __last1 && __first2 != __last2) { |
| 131 | + if (!std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) |
86 | 132 | break;
|
| 133 | + ++__first1; |
| 134 | + ++__first2; |
| 135 | + } |
| 136 | + |
87 | 137 | if (__first1 == __last1)
|
88 | 138 | return __first2 == __last2;
|
89 |
| - else if (__first2 == __last2) |
| 139 | + if (__first2 == __last2) // Second range is shorter |
90 | 140 | return false;
|
91 | 141 |
|
92 |
| - typedef typename iterator_traits<_ForwardIterator1>::difference_type _D1; |
93 |
| - _D1 __l1 = _VSTD::distance(__first1, __last1); |
| 142 | + using _D1 = __iter_diff_t<_Iter1>; |
| 143 | + _D1 __l1 = _IterOps<_AlgPolicy>::distance(__first1, __last1); |
94 | 144 |
|
95 |
| - typedef typename iterator_traits<_ForwardIterator2>::difference_type _D2; |
96 |
| - _D2 __l2 = _VSTD::distance(__first2, __last2); |
| 145 | + using _D2 = __iter_diff_t<_Iter2>; |
| 146 | + _D2 __l2 = _IterOps<_AlgPolicy>::distance(__first2, __last2); |
97 | 147 | if (__l1 != __l2)
|
98 | 148 | return false;
|
99 | 149 |
|
100 |
| - // For each element in [f1, l1) see if there are the same number of |
101 |
| - // equal elements in [f2, l2) |
102 |
| - for (_ForwardIterator1 __i = __first1; __i != __last1; ++__i) { |
103 |
| - // Have we already counted the number of *__i in [f1, l1)? |
104 |
| - _ForwardIterator1 __match = __first1; |
105 |
| - for (; __match != __i; ++__match) |
106 |
| - if (__pred(*__match, *__i)) |
107 |
| - break; |
108 |
| - if (__match == __i) { |
109 |
| - // Count number of *__i in [f2, l2) |
110 |
| - _D1 __c2 = 0; |
111 |
| - for (_ForwardIterator2 __j = __first2; __j != __last2; ++__j) |
112 |
| - if (__pred(*__i, *__j)) |
113 |
| - ++__c2; |
114 |
| - if (__c2 == 0) |
115 |
| - return false; |
116 |
| - // Count number of *__i in [__i, l1) (we can start with 1) |
117 |
| - _D1 __c1 = 1; |
118 |
| - for (_ForwardIterator1 __j = _VSTD::next(__i); __j != __last1; ++__j) |
119 |
| - if (__pred(*__i, *__j)) |
120 |
| - ++__c1; |
121 |
| - if (__c1 != __c2) |
122 |
| - return false; |
123 |
| - } |
124 |
| - } |
125 |
| - return true; |
| 150 | + return std::__is_permutation_impl<_AlgPolicy>( |
| 151 | + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), |
| 152 | + __pred, __proj1, __proj2); |
126 | 153 | }
|
127 | 154 |
|
128 |
| -template <class _BinaryPredicate, class _RandomAccessIterator1, class _RandomAccessIterator2> |
129 |
| -_LIBCPP_CONSTEXPR_AFTER_CXX17 bool __is_permutation(_RandomAccessIterator1 __first1, _RandomAccessIterator2 __last1, |
130 |
| - _RandomAccessIterator1 __first2, _RandomAccessIterator2 __last2, |
131 |
| - _BinaryPredicate __pred, random_access_iterator_tag, |
132 |
| - random_access_iterator_tag) { |
133 |
| - if (_VSTD::distance(__first1, __last1) != _VSTD::distance(__first2, __last2)) |
| 155 | +// 2+2 iterators, predicate, specialization for constant-time `distance` call. |
| 156 | +template <class _AlgPolicy, |
| 157 | + class _Iter1, class _Sent1, class _Iter2, class _Sent2, |
| 158 | + class _Proj1, class _Proj2, class _Pred> |
| 159 | +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool |
| 160 | +__is_permutation(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, |
| 161 | + _Pred&& __pred, _Proj1&& __proj1, _Proj2&& __proj2, |
| 162 | + /*_ConstTimeDistance=*/true_type) { |
| 163 | + if (std::distance(__first1, __last1) != std::distance(__first2, __last2)) |
134 | 164 | return false;
|
135 |
| - return _VSTD::is_permutation<_RandomAccessIterator1, _RandomAccessIterator2, |
136 |
| - _BinaryPredicate&>(__first1, __last1, __first2, __pred); |
| 165 | + return std::__is_permutation<_AlgPolicy>( |
| 166 | + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), |
| 167 | + __pred, __proj1, __proj2, |
| 168 | + /*_ConstTimeDistance=*/false_type()); |
| 169 | +} |
| 170 | + |
| 171 | +// 2+2 iterators, predicate |
| 172 | +template <class _AlgPolicy, |
| 173 | + class _Iter1, class _Sent1, class _Iter2, class _Sent2, |
| 174 | + class _Proj1, class _Proj2, class _Pred> |
| 175 | +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool |
| 176 | +__is_permutation(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, |
| 177 | + _Pred&& __pred, _Proj1&& __proj1, _Proj2&& __proj2) { |
| 178 | + return std::__is_permutation<_AlgPolicy>( |
| 179 | + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), |
| 180 | + __pred, __proj1, __proj2, |
| 181 | + _ConstTimeDistance<_Iter1, _Sent1, _Iter2, _Sent2>()); |
137 | 182 | }
|
138 | 183 |
|
| 184 | +// Public interface |
| 185 | + |
| 186 | +// 2+1 iterators, predicate |
139 | 187 | template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
|
140 |
| -_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool |
| 188 | +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool |
141 | 189 | is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
|
142 |
| - _ForwardIterator2 __last2, _BinaryPredicate __pred) { |
143 |
| - return _VSTD::__is_permutation<_BinaryPredicate&>( |
144 |
| - __first1, __last1, __first2, __last2, __pred, typename iterator_traits<_ForwardIterator1>::iterator_category(), |
145 |
| - typename iterator_traits<_ForwardIterator2>::iterator_category()); |
| 190 | + _BinaryPredicate __pred) { |
| 191 | + static_assert(__is_callable<_BinaryPredicate, decltype(*__first1), decltype(*__first2)>::value, |
| 192 | + "The predicate has to be callable"); |
| 193 | + |
| 194 | + return std::__is_permutation<_ClassicAlgPolicy>( |
| 195 | + std::move(__first1), std::move(__last1), std::move(__first2), __pred); |
146 | 196 | }
|
147 | 197 |
|
| 198 | +// 2+1 iterators |
| 199 | +template <class _ForwardIterator1, class _ForwardIterator2> |
| 200 | +_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool |
| 201 | +is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) { |
| 202 | + using __v1 = __iter_value_type<_ForwardIterator1>; |
| 203 | + using __v2 = __iter_value_type<_ForwardIterator2>; |
| 204 | + return std::is_permutation(__first1, __last1, __first2, __equal_to<__v1, __v2>()); |
| 205 | +} |
| 206 | + |
| 207 | +#if _LIBCPP_STD_VER > 11 |
| 208 | + |
| 209 | +// 2+2 iterators |
148 | 210 | template <class _ForwardIterator1, class _ForwardIterator2>
|
149 |
| -_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool |
| 211 | +_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool |
150 | 212 | is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
|
151 | 213 | _ForwardIterator2 __last2) {
|
152 |
| - typedef typename iterator_traits<_ForwardIterator1>::value_type __v1; |
153 |
| - typedef typename iterator_traits<_ForwardIterator2>::value_type __v2; |
154 |
| - return _VSTD::__is_permutation(__first1, __last1, __first2, __last2, __equal_to<__v1, __v2>(), |
155 |
| - typename iterator_traits<_ForwardIterator1>::iterator_category(), |
156 |
| - typename iterator_traits<_ForwardIterator2>::iterator_category()); |
| 214 | + using __v1 = __iter_value_type<_ForwardIterator1>; |
| 215 | + using __v2 = __iter_value_type<_ForwardIterator2>; |
| 216 | + |
| 217 | + return std::__is_permutation<_ClassicAlgPolicy>( |
| 218 | + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), |
| 219 | + __equal_to<__v1, __v2>(), __identity(), __identity()); |
157 | 220 | }
|
158 |
| -#endif |
| 221 | + |
| 222 | +// 2+2 iterators, predicate |
| 223 | +template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate> |
| 224 | +_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool |
| 225 | +is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, |
| 226 | + _ForwardIterator2 __last2, _BinaryPredicate __pred) { |
| 227 | + static_assert(__is_callable<_BinaryPredicate, decltype(*__first1), decltype(*__first2)>::value, |
| 228 | + "The predicate has to be callable"); |
| 229 | + |
| 230 | + return std::__is_permutation<_ClassicAlgPolicy>( |
| 231 | + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), |
| 232 | + __pred, __identity(), __identity()); |
| 233 | +} |
| 234 | + |
| 235 | +#endif // _LIBCPP_STD_VER > 11 |
159 | 236 |
|
160 | 237 | _LIBCPP_END_NAMESPACE_STD
|
161 | 238 |
|
|
0 commit comments