diff --git a/sprout/algorithm/is_permutation.hpp b/sprout/algorithm/is_permutation.hpp index 4e057971..708d8404 100644 --- a/sprout/algorithm/is_permutation.hpp +++ b/sprout/algorithm/is_permutation.hpp @@ -17,27 +17,38 @@ #include #include #include +#include +#include namespace sprout { namespace detail { + template + inline SPROUT_CONSTEXPR bool + is_permutation_impl_check(Difference count, ForwardIterator first, ForwardIterator last, BinaryPredicate pred) + { + return count != 0 && sprout::count_if(sprout::next(first), last, sprout::bind2nd(pred, *first)) + 1 == count; + } template inline SPROUT_CONSTEXPR bool is_permutation_impl_ra( RandomAccessIterator1 first1, RandomAccessIterator1 last1, RandomAccessIterator2 first2, RandomAccessIterator2 last2, - BinaryPredicate pred, - typename std::iterator_traits::difference_type pivot + BinaryPredicate pred, RandomAccessIterator1 current, + typename std::iterator_traits::difference_type size ) { - return pivot == 0 ? sprout::count_if(first1, last1, sprout::bind2nd(pred, *first1)) - <= sprout::count_if(first2, last2, sprout::bind2nd(pred, *first1)) + return size == 1 ? sprout::find_if(first1, current, sprout::bind2nd(pred, *current)) != current + || sprout::detail::is_permutation_impl_check( + sprout::count_if(first2, last2, sprout::bind2nd(pred, *current)), + current, last1, pred + ) : sprout::detail::is_permutation_impl_ra( first1, last1, first2, last2, - pred, pivot / 2 + pred, current, size / 2 ) && sprout::detail::is_permutation_impl_ra( - sprout::next(first1, pivot), last1, first2, last2, - pred, (sprout::distance(first1, last1) - pivot) / 2 + first1, last1, first2, last2, + pred, sprout::next(current, size / 2), size - size / 2 ) ; } @@ -47,68 +58,70 @@ namespace sprout { bool >::type is_permutation( - RandomAccessIterator1 first1, RandomAccessIterator1 last1, RandomAccessIterator2 first2, BinaryPredicate pred, + sprout::pair first, RandomAccessIterator1 last1, BinaryPredicate pred, std::random_access_iterator_tag* ) { - return first1 == last1 ? true - : sprout::detail::is_permutation_impl_ra( - first1, last1, first2, sprout::next(first2, sprout::distance(first1, last1)), - pred, sprout::distance(first1, last1) / 2 + return first.first == last1 + || sprout::detail::is_permutation_impl_ra( + first.first, last1, first.second, sprout::next(first.second, sprout::distance(first.first, last1)), + pred, first.first, sprout::distance(first.first, last1) ) ; } - template inline SPROUT_CONSTEXPR sprout::pair is_permutation_impl_1( sprout::pair const& current, - ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, + ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred, typename std::iterator_traits::difference_type n ) { typedef sprout::pair type; return !current.second || current.first == last1 ? current - : n == 1 ? sprout::count_if(current.first, last1, sprout::bind2nd(pred, *current.first)) - <= sprout::count_if(first2, last2, sprout::bind2nd(pred, *current.first)) + : n == 1 ? sprout::find_if(first1, current.first, sprout::bind2nd(pred, *current.first)) != current.first + || sprout::detail::is_permutation_impl_check( + sprout::count_if(first2, last2, sprout::bind2nd(pred, *current.first)), + current.first, last1, pred + ) ? type(sprout::next(current.first), true) : type(current.first, false) : sprout::detail::is_permutation_impl_1( sprout::detail::is_permutation_impl_1( current, - last1, first2, last2, pred, n / 2 + first1, last1, first2, last2, pred, n / 2 ), - last1, first2, last2, pred, n - n / 2 - ) - ; - } - template - inline SPROUT_CONSTEXPR sprout::pair - is_permutation_impl( - sprout::pair const& current, - ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, - BinaryPredicate pred, typename std::iterator_traits::difference_type n - ) - { - return !current.second || current.first == last1 ? current - : sprout::detail::is_permutation_impl( - sprout::detail::is_permutation_impl_1( - current, - last1, first2, last2, pred, n - ), - last1, first2, last2, pred, n * 2 + first1, last1, first2, last2, pred, n - n / 2 ) ; } template inline SPROUT_CONSTEXPR bool - is_permutation( - ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, BinaryPredicate pred, - std::forward_iterator_tag* + is_permutation_impl( + ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, + BinaryPredicate pred, typename std::iterator_traits::difference_type size ) { typedef sprout::pair type; - return sprout::detail::is_permutation_impl(type(first1, true), last1, first2, sprout::next(first2, sprout::distance(first1, last1)), pred, 1).second; + return sprout::detail::is_permutation_impl_1( + type(first1, true), + first1, last1, first2, sprout::next(first2, size), + pred, size + ).second + ; + } + template + inline SPROUT_CONSTEXPR bool + is_permutation( + sprout::pair first, ForwardIterator1 last1, BinaryPredicate pred, + std::forward_iterator_tag* + ) + { + return first.first == last1 + || sprout::detail::is_permutation_impl( + first.first, last1, first.second, pred, sprout::distance(first.first, last1) + ) + ; } } // namespace detail @@ -121,7 +134,7 @@ namespace sprout { inline SPROUT_CONSTEXPR bool is_permutation(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, BinaryPredicate pred) { typedef typename sprout::common_iterator_category::type* category; - return sprout::detail::is_permutation(first1, last1, first2, pred, category()); + return sprout::detail::is_permutation(sprout::mismatch(first1, last1, first2, pred), last1, pred, category()); } template inline SPROUT_CONSTEXPR bool @@ -130,6 +143,20 @@ namespace sprout { } namespace detail { + template + inline SPROUT_CONSTEXPR bool + is_permutation_impl_ra_1( + sprout::pair first, + RandomAccessIterator1 last1, RandomAccessIterator2 last2, BinaryPredicate pred + ) + { + return first.first == last1 + || sprout::detail::is_permutation_impl_ra( + first.first, last1, first.second, last2, + pred, first.first, sprout::distance(first.first, last1) + ) + ; + } template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::is_constant_distance_iterator::value && sprout::is_constant_distance_iterator::value, @@ -141,13 +168,40 @@ namespace sprout { ) { return sprout::distance(first1, last1) == sprout::distance(first2, last2) - && sprout::detail::is_permutation_impl_ra( - first1, last1, first2, last2, - pred, sprout::distance(first1, last1) / 2 - ) + && sprout::detail::is_permutation_impl_ra_1( + sprout::mismatch(first1, last1, first2, last2, pred), + last1, last2, pred) + ; + } + template + inline SPROUT_CONSTEXPR bool + is_permutation_impl_3( + ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred, + Difference1 size1, Difference2 size2 + ) + { + typedef sprout::pair type; + return size1 == size2 + && sprout::detail::is_permutation_impl_1( + type(first1, true), first1, last1, first2, last2, + pred, size1 + ).second + ; + } + template + inline SPROUT_CONSTEXPR bool + is_permutation_impl_2( + sprout::pair first, + ForwardIterator1 last1, ForwardIterator2 last2, BinaryPredicate pred + ) + { + return sprout::detail::is_permutation_impl_3( + first.first, last1, first.second, last2, pred, + sprout::distance(first.first, last1), sprout::distance(first.second, last2) + ) ; } - template inline SPROUT_CONSTEXPR bool is_permutation( @@ -155,10 +209,9 @@ namespace sprout { std::forward_iterator_tag* ) { - typedef sprout::pair type; - return sprout::distance(first1, last1) == sprout::distance(first2, last2) - && sprout::detail::is_permutation_impl(type(first1, true), last1, first2, last2, pred, 1).second - ; + return sprout::detail::is_permutation_impl_2( + sprout::mismatch(first1, last1, first2, last2, pred), + last1, last2, pred); } } // namespace detail