From d732a73431bb4261fa9aff046263e77670944b8e Mon Sep 17 00:00:00 2001 From: bolero-MURAKAMI Date: Thu, 16 May 2013 19:03:27 +0900 Subject: [PATCH] add is_permutation algorithm: robust version (N3607) --- libs/algorithm/test/is_permutation.cpp | 236 +++++++++++++++++++++++++ sprout/algorithm/equal.hpp | 30 +--- sprout/algorithm/is_permutation.hpp | 78 ++++++-- 3 files changed, 308 insertions(+), 36 deletions(-) diff --git a/libs/algorithm/test/is_permutation.cpp b/libs/algorithm/test/is_permutation.cpp index d9e8018c..2db24873 100644 --- a/libs/algorithm/test/is_permutation.cpp +++ b/libs/algorithm/test/is_permutation.cpp @@ -225,6 +225,242 @@ namespace testspr { TESTSPR_BOTH_ASSERT(result); } #endif + + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + sprout::begin(arr1), + sprout::end(arr1), + sprout::begin(arr2), + sprout::end(arr2) + ); + TESTSPR_BOTH_ASSERT(result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + sprout::begin(arr1), + sprout::end(arr1), + sprout::begin(arr3), + sprout::end(arr3) + ); + TESTSPR_BOTH_ASSERT(!result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + sprout::begin(arr1), + sprout::begin(arr1) + 5, + sprout::begin(arr2), + sprout::end(arr2) + 5 + ); + TESTSPR_BOTH_ASSERT(!result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + sprout::begin(arr1), + sprout::begin(arr1) + 5, + sprout::begin(arr3), + sprout::begin(arr3) + 5 + ); + TESTSPR_BOTH_ASSERT(result); + } + + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + sprout::begin(arr1), + sprout::end(arr1), + sprout::begin(arr2), + sprout::end(arr2), + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + sprout::begin(arr1), + sprout::end(arr1), + sprout::begin(arr3), + sprout::end(arr3), + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(!result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + sprout::begin(arr1), + sprout::begin(arr1) + 5, + sprout::begin(arr2), + sprout::begin(arr2) + 5, + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(!result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + sprout::begin(arr1), + sprout::begin(arr1) + 5, + sprout::begin(arr3), + sprout::begin(arr3) + 5, + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(result); + } + + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_forward(sprout::begin(arr1)), + testspr::reduct_forward(sprout::end(arr1)), + testspr::reduct_forward(sprout::begin(arr2)), + testspr::reduct_forward(sprout::end(arr2)) + ); + TESTSPR_BOTH_ASSERT(result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_forward(sprout::begin(arr1)), + testspr::reduct_forward(sprout::end(arr1)), + testspr::reduct_forward(sprout::begin(arr3)), + testspr::reduct_forward(sprout::end(arr3)) + ); + TESTSPR_BOTH_ASSERT(!result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_forward(sprout::begin(arr1)), + testspr::reduct_forward(sprout::begin(arr1) + 5), + testspr::reduct_forward(sprout::begin(arr2)), + testspr::reduct_forward(sprout::begin(arr2) + 5) + ); + TESTSPR_BOTH_ASSERT(!result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_forward(sprout::begin(arr1)), + testspr::reduct_forward(sprout::begin(arr1) + 5), + testspr::reduct_forward(sprout::begin(arr3)), + testspr::reduct_forward(sprout::begin(arr3) + 5) + ); + TESTSPR_BOTH_ASSERT(result); + } + + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_forward(sprout::begin(arr1)), + testspr::reduct_forward(sprout::end(arr1)), + testspr::reduct_forward(sprout::begin(arr2)), + testspr::reduct_forward(sprout::end(arr2)), + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_forward(sprout::begin(arr1)), + testspr::reduct_forward(sprout::end(arr1)), + testspr::reduct_forward(sprout::begin(arr3)), + testspr::reduct_forward(sprout::end(arr3)), + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(!result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_forward(sprout::begin(arr1)), + testspr::reduct_forward(sprout::begin(arr1) + 5), + testspr::reduct_forward(sprout::begin(arr2)), + testspr::reduct_forward(sprout::begin(arr2) + 5), + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(!result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_forward(sprout::begin(arr1)), + testspr::reduct_forward(sprout::begin(arr1) + 5), + testspr::reduct_forward(sprout::begin(arr3)), + testspr::reduct_forward(sprout::begin(arr3) + 5), + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(result); + } + +#if defined(__clang__) + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_random_access(sprout::begin(arr1)), + testspr::reduct_random_access(sprout::end(arr1)), + testspr::reduct_random_access(sprout::begin(arr2)), + testspr::reduct_random_access(sprout::end(arr2)) + ); + TESTSPR_BOTH_ASSERT(result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_random_access(sprout::begin(arr1)), + testspr::reduct_random_access(sprout::end(arr1)), + testspr::reduct_random_access(sprout::begin(arr3)), + testspr::reduct_random_access(sprout::end(arr3)) + ); + TESTSPR_BOTH_ASSERT(!result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_random_access(sprout::begin(arr1)), + testspr::reduct_random_access(sprout::begin(arr1) + 5), + testspr::reduct_random_access(sprout::begin(arr2)), + testspr::reduct_random_access(sprout::begin(arr2) + 5) + ); + TESTSPR_BOTH_ASSERT(!result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_random_access(sprout::begin(arr1)), + testspr::reduct_random_access(sprout::begin(arr1) + 5), + testspr::reduct_random_access(sprout::begin(arr3)), + testspr::reduct_random_access(sprout::begin(arr3) + 5) + ); + TESTSPR_BOTH_ASSERT(result); + } + + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_random_access(sprout::begin(arr1)), + testspr::reduct_random_access(sprout::end(arr1)), + testspr::reduct_random_access(sprout::begin(arr2)), + testspr::reduct_random_access(sprout::end(arr2)), + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_random_access(sprout::begin(arr1)), + testspr::reduct_random_access(sprout::end(arr1)), + testspr::reduct_random_access(sprout::begin(arr3)), + testspr::reduct_random_access(sprout::end(arr3)), + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(!result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_random_access(sprout::begin(arr1)), + testspr::reduct_random_access(sprout::begin(arr1) + 5), + testspr::reduct_random_access(sprout::begin(arr2)), + testspr::reduct_random_access(sprout::begin(arr2) + 5), + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(!result); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::is_permutation( + testspr::reduct_random_access(sprout::begin(arr1)), + testspr::reduct_random_access(sprout::begin(arr1) + 5), + testspr::reduct_random_access(sprout::begin(arr3)), + testspr::reduct_random_access(sprout::begin(arr3) + 5), + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(result); + } +#endif } } } // namespace testspr diff --git a/sprout/algorithm/equal.hpp b/sprout/algorithm/equal.hpp index 6ae85cf6..5e808446 100644 --- a/sprout/algorithm/equal.hpp +++ b/sprout/algorithm/equal.hpp @@ -126,37 +126,23 @@ namespace sprout { template inline SPROUT_CONSTEXPR bool - equal2_impl_ra_1( + equal2_impl_ra( RandomAccessIterator1 first1, RandomAccessIterator1 last1, RandomAccessIterator2 first2, RandomAccessIterator2 last2, BinaryPredicate pred, typename std::iterator_traits::difference_type pivot ) { return pivot == 0 ? pred(*first1, *first2) - : sprout::detail::equal2_impl_ra_1( + : sprout::detail::equal2_impl_ra( first1, sprout::next(first1, pivot), first2, sprout::next(first2, pivot), pred, pivot / 2 ) - && sprout::detail::equal2_impl_ra_1( + && sprout::detail::equal2_impl_ra( sprout::next(first1, pivot), last1, sprout::next(first2, pivot), last2, pred, (sprout::distance(first1, last1) - pivot) / 2 ) ; } template - inline SPROUT_CONSTEXPR bool - equal2_impl_ra( - RandomAccessIterator1 first1, RandomAccessIterator1 last1, RandomAccessIterator2 first2, RandomAccessIterator2 last2, BinaryPredicate pred, - typename std::iterator_traits::difference_type size1, typename std::iterator_traits::difference_type size2 - ) - { - return size1 == size2 - && sprout::detail::equal2_impl_ra_1( - first1, last1, first2, last2, pred, - size1 / 2 - ) - ; - } - template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::is_constant_distance_iterator::value && sprout::is_constant_distance_iterator::value, bool @@ -166,10 +152,12 @@ namespace sprout { std::random_access_iterator_tag* ) { - return sprout::detail::equal2_impl_ra( - first1, last1, first2, last2, pred, - sprout::distance(first1, last1), sprout::distance(first2, last2) - ); + return sprout::distance(first1, last1) == sprout::distance(first2, last2) + && sprout::detail::equal2_impl_ra( + first1, last1, first2, last2, pred, + sprout::distance(first1, last1) / 2 + ) + ; } template diff --git a/sprout/algorithm/is_permutation.hpp b/sprout/algorithm/is_permutation.hpp index b3e8df77..1f1aebcd 100644 --- a/sprout/algorithm/is_permutation.hpp +++ b/sprout/algorithm/is_permutation.hpp @@ -10,7 +10,6 @@ #include #include #include -#include namespace sprout { namespace detail { @@ -18,19 +17,19 @@ namespace sprout { inline SPROUT_CONSTEXPR bool is_permutation_impl_ra( RandomAccessIterator1 first1, RandomAccessIterator1 last1, - RandomAccessIterator2 first2, typename std::iterator_traits::difference_type d2, + RandomAccessIterator2 first2, RandomAccessIterator2 last2, BinaryPredicate pred, typename std::iterator_traits::difference_type pivot ) { return pivot == 0 ? sprout::count_if(first1, last1, sprout::bind2nd(pred, *first1)) - <= sprout::detail::count_n_if(first2, d2, sprout::bind2nd(pred, *first1)) + <= sprout::count_if(first2, last2, sprout::bind2nd(pred, *first1)) : sprout::detail::is_permutation_impl_ra( - first1, last1, first2, d2, + first1, last1, first2, last2, pred, pivot / 2 ) && sprout::detail::is_permutation_impl_ra( - sprout::next(first1, pivot), last1, first2, d2, + sprout::next(first1, pivot), last1, first2, last2, pred, (sprout::distance(first1, last1) - pivot) / 2 ) ; @@ -47,7 +46,7 @@ namespace sprout { { return first1 == last1 ? true : sprout::detail::is_permutation_impl_ra( - first1, last1, first2, sprout::distance(first1, last1), + first1, last1, first2, sprout::next(first2, sprout::distance(first1, last1)), pred, sprout::distance(first1, last1) / 2 ) ; @@ -57,22 +56,22 @@ namespace sprout { inline SPROUT_CONSTEXPR sprout::pair is_permutation_impl_1( sprout::pair const& current, - ForwardIterator1 last1, ForwardIterator2 first2, typename std::iterator_traits::difference_type d2, + 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::detail::count_n_if(first2, d2, sprout::bind2nd(pred, *current.first)) + <= sprout::count_if(first2, last2, sprout::bind2nd(pred, *current.first)) ? 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, d2, pred, n / 2 + last1, first2, last2, pred, n / 2 ), - last1, first2, d2, pred, n - n / 2 + last1, first2, last2, pred, n - n / 2 ) ; } @@ -80,7 +79,7 @@ namespace sprout { inline SPROUT_CONSTEXPR sprout::pair is_permutation_impl( sprout::pair const& current, - ForwardIterator1 last1, ForwardIterator2 first2, typename std::iterator_traits::difference_type d2, + ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred, typename std::iterator_traits::difference_type n ) { @@ -88,9 +87,9 @@ namespace sprout { : sprout::detail::is_permutation_impl( sprout::detail::is_permutation_impl_1( current, - last1, first2, d2, pred, n + last1, first2, last2, pred, n ), - last1, first2, d2, pred, n * 2 + last1, first2, last2, pred, n * 2 ) ; } @@ -102,7 +101,7 @@ namespace sprout { ) { typedef sprout::pair type; - return sprout::detail::is_permutation_impl(type(first1, true), last1, first2, sprout::distance(first1, last1), pred, 1).second; + return sprout::detail::is_permutation_impl(type(first1, true), last1, first2, sprout::next(first2, sprout::distance(first1, last1)), pred, 1).second; } } // namespace detail @@ -117,12 +116,61 @@ namespace sprout { typedef typename sprout::common_iterator_category::type* category; return sprout::detail::is_permutation(first1, last1, first2, pred, category()); } - template inline SPROUT_CONSTEXPR bool is_permutation(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2) { return sprout::is_permutation(first1, last1, first2, sprout::equal_to<>()); } + + namespace detail { + template + inline SPROUT_CONSTEXPR typename std::enable_if< + sprout::is_constant_distance_iterator::value && sprout::is_constant_distance_iterator::value, + bool + >::type + is_permutation( + RandomAccessIterator1 first1, RandomAccessIterator1 last1, RandomAccessIterator2 first2, RandomAccessIterator2 last2, BinaryPredicate pred, + std::random_access_iterator_tag* + ) + { + 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 + ) + ; + } + + template + inline SPROUT_CONSTEXPR bool + is_permutation( + ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred, + 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 + ; + } + } // namespace detail + + // 25.2.12 Is permutation + // + // recursion depth: + // O(log N) + // + template + inline SPROUT_CONSTEXPR bool + is_permutation(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred) { + typedef typename sprout::common_iterator_category::type* category; + return sprout::detail::is_permutation(first1, last1, first2, last2, pred, category()); + } + template + inline SPROUT_CONSTEXPR bool + is_permutation(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) { + return sprout::is_permutation(first1, last1, first2, last2, sprout::equal_to<>()); + } } // namespace sprout #endif // #ifndef SPROUT_ALGORITHM_IS_PERMUTATION_HPP