xref: /llvm-project/libcxx/include/__algorithm/is_permutation.h (revision 7ed7d4ccb8991e2b5b95334b508f8cec2faee737)
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
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
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef _LIBCPP___ALGORITHM_IS_PERMUTATION_H
11 #define _LIBCPP___ALGORITHM_IS_PERMUTATION_H
12 
13 #include <__config>
14 #include <__iterator/iterator_traits.h>
15 #include <__iterator/next.h>
16 #include <iterator> // FIXME: replace with <__iterator/distance.h> when it lands
17 
18 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
19 #pragma GCC system_header
20 #endif
21 
22 _LIBCPP_PUSH_MACROS
23 #include <__undef_macros>
24 
25 _LIBCPP_BEGIN_NAMESPACE_STD
26 
27 template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
28 _LIBCPP_NODISCARD_EXT _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
29 is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
30                _BinaryPredicate __pred) {
31   //  shorten sequences as much as possible by lopping of any equal prefix
32   for (; __first1 != __last1; ++__first1, (void)++__first2)
33     if (!__pred(*__first1, *__first2))
34       break;
35   if (__first1 == __last1)
36     return true;
37 
38   //  __first1 != __last1 && *__first1 != *__first2
39   typedef typename iterator_traits<_ForwardIterator1>::difference_type _D1;
40   _D1 __l1 = _VSTD::distance(__first1, __last1);
41   if (__l1 == _D1(1))
42     return false;
43   _ForwardIterator2 __last2 = _VSTD::next(__first2, __l1);
44   // For each element in [f1, l1) see if there are the same number of
45   //    equal elements in [f2, l2)
46   for (_ForwardIterator1 __i = __first1; __i != __last1; ++__i) {
47     //  Have we already counted the number of *__i in [f1, l1)?
48     _ForwardIterator1 __match = __first1;
49     for (; __match != __i; ++__match)
50       if (__pred(*__match, *__i))
51         break;
52     if (__match == __i) {
53       // Count number of *__i in [f2, l2)
54       _D1 __c2 = 0;
55       for (_ForwardIterator2 __j = __first2; __j != __last2; ++__j)
56         if (__pred(*__i, *__j))
57           ++__c2;
58       if (__c2 == 0)
59         return false;
60       // Count number of *__i in [__i, l1) (we can start with 1)
61       _D1 __c1 = 1;
62       for (_ForwardIterator1 __j = _VSTD::next(__i); __j != __last1; ++__j)
63         if (__pred(*__i, *__j))
64           ++__c1;
65       if (__c1 != __c2)
66         return false;
67     }
68   }
69   return true;
70 }
71 
72 template <class _ForwardIterator1, class _ForwardIterator2>
73 _LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
74 is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) {
75   typedef typename iterator_traits<_ForwardIterator1>::value_type __v1;
76   typedef typename iterator_traits<_ForwardIterator2>::value_type __v2;
77   return _VSTD::is_permutation(__first1, __last1, __first2, __equal_to<__v1, __v2>());
78 }
79 
80 #if _LIBCPP_STD_VER > 11
81 template <class _BinaryPredicate, class _ForwardIterator1, class _ForwardIterator2>
82 _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
83 __is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
84                  _ForwardIterator2 __last2, _BinaryPredicate __pred, forward_iterator_tag, forward_iterator_tag) {
85   //  shorten sequences as much as possible by lopping of any equal prefix
86   for (; __first1 != __last1 && __first2 != __last2; ++__first1, (void)++__first2)
87     if (!__pred(*__first1, *__first2))
88       break;
89   if (__first1 == __last1)
90     return __first2 == __last2;
91   else if (__first2 == __last2)
92     return false;
93 
94   typedef typename iterator_traits<_ForwardIterator1>::difference_type _D1;
95   _D1 __l1 = _VSTD::distance(__first1, __last1);
96 
97   typedef typename iterator_traits<_ForwardIterator2>::difference_type _D2;
98   _D2 __l2 = _VSTD::distance(__first2, __last2);
99   if (__l1 != __l2)
100     return false;
101 
102   // For each element in [f1, l1) see if there are the same number of
103   //    equal elements in [f2, l2)
104   for (_ForwardIterator1 __i = __first1; __i != __last1; ++__i) {
105     //  Have we already counted the number of *__i in [f1, l1)?
106     _ForwardIterator1 __match = __first1;
107     for (; __match != __i; ++__match)
108       if (__pred(*__match, *__i))
109         break;
110     if (__match == __i) {
111       // Count number of *__i in [f2, l2)
112       _D1 __c2 = 0;
113       for (_ForwardIterator2 __j = __first2; __j != __last2; ++__j)
114         if (__pred(*__i, *__j))
115           ++__c2;
116       if (__c2 == 0)
117         return false;
118       // Count number of *__i in [__i, l1) (we can start with 1)
119       _D1 __c1 = 1;
120       for (_ForwardIterator1 __j = _VSTD::next(__i); __j != __last1; ++__j)
121         if (__pred(*__i, *__j))
122           ++__c1;
123       if (__c1 != __c2)
124         return false;
125     }
126   }
127   return true;
128 }
129 
130 template <class _BinaryPredicate, class _RandomAccessIterator1, class _RandomAccessIterator2>
131 _LIBCPP_CONSTEXPR_AFTER_CXX17 bool __is_permutation(_RandomAccessIterator1 __first1, _RandomAccessIterator2 __last1,
132                                                     _RandomAccessIterator1 __first2, _RandomAccessIterator2 __last2,
133                                                     _BinaryPredicate __pred, random_access_iterator_tag,
134                                                     random_access_iterator_tag) {
135   if (_VSTD::distance(__first1, __last1) != _VSTD::distance(__first2, __last2))
136     return false;
137   return _VSTD::is_permutation<_RandomAccessIterator1, _RandomAccessIterator2,
138                                typename add_lvalue_reference<_BinaryPredicate>::type>(__first1, __last1, __first2,
139                                                                                       __pred);
140 }
141 
142 template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
143 _LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
144 is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
145                _ForwardIterator2 __last2, _BinaryPredicate __pred) {
146   return _VSTD::__is_permutation<typename add_lvalue_reference<_BinaryPredicate>::type>(
147       __first1, __last1, __first2, __last2, __pred, typename iterator_traits<_ForwardIterator1>::iterator_category(),
148       typename iterator_traits<_ForwardIterator2>::iterator_category());
149 }
150 
151 template <class _ForwardIterator1, class _ForwardIterator2>
152 _LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
153 is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
154                _ForwardIterator2 __last2) {
155   typedef typename iterator_traits<_ForwardIterator1>::value_type __v1;
156   typedef typename iterator_traits<_ForwardIterator2>::value_type __v2;
157   return _VSTD::__is_permutation(__first1, __last1, __first2, __last2, __equal_to<__v1, __v2>(),
158                                  typename iterator_traits<_ForwardIterator1>::iterator_category(),
159                                  typename iterator_traits<_ForwardIterator2>::iterator_category());
160 }
161 #endif
162 
163 _LIBCPP_END_NAMESPACE_STD
164 
165 _LIBCPP_POP_MACROS
166 
167 #endif // _LIBCPP___ALGORITHM_IS_PERMUTATION_H
168