diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index ef482ec7e..360b9732d 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -47,10 +47,10 @@ boostbook standalone ############################################################################### alias boostdoc - : algorithm ../string/doc/string_algo.xml + : ../string/doc/string_algo.xml : - : autodoc ../string/doc//autodoc + : ../string/doc//autodoc : ; explicit boostdoc ; -alias boostrelease ; +alias boostrelease : standalone ; explicit boostrelease ; diff --git a/doc/boyer_moore.qbk b/doc/boyer_moore.qbk index 13c966677..16511335c 100644 --- a/doc/boyer_moore.qbk +++ b/doc/boyer_moore.qbk @@ -37,7 +37,7 @@ public: ~boyer_moore (); template - corpusIter operator () ( corpusIter corpus_first, corpusIter corpus_last ); + pair operator () ( corpusIter corpus_first, corpusIter corpus_last ); }; `` @@ -45,14 +45,28 @@ and here is the corresponding procedural interface: `` template -corpusIter boyer_moore_search ( +pair boyer_moore_search ( corpusIter corpus_first, corpusIter corpus_last, patIter pat_first, patIter pat_last ); `` Each of the functions is passed two pairs of iterators. The first two define the corpus and the second two define the pattern. Note that the two pairs need not be of the same type, but they do need to "point" at the same type. In other words, `patIter::value_type` and `curpusIter::value_type` need to be the same type. -The return value of the function is an iterator pointing to the start of the pattern in the corpus. If the pattern is not found, it returns the end of the corpus (`corpus_last`). +The return value of the function is a pair of iterators pointing to the position of the pattern in the corpus. If the pattern is empty, it returns at empty range at the start of the corpus (`corpus_first`, `corpus_first`). If the pattern is not found, it returns at empty range at the end of the corpus (`corpus_last`, `corpus_last`). + +[heading Compatibility Note] + +Earlier versions of this searcher returned only a single iterator. As explained in [@https://cplusplusmusings.wordpress.com/2016/02/01/sometimes-you-get-things-wrong/], this was a suboptimal interface choice, and has been changed, starting in the 1.62.0 release. Old code that is expecting a single iterator return value can be updated by replacing the return value of the searcher's `operator ()` with the `.first` field of the pair. + +Instead of: +`` +iterator foo = searcher(a, b); +`` + +you now write: +`` +iterator foo = searcher(a, b).first; +`` [heading Performance] diff --git a/doc/boyer_moore_horspool.qbk b/doc/boyer_moore_horspool.qbk index 3a10c3253..5b8491a23 100644 --- a/doc/boyer_moore_horspool.qbk +++ b/doc/boyer_moore_horspool.qbk @@ -35,7 +35,7 @@ public: ~boyer_moore_horspool (); template - corpusIter operator () ( corpusIter corpus_first, corpusIter corpus_last ); + pair operator () ( corpusIter corpus_first, corpusIter corpus_last ); }; `` @@ -43,14 +43,28 @@ and here is the corresponding procedural interface: `` template -corpusIter boyer_moore_horspool_search ( +pair boyer_moore_horspool_search ( corpusIter corpus_first, corpusIter corpus_last, patIter pat_first, patIter pat_last ); `` Each of the functions is passed two pairs of iterators. The first two define the corpus and the second two define the pattern. Note that the two pairs need not be of the same type, but they do need to "point" at the same type. In other words, `patIter::value_type` and `curpusIter::value_type` need to be the same type. -The return value of the function is an iterator pointing to the start of the pattern in the corpus. If the pattern is not found, it returns the end of the corpus (`corpus_last`). +The return value of the function is a pair of iterators pointing to the position of the pattern in the corpus. If the pattern is empty, it returns at empty range at the start of the corpus (`corpus_first`, `corpus_first`). If the pattern is not found, it returns at empty range at the end of the corpus (`corpus_last`, `corpus_last`). + +[heading Compatibility Note] + +Earlier versions of this searcher returned only a single iterator. As explained in [@https://cplusplusmusings.wordpress.com/2016/02/01/sometimes-you-get-things-wrong/], this was a suboptimal interface choice, and has been changed, starting in the 1.62.0 release. Old code that is expecting a single iterator return value can be updated by replacing the return value of the searcher's `operator ()` with the `.first` field of the pair. + +Instead of: +`` +iterator foo = searcher(a, b); +`` + +you now write: +`` +iterator foo = searcher(a, b).first; +`` [heading Performance] diff --git a/doc/knuth_morris_pratt.qbk b/doc/knuth_morris_pratt.qbk index 7b184cfb7..b2620f1ec 100644 --- a/doc/knuth_morris_pratt.qbk +++ b/doc/knuth_morris_pratt.qbk @@ -39,7 +39,7 @@ public: ~knuth_morris_pratt (); template - corpusIter operator () ( corpusIter corpus_first, corpusIter corpus_last ); + pair operator () ( corpusIter corpus_first, corpusIter corpus_last ); }; `` @@ -47,15 +47,28 @@ and here is the corresponding procedural interface: `` template -corpusIter knuth_morris_pratt_search ( +pair knuth_morris_pratt_search ( corpusIter corpus_first, corpusIter corpus_last, patIter pat_first, patIter pat_last ); `` Each of the functions is passed two pairs of iterators. The first two define the corpus and the second two define the pattern. Note that the two pairs need not be of the same type, but they do need to "point" at the same type. In other words, `patIter::value_type` and `curpusIter::value_type` need to be the same type. -The return value of the function is an iterator pointing to the start of the pattern in the corpus. If the pattern is not found, it returns the end of the corpus (`corpus_last`). +The return value of the function is a pair of iterators pointing to the position of the pattern in the corpus. If the pattern is empty, it returns at empty range at the start of the corpus (`corpus_first`, `corpus_first`). If the pattern is not found, it returns at empty range at the end of the corpus (`corpus_last`, `corpus_last`). +[heading Compatibility Note] + +Earlier versions of this searcher returned only a single iterator. As explained in [@https://cplusplusmusings.wordpress.com/2016/02/01/sometimes-you-get-things-wrong/], this was a suboptimal interface choice, and has been changed, starting in the 1.62.0 release. Old code that is expecting a single iterator return value can be updated by replacing the return value of the searcher's `operator ()` with the `.first` field of the pair. + +Instead of: +`` +iterator foo = searcher(a, b); +`` + +you now write: +`` +iterator foo = searcher(a, b).first; +`` [heading Performance] The execution time of the Knuth-Morris-Pratt algorithm is linear in the size of the string being searched. Generally the algorithm gets faster as the pattern being searched for becomes longer. Its efficiency derives from the fact that with each unsuccessful attempt to find a match between the search string and the text it is searching, it uses the information gained from that attempt to rule out as many positions of the text as possible where the string cannot match. diff --git a/include/boost/algorithm/cxx14/equal.hpp b/include/boost/algorithm/cxx14/equal.hpp index f1539f885..9f97be1d6 100644 --- a/include/boost/algorithm/cxx14/equal.hpp +++ b/include/boost/algorithm/cxx14/equal.hpp @@ -13,7 +13,6 @@ #define BOOST_ALGORITHM_EQUAL_HPP #include // for std::equal -#include // for std::binary_function #include namespace boost { namespace algorithm { @@ -21,7 +20,7 @@ namespace boost { namespace algorithm { namespace detail { template - struct eq : public std::binary_function { + struct eq { bool operator () ( const T1& v1, const T2& v2 ) const { return v1 == v2 ;} }; diff --git a/include/boost/algorithm/is_palindrome.hpp b/include/boost/algorithm/is_palindrome.hpp index cc63e1807..09881109a 100644 --- a/include/boost/algorithm/is_palindrome.hpp +++ b/include/boost/algorithm/is_palindrome.hpp @@ -35,7 +35,7 @@ namespace boost { namespace algorithm { /// For other sequences function will return false. /// Complexity: O(N). template -bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predicate p ) +bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predicate p) { if(begin == end) { @@ -63,7 +63,7 @@ bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predi /// \return true if the entire sequence is palindrome /// /// \param begin The start of the input sequence -/// \param end One past the end of the input sequence +/// \param end One past the end of the input sequence /// /// \note This function will return true for empty sequences and for palindromes. /// For other sequences function will return false. @@ -71,26 +71,8 @@ bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predi template bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end) { - if(begin == end) - { - return true; - } - - --end; - while(begin != end) - { - if(!(*begin == *end)) - { - return false; - } - ++begin; - if(begin == end) - { - break; - } - --end; - } - return true; + return is_palindrome(begin, end, + std::equal_to::value_type> ()); } /// \fn is_palindrome ( const R& range ) @@ -122,7 +104,6 @@ bool is_palindrome(const R& range, Predicate p) return is_palindrome(boost::begin(range), boost::end(range), p); } - /// \fn is_palindrome ( const char* str ) /// \return true if the entire sequence is palindrome /// @@ -138,7 +119,6 @@ bool is_palindrome(const char* str) return is_palindrome(str, str + strlen(str)); } - /// \fn is_palindrome ( const char* str, Predicate p ) /// \return true if the entire sequence is palindrome /// @@ -155,7 +135,6 @@ bool is_palindrome(const char* str, Predicate p) return true; return is_palindrome(str, str + strlen(str), p); } - }} #endif // BOOST_ALGORITHM_IS_PALINDROME_HPP diff --git a/include/boost/algorithm/searching/boyer_moore.hpp b/include/boost/algorithm/searching/boyer_moore.hpp index 65a809dd4..192d4dec2 100644 --- a/include/boost/algorithm/searching/boyer_moore.hpp +++ b/include/boost/algorithm/searching/boyer_moore.hpp @@ -152,8 +152,8 @@ mismatch on a character that _is_ in the pattern. template - void compute_bm_prefix ( Iter pat_first, Iter pat_last, Container &prefix ) { - const std::size_t count = std::distance ( pat_first, pat_last ); + void compute_bm_prefix ( Iter first, Iter last, Container &prefix ) { + const std::size_t count = std::distance ( first, last ); BOOST_ASSERT ( count > 0 ); BOOST_ASSERT ( prefix.size () == count ); @@ -161,26 +161,26 @@ mismatch on a character that _is_ in the pattern. std::size_t k = 0; for ( std::size_t i = 1; i < count; ++i ) { BOOST_ASSERT ( k < count ); - while ( k > 0 && ( pat_first[k] != pat_first[i] )) { + while ( k > 0 && ( first[k] != first[i] )) { BOOST_ASSERT ( k < count ); k = prefix [ k - 1 ]; } - if ( pat_first[k] == pat_first[i] ) + if ( first[k] == first[i] ) k++; prefix [ i ] = k; } } - void build_suffix_table ( patIter pat_first, patIter pat_last ) { - const std::size_t count = (std::size_t) std::distance ( pat_first, pat_last ); + void build_suffix_table ( patIter first, patIter last ) { + const std::size_t count = (std::size_t) std::distance ( first, last ); if ( count > 0 ) { // empty pattern std::vector::value_type> reversed(count); - (void) std::reverse_copy ( pat_first, pat_last, reversed.begin ()); + (void) std::reverse_copy ( first, last, reversed.begin ()); std::vector prefix (count); - compute_bm_prefix ( pat_first, pat_last, prefix ); + compute_bm_prefix ( first, last, prefix ); std::vector prefix_reversed (count); compute_bm_prefix ( reversed.begin (), reversed.end (), prefix_reversed ); diff --git a/include/boost/algorithm/string/detail/case_conv.hpp b/include/boost/algorithm/string/detail/case_conv.hpp index 42621c74f..233912ca0 100644 --- a/include/boost/algorithm/string/detail/case_conv.hpp +++ b/include/boost/algorithm/string/detail/case_conv.hpp @@ -30,8 +30,10 @@ namespace boost { // a tolower functor template - struct to_lowerF : public std::unary_function + struct to_lowerF { + typedef CharT argument_type; + typedef CharT result_type; // Constructor to_lowerF( const std::locale& Loc ) : m_Loc( &Loc ) {} @@ -50,8 +52,10 @@ namespace boost { // a toupper functor template - struct to_upperF : public std::unary_function + struct to_upperF { + typedef CharT argument_type; + typedef CharT result_type; // Constructor to_upperF( const std::locale& Loc ) : m_Loc( &Loc ) {} diff --git a/include/boost/algorithm/string/detail/find_iterator.hpp b/include/boost/algorithm/string/detail/find_iterator.hpp index 9b78a0f7e..4f90a98fc 100644 --- a/include/boost/algorithm/string/detail/find_iterator.hpp +++ b/include/boost/algorithm/string/detail/find_iterator.hpp @@ -40,7 +40,7 @@ namespace boost { // Protected construction/destruction // Default constructor - find_iterator_base() {}; + find_iterator_base() {} // Copy construction find_iterator_base( const find_iterator_base& Other ) : m_Finder(Other.m_Finder) {} diff --git a/include/boost/algorithm/string/detail/util.hpp b/include/boost/algorithm/string/detail/util.hpp index cf4a8b1c8..7844b6723 100644 --- a/include/boost/algorithm/string/detail/util.hpp +++ b/include/boost/algorithm/string/detail/util.hpp @@ -89,9 +89,10 @@ namespace boost { template< typename SeqT, typename IteratorT=BOOST_STRING_TYPENAME SeqT::const_iterator > - struct copy_iterator_rangeF : - public std::unary_function< iterator_range, SeqT > + struct copy_iterator_rangeF { + typedef iterator_range argument_type; + typedef SeqT result_type; SeqT operator()( const iterator_range& Range ) const { return copy_range(Range); diff --git a/test/all_of_test.cpp b/test/all_of_test.cpp index 36918d5e8..b90eb273f 100644 --- a/test/all_of_test.cpp +++ b/test/all_of_test.cpp @@ -18,7 +18,7 @@ #include template -struct is_ : public std::unary_function { +struct is_ { is_ ( T v ) : val_ ( v ) {} ~is_ () {} bool operator () ( T comp ) const { return val_ == comp; } diff --git a/test/any_of_test.cpp b/test/any_of_test.cpp index a3267c59f..f576a3cc3 100644 --- a/test/any_of_test.cpp +++ b/test/any_of_test.cpp @@ -18,7 +18,7 @@ #include template -struct is_ : public std::unary_function { +struct is_ { is_ ( T v ) : val_ ( v ) {} ~is_ () {} bool operator () ( T comp ) const { return val_ == comp; } diff --git a/test/none_of_test.cpp b/test/none_of_test.cpp index fc74945e9..b9b40c674 100644 --- a/test/none_of_test.cpp +++ b/test/none_of_test.cpp @@ -18,7 +18,7 @@ #include template -struct is_ : public std::unary_function { +struct is_ { is_ ( T v ) : val_ ( v ) {} ~is_ () {} bool operator () ( T comp ) const { return val_ == comp; } diff --git a/test/one_of_test.cpp b/test/one_of_test.cpp index 942288189..ccc3a9774 100644 --- a/test/one_of_test.cpp +++ b/test/one_of_test.cpp @@ -18,7 +18,7 @@ #include template -struct is_ : public std::unary_function { +struct is_ { is_ ( T v ) : val_ ( v ) {} ~is_ () {} bool operator () ( T comp ) const { return val_ == comp; } diff --git a/test/partition_subrange_test.cpp b/test/partition_subrange_test.cpp index 018f1407d..c33fb46b5 100644 --- a/test/partition_subrange_test.cpp +++ b/test/partition_subrange_test.cpp @@ -7,6 +7,20 @@ #include #include + +#if __cplusplus >= 201103L +#include + +std::default_random_engine gen; +template +void do_shuffle(RandomIt first, RandomIt last) +{ std::shuffle(first, last, gen); } +#else +template +void do_shuffle(RandomIt first, RandomIt last) +{ std::random_shuffle(first, last); } +#endif + namespace ba = boost::algorithm; template @@ -72,14 +86,14 @@ BOOST_AUTO_TEST_CASE( test_main ) // BOOST_CHECK_EQUAL(v[5], 5); // Mix them up and try again - single element - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::partition_subrange(b, v.end(), b + 7, b + 8); check_sequence (b, v.end(), b + 7, b + 8); // BOOST_CHECK_EQUAL(v[7], 7); // Mix them up and try again - at the end - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::partition_subrange(b, v.end(), b + 7, v.end()); check_sequence (b, v.end(), b + 7, v.end()); @@ -88,7 +102,7 @@ BOOST_AUTO_TEST_CASE( test_main ) // BOOST_CHECK_EQUAL(v[9], 9); // Mix them up and try again - at the beginning - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::partition_subrange(b, v.end(), b, b + 2); check_sequence (b, v.end(), b, b + 2); @@ -96,12 +110,12 @@ BOOST_AUTO_TEST_CASE( test_main ) // BOOST_CHECK_EQUAL(v[1], 1); // Mix them up and try again - empty subrange - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::partition_subrange(b, v.end(), b, b); check_sequence (b, v.end(), b, b); // Mix them up and try again - entire subrange - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::partition_subrange(b, v.end(), b, v.end()); check_sequence (b, v.end(), b, v.end()); } @@ -120,14 +134,14 @@ BOOST_AUTO_TEST_CASE( test_main ) // BOOST_CHECK_EQUAL(v[5], 4); // Mix them up and try again - single element - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::partition_subrange(b, v.end(), b + 7, b + 8, std::greater()); check_sequence (b, v.end(), b + 7, b + 8, std::greater()); // BOOST_CHECK_EQUAL(v[7], 2); // Mix them up and try again - at the end - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::partition_subrange(b, v.end(), b + 7, v.end(), std::greater()); check_sequence (b, v.end(), b + 7, v.end(), std::greater()); @@ -136,7 +150,7 @@ BOOST_AUTO_TEST_CASE( test_main ) // BOOST_CHECK_EQUAL(v[9], 0); // Mix them up and try again - at the beginning - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::partition_subrange(b, v.end(), b, b + 2, std::greater()); check_sequence (b, v.end(), b, b + 2, std::greater()); @@ -144,12 +158,12 @@ BOOST_AUTO_TEST_CASE( test_main ) // BOOST_CHECK_EQUAL(v[1], 8); // Mix them up and try again - empty subrange - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::partition_subrange(b, v.end(), b, b, std::greater()); check_sequence (b, v.end(), b, b, std::greater()); // Mix them up and try again - entire subrange - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::partition_subrange(b, v.end(), b, v.end(), std::greater()); check_sequence (b, v.end(), b, v.end(), std::greater()); } diff --git a/test/sort_subrange_test.cpp b/test/sort_subrange_test.cpp index 4c1192eb8..de6a3fa46 100644 --- a/test/sort_subrange_test.cpp +++ b/test/sort_subrange_test.cpp @@ -7,6 +7,20 @@ #include #include + +#if __cplusplus >= 201103L +#include + +std::default_random_engine gen; +template +void do_shuffle(RandomIt first, RandomIt last) +{ std::shuffle(first, last, gen); } +#else +template +void do_shuffle(RandomIt first, RandomIt last) +{ std::random_shuffle(first, last); } +#endif + namespace ba = boost::algorithm; template @@ -53,14 +67,14 @@ BOOST_AUTO_TEST_CASE( test_main ) BOOST_CHECK_EQUAL(v[5], 5); // Mix them up and try again - single element - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::sort_subrange(b, v.end(), b + 7, b + 8); check_sequence (b, v.end(), b + 7, b + 8); BOOST_CHECK_EQUAL(v[7], 7); // Mix them up and try again - at the end - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::sort_subrange(b, v.end(), b + 7, v.end()); check_sequence (b, v.end(), b + 7, v.end()); @@ -69,7 +83,7 @@ BOOST_AUTO_TEST_CASE( test_main ) BOOST_CHECK_EQUAL(v[9], 9); // Mix them up and try again - at the beginning - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::sort_subrange(b, v.end(), b, b + 2); check_sequence (b, v.end(), b, b + 2); @@ -77,12 +91,12 @@ BOOST_AUTO_TEST_CASE( test_main ) BOOST_CHECK_EQUAL(v[1], 1); // Mix them up and try again - empty subrange - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::sort_subrange(b, v.end(), b, b); check_sequence (b, v.end(), b, b); // Mix them up and try again - entire subrange - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::sort_subrange(b, v.end(), b, v.end()); check_sequence (b, v.end(), b, v.end()); } @@ -101,14 +115,14 @@ BOOST_AUTO_TEST_CASE( test_main ) BOOST_CHECK_EQUAL(v[5], 4); // Mix them up and try again - single element - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::sort_subrange(b, v.end(), b + 7, b + 8, std::greater()); check_sequence (b, v.end(), b + 7, b + 8, std::greater()); BOOST_CHECK_EQUAL(v[7], 2); // Mix them up and try again - at the end - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::sort_subrange(b, v.end(), b + 7, v.end(), std::greater()); check_sequence (b, v.end(), b + 7, v.end(), std::greater()); @@ -117,7 +131,7 @@ BOOST_AUTO_TEST_CASE( test_main ) BOOST_CHECK_EQUAL(v[9], 0); // Mix them up and try again - at the beginning - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::sort_subrange(b, v.end(), b, b + 2, std::greater()); check_sequence (b, v.end(), b, b + 2, std::greater()); @@ -125,12 +139,12 @@ BOOST_AUTO_TEST_CASE( test_main ) BOOST_CHECK_EQUAL(v[1], 8); // Mix them up and try again - empty subrange - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::sort_subrange(b, v.end(), b, b, std::greater()); check_sequence (b, v.end(), b, b, std::greater()); // Mix them up and try again - entire subrange - std::random_shuffle(v.begin(), v.end()); + do_shuffle(v.begin(), v.end()); ba::sort_subrange(b, v.end(), b, v.end(), std::greater()); check_sequence (b, v.end(), b, v.end(), std::greater()); }