xref: /llvm-project/libcxx/include/__algorithm/is_permutation.h (revision b905bcc5090cde734e8b7bbceae13bd5a606cc14)
1134723edSLouis Dionne // -*- C++ -*-
2134723edSLouis Dionne //===----------------------------------------------------------------------===//
3134723edSLouis Dionne //
4134723edSLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5134723edSLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
6134723edSLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7134723edSLouis Dionne //
8134723edSLouis Dionne //===----------------------------------------------------------------------===//
9134723edSLouis Dionne 
10134723edSLouis Dionne #ifndef _LIBCPP___ALGORITHM_IS_PERMUTATION_H
11134723edSLouis Dionne #define _LIBCPP___ALGORITHM_IS_PERMUTATION_H
12134723edSLouis Dionne 
13134723edSLouis Dionne #include <__algorithm/comp.h>
144038c859SNikolas Klauser #include <__algorithm/iterator_operations.h>
15134723edSLouis Dionne #include <__config>
164038c859SNikolas Klauser #include <__functional/identity.h>
174038c859SNikolas Klauser #include <__iterator/concepts.h>
189807626bSJoe Loser #include <__iterator/distance.h>
19134723edSLouis Dionne #include <__iterator/iterator_traits.h>
20*09e3a360SLouis Dionne #include <__type_traits/enable_if.h>
21*09e3a360SLouis Dionne #include <__type_traits/invoke.h>
22e698c595SNikolas Klauser #include <__type_traits/is_callable.h>
23*09e3a360SLouis Dionne #include <__type_traits/is_same.h>
244038c859SNikolas Klauser #include <__utility/move.h>
25134723edSLouis Dionne 
26134723edSLouis Dionne #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
27134723edSLouis Dionne #  pragma GCC system_header
28134723edSLouis Dionne #endif
29134723edSLouis Dionne 
3092e4d679SNicole Rabjohn _LIBCPP_PUSH_MACROS
3192e4d679SNicole Rabjohn #include <__undef_macros>
3292e4d679SNicole Rabjohn 
33134723edSLouis Dionne _LIBCPP_BEGIN_NAMESPACE_STD
34134723edSLouis Dionne 
354038c859SNikolas Klauser template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class = void>
364038c859SNikolas Klauser struct _ConstTimeDistance : false_type {};
374038c859SNikolas Klauser 
384f15267dSNikolas Klauser #if _LIBCPP_STD_VER >= 20
394038c859SNikolas Klauser 
404038c859SNikolas Klauser template <class _Iter1, class _Sent1, class _Iter2, class _Sent2>
419783f28cSLouis Dionne struct _ConstTimeDistance<_Iter1,
429783f28cSLouis Dionne                           _Sent1,
439783f28cSLouis Dionne                           _Iter2,
449783f28cSLouis Dionne                           _Sent2,
459783f28cSLouis Dionne                           __enable_if_t< sized_sentinel_for<_Sent1, _Iter1> && sized_sentinel_for<_Sent2, _Iter2> >>
469783f28cSLouis Dionne     : true_type {};
474038c859SNikolas Klauser 
484038c859SNikolas Klauser #else
494038c859SNikolas Klauser 
504038c859SNikolas Klauser template <class _Iter1, class _Iter2>
519783f28cSLouis Dionne struct _ConstTimeDistance<
529783f28cSLouis Dionne     _Iter1,
539783f28cSLouis Dionne     _Iter1,
549783f28cSLouis Dionne     _Iter2,
559783f28cSLouis Dionne     _Iter2,
569783f28cSLouis Dionne     __enable_if_t< is_same<typename iterator_traits<_Iter1>::iterator_category, random_access_iterator_tag>::value &&
579783f28cSLouis Dionne                    is_same<typename iterator_traits<_Iter2>::iterator_category, random_access_iterator_tag>::value > >
589783f28cSLouis Dionne     : true_type {};
594038c859SNikolas Klauser 
604f15267dSNikolas Klauser #endif // _LIBCPP_STD_VER >= 20
614038c859SNikolas Klauser 
624038c859SNikolas Klauser // Internal functions
634038c859SNikolas Klauser 
644038c859SNikolas Klauser // For each element in [f1, l1) see if there are the same number of equal elements in [f2, l2)
654038c859SNikolas Klauser template <class _AlgPolicy,
669783f28cSLouis Dionne           class _Iter1,
679783f28cSLouis Dionne           class _Sent1,
689783f28cSLouis Dionne           class _Iter2,
699783f28cSLouis Dionne           class _Sent2,
709783f28cSLouis Dionne           class _Proj1,
719783f28cSLouis Dionne           class _Proj2,
729783f28cSLouis Dionne           class _Pred>
739783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation_impl(
749783f28cSLouis Dionne     _Iter1 __first1,
759783f28cSLouis Dionne     _Sent1 __last1,
769783f28cSLouis Dionne     _Iter2 __first2,
779783f28cSLouis Dionne     _Sent2 __last2,
789783f28cSLouis Dionne     _Pred&& __pred,
799783f28cSLouis Dionne     _Proj1&& __proj1,
809783f28cSLouis Dionne     _Proj2&& __proj2) {
814038c859SNikolas Klauser   using _D1 = __iter_diff_t<_Iter1>;
824038c859SNikolas Klauser 
834038c859SNikolas Klauser   for (auto __i = __first1; __i != __last1; ++__i) {
844038c859SNikolas Klauser     //  Have we already counted the number of *__i in [f1, l1)?
854038c859SNikolas Klauser     auto __match = __first1;
864038c859SNikolas Klauser     for (; __match != __i; ++__match) {
874038c859SNikolas Klauser       if (std::__invoke(__pred, std::__invoke(__proj1, *__match), std::__invoke(__proj1, *__i)))
884038c859SNikolas Klauser         break;
894038c859SNikolas Klauser     }
904038c859SNikolas Klauser 
914038c859SNikolas Klauser     if (__match == __i) {
924038c859SNikolas Klauser       // Count number of *__i in [f2, l2)
934038c859SNikolas Klauser       _D1 __c2 = 0;
944038c859SNikolas Klauser       for (auto __j = __first2; __j != __last2; ++__j) {
954038c859SNikolas Klauser         if (std::__invoke(__pred, std::__invoke(__proj1, *__i), std::__invoke(__proj2, *__j)))
964038c859SNikolas Klauser           ++__c2;
974038c859SNikolas Klauser       }
984038c859SNikolas Klauser       if (__c2 == 0)
994038c859SNikolas Klauser         return false;
1004038c859SNikolas Klauser 
1014038c859SNikolas Klauser       // Count number of *__i in [__i, l1) (we can start with 1)
1024038c859SNikolas Klauser       _D1 __c1 = 1;
1034038c859SNikolas Klauser       for (auto __j = _IterOps<_AlgPolicy>::next(__i); __j != __last1; ++__j) {
1044038c859SNikolas Klauser         if (std::__invoke(__pred, std::__invoke(__proj1, *__i), std::__invoke(__proj1, *__j)))
1054038c859SNikolas Klauser           ++__c1;
1064038c859SNikolas Klauser       }
1074038c859SNikolas Klauser       if (__c1 != __c2)
1084038c859SNikolas Klauser         return false;
1094038c859SNikolas Klauser     }
1104038c859SNikolas Klauser   }
1114038c859SNikolas Klauser 
1124038c859SNikolas Klauser   return true;
1134038c859SNikolas Klauser }
1144038c859SNikolas Klauser 
1154038c859SNikolas Klauser // 2+1 iterators, predicate. Not used by range algorithms.
1164038c859SNikolas Klauser template <class _AlgPolicy, class _ForwardIterator1, class _Sentinel1, class _ForwardIterator2, class _BinaryPredicate>
11717e0686aSNikolas Klauser [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation(
1189783f28cSLouis Dionne     _ForwardIterator1 __first1, _Sentinel1 __last1, _ForwardIterator2 __first2, _BinaryPredicate&& __pred) {
1194038c859SNikolas Klauser   // Shorten sequences as much as possible by lopping of any equal prefix.
1204038c859SNikolas Klauser   for (; __first1 != __last1; ++__first1, (void)++__first2) {
121134723edSLouis Dionne     if (!__pred(*__first1, *__first2))
122134723edSLouis Dionne       break;
1234038c859SNikolas Klauser   }
1244038c859SNikolas Klauser 
125134723edSLouis Dionne   if (__first1 == __last1)
126134723edSLouis Dionne     return true;
127134723edSLouis Dionne 
128134723edSLouis Dionne   //  __first1 != __last1 && *__first1 != *__first2
1294038c859SNikolas Klauser   using _D1 = __iter_diff_t<_ForwardIterator1>;
1304038c859SNikolas Klauser   _D1 __l1  = _IterOps<_AlgPolicy>::distance(__first1, __last1);
131134723edSLouis Dionne   if (__l1 == _D1(1))
132134723edSLouis Dionne     return false;
1334038c859SNikolas Klauser   auto __last2 = _IterOps<_AlgPolicy>::next(__first2, __l1);
1344038c859SNikolas Klauser 
1354038c859SNikolas Klauser   return std::__is_permutation_impl<_AlgPolicy>(
1369783f28cSLouis Dionne       std::move(__first1),
1379783f28cSLouis Dionne       std::move(__last1),
1389783f28cSLouis Dionne       std::move(__first2),
1399783f28cSLouis Dionne       std::move(__last2),
1409783f28cSLouis Dionne       __pred,
1419783f28cSLouis Dionne       __identity(),
1429783f28cSLouis Dionne       __identity());
143134723edSLouis Dionne }
144134723edSLouis Dionne 
1454038c859SNikolas Klauser // 2+2 iterators, predicate, non-constant time `distance`.
1464038c859SNikolas Klauser template <class _AlgPolicy,
1479783f28cSLouis Dionne           class _Iter1,
1489783f28cSLouis Dionne           class _Sent1,
1499783f28cSLouis Dionne           class _Iter2,
1509783f28cSLouis Dionne           class _Sent2,
1519783f28cSLouis Dionne           class _Proj1,
1529783f28cSLouis Dionne           class _Proj2,
1539783f28cSLouis Dionne           class _Pred>
1549783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation(
1559783f28cSLouis Dionne     _Iter1 __first1,
1569783f28cSLouis Dionne     _Sent1 __last1,
1579783f28cSLouis Dionne     _Iter2 __first2,
1589783f28cSLouis Dionne     _Sent2 __last2,
1599783f28cSLouis Dionne     _Pred&& __pred,
1609783f28cSLouis Dionne     _Proj1&& __proj1,
1619783f28cSLouis Dionne     _Proj2&& __proj2,
1624038c859SNikolas Klauser     /*_ConstTimeDistance=*/false_type) {
1634038c859SNikolas Klauser   // Shorten sequences as much as possible by lopping of any equal prefix.
1644038c859SNikolas Klauser   while (__first1 != __last1 && __first2 != __last2) {
1654038c859SNikolas Klauser     if (!std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2)))
1664038c859SNikolas Klauser       break;
1674038c859SNikolas Klauser     ++__first1;
1684038c859SNikolas Klauser     ++__first2;
169134723edSLouis Dionne   }
170134723edSLouis Dionne 
171134723edSLouis Dionne   if (__first1 == __last1)
172134723edSLouis Dionne     return __first2 == __last2;
1734038c859SNikolas Klauser   if (__first2 == __last2) // Second range is shorter
174134723edSLouis Dionne     return false;
175134723edSLouis Dionne 
1764038c859SNikolas Klauser   using _D1 = __iter_diff_t<_Iter1>;
1774038c859SNikolas Klauser   _D1 __l1  = _IterOps<_AlgPolicy>::distance(__first1, __last1);
178134723edSLouis Dionne 
1794038c859SNikolas Klauser   using _D2 = __iter_diff_t<_Iter2>;
1804038c859SNikolas Klauser   _D2 __l2  = _IterOps<_AlgPolicy>::distance(__first2, __last2);
181134723edSLouis Dionne   if (__l1 != __l2)
182134723edSLouis Dionne     return false;
183134723edSLouis Dionne 
1844038c859SNikolas Klauser   return std::__is_permutation_impl<_AlgPolicy>(
1859783f28cSLouis Dionne       std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __pred, __proj1, __proj2);
186134723edSLouis Dionne }
187134723edSLouis Dionne 
1884038c859SNikolas Klauser // 2+2 iterators, predicate, specialization for constant-time `distance` call.
1894038c859SNikolas Klauser template <class _AlgPolicy,
1909783f28cSLouis Dionne           class _Iter1,
1919783f28cSLouis Dionne           class _Sent1,
1929783f28cSLouis Dionne           class _Iter2,
1939783f28cSLouis Dionne           class _Sent2,
1949783f28cSLouis Dionne           class _Proj1,
1959783f28cSLouis Dionne           class _Proj2,
1969783f28cSLouis Dionne           class _Pred>
1979783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation(
1989783f28cSLouis Dionne     _Iter1 __first1,
1999783f28cSLouis Dionne     _Sent1 __last1,
2009783f28cSLouis Dionne     _Iter2 __first2,
2019783f28cSLouis Dionne     _Sent2 __last2,
2029783f28cSLouis Dionne     _Pred&& __pred,
2039783f28cSLouis Dionne     _Proj1&& __proj1,
2049783f28cSLouis Dionne     _Proj2&& __proj2,
2054038c859SNikolas Klauser     /*_ConstTimeDistance=*/true_type) {
2064038c859SNikolas Klauser   if (std::distance(__first1, __last1) != std::distance(__first2, __last2))
207134723edSLouis Dionne     return false;
2084038c859SNikolas Klauser   return std::__is_permutation<_AlgPolicy>(
2099783f28cSLouis Dionne       std::move(__first1),
2109783f28cSLouis Dionne       std::move(__last1),
2119783f28cSLouis Dionne       std::move(__first2),
2129783f28cSLouis Dionne       std::move(__last2),
2139783f28cSLouis Dionne       __pred,
2149783f28cSLouis Dionne       __proj1,
2159783f28cSLouis Dionne       __proj2,
2164038c859SNikolas Klauser       /*_ConstTimeDistance=*/false_type());
217134723edSLouis Dionne }
218134723edSLouis Dionne 
2194038c859SNikolas Klauser // 2+2 iterators, predicate
2204038c859SNikolas Klauser template <class _AlgPolicy,
2219783f28cSLouis Dionne           class _Iter1,
2229783f28cSLouis Dionne           class _Sent1,
2239783f28cSLouis Dionne           class _Iter2,
2249783f28cSLouis Dionne           class _Sent2,
2259783f28cSLouis Dionne           class _Proj1,
2269783f28cSLouis Dionne           class _Proj2,
2279783f28cSLouis Dionne           class _Pred>
2289783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation(
2299783f28cSLouis Dionne     _Iter1 __first1,
2309783f28cSLouis Dionne     _Sent1 __last1,
2319783f28cSLouis Dionne     _Iter2 __first2,
2329783f28cSLouis Dionne     _Sent2 __last2,
2339783f28cSLouis Dionne     _Pred&& __pred,
2349783f28cSLouis Dionne     _Proj1&& __proj1,
2359783f28cSLouis Dionne     _Proj2&& __proj2) {
2364038c859SNikolas Klauser   return std::__is_permutation<_AlgPolicy>(
2379783f28cSLouis Dionne       std::move(__first1),
2389783f28cSLouis Dionne       std::move(__last1),
2399783f28cSLouis Dionne       std::move(__first2),
2409783f28cSLouis Dionne       std::move(__last2),
2419783f28cSLouis Dionne       __pred,
2429783f28cSLouis Dionne       __proj1,
2439783f28cSLouis Dionne       __proj2,
2444038c859SNikolas Klauser       _ConstTimeDistance<_Iter1, _Sent1, _Iter2, _Sent2>());
2454038c859SNikolas Klauser }
2464038c859SNikolas Klauser 
2474038c859SNikolas Klauser // Public interface
2484038c859SNikolas Klauser 
2494038c859SNikolas Klauser // 2+1 iterators, predicate
250134723edSLouis Dionne template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
25117e0686aSNikolas Klauser [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool is_permutation(
2529783f28cSLouis Dionne     _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _BinaryPredicate __pred) {
25325783158SLouis Dionne   static_assert(__is_callable<_BinaryPredicate&, decltype(*__first1), decltype(*__first2)>::value,
25425783158SLouis Dionne                 "The comparator has to be callable");
2554038c859SNikolas Klauser 
2569783f28cSLouis Dionne   return std::__is_permutation<_ClassicAlgPolicy>(std::move(__first1), std::move(__last1), std::move(__first2), __pred);
257134723edSLouis Dionne }
258134723edSLouis Dionne 
2594038c859SNikolas Klauser // 2+1 iterators
260134723edSLouis Dionne template <class _ForwardIterator1, class _ForwardIterator2>
26117e0686aSNikolas Klauser [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
2624038c859SNikolas Klauser is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) {
263e07ca2aeSAlvin Wong   return std::is_permutation(__first1, __last1, __first2, __equal_to());
2644038c859SNikolas Klauser }
2654038c859SNikolas Klauser 
2664f15267dSNikolas Klauser #if _LIBCPP_STD_VER >= 14
2674038c859SNikolas Klauser 
2684038c859SNikolas Klauser // 2+2 iterators
2694038c859SNikolas Klauser template <class _ForwardIterator1, class _ForwardIterator2>
27017e0686aSNikolas Klauser [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool is_permutation(
271e07ca2aeSAlvin Wong     _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2) {
2724038c859SNikolas Klauser   return std::__is_permutation<_ClassicAlgPolicy>(
273e07ca2aeSAlvin Wong       std::move(__first1),
274e07ca2aeSAlvin Wong       std::move(__last1),
275e07ca2aeSAlvin Wong       std::move(__first2),
276e07ca2aeSAlvin Wong       std::move(__last2),
277e07ca2aeSAlvin Wong       __equal_to(),
278e07ca2aeSAlvin Wong       __identity(),
279e07ca2aeSAlvin Wong       __identity());
280134723edSLouis Dionne }
2814038c859SNikolas Klauser 
2824038c859SNikolas Klauser // 2+2 iterators, predicate
2834038c859SNikolas Klauser template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
28417e0686aSNikolas Klauser [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool is_permutation(
2859783f28cSLouis Dionne     _ForwardIterator1 __first1,
2869783f28cSLouis Dionne     _ForwardIterator1 __last1,
2879783f28cSLouis Dionne     _ForwardIterator2 __first2,
2889783f28cSLouis Dionne     _ForwardIterator2 __last2,
2899783f28cSLouis Dionne     _BinaryPredicate __pred) {
29025783158SLouis Dionne   static_assert(__is_callable<_BinaryPredicate&, decltype(*__first1), decltype(*__first2)>::value,
29125783158SLouis Dionne                 "The comparator has to be callable");
2924038c859SNikolas Klauser 
2934038c859SNikolas Klauser   return std::__is_permutation<_ClassicAlgPolicy>(
2949783f28cSLouis Dionne       std::move(__first1),
2959783f28cSLouis Dionne       std::move(__last1),
2969783f28cSLouis Dionne       std::move(__first2),
2979783f28cSLouis Dionne       std::move(__last2),
2989783f28cSLouis Dionne       __pred,
2999783f28cSLouis Dionne       __identity(),
3009783f28cSLouis Dionne       __identity());
3014038c859SNikolas Klauser }
3024038c859SNikolas Klauser 
3034f15267dSNikolas Klauser #endif // _LIBCPP_STD_VER >= 14
304134723edSLouis Dionne 
305134723edSLouis Dionne _LIBCPP_END_NAMESPACE_STD
306134723edSLouis Dionne 
30792e4d679SNicole Rabjohn _LIBCPP_POP_MACROS
30892e4d679SNicole Rabjohn 
309134723edSLouis Dionne #endif // _LIBCPP___ALGORITHM_IS_PERMUTATION_H
310