/// \file // Range v3 library // // Copyright Eric Niebler 2014-present // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/range-v3 // //===-------------------------- algorithm ---------------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef RANGES_V3_ALGORITHM_PERMUTATION_HPP #define RANGES_V3_ALGORITHM_PERMUTATION_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \addtogroup group-algorithms /// @{ /// \cond namespace detail { template bool is_permutation_impl(I1 begin1, S1 end1, I2 begin2, S2 end2, C pred, P1 proj1, P2 proj2) { // shorten sequences as much as possible by lopping off any equal parts for(; begin1 != end1 && begin2 != end2; ++begin1, ++begin2) if(!invoke(pred, invoke(proj1, *begin1), invoke(proj2, *begin2))) goto not_done; return begin1 == end1 && begin2 == end2; not_done: // begin1 != end1 && begin2 != end2 && *begin1 != *begin2 auto l1 = distance(begin1, end1); auto l2 = distance(begin2, end2); if(l1 != l2) return false; // For each element in [f1, l1) see if there are the same number of // equal elements in [f2, l2) for(I1 i = begin1; i != end1; ++i) { // Have we already counted the number of *i in [f1, l1)? for(I1 j = begin1; j != i; ++j) if(invoke(pred, invoke(proj1, *j), invoke(proj1, *i))) goto next_iter; { // Count number of *i in [f2, l2) iter_difference_t c2 = 0; for(I2 j = begin2; j != end2; ++j) if(invoke(pred, invoke(proj1, *i), invoke(proj2, *j))) ++c2; if(c2 == 0) return false; // Count number of *i in [i, l1) (we can start with 1) iter_difference_t c1 = 1; for(I1 j = next(i); j != end1; ++j) if(invoke(pred, invoke(proj1, *i), invoke(proj1, *j))) ++c1; if(c1 != c2) return false; } next_iter:; } return true; } } // namespace detail /// \endcond RANGES_BEGIN_NIEBLOID(is_permutation) /// \brief function template \c is_permutation template RANGES_DEPRECATED( "Use the variant of ranges::is_permutation that takes an upper bound " "for both sequences") auto RANGES_FUN_NIEBLOID(is_permutation)(I1 begin1, S1 end1, I2 begin2, C pred = C{}, P1 proj1 = P1{}, P2 proj2 = P2{}) // ->CPP_ret(bool)( // requires forward_iterator && sentinel_for && forward_iterator && indirectly_comparable) { // shorten sequences as much as possible by lopping off any equal parts for(; begin1 != end1; ++begin1, ++begin2) if(!invoke(pred, invoke(proj1, *begin1), invoke(proj2, *begin2))) goto not_done; return true; not_done: // begin1 != end1 && *begin1 != *begin2 auto l1 = distance(begin1, end1); if(l1 == 1) return false; I2 end2 = next(begin2, l1); // For each element in [f1, l1) see if there are the same number of // equal elements in [f2, l2) for(I1 i = begin1; i != end1; ++i) { // Have we already counted the number of *i in [f1, l1)? for(I1 j = begin1; j != i; ++j) if(invoke(pred, invoke(proj1, *j), invoke(proj1, *i))) goto next_iter; { // Count number of *i in [f2, l2) iter_difference_t c2 = 0; for(I2 j = begin2; j != end2; ++j) if(invoke(pred, invoke(proj1, *i), invoke(proj2, *j))) ++c2; if(c2 == 0) return false; // Count number of *i in [i, l1) (we can start with 1) iter_difference_t c1 = 1; for(I1 j = next(i); j != end1; ++j) if(invoke(pred, invoke(proj1, *i), invoke(proj1, *j))) ++c1; if(c1 != c2) return false; } next_iter:; } return true; } /// \overload template auto RANGES_FUN_NIEBLOID(is_permutation)(I1 begin1, S1 end1, I2 begin2, S2 end2, C pred = C{}, P1 proj1 = P1{}, P2 proj2 = P2{}) // ->CPP_ret(bool)( // requires forward_iterator && sentinel_for && forward_iterator && sentinel_for && indirectly_comparable) { if(RANGES_CONSTEXPR_IF(sized_sentinel_for && sized_sentinel_for)) { RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS return distance(begin1, end1) == distance(begin2, end2) && (*this)(std::move(begin1), std::move(end1), std::move(begin2), std::move(pred), std::move(proj1), std::move(proj2)); RANGES_DIAGNOSTIC_POP } return detail::is_permutation_impl(std::move(begin1), std::move(end1), std::move(begin2), std::move(end2), std::move(pred), std::move(proj1), std::move(proj2)); } /// \overload template RANGES_DEPRECATED( "Use the variant of ranges::is_permutation that takes an upper bound " "for both sequences") auto RANGES_FUN_NIEBLOID(is_permutation)(Rng1 && rng1, I2Ref && begin2, C pred = C{}, P1 proj1 = P1{}, P2 proj2 = P2{}) // ->CPP_ret(bool)( // requires forward_range && forward_iterator> && indirectly_comparable, uncvref_t, C, P1, P2>) { RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS return (*this)(begin(rng1), end(rng1), (I2Ref &&) begin2, std::move(pred), std::move(proj1), std::move(proj2)); RANGES_DIAGNOSTIC_POP } /// \overload template auto RANGES_FUN_NIEBLOID(is_permutation)( Rng1 && rng1, Rng2 && rng2, C pred = C{}, P1 proj1 = P1{}, P2 proj2 = P2{}) // ->CPP_ret(bool)( // requires forward_range && forward_range && indirectly_comparable, iterator_t, C, P1, P2>) { if(RANGES_CONSTEXPR_IF(sized_range && sized_range)) { RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS return distance(rng1) == distance(rng2) && (*this)(begin(rng1), end(rng1), begin(rng2), std::move(pred), std::move(proj1), std::move(proj2)); RANGES_DIAGNOSTIC_POP } return detail::is_permutation_impl(begin(rng1), end(rng1), begin(rng2), end(rng2), std::move(pred), std::move(proj1), std::move(proj2)); } RANGES_END_NIEBLOID(is_permutation) RANGES_BEGIN_NIEBLOID(next_permutation) /// \brief function template \c next_permutation template auto RANGES_FUN_NIEBLOID(next_permutation)( I first, S end_, C pred = C{}, P proj = P{}) // ->CPP_ret(bool)( // requires bidirectional_iterator && sentinel_for && sortable) { if(first == end_) return false; I last = ranges::next(first, end_), i = last; if(first == --i) return false; while(true) { I ip1 = i; if(invoke(pred, invoke(proj, *--i), invoke(proj, *ip1))) { I j = last; while(!invoke(pred, invoke(proj, *i), invoke(proj, *--j))) ; ranges::iter_swap(i, j); ranges::reverse(ip1, last); return true; } if(i == first) { ranges::reverse(first, last); return false; } } } /// \overload template auto RANGES_FUN_NIEBLOID(next_permutation)( Rng && rng, C pred = C{}, P proj = P{}) // ->CPP_ret(bool)( // requires bidirectional_range && sortable, C, P>) { return (*this)(begin(rng), end(rng), std::move(pred), std::move(proj)); } RANGES_END_NIEBLOID(next_permutation) RANGES_BEGIN_NIEBLOID(prev_permutation) /// \brief function template \c prev_permutation template auto RANGES_FUN_NIEBLOID(prev_permutation)( I first, S end_, C pred = C{}, P proj = P{}) // ->CPP_ret(bool)( // requires bidirectional_iterator && sentinel_for && sortable) { if(first == end_) return false; I last = ranges::next(first, end_), i = last; if(first == --i) return false; while(true) { I ip1 = i; if(invoke(pred, invoke(proj, *ip1), invoke(proj, *--i))) { I j = last; while(!invoke(pred, invoke(proj, *--j), invoke(proj, *i))) ; ranges::iter_swap(i, j); ranges::reverse(ip1, last); return true; } if(i == first) { ranges::reverse(first, last); return false; } } } /// \overload template auto RANGES_FUN_NIEBLOID(prev_permutation)( Rng && rng, C pred = C{}, P proj = P{}) // ->CPP_ret(bool)( // requires bidirectional_range && sortable, C, P>) { return (*this)(begin(rng), end(rng), std::move(pred), std::move(proj)); } RANGES_END_NIEBLOID(prev_permutation) namespace cpp20 { using ranges::is_permutation; using ranges::next_permutation; using ranges::prev_permutation; } // namespace cpp20 /// @} } // namespace ranges #endif // include guard