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 <__algorithm/comp.h>
14 #include <__algorithm/iterator_operations.h>
16 #include <__functional/identity.h>
17 #include <__iterator/concepts.h>
18 #include <__iterator/distance.h>
19 #include <__iterator/iterator_traits.h>
20 #include <__iterator/next.h>
21 #include <__type_traits/enable_if.h>
22 #include <__type_traits/invoke.h>
23 #include <__type_traits/is_callable.h>
24 #include <__type_traits/is_same.h>
25 #include <__utility/move.h>
27 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
28 # pragma GCC system_header
32 #include <__undef_macros>
34 _LIBCPP_BEGIN_NAMESPACE_STD
36 template <class _Iter1
, class _Sent1
, class _Iter2
, class _Sent2
, class = void>
37 struct _ConstTimeDistance
: false_type
{};
39 #if _LIBCPP_STD_VER >= 20
41 template <class _Iter1
, class _Sent1
, class _Iter2
, class _Sent2
>
42 struct _ConstTimeDistance
<_Iter1
,
46 __enable_if_t
< sized_sentinel_for
<_Sent1
, _Iter1
> && sized_sentinel_for
<_Sent2
, _Iter2
> >>
51 template <class _Iter1
, class _Iter2
>
52 struct _ConstTimeDistance
<
57 __enable_if_t
< is_same
<typename iterator_traits
<_Iter1
>::iterator_category
, random_access_iterator_tag
>::value
&&
58 is_same
<typename iterator_traits
<_Iter2
>::iterator_category
, random_access_iterator_tag
>::value
> >
61 #endif // _LIBCPP_STD_VER >= 20
65 // For each element in [f1, l1) see if there are the same number of equal elements in [f2, l2)
66 template <class _AlgPolicy
,
74 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool __is_permutation_impl(
82 using _D1
= __iter_diff_t
<_Iter1
>;
84 for (auto __i
= __first1
; __i
!= __last1
; ++__i
) {
85 // Have we already counted the number of *__i in [f1, l1)?
86 auto __match
= __first1
;
87 for (; __match
!= __i
; ++__match
) {
88 if (std::__invoke(__pred
, std::__invoke(__proj1
, *__match
), std::__invoke(__proj1
, *__i
)))
93 // Count number of *__i in [f2, l2)
95 for (auto __j
= __first2
; __j
!= __last2
; ++__j
) {
96 if (std::__invoke(__pred
, std::__invoke(__proj1
, *__i
), std::__invoke(__proj2
, *__j
)))
102 // Count number of *__i in [__i, l1) (we can start with 1)
104 for (auto __j
= _IterOps
<_AlgPolicy
>::next(__i
); __j
!= __last1
; ++__j
) {
105 if (std::__invoke(__pred
, std::__invoke(__proj1
, *__i
), std::__invoke(__proj1
, *__j
)))
116 // 2+1 iterators, predicate. Not used by range algorithms.
117 template <class _AlgPolicy
, class _ForwardIterator1
, class _Sentinel1
, class _ForwardIterator2
, class _BinaryPredicate
>
118 [[__nodiscard__
]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool __is_permutation(
119 _ForwardIterator1 __first1
, _Sentinel1 __last1
, _ForwardIterator2 __first2
, _BinaryPredicate
&& __pred
) {
120 // Shorten sequences as much as possible by lopping of any equal prefix.
121 for (; __first1
!= __last1
; ++__first1
, (void)++__first2
) {
122 if (!__pred(*__first1
, *__first2
))
126 if (__first1
== __last1
)
129 // __first1 != __last1 && *__first1 != *__first2
130 using _D1
= __iter_diff_t
<_ForwardIterator1
>;
131 _D1 __l1
= _IterOps
<_AlgPolicy
>::distance(__first1
, __last1
);
134 auto __last2
= _IterOps
<_AlgPolicy
>::next(__first2
, __l1
);
136 return std::__is_permutation_impl
<_AlgPolicy
>(
146 // 2+2 iterators, predicate, non-constant time `distance`.
147 template <class _AlgPolicy
,
155 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool __is_permutation(
163 /*_ConstTimeDistance=*/false_type
) {
164 // Shorten sequences as much as possible by lopping of any equal prefix.
165 while (__first1
!= __last1
&& __first2
!= __last2
) {
166 if (!std::__invoke(__pred
, std::__invoke(__proj1
, *__first1
), std::__invoke(__proj2
, *__first2
)))
172 if (__first1
== __last1
)
173 return __first2
== __last2
;
174 if (__first2
== __last2
) // Second range is shorter
177 using _D1
= __iter_diff_t
<_Iter1
>;
178 _D1 __l1
= _IterOps
<_AlgPolicy
>::distance(__first1
, __last1
);
180 using _D2
= __iter_diff_t
<_Iter2
>;
181 _D2 __l2
= _IterOps
<_AlgPolicy
>::distance(__first2
, __last2
);
185 return std::__is_permutation_impl
<_AlgPolicy
>(
186 std::move(__first1
), std::move(__last1
), std::move(__first2
), std::move(__last2
), __pred
, __proj1
, __proj2
);
189 // 2+2 iterators, predicate, specialization for constant-time `distance` call.
190 template <class _AlgPolicy
,
198 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool __is_permutation(
206 /*_ConstTimeDistance=*/true_type
) {
207 if (std::distance(__first1
, __last1
) != std::distance(__first2
, __last2
))
209 return std::__is_permutation
<_AlgPolicy
>(
217 /*_ConstTimeDistance=*/false_type());
220 // 2+2 iterators, predicate
221 template <class _AlgPolicy
,
229 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool __is_permutation(
237 return std::__is_permutation
<_AlgPolicy
>(
245 _ConstTimeDistance
<_Iter1
, _Sent1
, _Iter2
, _Sent2
>());
250 // 2+1 iterators, predicate
251 template <class _ForwardIterator1
, class _ForwardIterator2
, class _BinaryPredicate
>
252 [[__nodiscard__
]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool is_permutation(
253 _ForwardIterator1 __first1
, _ForwardIterator1 __last1
, _ForwardIterator2 __first2
, _BinaryPredicate __pred
) {
254 static_assert(__is_callable
<_BinaryPredicate
&, decltype(*__first1
), decltype(*__first2
)>::value
,
255 "The comparator has to be callable");
257 return std::__is_permutation
<_ClassicAlgPolicy
>(std::move(__first1
), std::move(__last1
), std::move(__first2
), __pred
);
261 template <class _ForwardIterator1
, class _ForwardIterator2
>
262 [[__nodiscard__
]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool
263 is_permutation(_ForwardIterator1 __first1
, _ForwardIterator1 __last1
, _ForwardIterator2 __first2
) {
264 return std::is_permutation(__first1
, __last1
, __first2
, __equal_to());
267 #if _LIBCPP_STD_VER >= 14
270 template <class _ForwardIterator1
, class _ForwardIterator2
>
271 [[__nodiscard__
]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool is_permutation(
272 _ForwardIterator1 __first1
, _ForwardIterator1 __last1
, _ForwardIterator2 __first2
, _ForwardIterator2 __last2
) {
273 return std::__is_permutation
<_ClassicAlgPolicy
>(
283 // 2+2 iterators, predicate
284 template <class _ForwardIterator1
, class _ForwardIterator2
, class _BinaryPredicate
>
285 [[__nodiscard__
]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool is_permutation(
286 _ForwardIterator1 __first1
,
287 _ForwardIterator1 __last1
,
288 _ForwardIterator2 __first2
,
289 _ForwardIterator2 __last2
,
290 _BinaryPredicate __pred
) {
291 static_assert(__is_callable
<_BinaryPredicate
&, decltype(*__first1
), decltype(*__first2
)>::value
,
292 "The comparator has to be callable");
294 return std::__is_permutation
<_ClassicAlgPolicy
>(
304 #endif // _LIBCPP_STD_VER >= 14
306 _LIBCPP_END_NAMESPACE_STD
310 #endif // _LIBCPP___ALGORITHM_IS_PERMUTATION_H