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