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