Line data Source code
1 : // (C) Copyright Gennadiy Rozental 2001.
2 : // Distributed under the Boost Software License, Version 1.0.
3 : // (See accompanying file LICENSE_1_0.txt or copy at
4 : // http://www.boost.org/LICENSE_1_0.txt)
5 :
6 : // See http://www.boost.org/libs/test for the library home page.
7 : //
8 : /// @file
9 : /// Addition to STL algorithms
10 : // ***************************************************************************
11 :
12 : #ifndef BOOST_TEST_UTILS_ALGORITHM_HPP
13 : #define BOOST_TEST_UTILS_ALGORITHM_HPP
14 :
15 : #include <boost/test/detail/config.hpp>
16 :
17 : // STL
18 : #include <utility>
19 : #include <algorithm> // std::find
20 : #include <functional> // std::bind1st or std::bind
21 :
22 : #include <boost/test/detail/suppress_warnings.hpp>
23 :
24 : #ifdef BOOST_NO_CXX98_BINDERS
25 : #define BOOST_TEST_BIND1ST(F,A) std::bind( (F), (A), std::placeholders::_1 )
26 : #else
27 : #define BOOST_TEST_BIND1ST(F,A) std::bind1st( (F), (A) )
28 : #endif
29 :
30 : //____________________________________________________________________________//
31 :
32 : namespace boost {
33 : namespace unit_test {
34 : namespace utils {
35 :
36 : /// @brief this algorithm search through two collections for first mismatch position that get returned as a pair
37 : /// of iterators, first pointing to the mismatch position in first collection, second iterator in second one
38 : ///
39 : /// @param first1 - first collection begin iterator
40 : /// @param last1 - first collection end iterator
41 : /// @param first2 - second collection begin iterator
42 : /// @param last2 - second collection end iterator
43 : template <class InputIter1, class InputIter2>
44 : inline std::pair<InputIter1, InputIter2>
45 : mismatch( InputIter1 first1, InputIter1 last1,
46 : InputIter2 first2, InputIter2 last2 )
47 : {
48 : while( first1 != last1 && first2 != last2 && *first1 == *first2 ) {
49 : ++first1;
50 : ++first2;
51 : }
52 :
53 : return std::pair<InputIter1, InputIter2>(first1, first2);
54 : }
55 :
56 : //____________________________________________________________________________//
57 :
58 : /// @brief this algorithm search through two collections for first mismatch position that get returned as a pair
59 : /// of iterators, first pointing to the mismatch position in first collection, second iterator in second one. This algorithms
60 : /// uses supplied predicate for collection elements comparison
61 : ///
62 : /// @param first1 - first collection begin iterator
63 : /// @param last1 - first collection end iterator
64 : /// @param first2 - second collection begin iterator
65 : /// @param last2 - second collection end iterator
66 : /// @param pred - predicate to be used for search
67 : template <class InputIter1, class InputIter2, class Predicate>
68 : inline std::pair<InputIter1, InputIter2>
69 : mismatch( InputIter1 first1, InputIter1 last1,
70 : InputIter2 first2, InputIter2 last2,
71 : Predicate pred )
72 : {
73 : while( first1 != last1 && first2 != last2 && pred( *first1, *first2 ) ) {
74 : ++first1;
75 : ++first2;
76 : }
77 :
78 : return std::pair<InputIter1, InputIter2>(first1, first2);
79 : }
80 :
81 : //____________________________________________________________________________//
82 :
83 : /// @brief this algorithm search through first collection for first element that does not belong a second one
84 : ///
85 : /// @param first1 - first collection begin iterator
86 : /// @param last1 - first collection end iterator
87 : /// @param first2 - second collection begin iterator
88 : /// @param last2 - second collection end iterator
89 : template<class ForwardIterator1, class ForwardIterator2>
90 : inline ForwardIterator1
91 : find_first_not_of( ForwardIterator1 first1, ForwardIterator1 last1,
92 : ForwardIterator2 first2, ForwardIterator2 last2 )
93 : {
94 : while( first1 != last1 ) {
95 : if( std::find( first2, last2, *first1 ) == last2 )
96 : break;
97 : ++first1;
98 : }
99 :
100 : return first1;
101 : }
102 :
103 : //____________________________________________________________________________//
104 :
105 : /// @brief this algorithm search through first collection for first element that does not satisfy binary
106 : /// predicate in conjunction will any element in second collection
107 : ///
108 : /// @param first1 - first collection begin iterator
109 : /// @param last1 - first collection end iterator
110 : /// @param first2 - second collection begin iterator
111 : /// @param last2 - second collection end iterator
112 : /// @param pred - predicate to be used for search
113 : template<class ForwardIterator1, class ForwardIterator2, class Predicate>
114 : inline ForwardIterator1
115 : find_first_not_of( ForwardIterator1 first1, ForwardIterator1 last1,
116 : ForwardIterator2 first2, ForwardIterator2 last2,
117 : Predicate pred )
118 : {
119 : while( first1 != last1 ) {
120 : if( std::find_if( first2, last2, BOOST_TEST_BIND1ST( pred, *first1 ) ) == last2 )
121 : break;
122 : ++first1;
123 : }
124 :
125 : return first1;
126 : }
127 :
128 : //____________________________________________________________________________//
129 :
130 : /// @brief this algorithm search through first collection for last element that belongs to a second one
131 : ///
132 : /// @param first1 - first collection begin iterator
133 : /// @param last1 - first collection end iterator
134 : /// @param first2 - second collection begin iterator
135 : /// @param last2 - second collection end iterator
136 : template<class BidirectionalIterator1, class ForwardIterator2>
137 : inline BidirectionalIterator1
138 146 : find_last_of( BidirectionalIterator1 first1, BidirectionalIterator1 last1,
139 : ForwardIterator2 first2, ForwardIterator2 last2 )
140 : {
141 146 : if( first1 == last1 || first2 == last2 )
142 0 : return last1;
143 :
144 146 : BidirectionalIterator1 it1 = last1;
145 1460 : while( --it1 != first1 && std::find( first2, last2, *it1 ) == last2 ) {}
146 :
147 146 : return it1 == first1 && std::find( first2, last2, *it1 ) == last2 ? last1 : it1;
148 146 : }
149 :
150 : //____________________________________________________________________________//
151 :
152 : /// @brief this algorithm search through first collection for last element that satisfy binary
153 : /// predicate in conjunction will at least one element in second collection
154 : ///
155 : /// @param first1 - first collection begin iterator
156 : /// @param last1 - first collection end iterator
157 : /// @param first2 - second collection begin iterator
158 : /// @param last2 - second collection end iterator
159 : /// @param pred - predicate to be used for search
160 : template<class BidirectionalIterator1, class ForwardIterator2, class Predicate>
161 : inline BidirectionalIterator1
162 : find_last_of( BidirectionalIterator1 first1, BidirectionalIterator1 last1,
163 : ForwardIterator2 first2, ForwardIterator2 last2,
164 : Predicate pred )
165 : {
166 : if( first1 == last1 || first2 == last2 )
167 : return last1;
168 :
169 : BidirectionalIterator1 it1 = last1;
170 : while( --it1 != first1 && std::find_if( first2, last2, BOOST_TEST_BIND1ST( pred, *it1 ) ) == last2 ) {}
171 :
172 : return it1 == first1 && std::find_if( first2, last2, BOOST_TEST_BIND1ST( pred, *it1 ) ) == last2 ? last1 : it1;
173 : }
174 :
175 : //____________________________________________________________________________//
176 :
177 : /// @brief this algorithm search through first collection for last element that does not belong to a second one
178 : ///
179 : /// @param first1 - first collection begin iterator
180 : /// @param last1 - first collection end iterator
181 : /// @param first2 - second collection begin iterator
182 : /// @param last2 - second collection end iterator
183 : template<class BidirectionalIterator1, class ForwardIterator2>
184 : inline BidirectionalIterator1
185 : find_last_not_of( BidirectionalIterator1 first1, BidirectionalIterator1 last1,
186 : ForwardIterator2 first2, ForwardIterator2 last2 )
187 : {
188 : if( first1 == last1 || first2 == last2 )
189 : return last1;
190 :
191 : BidirectionalIterator1 it1 = last1;
192 : while( --it1 != first1 && std::find( first2, last2, *it1 ) != last2 ) {}
193 :
194 : return it1 == first1 && std::find( first2, last2, *it1 ) != last2 ? last1 : it1;
195 : }
196 :
197 : //____________________________________________________________________________//
198 :
199 : /// @brief this algorithm search through first collection for last element that does not satisfy binary
200 : /// predicate in conjunction will any element in second collection
201 : ///
202 : /// @param first1 - first collection begin iterator
203 : /// @param last1 - first collection end iterator
204 : /// @param first2 - second collection begin iterator
205 : /// @param last2 - second collection end iterator
206 : /// @param pred - predicate to be used for search
207 : template<class BidirectionalIterator1, class ForwardIterator2, class Predicate>
208 : inline BidirectionalIterator1
209 : find_last_not_of( BidirectionalIterator1 first1, BidirectionalIterator1 last1,
210 : ForwardIterator2 first2, ForwardIterator2 last2,
211 : Predicate pred )
212 : {
213 : if( first1 == last1 || first2 == last2 )
214 : return last1;
215 :
216 : BidirectionalIterator1 it1 = last1;
217 : while( --it1 != first1 && std::find_if( first2, last2, BOOST_TEST_BIND1ST( pred, *it1 ) ) != last2 ) {}
218 :
219 : return it1 == first1 && std::find_if( first2, last2, BOOST_TEST_BIND1ST( pred, *it1 ) ) == last2 ? last1 : it1;
220 : }
221 :
222 : //____________________________________________________________________________//
223 :
224 :
225 : /// @brief This algorithm replaces all occurrences of a set of substrings by another substrings
226 : ///
227 : /// @param str - string of operation
228 : /// @param first1 - iterator to the beginning of the substrings to replace
229 : /// @param last1 - iterator to the end of the substrings to replace
230 : /// @param first2 - iterator to the beginning of the substrings to replace with
231 : /// @param last2 - iterator to the end of the substrings to replace with
232 : template<class StringClass, class ForwardIterator>
233 : inline StringClass
234 0 : replace_all_occurrences_of( StringClass str,
235 : ForwardIterator first1, ForwardIterator last1,
236 : ForwardIterator first2, ForwardIterator last2)
237 : {
238 0 : for(; first1 != last1 && first2 != last2; ++first1, ++first2) {
239 0 : std::size_t found = str.find( *first1 );
240 0 : while( found != StringClass::npos ) {
241 0 : str.replace(found, first1->size(), *first2 );
242 0 : found = str.find( *first1, found + first2->size() );
243 : }
244 0 : }
245 :
246 0 : return str;
247 : }
248 :
249 : /// @brief This algorithm replaces all occurrences of a string with basic wildcards
250 : /// with another (optionally containing wildcards as well).
251 : ///
252 : /// @param str - string to transform
253 : /// @param it_string_to_find - iterator to the beginning of the substrings to replace
254 : /// @param it_string_to_find_end - iterator to the end of the substrings to replace
255 : /// @param it_string_to_replace - iterator to the beginning of the substrings to replace with
256 : /// @param it_string_to_replace_end - iterator to the end of the substrings to replace with
257 : ///
258 : /// The wildcard is the symbol '*'. Only a unique wildcard per string is supported. The replacement
259 : /// string may also contain a wildcard, in which case it is considered as a placeholder to the content
260 : /// of the wildcard in the source string.
261 : /// Example:
262 : /// - In order to replace the occurrences of @c 'time=\"some-variable-value\"' to a constant string,
263 : /// one may use @c 'time=\"*\"' as the string to search for, and 'time=\"0.0\"' as the replacement string.
264 : /// - In order to replace the occurrences of 'file.cpp(XX)' per 'file.cpp:XX', where XX is a variable to keep,
265 : /// on may use @c 'file.cpp(*)' as the string to search for, and 'file.cpp:*' as the replacement string.
266 : template<class StringClass, class ForwardIterator>
267 : inline StringClass
268 : replace_all_occurrences_with_wildcards(
269 : StringClass str,
270 : ForwardIterator it_string_to_find, ForwardIterator it_string_to_find_end,
271 : ForwardIterator it_string_to_replace, ForwardIterator it_string_to_replace_end)
272 : {
273 : for(; it_string_to_find != it_string_to_find_end && it_string_to_replace != it_string_to_replace_end;
274 : ++it_string_to_find, ++ it_string_to_replace) {
275 :
276 : std::size_t wildcard_pos = it_string_to_find->find("*");
277 : if(wildcard_pos == StringClass::npos) {
278 : ForwardIterator it_to_find_current_end(it_string_to_find);
279 : ForwardIterator it_to_replace_current_end(it_string_to_replace);
280 : str = replace_all_occurrences_of(
281 : str,
282 : it_string_to_find, ++it_to_find_current_end,
283 : it_string_to_replace, ++it_to_replace_current_end);
284 : continue;
285 : }
286 :
287 : std::size_t wildcard_pos_replace = it_string_to_replace->find("*");
288 :
289 : std::size_t found_begin = str.find( it_string_to_find->substr(0, wildcard_pos) );
290 : while( found_begin != StringClass::npos ) {
291 : std::size_t found_end = str.find(it_string_to_find->substr(wildcard_pos+1), found_begin + wildcard_pos + 1); // to simplify
292 : if( found_end != StringClass::npos ) {
293 :
294 : if( wildcard_pos_replace == StringClass::npos ) {
295 : StringClass replace_content = *it_string_to_replace;
296 : str.replace(
297 : found_begin,
298 : found_end + (it_string_to_find->size() - wildcard_pos - 1 ) - found_begin,
299 : replace_content);
300 : } else {
301 : StringClass replace_content =
302 : it_string_to_replace->substr(0, wildcard_pos_replace)
303 : + str.substr(found_begin + wildcard_pos,
304 : found_end - found_begin - wildcard_pos)
305 : + it_string_to_replace->substr(wildcard_pos_replace+1) ;
306 : str.replace(
307 : found_begin,
308 : found_end + (it_string_to_find->size() - wildcard_pos - 1 ) - found_begin,
309 : replace_content);
310 :
311 : }
312 : }
313 :
314 : // may adapt the restart to the replacement and be more efficient
315 : found_begin = str.find( it_string_to_find->substr(0, wildcard_pos), found_begin + 1 );
316 : }
317 : }
318 :
319 : return str;
320 : }
321 :
322 : } // namespace utils
323 : } // namespace unit_test
324 : } // namespace boost
325 :
326 : #include <boost/test/detail/enable_warnings.hpp>
327 :
328 : #endif // BOOST_TEST_UTILS_ALGORITHM_HPP
|