2 //===----------------------------------------------------------------------===//
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___ALGORITHM_IS_PERMUTATION_H
11 #define _LIBCPP___ALGORITHM_IS_PERMUTATION_H
13 #include <__cxx03/__algorithm/comp.h>
14 #include <__cxx03/__algorithm/iterator_operations.h>
15 #include <__cxx03/__config>
16 #include <__cxx03/__functional/identity.h>
17 #include <__cxx03/__functional/invoke.h>
18 #include <__cxx03/__iterator/concepts.h>
19 #include <__cxx03/__iterator/distance.h>
20 #include <__cxx03/__iterator/iterator_traits.h>
21 #include <__cxx03/__iterator/next.h>
22 #include <__cxx03/__type_traits/is_callable.h>
23 #include <__cxx03/__utility/move.h>
25 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
26 # pragma GCC system_header
30 #include <__cxx03/__undef_macros>
32 _LIBCPP_BEGIN_NAMESPACE_STD
34 template <class _Iter1
, class _Sent1
, class _Iter2
, class _Sent2
, class = void>
35 struct _ConstTimeDistance
: false_type
{};
37 #if _LIBCPP_STD_VER >= 20
39 template <class _Iter1
, class _Sent1
, class _Iter2
, class _Sent2
>
40 struct _ConstTimeDistance
<_Iter1
,
44 __enable_if_t
< sized_sentinel_for
<_Sent1
, _Iter1
> && sized_sentinel_for
<_Sent2
, _Iter2
> >>
49 template <class _Iter1
, class _Iter2
>
50 struct _ConstTimeDistance
<
55 __enable_if_t
< is_same
<typename iterator_traits
<_Iter1
>::iterator_category
, random_access_iterator_tag
>::value
&&
56 is_same
<typename iterator_traits
<_Iter2
>::iterator_category
, random_access_iterator_tag
>::value
> >
59 #endif // _LIBCPP_STD_VER >= 20
63 // For each element in [f1, l1) see if there are the same number of equal elements in [f2, l2)
64 template <class _AlgPolicy
,
72 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool __is_permutation_impl(
80 using _D1
= __iter_diff_t
<_Iter1
>;
82 for (auto __i
= __first1
; __i
!= __last1
; ++__i
) {
83 // Have we already counted the number of *__i in [f1, l1)?
84 auto __match
= __first1
;
85 for (; __match
!= __i
; ++__match
) {
86 if (std::__invoke(__pred
, std::__invoke(__proj1
, *__match
), std::__invoke(__proj1
, *__i
)))
91 // Count number of *__i in [f2, l2)
93 for (auto __j
= __first2
; __j
!= __last2
; ++__j
) {
94 if (std::__invoke(__pred
, std::__invoke(__proj1
, *__i
), std::__invoke(__proj2
, *__j
)))
100 // Count number of *__i in [__i, l1) (we can start with 1)
102 for (auto __j
= _IterOps
<_AlgPolicy
>::next(__i
); __j
!= __last1
; ++__j
) {
103 if (std::__invoke(__pred
, std::__invoke(__proj1
, *__i
), std::__invoke(__proj1
, *__j
)))
114 // 2+1 iterators, predicate. Not used by range algorithms.
115 template <class _AlgPolicy
, class _ForwardIterator1
, class _Sentinel1
, class _ForwardIterator2
, class _BinaryPredicate
>
116 _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool __is_permutation(
117 _ForwardIterator1 __first1
, _Sentinel1 __last1
, _ForwardIterator2 __first2
, _BinaryPredicate
&& __pred
) {
118 // Shorten sequences as much as possible by lopping of any equal prefix.
119 for (; __first1
!= __last1
; ++__first1
, (void)++__first2
) {
120 if (!__pred(*__first1
, *__first2
))
124 if (__first1
== __last1
)
127 // __first1 != __last1 && *__first1 != *__first2
128 using _D1
= __iter_diff_t
<_ForwardIterator1
>;
129 _D1 __l1
= _IterOps
<_AlgPolicy
>::distance(__first1
, __last1
);
132 auto __last2
= _IterOps
<_AlgPolicy
>::next(__first2
, __l1
);
134 return std::__is_permutation_impl
<_AlgPolicy
>(
144 // 2+2 iterators, predicate, non-constant time `distance`.
145 template <class _AlgPolicy
,
153 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool __is_permutation(
161 /*_ConstTimeDistance=*/false_type
) {
162 // Shorten sequences as much as possible by lopping of any equal prefix.
163 while (__first1
!= __last1
&& __first2
!= __last2
) {
164 if (!std::__invoke(__pred
, std::__invoke(__proj1
, *__first1
), std::__invoke(__proj2
, *__first2
)))
170 if (__first1
== __last1
)
171 return __first2
== __last2
;
172 if (__first2
== __last2
) // Second range is shorter
175 using _D1
= __iter_diff_t
<_Iter1
>;
176 _D1 __l1
= _IterOps
<_AlgPolicy
>::distance(__first1
, __last1
);
178 using _D2
= __iter_diff_t
<_Iter2
>;
179 _D2 __l2
= _IterOps
<_AlgPolicy
>::distance(__first2
, __last2
);
183 return std::__is_permutation_impl
<_AlgPolicy
>(
184 std::move(__first1
), std::move(__last1
), std::move(__first2
), std::move(__last2
), __pred
, __proj1
, __proj2
);
187 // 2+2 iterators, predicate, specialization for constant-time `distance` call.
188 template <class _AlgPolicy
,
196 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool __is_permutation(
204 /*_ConstTimeDistance=*/true_type
) {
205 if (std::distance(__first1
, __last1
) != std::distance(__first2
, __last2
))
207 return std::__is_permutation
<_AlgPolicy
>(
215 /*_ConstTimeDistance=*/false_type());
218 // 2+2 iterators, predicate
219 template <class _AlgPolicy
,
227 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool __is_permutation(
235 return std::__is_permutation
<_AlgPolicy
>(
243 _ConstTimeDistance
<_Iter1
, _Sent1
, _Iter2
, _Sent2
>());
248 // 2+1 iterators, predicate
249 template <class _ForwardIterator1
, class _ForwardIterator2
, class _BinaryPredicate
>
250 _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool is_permutation(
251 _ForwardIterator1 __first1
, _ForwardIterator1 __last1
, _ForwardIterator2 __first2
, _BinaryPredicate __pred
) {
252 static_assert(__is_callable
<_BinaryPredicate
, decltype(*__first1
), decltype(*__first2
)>::value
,
253 "The predicate has to be callable");
255 return std::__is_permutation
<_ClassicAlgPolicy
>(std::move(__first1
), std::move(__last1
), std::move(__first2
), __pred
);
259 template <class _ForwardIterator1
, class _ForwardIterator2
>
260 _LIBCPP_NODISCARD
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool
261 is_permutation(_ForwardIterator1 __first1
, _ForwardIterator1 __last1
, _ForwardIterator2 __first2
) {
262 return std::is_permutation(__first1
, __last1
, __first2
, __equal_to());
265 #if _LIBCPP_STD_VER >= 14
268 template <class _ForwardIterator1
, class _ForwardIterator2
>
269 _LIBCPP_NODISCARD
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool is_permutation(
270 _ForwardIterator1 __first1
, _ForwardIterator1 __last1
, _ForwardIterator2 __first2
, _ForwardIterator2 __last2
) {
271 return std::__is_permutation
<_ClassicAlgPolicy
>(
281 // 2+2 iterators, predicate
282 template <class _ForwardIterator1
, class _ForwardIterator2
, class _BinaryPredicate
>
283 _LIBCPP_NODISCARD
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool is_permutation(
284 _ForwardIterator1 __first1
,
285 _ForwardIterator1 __last1
,
286 _ForwardIterator2 __first2
,
287 _ForwardIterator2 __last2
,
288 _BinaryPredicate __pred
) {
289 static_assert(__is_callable
<_BinaryPredicate
, decltype(*__first1
), decltype(*__first2
)>::value
,
290 "The predicate has to be callable");
292 return std::__is_permutation
<_ClassicAlgPolicy
>(
302 #endif // _LIBCPP_STD_VER >= 14
304 _LIBCPP_END_NAMESPACE_STD
308 #endif // _LIBCPP___ALGORITHM_IS_PERMUTATION_H