is_permutation.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. Copyright (c) Marshall Clow 2011-2012.
  3. Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. */
  6. /// \file is_permutation.hpp
  7. /// \brief Is a sequence a permutation of another sequence
  8. /// \author Marshall Clow
  9. #ifndef BOOST_ALGORITHM_IS_PERMUTATION_HPP
  10. #define BOOST_ALGORITHM_IS_PERMUTATION_HPP
  11. #include <algorithm> // for std::less, tie, mismatch and is_permutation (if available)
  12. #include <utility> // for std::make_pair
  13. #include <functional> // for std::equal_to
  14. #include <iterator>
  15. #include <boost/range/begin.hpp>
  16. #include <boost/range/end.hpp>
  17. #include <boost/utility/enable_if.hpp>
  18. #include <boost/type_traits/is_same.hpp>
  19. #include <boost/tr1/tr1/tuple> // for tie
  20. namespace boost { namespace algorithm {
  21. /// \cond DOXYGEN_HIDE
  22. namespace detail {
  23. template <typename Predicate, typename Iterator>
  24. struct value_predicate {
  25. value_predicate ( Predicate p, Iterator it ) : p_ ( p ), it_ ( it ) {}
  26. template <typename T1>
  27. bool operator () ( const T1 &t1 ) const { return p_ ( *it_, t1 ); }
  28. private:
  29. Predicate p_;
  30. Iterator it_;
  31. };
  32. // Preconditions:
  33. // 1. The sequences are the same length
  34. // 2. Any common elements on the front have been removed (not necessary for correctness, just for performance)
  35. template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate >
  36. bool is_permutation_inner ( ForwardIterator1 first1, ForwardIterator1 last1,
  37. ForwardIterator2 first2, ForwardIterator2 last2,
  38. BinaryPredicate p ) {
  39. // for each unique value in the sequence [first1,last1), count how many times
  40. // it occurs, and make sure it occurs the same number of times in [first2, last2)
  41. for ( ForwardIterator1 iter = first1; iter != last1; ++iter ) {
  42. value_predicate<BinaryPredicate, ForwardIterator1> pred ( p, iter );
  43. /* For each value we haven't seen yet... */
  44. if ( std::find_if ( first1, iter, pred ) == iter ) {
  45. std::size_t dest_count = std::count_if ( first2, last2, pred );
  46. if ( dest_count == 0 || dest_count != (std::size_t) std::count_if ( iter, last1, pred ))
  47. return false;
  48. }
  49. }
  50. return true;
  51. }
  52. template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate>
  53. bool is_permutation_tag ( ForwardIterator1 first1, ForwardIterator1 last1,
  54. ForwardIterator2 first2, ForwardIterator2 last2,
  55. BinaryPredicate p,
  56. std::forward_iterator_tag, std::forward_iterator_tag ) {
  57. // Skip the common prefix (if any)
  58. while ( first1 != last1 && first2 != last2 && p ( *first1, *first2 )) {
  59. ++first1;
  60. ++first2;
  61. }
  62. if ( first1 != last1 && first2 != last2 )
  63. return boost::algorithm::detail::is_permutation_inner ( first1, last1, first2, last2,
  64. std::equal_to<typename std::iterator_traits<ForwardIterator1>::value_type> ());
  65. return first1 == last1 && first2 == last2;
  66. }
  67. template <class RandomAccessIterator1, class RandomAccessIterator2, class BinaryPredicate>
  68. bool is_permutation_tag ( RandomAccessIterator1 first1, RandomAccessIterator1 last1,
  69. RandomAccessIterator2 first2, RandomAccessIterator2 last2,
  70. BinaryPredicate p,
  71. std::random_access_iterator_tag, std::random_access_iterator_tag ) {
  72. // Cheap check
  73. if ( std::distance ( first1, last1 ) != std::distance ( first2, last2 ))
  74. return false;
  75. // Skip the common prefix (if any)
  76. while ( first1 != last1 && first2 != last2 && p ( *first1, *first2 )) {
  77. ++first1;
  78. ++first2;
  79. }
  80. if ( first1 != last1 && first2 != last2 )
  81. return is_permutation_inner (first1, last1, first2, last2, p);
  82. return first1 == last1 && first2 == last2;
  83. }
  84. }
  85. /// \endcond
  86. #if __cplusplus >= 201103L
  87. // Use the C++11 versions of is_permutation if it is available
  88. using std::is_permutation; // Section 25.2.12
  89. #else
  90. /// \fn is_permutation ( ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 first2, BinaryPredicate p )
  91. /// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2
  92. ///
  93. /// \param first1 The start of the input sequence
  94. /// \param last1 One past the end of the input sequence
  95. /// \param first2 The start of the second sequence
  96. /// \param p The predicate to compare elements with
  97. ///
  98. /// \note This function is part of the C++2011 standard library.
  99. /// We will use the standard one if it is available,
  100. /// otherwise we have our own implementation.
  101. template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate >
  102. bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1,
  103. ForwardIterator2 first2, BinaryPredicate p )
  104. {
  105. // Skip the common prefix (if any)
  106. // std::tie (first1, first2) = std::mismatch (first1, last1, first2, p);
  107. std::pair<ForwardIterator1, ForwardIterator2> eq = std::mismatch (first1, last1, first2, p);
  108. first1 = eq.first;
  109. first2 = eq.second;
  110. if ( first1 != last1 ) {
  111. // Create last2
  112. ForwardIterator2 last2 = first2;
  113. std::advance ( last2, std::distance (first1, last1));
  114. return boost::algorithm::detail::is_permutation_inner ( first1, last1, first2, last2, p );
  115. }
  116. return true;
  117. }
  118. /// \fn is_permutation ( ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 first2 )
  119. /// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2
  120. ///
  121. /// \param first1 The start of the input sequence
  122. /// \param last2 One past the end of the input sequence
  123. /// \param first2 The start of the second sequence
  124. /// \note This function is part of the C++2011 standard library.
  125. /// We will use the standard one if it is available,
  126. /// otherwise we have our own implementation.
  127. template< class ForwardIterator1, class ForwardIterator2 >
  128. bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2 )
  129. {
  130. // How should I deal with the idea that ForwardIterator1::value_type
  131. // and ForwardIterator2::value_type could be different? Define my own comparison predicate?
  132. // Skip the common prefix (if any)
  133. std::pair<ForwardIterator1, ForwardIterator2> eq = std::mismatch (first1, last1, first2 );
  134. first1 = eq.first;
  135. first2 = eq.second;
  136. if ( first1 != last1 ) {
  137. // Create last2
  138. ForwardIterator2 last2 = first2;
  139. std::advance ( last2, std::distance (first1, last1));
  140. return boost::algorithm::detail::is_permutation_inner ( first1, last1, first2, last2,
  141. std::equal_to<typename std::iterator_traits<ForwardIterator1>::value_type> ());
  142. }
  143. return true;
  144. }
  145. #endif
  146. /// \fn is_permutation ( ForwardIterator1 first, ForwardIterator1 last,
  147. /// ForwardIterator2 first2, ForwardIterator2 last2 )
  148. /// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2
  149. ///
  150. /// \param first1 The start of the input sequence
  151. /// \param last2 One past the end of the input sequence
  152. /// \param first2 The start of the second sequence
  153. /// \param last1 One past the end of the second sequence
  154. /// \note This function is part of the C++2011 standard library.
  155. /// We will use the standard one if it is available,
  156. /// otherwise we have our own implementation.
  157. template< class ForwardIterator1, class ForwardIterator2 >
  158. bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1,
  159. ForwardIterator2 first2, ForwardIterator2 last2 )
  160. {
  161. // How should I deal with the idea that ForwardIterator1::value_type
  162. // and ForwardIterator2::value_type could be different? Define my own comparison predicate?
  163. return boost::algorithm::detail::is_permutation_tag (
  164. first1, last1, first2, last2,
  165. std::equal_to<typename std::iterator_traits<ForwardIterator1>::value_type> (),
  166. typename std::iterator_traits<ForwardIterator1>::iterator_category (),
  167. typename std::iterator_traits<ForwardIterator2>::iterator_category ());
  168. }
  169. /// \fn is_permutation ( ForwardIterator1 first, ForwardIterator1 last,
  170. /// ForwardIterator2 first2, ForwardIterator2 last2,
  171. /// BinaryPredicate p )
  172. /// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2
  173. ///
  174. /// \param first1 The start of the input sequence
  175. /// \param last1 One past the end of the input sequence
  176. /// \param first2 The start of the second sequence
  177. /// \param last2 One past the end of the second sequence
  178. /// \param pred The predicate to compare elements with
  179. ///
  180. /// \note This function is part of the C++2011 standard library.
  181. /// We will use the standard one if it is available,
  182. /// otherwise we have our own implementation.
  183. template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate >
  184. bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1,
  185. ForwardIterator2 first2, ForwardIterator2 last2,
  186. BinaryPredicate pred )
  187. {
  188. return boost::algorithm::detail::is_permutation_tag (
  189. first1, last1, first2, last2, pred,
  190. typename std::iterator_traits<ForwardIterator1>::iterator_category (),
  191. typename std::iterator_traits<ForwardIterator2>::iterator_category ());
  192. }
  193. /// \fn is_permutation ( const Range &r, ForwardIterator first2 )
  194. /// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2
  195. ///
  196. /// \param r The input range
  197. /// \param first2 The start of the second sequence
  198. template <typename Range, typename ForwardIterator>
  199. bool is_permutation ( const Range &r, ForwardIterator first2 )
  200. {
  201. return boost::algorithm::is_permutation (boost::begin (r), boost::end (r), first2 );
  202. }
  203. /// \fn is_permutation ( const Range &r, ForwardIterator first2, BinaryPredicate pred )
  204. /// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2
  205. ///
  206. /// \param r The input range
  207. /// \param first2 The start of the second sequence
  208. /// \param pred The predicate to compare elements with
  209. ///
  210. // Disable this template when the first two parameters are the same type
  211. // That way the non-range version will be chosen.
  212. template <typename Range, typename ForwardIterator, typename BinaryPredicate>
  213. typename boost::disable_if_c<boost::is_same<Range, ForwardIterator>::value, bool>::type
  214. is_permutation ( const Range &r, ForwardIterator first2, BinaryPredicate pred )
  215. {
  216. return boost::algorithm::is_permutation (boost::begin (r), boost::end (r), first2, pred );
  217. }
  218. }}
  219. #endif // BOOST_ALGORITHM_IS_PERMUTATION_HPP