321 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			321 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | //  (C) Copyright Gennadiy Rozental 2001. | ||
|  | //  Distributed under 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) | ||
|  | 
 | ||
|  | //  See http://www.boost.org/libs/test for the library home page. | ||
|  | // | ||
|  | /// @file | ||
|  | /// Addition to STL algorithms | ||
|  | // *************************************************************************** | ||
|  | 
 | ||
|  | #ifndef BOOST_TEST_UTILS_ALGORITHM_HPP | ||
|  | #define BOOST_TEST_UTILS_ALGORITHM_HPP | ||
|  | 
 | ||
|  | // STL | ||
|  | #include <utility> | ||
|  | #include <algorithm> // std::find | ||
|  | #include <functional> // std::bind1st | ||
|  | 
 | ||
|  | #include <boost/test/detail/suppress_warnings.hpp> | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | namespace boost { | ||
|  | namespace unit_test { | ||
|  | namespace utils { | ||
|  | 
 | ||
|  | /// @brief this algorithm search through two collections for first mismatch position that get returned as a pair | ||
|  | /// of iterators, first pointing to the mismatch position in first collection, second iterator in second one | ||
|  | /// | ||
|  | /// @param first1 - first collection begin iterator | ||
|  | /// @param last1 - first collection end iterator | ||
|  | /// @param first2 - second collection begin iterator | ||
|  | /// @param last2 - second collection end iterator | ||
|  | template <class InputIter1, class InputIter2> | ||
|  | inline std::pair<InputIter1, InputIter2> | ||
|  | mismatch( InputIter1 first1, InputIter1 last1, | ||
|  |           InputIter2 first2, InputIter2 last2 ) | ||
|  | { | ||
|  |     while( first1 != last1 && first2 != last2 && *first1 == *first2 ) { | ||
|  |         ++first1; | ||
|  |         ++first2; | ||
|  |     } | ||
|  | 
 | ||
|  |     return std::pair<InputIter1, InputIter2>(first1, first2); | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | /// @brief this algorithm search through two collections for first mismatch position that get returned as a pair | ||
|  | /// of iterators, first pointing to the mismatch position in first collection, second iterator in second one. This algorithms | ||
|  | /// uses supplied predicate for collection elements comparison | ||
|  | /// | ||
|  | /// @param first1 - first collection begin iterator | ||
|  | /// @param last1 - first collection end iterator | ||
|  | /// @param first2 - second collection begin iterator | ||
|  | /// @param last2 - second collection end iterator | ||
|  | /// @param pred - predicate to be used for search | ||
|  | template <class InputIter1, class InputIter2, class Predicate> | ||
|  | inline std::pair<InputIter1, InputIter2> | ||
|  | mismatch( InputIter1 first1, InputIter1 last1, | ||
|  |           InputIter2 first2, InputIter2 last2, | ||
|  |           Predicate pred ) | ||
|  | { | ||
|  |     while( first1 != last1 && first2 != last2 && pred( *first1, *first2 ) ) { | ||
|  |         ++first1; | ||
|  |         ++first2; | ||
|  |     } | ||
|  | 
 | ||
|  |     return std::pair<InputIter1, InputIter2>(first1, first2); | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | /// @brief this algorithm search through first collection for first element that does not belong a second one | ||
|  | /// | ||
|  | /// @param first1 - first collection begin iterator | ||
|  | /// @param last1 - first collection end iterator | ||
|  | /// @param first2 - second collection begin iterator | ||
|  | /// @param last2 - second collection end iterator | ||
|  | template<class ForwardIterator1, class ForwardIterator2> | ||
|  | inline ForwardIterator1 | ||
|  | find_first_not_of( ForwardIterator1 first1, ForwardIterator1 last1, | ||
|  |                    ForwardIterator2 first2, ForwardIterator2 last2 ) | ||
|  | { | ||
|  |     while( first1 != last1 ) { | ||
|  |         if( std::find( first2, last2, *first1 ) == last2 ) | ||
|  |             break; | ||
|  |         ++first1; | ||
|  |     } | ||
|  | 
 | ||
|  |     return first1; | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | /// @brief this algorithm search through first collection for first element that does not satisfy binary | ||
|  | /// predicate in conjunction will any element in second collection | ||
|  | /// | ||
|  | /// @param first1 - first collection begin iterator | ||
|  | /// @param last1 - first collection end iterator | ||
|  | /// @param first2 - second collection begin iterator | ||
|  | /// @param last2 - second collection end iterator | ||
|  | /// @param pred - predicate to be used for search | ||
|  | template<class ForwardIterator1, class ForwardIterator2, class Predicate> | ||
|  | inline ForwardIterator1 | ||
|  | find_first_not_of( ForwardIterator1 first1, ForwardIterator1 last1, | ||
|  |                    ForwardIterator2 first2, ForwardIterator2 last2, | ||
|  |                    Predicate pred ) | ||
|  | { | ||
|  |     while( first1 != last1 ) { | ||
|  |         if( std::find_if( first2, last2, std::bind1st( pred, *first1 ) ) == last2 ) | ||
|  |             break; | ||
|  |         ++first1; | ||
|  |     } | ||
|  | 
 | ||
|  |     return first1; | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | /// @brief this algorithm search through first collection for last element that belongs to a second one | ||
|  | /// | ||
|  | /// @param first1 - first collection begin iterator | ||
|  | /// @param last1 - first collection end iterator | ||
|  | /// @param first2 - second collection begin iterator | ||
|  | /// @param last2 - second collection end iterator | ||
|  | template<class BidirectionalIterator1, class ForwardIterator2> | ||
|  | inline BidirectionalIterator1 | ||
|  | find_last_of( BidirectionalIterator1 first1, BidirectionalIterator1 last1, | ||
|  |               ForwardIterator2 first2, ForwardIterator2 last2 ) | ||
|  | { | ||
|  |     if( first1 == last1 || first2 == last2 ) | ||
|  |         return last1; | ||
|  | 
 | ||
|  |     BidirectionalIterator1 it1 = last1; | ||
|  |     while( --it1 != first1 && std::find( first2, last2, *it1 ) == last2 ) {} | ||
|  | 
 | ||
|  |     return it1 == first1 && std::find( first2, last2, *it1 ) == last2 ? last1 : it1; | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | /// @brief this algorithm search through first collection for last element that satisfy binary | ||
|  | /// predicate in conjunction will at least one element in second collection | ||
|  | /// | ||
|  | /// @param first1 - first collection begin iterator | ||
|  | /// @param last1 - first collection end iterator | ||
|  | /// @param first2 - second collection begin iterator | ||
|  | /// @param last2 - second collection end iterator | ||
|  | /// @param pred - predicate to be used for search | ||
|  | template<class BidirectionalIterator1, class ForwardIterator2, class Predicate> | ||
|  | inline BidirectionalIterator1 | ||
|  | find_last_of( BidirectionalIterator1 first1, BidirectionalIterator1 last1, | ||
|  |               ForwardIterator2 first2, ForwardIterator2 last2, | ||
|  |               Predicate pred ) | ||
|  | { | ||
|  |     if( first1 == last1 || first2 == last2 ) | ||
|  |         return last1; | ||
|  | 
 | ||
|  |     BidirectionalIterator1 it1 = last1; | ||
|  |     while( --it1 != first1 && std::find_if( first2, last2, std::bind1st( pred, *it1 ) ) == last2 ) {} | ||
|  | 
 | ||
|  |     return it1 == first1 && std::find_if( first2, last2, std::bind1st( pred, *it1 ) ) == last2 ? last1 : it1; | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | /// @brief this algorithm search through first collection for last element that does not belong to a second one | ||
|  | /// | ||
|  | /// @param first1 - first collection begin iterator | ||
|  | /// @param last1 - first collection end iterator | ||
|  | /// @param first2 - second collection begin iterator | ||
|  | /// @param last2 - second collection end iterator | ||
|  | template<class BidirectionalIterator1, class ForwardIterator2> | ||
|  | inline BidirectionalIterator1 | ||
|  | find_last_not_of( BidirectionalIterator1 first1, BidirectionalIterator1 last1, | ||
|  |                   ForwardIterator2 first2, ForwardIterator2 last2 ) | ||
|  | { | ||
|  |     if( first1 == last1 || first2 == last2 ) | ||
|  |         return last1; | ||
|  | 
 | ||
|  |     BidirectionalIterator1 it1 = last1; | ||
|  |     while( --it1 != first1 && std::find( first2, last2, *it1 ) != last2 ) {} | ||
|  | 
 | ||
|  |     return it1 == first1 && std::find( first2, last2, *it1 ) != last2 ? last1 : it1; | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | /// @brief this algorithm search through first collection for last element that does not satisfy binary | ||
|  | /// predicate in conjunction will any element in second collection | ||
|  | /// | ||
|  | /// @param first1 - first collection begin iterator | ||
|  | /// @param last1 - first collection end iterator | ||
|  | /// @param first2 - second collection begin iterator | ||
|  | /// @param last2 - second collection end iterator | ||
|  | /// @param pred - predicate to be used for search | ||
|  | template<class BidirectionalIterator1, class ForwardIterator2, class Predicate> | ||
|  | inline BidirectionalIterator1 | ||
|  | find_last_not_of( BidirectionalIterator1 first1, BidirectionalIterator1 last1, | ||
|  |                   ForwardIterator2 first2, ForwardIterator2 last2, | ||
|  |                   Predicate pred ) | ||
|  | { | ||
|  |     if( first1 == last1 || first2 == last2 ) | ||
|  |         return last1; | ||
|  | 
 | ||
|  |     BidirectionalIterator1 it1 = last1; | ||
|  |     while( --it1 != first1 && std::find_if( first2, last2, std::bind1st( pred, *it1 ) ) != last2 ) {} | ||
|  | 
 | ||
|  |     return it1 == first1 && std::find_if( first2, last2, std::bind1st( pred, *it1 ) ) == last2 ? last1 : it1; | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | 
 | ||
|  | /// @brief This algorithm replaces all occurrences of a set of substrings by another substrings | ||
|  | /// | ||
|  | /// @param str - string of operation | ||
|  | /// @param first1 - iterator to the beginning of the substrings to replace | ||
|  | /// @param last1 - iterator to the end of the substrings to replace | ||
|  | /// @param first2 - iterator to the beginning of the substrings to replace with | ||
|  | /// @param last2 - iterator to the end of the substrings to replace with | ||
|  | template<class StringClass, class ForwardIterator> | ||
|  | inline StringClass | ||
|  | replace_all_occurrences_of( StringClass str, | ||
|  |                             ForwardIterator first1, ForwardIterator last1, | ||
|  |                             ForwardIterator first2, ForwardIterator last2) | ||
|  | { | ||
|  |     for(; first1 != last1 && first2 != last2; ++first1, ++first2) { | ||
|  |         std::size_t found = str.find( *first1 ); | ||
|  |         while( found != StringClass::npos ) { | ||
|  |             str.replace(found, first1->size(), *first2 ); | ||
|  |             found = str.find( *first1, found + first2->size() ); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return str; | ||
|  | } | ||
|  | 
 | ||
|  | /// @brief This algorithm replaces all occurrences of a string with basic wildcards | ||
|  | /// with another (optionally containing wildcards as well). | ||
|  | /// | ||
|  | /// @param str - string to transform | ||
|  | /// @param it_string_to_find - iterator to the beginning of the substrings to replace | ||
|  | /// @param it_string_to_find_end - iterator to the end of the substrings to replace | ||
|  | /// @param it_string_to_replace - iterator to the beginning of the substrings to replace with | ||
|  | /// @param it_string_to_replace_end - iterator to the end of the substrings to replace with | ||
|  | /// | ||
|  | /// The wildcard is the symbol '*'. Only a unique wildcard per string is supported. The replacement | ||
|  | /// string may also contain a wildcard, in which case it is considered as a placeholder to the content | ||
|  | /// of the wildcard in the source string. | ||
|  | /// Example: | ||
|  | /// - In order to replace the occurrences of @c 'time=\"some-variable-value\"' to a constant string, | ||
|  | ///   one may use @c 'time=\"*\"' as the string to search for, and 'time=\"0.0\"' as the replacement string. | ||
|  | /// - In order to replace the occurrences of 'file.cpp(XX)' per 'file.cpp:XX', where XX is a variable to keep, | ||
|  | ///   on may use @c 'file.cpp(*)' as the string to search for, and 'file.cpp:*' as the replacement string. | ||
|  | template<class StringClass, class ForwardIterator> | ||
|  | inline StringClass | ||
|  | replace_all_occurrences_with_wildcards( | ||
|  |     StringClass str, | ||
|  |     ForwardIterator it_string_to_find, ForwardIterator it_string_to_find_end, | ||
|  |     ForwardIterator it_string_to_replace, ForwardIterator it_string_to_replace_end) | ||
|  | { | ||
|  |     for(; it_string_to_find != it_string_to_find_end && it_string_to_replace != it_string_to_replace_end; | ||
|  |         ++it_string_to_find, ++ it_string_to_replace) { | ||
|  | 
 | ||
|  |         std::size_t wildcard_pos = it_string_to_find->find("*"); | ||
|  |         if(wildcard_pos == StringClass::npos) { | ||
|  |             ForwardIterator it_to_find_current_end(it_string_to_find); | ||
|  |             ForwardIterator it_to_replace_current_end(it_string_to_replace); | ||
|  |             str = replace_all_occurrences_of( | ||
|  |                 str, | ||
|  |                 it_string_to_find, ++it_to_find_current_end, | ||
|  |                 it_string_to_replace, ++it_to_replace_current_end); | ||
|  |             continue; | ||
|  |         } | ||
|  | 
 | ||
|  |         std::size_t wildcard_pos_replace = it_string_to_replace->find("*"); | ||
|  | 
 | ||
|  |         std::size_t found_begin = str.find( it_string_to_find->substr(0, wildcard_pos) ); | ||
|  |         while( found_begin != StringClass::npos ) { | ||
|  |             std::size_t found_end = str.find(it_string_to_find->substr(wildcard_pos+1), found_begin + wildcard_pos + 1); // to simplify | ||
|  |             if( found_end != StringClass::npos ) { | ||
|  | 
 | ||
|  |                 if( wildcard_pos_replace == StringClass::npos ) { | ||
|  |                     StringClass replace_content = *it_string_to_replace; | ||
|  |                     str.replace( | ||
|  |                         found_begin, | ||
|  |                         found_end + (it_string_to_find->size() - wildcard_pos - 1 ) - found_begin, | ||
|  |                         replace_content); | ||
|  |                 } else { | ||
|  |                     StringClass replace_content = | ||
|  |                         it_string_to_replace->substr(0, wildcard_pos_replace) | ||
|  |                         + str.substr(found_begin + wildcard_pos, | ||
|  |                                      found_end - found_begin - wildcard_pos) | ||
|  |                         + it_string_to_replace->substr(wildcard_pos_replace+1) ; | ||
|  |                     str.replace( | ||
|  |                         found_begin, | ||
|  |                         found_end + (it_string_to_find->size() - wildcard_pos - 1 ) - found_begin, | ||
|  |                         replace_content); | ||
|  | 
 | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             // may adapt the restart to the replacement and be more efficient | ||
|  |             found_begin = str.find( it_string_to_find->substr(0, wildcard_pos), found_begin + 1 ); | ||
|  |        } | ||
|  |     } | ||
|  | 
 | ||
|  |     return str; | ||
|  | } | ||
|  | 
 | ||
|  | } // namespace utils | ||
|  | } // namespace unit_test | ||
|  | } // namespace boost | ||
|  | 
 | ||
|  | #include <boost/test/detail/enable_warnings.hpp> | ||
|  | 
 | ||
|  | #endif // BOOST_TEST_UTILS_ALGORITHM_HPP |