From 782d7665dc3c1b137a353fe6469c9d974471be3a Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Sun, 7 Feb 2016 13:20:22 -0500 Subject: [PATCH 01/36] Comment out unused parameter to silence a warning. Thanks to @meetingcpp for the report --- include/boost/algorithm/searching/detail/bm_traits.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/algorithm/searching/detail/bm_traits.hpp b/include/boost/algorithm/searching/detail/bm_traits.hpp index b39e539..1214363 100644 --- a/include/boost/algorithm/searching/detail/bm_traits.hpp +++ b/include/boost/algorithm/searching/detail/bm_traits.hpp @@ -79,7 +79,7 @@ namespace boost { namespace algorithm { namespace detail { skip_map skip_; const value_type k_default_value; public: - skip_table ( std::size_t patSize, value_type default_value ) : k_default_value ( default_value ) { + skip_table ( std::size_t /*patSize*/, value_type default_value ) : k_default_value ( default_value ) { std::fill_n ( skip_.begin(), skip_.size(), default_value ); } From 205f5ff4bbb00ece289892089a6c94c975e97ca2 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Mon, 15 Feb 2016 22:23:58 -0800 Subject: [PATCH 02/36] Update searchers to return a pair of iterators --- .../boost/algorithm/searching/boyer_moore.hpp | 32 +++--- .../searching/boyer_moore_horspool.hpp | 33 +++--- .../searching/knuth_morris_pratt.hpp | 33 +++--- test/empty_search_test.cpp | 18 +-- test/search_test1.cpp | 103 ++++++++++-------- test/search_test2.cpp | 30 +++-- test/search_test3.cpp | 30 +++-- test/search_test4.cpp | 30 +++-- 8 files changed, 176 insertions(+), 133 deletions(-) diff --git a/include/boost/algorithm/searching/boyer_moore.hpp b/include/boost/algorithm/searching/boyer_moore.hpp index c5fe9fa..65a809d 100644 --- a/include/boost/algorithm/searching/boyer_moore.hpp +++ b/include/boost/algorithm/searching/boyer_moore.hpp @@ -75,25 +75,27 @@ Requirements: /// \param corpus_last One past the end of the data to search /// template - corpusIter operator () ( corpusIter corpus_first, corpusIter corpus_last ) const { + std::pair + operator () ( corpusIter corpus_first, corpusIter corpus_last ) const { BOOST_STATIC_ASSERT (( boost::is_same< typename std::iterator_traits::value_type, typename std::iterator_traits::value_type>::value )); - if ( corpus_first == corpus_last ) return corpus_last; // if nothing to search, we didn't find it! - if ( pat_first == pat_last ) return corpus_first; // empty pattern matches at start + if ( corpus_first == corpus_last ) return std::make_pair(corpus_last, corpus_last); // if nothing to search, we didn't find it! + if ( pat_first == pat_last ) return std::make_pair(corpus_first, corpus_first); // empty pattern matches at start const difference_type k_corpus_length = std::distance ( corpus_first, corpus_last ); // If the pattern is larger than the corpus, we can't find it! if ( k_corpus_length < k_pattern_length ) - return corpus_last; + return std::make_pair(corpus_last, corpus_last); // Do the search - return this->do_search ( corpus_first, corpus_last ); + return this->do_search ( corpus_first, corpus_last ); } template - typename boost::range_iterator::type operator () ( Range &r ) const { + std::pair::type, typename boost::range_iterator::type> + operator () ( Range &r ) const { return (*this) (boost::begin(r), boost::end(r)); } @@ -112,7 +114,8 @@ Requirements: /// \param p A predicate used for the search comparisons. /// template - corpusIter do_search ( corpusIter corpus_first, corpusIter corpus_last ) const { + std::pair + do_search ( corpusIter corpus_first, corpusIter corpus_last ) const { /* ---- Do the matching ---- */ corpusIter curPos = corpus_first; const corpusIter lastPos = corpus_last - k_pattern_length; @@ -126,7 +129,7 @@ Requirements: j--; // We matched - we're done! if ( j == 0 ) - return curPos; + return std::make_pair(curPos, curPos + k_pattern_length); } // Since we didn't match, figure out how far to skip forward @@ -138,7 +141,7 @@ Requirements: curPos += suffix_ [ j ]; } - return corpus_last; // We didn't find anything + return std::make_pair(corpus_last, corpus_last); // We didn't find anything } @@ -211,7 +214,7 @@ Requirements: /// \param pat_last One past the end of the data to search for /// template - corpusIter boyer_moore_search ( + std::pair boyer_moore_search ( corpusIter corpus_first, corpusIter corpus_last, patIter pat_first, patIter pat_last ) { @@ -220,7 +223,7 @@ Requirements: } template - corpusIter boyer_moore_search ( + std::pair boyer_moore_search ( corpusIter corpus_first, corpusIter corpus_last, const PatternRange &pattern ) { typedef typename boost::range_iterator::type pattern_iterator; @@ -229,8 +232,9 @@ Requirements: } template - typename boost::lazy_disable_if_c< - boost::is_same::value, typename boost::range_iterator > + typename boost::disable_if_c< + boost::is_same::value, + std::pair::type, typename boost::range_iterator::type> > ::type boyer_moore_search ( CorpusRange &corpus, patIter pat_first, patIter pat_last ) { @@ -239,7 +243,7 @@ Requirements: } template - typename boost::range_iterator::type + std::pair::type, typename boost::range_iterator::type> boyer_moore_search ( CorpusRange &corpus, const PatternRange &pattern ) { typedef typename boost::range_iterator::type pattern_iterator; diff --git a/include/boost/algorithm/searching/boyer_moore_horspool.hpp b/include/boost/algorithm/searching/boyer_moore_horspool.hpp index 758ded2..aacb5cb 100644 --- a/include/boost/algorithm/searching/boyer_moore_horspool.hpp +++ b/include/boost/algorithm/searching/boyer_moore_horspool.hpp @@ -64,33 +64,34 @@ http://www-igm.univ-mlv.fr/%7Elecroq/string/node18.html ~boyer_moore_horspool () {} - /// \fn operator ( corpusIter corpus_first, corpusIter corpus_last, Pred p ) + /// \fn operator ( corpusIter corpus_first, corpusIter corpus_last) /// \brief Searches the corpus for the pattern that was passed into the constructor /// /// \param corpus_first The start of the data to search (Random Access Iterator) /// \param corpus_last One past the end of the data to search - /// \param p A predicate used for the search comparisons. /// template - corpusIter operator () ( corpusIter corpus_first, corpusIter corpus_last ) const { + std::pair + operator () ( corpusIter corpus_first, corpusIter corpus_last ) const { BOOST_STATIC_ASSERT (( boost::is_same< typename std::iterator_traits::value_type, typename std::iterator_traits::value_type>::value )); - if ( corpus_first == corpus_last ) return corpus_last; // if nothing to search, we didn't find it! - if ( pat_first == pat_last ) return corpus_first; // empty pattern matches at start + if ( corpus_first == corpus_last ) return std::make_pair(corpus_last, corpus_last); // if nothing to search, we didn't find it! + if ( pat_first == pat_last ) return std::make_pair(corpus_first, corpus_first); // empty pattern matches at start const difference_type k_corpus_length = std::distance ( corpus_first, corpus_last ); // If the pattern is larger than the corpus, we can't find it! if ( k_corpus_length < k_pattern_length ) - return corpus_last; + return std::make_pair(corpus_last, corpus_last); // Do the search return this->do_search ( corpus_first, corpus_last ); } template - typename boost::range_iterator::type operator () ( Range &r ) const { + std::pair::type, typename boost::range_iterator::type> + operator () ( Range &r ) const { return (*this) (boost::begin(r), boost::end(r)); } @@ -108,7 +109,8 @@ http://www-igm.univ-mlv.fr/%7Elecroq/string/node18.html /// \param k_corpus_length The length of the corpus to search /// template - corpusIter do_search ( corpusIter corpus_first, corpusIter corpus_last ) const { + std::pair + do_search ( corpusIter corpus_first, corpusIter corpus_last ) const { corpusIter curPos = corpus_first; const corpusIter lastPos = corpus_last - k_pattern_length; while ( curPos <= lastPos ) { @@ -117,14 +119,14 @@ http://www-igm.univ-mlv.fr/%7Elecroq/string/node18.html while ( pat_first [j] == curPos [j] ) { // We matched - we're done! if ( j == 0 ) - return curPos; + return std::make_pair(curPos, curPos + k_pattern_length); j--; } curPos += skip_ [ curPos [ k_pattern_length - 1 ]]; } - return corpus_last; + return std::make_pair(corpus_last, corpus_last); } // \endcond }; @@ -142,7 +144,7 @@ http://www-igm.univ-mlv.fr/%7Elecroq/string/node18.html /// \param pat_last One past the end of the data to search for /// template - corpusIter boyer_moore_horspool_search ( + std::pair boyer_moore_horspool_search ( corpusIter corpus_first, corpusIter corpus_last, patIter pat_first, patIter pat_last ) { @@ -151,7 +153,7 @@ http://www-igm.univ-mlv.fr/%7Elecroq/string/node18.html } template - corpusIter boyer_moore_horspool_search ( + std::pair boyer_moore_horspool_search ( corpusIter corpus_first, corpusIter corpus_last, const PatternRange &pattern ) { typedef typename boost::range_iterator::type pattern_iterator; @@ -160,8 +162,9 @@ http://www-igm.univ-mlv.fr/%7Elecroq/string/node18.html } template - typename boost::lazy_disable_if_c< - boost::is_same::value, typename boost::range_iterator > + typename boost::disable_if_c< + boost::is_same::value, + std::pair::type, typename boost::range_iterator::type> > ::type boyer_moore_horspool_search ( CorpusRange &corpus, patIter pat_first, patIter pat_last ) { @@ -170,7 +173,7 @@ http://www-igm.univ-mlv.fr/%7Elecroq/string/node18.html } template - typename boost::range_iterator::type + std::pair::type, typename boost::range_iterator::type> boyer_moore_horspool_search ( CorpusRange &corpus, const PatternRange &pattern ) { typedef typename boost::range_iterator::type pattern_iterator; diff --git a/include/boost/algorithm/searching/knuth_morris_pratt.hpp b/include/boost/algorithm/searching/knuth_morris_pratt.hpp index aaeeb51..c890c9c 100644 --- a/include/boost/algorithm/searching/knuth_morris_pratt.hpp +++ b/include/boost/algorithm/searching/knuth_morris_pratt.hpp @@ -69,23 +69,26 @@ namespace boost { namespace algorithm { /// \param p A predicate used for the search comparisons. /// template - corpusIter operator () ( corpusIter corpus_first, corpusIter corpus_last ) const { + std::pair + operator () ( corpusIter corpus_first, corpusIter corpus_last ) const { BOOST_STATIC_ASSERT (( boost::is_same< typename std::iterator_traits::value_type, typename std::iterator_traits::value_type>::value )); - if ( corpus_first == corpus_last ) return corpus_last; // if nothing to search, we didn't find it! - if ( pat_first == pat_last ) return corpus_first; // empty pattern matches at start + + if ( corpus_first == corpus_last ) return std::make_pair(corpus_last, corpus_last); // if nothing to search, we didn't find it! + if ( pat_first == pat_last ) return std::make_pair(corpus_first, corpus_first); // empty pattern matches at start const difference_type k_corpus_length = std::distance ( corpus_first, corpus_last ); // If the pattern is larger than the corpus, we can't find it! if ( k_corpus_length < k_pattern_length ) - return corpus_last; + return std::make_pair(corpus_last, corpus_last); - return do_search ( corpus_first, corpus_last, k_corpus_length ); + return do_search ( corpus_first, corpus_last, k_corpus_length ); } template - typename boost::range_iterator::type operator () ( Range &r ) const { + std::pair::type, typename boost::range_iterator::type> + operator () ( Range &r ) const { return (*this) (boost::begin(r), boost::end(r)); } @@ -103,7 +106,8 @@ namespace boost { namespace algorithm { /// \param p A predicate used for the search comparisons. /// template - corpusIter do_search ( corpusIter corpus_first, corpusIter corpus_last, + std::pair + do_search ( corpusIter corpus_first, corpusIter corpus_last, difference_type k_corpus_length ) const { difference_type match_start = 0; // position in the corpus that we're matching @@ -135,7 +139,7 @@ namespace boost { namespace algorithm { while ( match_start <= last_match ) { while ( pat_first [ idx ] == corpus_first [ match_start + idx ] ) { if ( ++idx == k_pattern_length ) - return corpus_first + match_start; + return std::make_pair(corpus_first + match_start, corpus_first + match_start + k_pattern_length); } // Figure out where to start searching again // assert ( idx - skip_ [ idx ] > 0 ); // we're always moving forward @@ -146,7 +150,7 @@ namespace boost { namespace algorithm { #endif // We didn't find anything - return corpus_last; + return std::make_pair(corpus_last, corpus_last); } @@ -202,7 +206,7 @@ namespace boost { namespace algorithm { /// \param pat_last One past the end of the data to search for /// template - corpusIter knuth_morris_pratt_search ( + std::pair knuth_morris_pratt_search ( corpusIter corpus_first, corpusIter corpus_last, patIter pat_first, patIter pat_last ) { @@ -211,7 +215,7 @@ namespace boost { namespace algorithm { } template - corpusIter knuth_morris_pratt_search ( + std::pair knuth_morris_pratt_search ( corpusIter corpus_first, corpusIter corpus_last, const PatternRange &pattern ) { typedef typename boost::range_iterator::type pattern_iterator; @@ -220,8 +224,9 @@ namespace boost { namespace algorithm { } template - typename boost::lazy_disable_if_c< - boost::is_same::value, typename boost::range_iterator > + typename boost::disable_if_c< + boost::is_same::value, + std::pair::type, typename boost::range_iterator::type> > ::type knuth_morris_pratt_search ( CorpusRange &corpus, patIter pat_first, patIter pat_last ) { @@ -230,7 +235,7 @@ namespace boost { namespace algorithm { } template - typename boost::range_iterator::type + std::pair::type, typename boost::range_iterator::type> knuth_morris_pratt_search ( CorpusRange &corpus, const PatternRange &pattern ) { typedef typename boost::range_iterator::type pattern_iterator; diff --git a/test/empty_search_test.cpp b/test/empty_search_test.cpp index 22317f1..cb37678 100644 --- a/test/empty_search_test.cpp +++ b/test/empty_search_test.cpp @@ -26,56 +26,56 @@ BOOST_AUTO_TEST_CASE( test_main ) BOOST_CHECK ( boost::algorithm::boyer_moore_search ( cs.begin (), cs.end (), estr.begin (), estr.end ()) - == cs.begin () + == std::make_pair(cs.begin(), cs.begin()) ); BOOST_CHECK ( boost::algorithm::boyer_moore_horspool_search ( cs.begin (), cs.end (), estr.begin (), estr.end ()) - == cs.begin () + == std::make_pair(cs.begin(), cs.begin()) ); BOOST_CHECK ( boost::algorithm::knuth_morris_pratt_search ( cs.begin (), cs.end (), estr.begin (), estr.end ()) - == cs.begin () + == std::make_pair(cs.begin(), cs.begin()) ); // empty corpus, non-empty pattern BOOST_CHECK ( boost::algorithm::boyer_moore_search ( estr.begin (), estr.end (), str.begin (), str.end ()) - == estr.end () + == std::make_pair(estr.end(), estr.end()) ); BOOST_CHECK ( boost::algorithm::boyer_moore_horspool_search ( estr.begin (), estr.end (), str.begin (), str.end ()) - == estr.end () + == std::make_pair(estr.end(), estr.end()) ); BOOST_CHECK ( boost::algorithm::knuth_morris_pratt_search ( estr.begin (), estr.end (), str.begin (), str.end ()) - == estr.end () + == std::make_pair(estr.end(), estr.end()) ); // non-empty corpus, empty pattern BOOST_CHECK ( boost::algorithm::boyer_moore_search ( str.begin (), str.end (), estr.begin (), estr.end ()) - == str.begin () + == std::make_pair(str.begin(), str.begin()) ); BOOST_CHECK ( boost::algorithm::boyer_moore_horspool_search ( str.begin (), str.end (), estr.begin (), estr.end ()) - == str.begin () + == std::make_pair(str.begin(), str.begin()) ); BOOST_CHECK ( boost::algorithm::knuth_morris_pratt_search ( str.begin (), str.end (), estr.begin (), estr.end ()) - == str.begin () + == std::make_pair(str.begin(), str.begin()) ); } diff --git a/test/search_test1.cpp b/test/search_test1.cpp index 7c49a3a..3fe3b91 100644 --- a/test/search_test1.cpp +++ b/test/search_test1.cpp @@ -34,6 +34,7 @@ namespace { template void check_one_iter ( const Container &haystack, const std::string &needle, int expected ) { typedef typename Container::const_iterator iter_type; + typedef typename std::pair ret_type; typedef std::string::const_iterator pattern_type; iter_type hBeg = haystack.begin (); @@ -41,33 +42,40 @@ namespace { pattern_type nBeg = needle.begin (); pattern_type nEnd = needle.end (); +// iter_type ret0 = std::search (hBeg, hEnd, nBeg, nEnd); + ret_type ret1 = ba::boyer_moore_search (hBeg, hEnd, nBeg, nEnd); + ret_type ret1r = ba::boyer_moore_search (haystack, nBeg, nEnd); + ret_type ret2 = ba::boyer_moore_horspool_search (hBeg, hEnd, nBeg, nEnd); + ret_type ret3 = ba::knuth_morris_pratt_search (hBeg, hEnd, nBeg, nEnd); + iter_type it0 = std::search (hBeg, hEnd, nBeg, nEnd); - iter_type it1 = ba::boyer_moore_search (hBeg, hEnd, nBeg, nEnd); - iter_type it1r = ba::boyer_moore_search (haystack, nBeg, nEnd); - iter_type it2 = ba::boyer_moore_horspool_search (hBeg, hEnd, nBeg, nEnd); - iter_type it3 = ba::knuth_morris_pratt_search (hBeg, hEnd, nBeg, nEnd); - const int dist = it1 == hEnd ? -1 : std::distance ( hBeg, it1 ); +// iter_type it1 = ret1.first; +// iter_type it1r = ret1r.first; +// iter_type it2 = ret2.first; +// iter_type it3 = ret3.first; + const int dist = ret1.first == hEnd ? -1 : std::distance ( hBeg, ret1.first ); std::cout << "(Iterators) Pattern is " << needle.length () << ", haysstack is " << haystack.length () << " chars long; " << std::endl; try { - if ( it0 != it1 ) { + if ( it0 != ret1.first ) { throw std::runtime_error ( std::string ( "results mismatch between std::search and boyer-moore search" )); } - if ( it1 != it1r ) { + if ( ret1.first != ret1r.first || ret1.second != ret1r.second ) { throw std::runtime_error ( std::string ( "results mismatch between iterator and range boyer_moore search" )); } - if ( it1 != it2 ) { + if ( ret1.first != ret2.first || ret1.second != ret2.second ) { throw std::runtime_error ( std::string ( "results mismatch between boyer-moore and boyer-moore-horspool search" )); } - if ( it1 != it3 ) + if ( ret1.first != ret3.first || ret1.second != ret3.second ) { throw std::runtime_error ( std::string ( "results mismatch between boyer-moore and knuth-morris-pratt search" )); + } } @@ -75,10 +83,10 @@ namespace { std::cout << "Searching for: " << needle << std::endl; std::cout << "Expected: " << expected << "\n"; std::cout << " std: " << std::distance ( hBeg, it0 ) << "\n"; - std::cout << " bm: " << std::distance ( hBeg, it1 ) << "\n"; - std::cout << " bm(r): " << std::distance ( hBeg, it1r ) << "\n"; - std::cout << " bmh: " << std::distance ( hBeg, it2 ) << "\n"; - std::cout << " kpm: " << std::distance ( hBeg, it3 )<< "\n"; + std::cout << " bm: " << std::distance ( hBeg, ret1.first ) << "\n"; + std::cout << " bm(r): " << std::distance ( hBeg, ret1r.first ) << "\n"; + std::cout << " bmh: " << std::distance ( hBeg, ret2.first ) << "\n"; + std::cout << " kpm: " << std::distance ( hBeg, ret3.first )<< "\n"; std::cout << std::flush; throw ; } @@ -91,32 +99,35 @@ namespace { template void check_one_pointer ( const Container &haystack, const std::string &needle, int expected ) { typedef const typename Container::value_type *ptr_type; + typedef typename std::pair ret_type; + ptr_type hBeg = haystack.size () == 0 ? NULL : &*haystack.begin (); ptr_type hEnd = hBeg + haystack.size (); ptr_type nBeg = needle.size () == 0 ? NULL : &*needle.begin (); ptr_type nEnd = nBeg + needle.size (); ptr_type it0 = std::search (hBeg, hEnd, nBeg, nEnd); - ptr_type it1 = ba::boyer_moore_search (hBeg, hEnd, nBeg, nEnd); - ptr_type it2 = ba::boyer_moore_horspool_search (hBeg, hEnd, nBeg, nEnd); - ptr_type it3 = ba::knuth_morris_pratt_search (hBeg, hEnd, nBeg, nEnd); - const int dist = it1 == hEnd ? -1 : std::distance ( hBeg, it1 ); + ret_type ret1 = ba::boyer_moore_search (hBeg, hEnd, nBeg, nEnd); + ret_type ret2 = ba::boyer_moore_horspool_search (hBeg, hEnd, nBeg, nEnd); + ret_type ret3 = ba::knuth_morris_pratt_search (hBeg, hEnd, nBeg, nEnd); + const int dist = ret1.first == hEnd ? -1 : std::distance ( hBeg, ret1.first ); std::cout << "(Pointers) Pattern is " << needle.length () << ", haysstack is " << haystack.length () << " chars long; " << std::endl; try { - if ( it0 != it1 ) { + if ( it0 != ret1.first ) { throw std::runtime_error ( std::string ( "results mismatch between std::search and boyer-moore search" )); } - if ( it1 != it2 ) { + if ( ret1.first != ret2.first || ret1.second != ret2.second ) { throw std::runtime_error ( std::string ( "results mismatch between boyer-moore and boyer-moore-horspool search" )); } - if ( it1 != it3 ) + if ( ret1.first != ret3.first || ret1.second != ret3.second ) { throw std::runtime_error ( std::string ( "results mismatch between boyer-moore and knuth-morris-pratt search" )); + } } @@ -124,9 +135,9 @@ namespace { std::cout << "Searching for: " << needle << std::endl; std::cout << "Expected: " << expected << "\n"; std::cout << " std: " << std::distance ( hBeg, it0 ) << "\n"; - std::cout << " bm: " << std::distance ( hBeg, it1 ) << "\n"; - std::cout << " bmh: " << std::distance ( hBeg, it2 ) << "\n"; - std::cout << " kpm: " << std::distance ( hBeg, it3 )<< "\n"; + std::cout << " bm: " << std::distance ( hBeg, ret1.first ) << "\n"; + std::cout << " bmh: " << std::distance ( hBeg, ret2.first ) << "\n"; + std::cout << " kpm: " << std::distance ( hBeg, ret3.first )<< "\n"; std::cout << std::flush; throw ; } @@ -138,6 +149,7 @@ namespace { template void check_one_object ( const Container &haystack, const std::string &needle, int expected ) { typedef typename Container::const_iterator iter_type; + typedef typename std::pair ret_type; typedef std::string::const_iterator pattern_type; iter_type hBeg = haystack.begin (); @@ -150,58 +162,59 @@ namespace { ba::boyer_moore_horspool bmh ( nBeg, nEnd ); ba::knuth_morris_pratt kmp ( nBeg, nEnd ); - iter_type it0 = std::search (hBeg, hEnd, nBeg, nEnd); - iter_type it1 = bm (hBeg, hEnd); - iter_type it1r = bm (haystack); - iter_type rt1 = bm_r (hBeg, hEnd); - iter_type rt1r = bm_r (haystack); - iter_type it2 = bmh (hBeg, hEnd); - iter_type it3 = kmp (hBeg, hEnd); - const int dist = it1 == hEnd ? -1 : std::distance ( hBeg, it1 ); + iter_type it0 = std::search (hBeg, hEnd, nBeg, nEnd); + ret_type ret1 = bm (hBeg, hEnd); + ret_type ret1r = bm (haystack); + ret_type retr1 = bm_r (hBeg, hEnd); + ret_type retr1r = bm_r (haystack); + ret_type ret2 = bmh (hBeg, hEnd); + ret_type ret3 = kmp (hBeg, hEnd); + const int dist = ret1.first == hEnd ? -1 : std::distance ( hBeg, ret1.first ); std::cout << "(Objects) Pattern is " << needle.length () << ", haysstack is " << haystack.length () << " chars long; " << std::endl; try { - if ( it0 != it1 ) { + if ( it0 != ret1.first ) { throw std::runtime_error ( std::string ( "results mismatch between std::search and boyer-moore search" )); } - if ( it1 != it1r ) { + if ( ret1.first != ret1r.first || ret1.second != ret1r.second ) { throw std::runtime_error ( std::string ( "results mismatch between iterator and range boyer_moore search(1)" )); } - if ( it1 != rt1 ) { + if ( ret1.first != retr1.first || ret1.second != retr1.second ) { throw std::runtime_error ( std::string ( "results mismatch between iterator and range boyer_moore search(2)" )); } - if ( rt1 != rt1r ) { + if ( ret1.first != retr1r.first || ret1.second != retr1r.second ) { throw std::runtime_error ( std::string ( "results mismatch between iterator and range boyer_moore search(3)" )); } - if ( it1 != it2 ) { + if ( ret1.first != ret2.first || ret1.second != ret2.second ) { throw std::runtime_error ( std::string ( "results mismatch between boyer-moore and boyer-moore-horspool search" )); } - if ( it1 != it3 ) + if ( ret1.first != ret3.first || ret1.second != ret3.second ) { throw std::runtime_error ( std::string ( "results mismatch between boyer-moore and knuth-morris-pratt search" )); + } } catch ( ... ) { std::cout << "Searching for: " << needle << std::endl; - std::cout << "Expected: " << expected << "\n"; - std::cout << " std: " << std::distance ( hBeg, it0 ) << "\n"; - std::cout << " bm: " << std::distance ( hBeg, it1 ) << "\n"; - std::cout << " bm(r1): " << std::distance ( hBeg, it1r ) << "\n"; - std::cout << " bm(r2): " << std::distance ( hBeg, rt1 ) << "\n"; - std::cout << " bm(r3): " << std::distance ( hBeg, rt1r ) << "\n"; - std::cout << " bmh: " << std::distance ( hBeg, it2 ) << "\n"; - std::cout << " kpm: " << std::distance ( hBeg, it3 )<< "\n"; + std::cout << "Expected: " << expected << "\n"; + std::cout << " std: " << std::distance ( hBeg, it0 ) << "\n"; + std::cout << " bm: " << std::distance ( hBeg, ret1.first ) << "\n"; + std::cout << " bm(r1): " << std::distance ( hBeg, ret1r.first ) << "\n"; + std::cout << " bm(r2): " << std::distance ( hBeg, retr1.first ) << "\n"; + std::cout << " bm(r3): " << std::distance ( hBeg, retr1r.first ) << "\n"; + std::cout << " bmh: " << std::distance ( hBeg, ret2.first ) << "\n"; + std::cout << " kpm: " << std::distance ( hBeg, ret3.first )<< "\n"; std::cout << std::flush; throw ; } diff --git a/test/search_test2.cpp b/test/search_test2.cpp index 4d772ca..eba105e 100644 --- a/test/search_test2.cpp +++ b/test/search_test2.cpp @@ -33,8 +33,8 @@ typedef std::vector vec; needle.begin (), needle.end ()); \ if ( res != exp ) { \ std::cout << "On run # " << i << " expected " \ - << exp - haystack.begin () << " got " \ - << res - haystack.begin () << std::endl; \ + << exp.first - haystack.begin () << " got " \ + << res.first - haystack.begin () << std::endl; \ throw std::runtime_error \ ( "Unexpected result from " #call ); \ } \ @@ -51,8 +51,8 @@ typedef std::vector vec; res = s_o ( haystack.begin (), haystack.end ()); \ if ( res != exp ) { \ std::cout << "On run # " << i << " expected " \ - << exp - haystack.begin () << " got " \ - << res - haystack.begin () << std::endl; \ + << exp.first - haystack.begin () << " got " \ + << res.first - haystack.begin () << std::endl; \ throw std::runtime_error \ ( "Unexpected result from " #obj " object" ); \ } \ @@ -90,27 +90,33 @@ namespace { std::clock_t sTime; unsigned long stdDiff; - vec::const_iterator res; - vec::const_iterator exp; // the expected result + std::pair res; + std::pair exp; // the expected result + vec::const_iterator exp_start; if ( expected >= 0 ) - exp = haystack.begin () + expected; + exp_start = haystack.begin () + expected; else if ( expected == -1 ) - exp = haystack.end (); // we didn't find it! + exp_start = haystack.end (); // we didn't find it! else if ( expected == -2 ) - exp = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ()); + exp_start = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ()); else throw std::logic_error ( "Expected must be -2, -1, or >= 0" ); + if ( expected == -1 ) + exp = std::make_pair(haystack.end(), haystack.end()); + else + exp = std::make_pair(exp_start, exp_start + needle.size()); + std::cout << "Pattern is " << needle.size () << " entries long" << std::endl; std::cout << "Corpus is " << haystack.size () << " entries long" << std::endl; // First, the std library search sTime = std::clock (); for ( i = 0; i < NUM_TRIES; ++i ) { - res = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ()); - if ( res != exp ) { - std::cout << "On run # " << i << " expected " << exp - haystack.begin () << " got " << res - haystack.begin () << std::endl; + vec::const_iterator s_res = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ()); + if ( s_res != exp.first ) { + std::cout << "On run # " << i << " expected " << exp.first - haystack.begin () << " got " << s_res - haystack.begin () << std::endl; throw std::runtime_error ( "Unexpected result from std::search" ); } } diff --git a/test/search_test3.cpp b/test/search_test3.cpp index 96226cd..e4c7661 100644 --- a/test/search_test3.cpp +++ b/test/search_test3.cpp @@ -34,8 +34,8 @@ typedef std::vector vec; needle.begin (), needle.end ()); \ if ( res != exp ) { \ std::cout << "On run # " << i << " expected " \ - << exp - haystack.begin () << " got " \ - << res - haystack.begin () << std::endl; \ + << exp.first - haystack.begin () << " got " \ + << res.first - haystack.begin () << std::endl; \ throw std::runtime_error \ ( "Unexpected result from " #call ); \ } \ @@ -52,8 +52,8 @@ typedef std::vector vec; res = s_o ( haystack.begin (), haystack.end ()); \ if ( res != exp ) { \ std::cout << "On run # " << i << " expected " \ - << exp - haystack.begin () << " got " \ - << res - haystack.begin () << std::endl; \ + << exp.first - haystack.begin () << " got " \ + << res.first - haystack.begin () << std::endl; \ throw std::runtime_error \ ( "Unexpected result from " #obj " object" ); \ } \ @@ -90,27 +90,33 @@ namespace { std::clock_t sTime; unsigned long stdDiff; - vec::const_iterator res; - vec::const_iterator exp; // the expected result + std::pair res; + std::pair exp; // the expected result + vec::const_iterator exp_start; if ( expected >= 0 ) - exp = haystack.begin () + expected; + exp_start = haystack.begin () + expected; else if ( expected == -1 ) - exp = haystack.end (); // we didn't find it1 + exp_start = haystack.end (); // we didn't find it1 else if ( expected == -2 ) - exp = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ()); + exp_start = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ()); else throw std::logic_error ( "Expected must be -2, -1, or >= 0" ); + if ( expected == -1 ) + exp = std::make_pair(haystack.end(), haystack.end()); + else + exp = std::make_pair(exp_start, exp_start + needle.size()); + std::cout << "Pattern is " << needle.size () << " entries long" << std::endl; std::cout << "Corpus is " << haystack.size () << " entries long" << std::endl; // First, the std library search sTime = std::clock (); for ( i = 0; i < NUM_TRIES; ++i ) { - res = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ()); - if ( res != exp ) { - std::cout << "On run # " << i << " expected " << exp - haystack.begin () << " got " << res - haystack.begin () << std::endl; + vec::const_iterator s_res = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ()); + if ( s_res != exp.first ) { + std::cout << "On run # " << i << " expected " << exp.first - haystack.begin () << " got " << s_res - haystack.begin () << std::endl; throw std::runtime_error ( "Unexpected result from std::search" ); } } diff --git a/test/search_test4.cpp b/test/search_test4.cpp index 2b83267..997e359 100644 --- a/test/search_test4.cpp +++ b/test/search_test4.cpp @@ -30,8 +30,8 @@ typedef std::vector vec; res = boost::algorithm::call ( haystack, needle ); \ if ( res != exp ) { \ std::cout << "Expected " \ - << exp - haystack.begin () << " got " \ - << res - haystack.begin () << std::endl; \ + << exp.first - haystack.begin () << " got " \ + << res.first - haystack.begin () << std::endl; \ throw std::runtime_error \ ( "Unexpected result from " #call ); \ } \ @@ -43,8 +43,8 @@ typedef std::vector vec; res = s_o ( haystack ); \ if ( res != exp ) { \ std::cout << "Expected " \ - << exp - haystack.begin () << " got " \ - << res - haystack.begin () << std::endl; \ + << exp.first - haystack.begin () << " got " \ + << res.first - haystack.begin () << std::endl; \ throw std::runtime_error \ ( "Unexpected result from " #obj " object" ); \ } \ @@ -64,25 +64,31 @@ namespace { void check_one ( const vec &haystack, const vec &needle, int expected ) { - vec::const_iterator res; - vec::const_iterator exp; // the expected result + std::pair res; + std::pair exp; // the expected result + vec::const_iterator exp_start; if ( expected >= 0 ) - exp = haystack.begin () + expected; + exp_start = haystack.begin () + expected; else if ( expected == -1 ) - exp = haystack.end (); // we didn't find it1 + exp_start = haystack.end (); // we didn't find it1 else if ( expected == -2 ) - exp = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ()); + exp_start = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ()); else throw std::logic_error ( "Expected must be -2, -1, or >= 0" ); + if ( expected == -1 ) + exp = std::make_pair(haystack.end(), haystack.end()); + else + exp = std::make_pair(exp_start, exp_start + needle.size()); + std::cout << "Pattern is " << needle.size () << " entries long" << std::endl; std::cout << "Corpus is " << haystack.size () << " entries long" << std::endl; // First, the std library search - res = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ()); - if ( res != exp ) { - std::cout << "Expected " << exp - haystack.begin () << " got " << res - haystack.begin () << std::endl; + vec::const_iterator s_res = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ()); + if ( s_res != exp.first ) { + std::cout << "Expected " << exp.first - haystack.begin () << " got " << s_res - haystack.begin () << std::endl; throw std::runtime_error ( "Unexpected result from std::search" ); } From d558476f41ec03ac152026d49c62f4081db50cf0 Mon Sep 17 00:00:00 2001 From: Nigel Stewart Date: Sun, 31 Jan 2016 19:08:45 +1000 Subject: [PATCH 03/36] Implement algorithm::hex_lower as lower-case alternative to algorithm::hex --- include/boost/algorithm/hex.hpp | 104 +++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 28 deletions(-) diff --git a/include/boost/algorithm/hex.hpp b/include/boost/algorithm/hex.hpp index 145a414..9f3763a 100644 --- a/include/boost/algorithm/hex.hpp +++ b/include/boost/algorithm/hex.hpp @@ -1,9 +1,9 @@ -/* +/* Copyright (c) Marshall Clow 2011-2012. 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) - + Thanks to Nevin for his comments/help. */ @@ -13,7 +13,7 @@ */ /// \file hex.hpp -/// \brief Convert sequence of integral types into a sequence of hexadecimal +/// \brief Convert sequence of integral types into a sequence of hexadecimal /// characters and back. Based on the MySQL functions HEX and UNHEX /// \author Marshall Clow @@ -33,17 +33,17 @@ namespace boost { namespace algorithm { -/*! - \struct hex_decode_error - \brief Base exception class for all hex decoding errors +/*! + \struct hex_decode_error + \brief Base exception class for all hex decoding errors */ /*! - \struct non_hex_input + \struct non_hex_input \brief Thrown when a non-hex value (0-9, A-F) encountered when decoding. Contains the offending character -*/ /*! - \struct not_enough_input +*/ /*! + \struct not_enough_input \brief Thrown when the input sequence unexpectedly ends - + */ struct hex_decode_error : virtual boost::exception, virtual std::exception {}; struct not_enough_input : virtual hex_decode_error {}; @@ -54,12 +54,12 @@ namespace detail { /// \cond DOXYGEN_HIDE template - OutputIterator encode_one ( T val, OutputIterator out ) { + OutputIterator encode_one ( T val, OutputIterator out, const char * hexDigits ) { const std::size_t num_hex_digits = 2 * sizeof ( T ); char res [ num_hex_digits ]; char *p = res + num_hex_digits; for ( std::size_t i = 0; i < num_hex_digits; ++i, val >>= 4 ) - *--p = "0123456789ABCDEF" [ val & 0x0F ]; + *--p = hexDigits [ val & 0x0F ]; return std::copy ( res, res + num_hex_digits, out ); } @@ -106,12 +106,12 @@ namespace detail { typedef T value_type; }; - template + template bool iter_end ( Iterator current, Iterator last ) { return current == last; } - + template bool ptr_end ( const T* ptr, const T* /*end*/ ) { return *ptr == '\0'; } - + // What can we assume here about the inputs? // is std::iterator_traits::value_type always 'char' ? // Could it be wchar_t, say? Does it matter? @@ -124,11 +124,11 @@ namespace detail { // Need to make sure that we get can read that many chars here. for ( std::size_t i = 0; i < 2 * sizeof ( T ); ++i, ++first ) { - if ( pred ( first, last )) + if ( pred ( first, last )) BOOST_THROW_EXCEPTION (not_enough_input ()); res = ( 16 * res ) + hex_char_to_int (*first); } - + *out = res; return ++out; } @@ -138,7 +138,7 @@ namespace detail { /// \fn hex ( InputIterator first, InputIterator last, OutputIterator out ) /// \brief Converts a sequence of integral types into a hexadecimal sequence of characters. -/// +/// /// \param first The start of the input sequence /// \param last One past the end of the input sequence /// \param out An output iterator to the results into @@ -148,14 +148,31 @@ template typename boost::enable_if::value_type>, OutputIterator>::type hex ( InputIterator first, InputIterator last, OutputIterator out ) { for ( ; first != last; ++first ) - out = detail::encode_one ( *first, out ); + out = detail::encode_one ( *first, out, "0123456789ABCDEF" ); return out; } - + + +/// \fn hex_lower ( InputIterator first, InputIterator last, OutputIterator out ) +/// \brief Converts a sequence of integral types into a lower case hexadecimal sequence of characters. +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param out An output iterator to the results into +/// \return The updated output iterator +/// \note Based on the MySQL function of the same name +template +typename boost::enable_if::value_type>, OutputIterator>::type +hex_lower ( InputIterator first, InputIterator last, OutputIterator out ) { + for ( ; first != last; ++first ) + out = detail::encode_one ( *first, out, "0123456789abcdef" ); + return out; + } + /// \fn hex ( const T *ptr, OutputIterator out ) /// \brief Converts a sequence of integral types into a hexadecimal sequence of characters. -/// +/// /// \param ptr A pointer to a 0-terminated sequence of data. /// \param out An output iterator to the results into /// \return The updated output iterator @@ -164,13 +181,30 @@ template typename boost::enable_if, OutputIterator>::type hex ( const T *ptr, OutputIterator out ) { while ( *ptr ) - out = detail::encode_one ( *ptr++, out ); + out = detail::encode_one ( *ptr++, out, "0123456789ABCDEF" ); return out; } + +/// \fn hex_lower ( const T *ptr, OutputIterator out ) +/// \brief Converts a sequence of integral types into a lower case hexadecimal sequence of characters. +/// +/// \param ptr A pointer to a 0-terminated sequence of data. +/// \param out An output iterator to the results into +/// \return The updated output iterator +/// \note Based on the MySQL function of the same name +template +typename boost::enable_if, OutputIterator>::type +hex_lower ( const T *ptr, OutputIterator out ) { + while ( *ptr ) + out = detail::encode_one ( *ptr++, out, "0123456789abcdef" ); + return out; + } + + /// \fn hex ( const Range &r, OutputIterator out ) /// \brief Converts a sequence of integral types into a hexadecimal sequence of characters. -/// +/// /// \param r The input range /// \param out An output iterator to the results into /// \return The updated output iterator @@ -182,9 +216,23 @@ hex ( const Range &r, OutputIterator out ) { } +/// \fn hex_lower ( const Range &r, OutputIterator out ) +/// \brief Converts a sequence of integral types into a lower case hexadecimal sequence of characters. +/// +/// \param r The input range +/// \param out An output iterator to the results into +/// \return The updated output iterator +/// \note Based on the MySQL function of the same name +template +typename boost::enable_if::value_type>, OutputIterator>::type +hex_lower ( const Range &r, OutputIterator out ) { + return hex_lower (boost::begin(r), boost::end(r), out); +} + + /// \fn unhex ( InputIterator first, InputIterator last, OutputIterator out ) /// \brief Converts a sequence of hexadecimal characters into a sequence of integers. -/// +/// /// \param first The start of the input sequence /// \param last One past the end of the input sequence /// \param out An output iterator to the results into @@ -200,7 +248,7 @@ OutputIterator unhex ( InputIterator first, InputIterator last, OutputIterator o /// \fn unhex ( const T *ptr, OutputIterator out ) /// \brief Converts a sequence of hexadecimal characters into a sequence of integers. -/// +/// /// \param ptr A pointer to a null-terminated input sequence. /// \param out An output iterator to the results into /// \return The updated output iterator @@ -218,7 +266,7 @@ OutputIterator unhex ( const T *ptr, OutputIterator out ) { /// \fn OutputIterator unhex ( const Range &r, OutputIterator out ) /// \brief Converts a sequence of hexadecimal characters into a sequence of integers. -/// +/// /// \param r The input range /// \param out An output iterator to the results into /// \return The updated output iterator @@ -231,7 +279,7 @@ OutputIterator unhex ( const Range &r, OutputIterator out ) { /// \fn String hex ( const String &input ) /// \brief Converts a sequence of integral types into a hexadecimal sequence of characters. -/// +/// /// \param input A container to be converted /// \return A container with the encoded text template @@ -244,7 +292,7 @@ String hex ( const String &input ) { /// \fn String unhex ( const String &input ) /// \brief Converts a sequence of hexadecimal characters into a sequence of characters. -/// +/// /// \param input A container to be converted /// \return A container with the decoded text template From b7d46e65311ac35d56b87d3196b97ece7a21c6a6 Mon Sep 17 00:00:00 2001 From: Nigel Stewart Date: Sun, 31 Jan 2016 20:17:23 +1000 Subject: [PATCH 04/36] Another overload of algorithm::hex_lower as lower-case alternative to algorithm::hex --- include/boost/algorithm/hex.hpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/boost/algorithm/hex.hpp b/include/boost/algorithm/hex.hpp index 9f3763a..ad20a20 100644 --- a/include/boost/algorithm/hex.hpp +++ b/include/boost/algorithm/hex.hpp @@ -290,6 +290,21 @@ String hex ( const String &input ) { return output; } + +/// \fn String hex_lower ( const String &input ) +/// \brief Converts a sequence of integral types into a lower case hexadecimal sequence of characters. +/// +/// \param input A container to be converted +/// \return A container with the encoded text +template +String hex_lower ( const String &input ) { + String output; + output.reserve (input.size () * (2 * sizeof (typename String::value_type))); + (void) hex_lower (input, std::back_inserter (output)); + return output; + } + + /// \fn String unhex ( const String &input ) /// \brief Converts a sequence of hexadecimal characters into a sequence of characters. /// From 3cedd051fa6edb9db3b999f7fe71a8d83651753d Mon Sep 17 00:00:00 2001 From: Nigel Stewart Date: Sun, 31 Jan 2016 20:18:22 +1000 Subject: [PATCH 05/36] Test coverage for algorithm::hex_lower, adapting existing coverage for algorithm::hex --- test/hex_test1.cpp | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/test/hex_test1.cpp b/test/hex_test1.cpp index d9f5364..31e3f9d 100644 --- a/test/hex_test1.cpp +++ b/test/hex_test1.cpp @@ -9,6 +9,7 @@ #include #include +#include #define BOOST_TEST_MAIN #include @@ -42,6 +43,31 @@ void test_to_hex ( const typename String::value_type ** tests ) { } } +template +void test_to_hex_lower ( const typename String::value_type ** tests ) { + for ( const typename String::value_type **p = tests; *p; p++ ) { + String arg, argh, one, two, three, four; + arg.assign ( *p ); + boost::algorithm::hex_lower ( *p, std::back_inserter ( one )); + boost::algorithm::hex_lower ( arg, std::back_inserter ( two )); + boost::algorithm::hex_lower ( arg.begin (), arg.end (), std::back_inserter ( three )); + four = boost::algorithm::hex_lower ( arg ); + BOOST_CHECK ( one == two ); + BOOST_CHECK ( one == three ); + BOOST_CHECK ( one == four ); + argh = one; + one.clear (); two.clear (); three.clear (); four.clear (); + boost::algorithm::unhex ( argh.c_str (), std::back_inserter ( one )); + boost::algorithm::unhex ( argh, std::back_inserter ( two )); + boost::algorithm::unhex ( argh.begin (), argh.end (), std::back_inserter ( three )); + four = boost::algorithm::unhex ( argh ); + BOOST_CHECK ( one == two ); + BOOST_CHECK ( one == three ); + BOOST_CHECK ( one == four ); + BOOST_CHECK ( one == arg ); + } + } + template void test_from_hex_success ( const typename String::value_type ** tests ) { @@ -61,6 +87,11 @@ void test_from_hex_success ( const typename String::value_type ** tests ) { boost::algorithm::hex ( argh, std::back_inserter ( two )); boost::algorithm::hex ( argh.begin (), argh.end (), std::back_inserter ( three )); four = boost::algorithm::hex ( argh ); + boost::algorithm::to_lower( arg ); + boost::algorithm::to_lower( one ); + boost::algorithm::to_lower( two ); + boost::algorithm::to_lower( three ); + boost::algorithm::to_lower( four ); BOOST_CHECK ( one == two ); BOOST_CHECK ( one == three ); BOOST_CHECK ( one == four ); @@ -113,6 +144,7 @@ const wchar_t *tohex_w [] = { const char *fromhex [] = { "20", "2122234556FF", + "2122234556ff", NULL // End of the list }; @@ -120,6 +152,7 @@ const char *fromhex [] = { const wchar_t *fromhex_w [] = { L"00101020", L"2122234556FF3456", + L"2122234556ff3456", NULL // End of the list }; @@ -129,6 +162,8 @@ const char *fromhex_fail [] = { "H", "234", "21222G4556FF", + "h", + "21222g4556ff", NULL // End of the list }; @@ -139,6 +174,8 @@ const wchar_t *fromhex_fail_w [] = { L"H", L"234", L"21222G4556FF", + L"h", + L"21222g4556ff", NULL // End of the list }; @@ -146,10 +183,12 @@ const wchar_t *fromhex_fail_w [] = { BOOST_AUTO_TEST_CASE( test_main ) { test_to_hex ( tohex ); + test_to_hex_lower ( tohex ); test_from_hex_success ( fromhex ); test_from_hex_failure ( fromhex_fail ); test_to_hex ( tohex_w ); + test_to_hex_lower ( tohex_w ); test_from_hex_success ( fromhex_w ); test_from_hex_failure ( fromhex_fail_w ); } From 352768cf66190c4d2708c0161f0b62d1d08966a2 Mon Sep 17 00:00:00 2001 From: aldonin Date: Wed, 27 Apr 2016 17:56:17 +0300 Subject: [PATCH 06/36] Fix missing include --- minmax/example/minmax_ex.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/minmax/example/minmax_ex.cpp b/minmax/example/minmax_ex.cpp index d806709..d77820b 100644 --- a/minmax/example/minmax_ex.cpp +++ b/minmax/example/minmax_ex.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include From 795c6c69e5885c5a164bd53f03d263f2ed7573b6 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Thu, 28 Apr 2016 08:47:47 -0700 Subject: [PATCH 07/36] Removed doc comment for replace_all that said it returned something; Fixes https://svn.boost.org/trac/boost/ticket/12163 --- include/boost/algorithm/string/replace.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/boost/algorithm/string/replace.hpp b/include/boost/algorithm/string/replace.hpp index 0c04e47..2adb031 100644 --- a/include/boost/algorithm/string/replace.hpp +++ b/include/boost/algorithm/string/replace.hpp @@ -401,7 +401,6 @@ namespace boost { \param Search A substring to be searched for \param Format A substitute string \param Loc A locale used for case insensitive comparison - \return A reference to the modified input */ template inline void ireplace_last( @@ -643,7 +642,6 @@ namespace boost { \param Input An input string \param Search A substring to be searched for \param Format A substitute string - \return A reference to the modified input */ template inline void replace_all( From 1da90fcc4af793b95f3617f8feafa48e11f139e4 Mon Sep 17 00:00:00 2001 From: Kolya Matteo Date: Fri, 29 Apr 2016 15:37:09 -0400 Subject: [PATCH 08/36] Remove unnecessary #include and correct some comments --- include/boost/algorithm/cxx11/all_of.hpp | 3 --- include/boost/algorithm/cxx11/any_of.hpp | 1 - include/boost/algorithm/cxx11/copy_if.hpp | 4 +--- include/boost/algorithm/cxx11/copy_n.hpp | 4 ---- include/boost/algorithm/cxx11/find_if_not.hpp | 4 ---- include/boost/algorithm/cxx11/iota.hpp | 4 ---- include/boost/algorithm/cxx11/is_partitioned.hpp | 4 ---- include/boost/algorithm/cxx11/is_permutation.hpp | 8 ++------ include/boost/algorithm/cxx11/is_sorted.hpp | 1 - include/boost/algorithm/cxx11/none_of.hpp | 1 - include/boost/algorithm/cxx11/partition_copy.hpp | 5 +---- include/boost/algorithm/cxx11/partition_point.hpp | 4 +--- 12 files changed, 5 insertions(+), 38 deletions(-) diff --git a/include/boost/algorithm/cxx11/all_of.hpp b/include/boost/algorithm/cxx11/all_of.hpp index 39cab39..8280b18 100644 --- a/include/boost/algorithm/cxx11/all_of.hpp +++ b/include/boost/algorithm/cxx11/all_of.hpp @@ -12,7 +12,6 @@ #ifndef BOOST_ALGORITHM_ALL_OF_HPP #define BOOST_ALGORITHM_ALL_OF_HPP -#include // for std::all_of, if available #include #include @@ -27,8 +26,6 @@ namespace boost { namespace algorithm { /// \param p A predicate for testing the elements of the sequence /// /// \note This function is part of the C++2011 standard library. -/// We will use the standard one if it is available, -/// otherwise we have our own implementation. template bool all_of ( InputIterator first, InputIterator last, Predicate p ) { diff --git a/include/boost/algorithm/cxx11/any_of.hpp b/include/boost/algorithm/cxx11/any_of.hpp index cf69348..e68135a 100644 --- a/include/boost/algorithm/cxx11/any_of.hpp +++ b/include/boost/algorithm/cxx11/any_of.hpp @@ -14,7 +14,6 @@ #ifndef BOOST_ALGORITHM_ANY_OF_HPP #define BOOST_ALGORITHM_ANY_OF_HPP -#include // for std::any_of, if available #include #include diff --git a/include/boost/algorithm/cxx11/copy_if.hpp b/include/boost/algorithm/cxx11/copy_if.hpp index d869caf..73e85d9 100644 --- a/include/boost/algorithm/cxx11/copy_if.hpp +++ b/include/boost/algorithm/cxx11/copy_if.hpp @@ -12,7 +12,7 @@ #ifndef BOOST_ALGORITHM_COPY_IF_HPP #define BOOST_ALGORITHM_COPY_IF_HPP -#include // for std::copy_if, if available +#include // for std::pair, std::make_pair #include #include @@ -28,8 +28,6 @@ namespace boost { namespace algorithm { /// \param result An output iterator to write the results into /// \param p A predicate for testing the elements of the range /// \note This function is part of the C++2011 standard library. -/// We will use the standard one if it is available, -/// otherwise we have our own implementation. template OutputIterator copy_if ( InputIterator first, InputIterator last, OutputIterator result, Predicate p ) { diff --git a/include/boost/algorithm/cxx11/copy_n.hpp b/include/boost/algorithm/cxx11/copy_n.hpp index ebfe889..ac88085 100644 --- a/include/boost/algorithm/cxx11/copy_n.hpp +++ b/include/boost/algorithm/cxx11/copy_n.hpp @@ -12,8 +12,6 @@ #ifndef BOOST_ALGORITHM_COPY_N_HPP #define BOOST_ALGORITHM_COPY_N_HPP -#include // for std::copy_n, if available - namespace boost { namespace algorithm { /// \fn copy_n ( InputIterator first, Size n, OutputIterator result ) @@ -25,8 +23,6 @@ namespace boost { namespace algorithm { /// \param n The number of elements to copy /// \param result An output iterator to write the results into /// \note This function is part of the C++2011 standard library. -/// We will use the standard one if it is available, -/// otherwise we have our own implementation. template OutputIterator copy_n ( InputIterator first, Size n, OutputIterator result ) { diff --git a/include/boost/algorithm/cxx11/find_if_not.hpp b/include/boost/algorithm/cxx11/find_if_not.hpp index 414697c..02ff4dc 100644 --- a/include/boost/algorithm/cxx11/find_if_not.hpp +++ b/include/boost/algorithm/cxx11/find_if_not.hpp @@ -12,8 +12,6 @@ #ifndef BOOST_ALGORITHM_FIND_IF_NOT_HPP #define BOOST_ALGORITHM_FIND_IF_NOT_HPP -#include // for std::find_if_not, if it exists - #include #include @@ -27,8 +25,6 @@ namespace boost { namespace algorithm { /// \param last One past the end of the input sequence /// \param p A predicate for testing the elements of the range /// \note This function is part of the C++2011 standard library. -/// We will use the standard one if it is available, -/// otherwise we have our own implementation. template InputIterator find_if_not ( InputIterator first, InputIterator last, Predicate p ) { diff --git a/include/boost/algorithm/cxx11/iota.hpp b/include/boost/algorithm/cxx11/iota.hpp index 2e638ec..675093f 100644 --- a/include/boost/algorithm/cxx11/iota.hpp +++ b/include/boost/algorithm/cxx11/iota.hpp @@ -12,8 +12,6 @@ #ifndef BOOST_ALGORITHM_IOTA_HPP #define BOOST_ALGORITHM_IOTA_HPP -#include - #include #include @@ -26,8 +24,6 @@ namespace boost { namespace algorithm { /// \param last One past the end of the input sequence /// \param value The initial value of the sequence to be generated /// \note This function is part of the C++2011 standard library. -/// We will use the standard one if it is available, -/// otherwise we have our own implementation. template void iota ( ForwardIterator first, ForwardIterator last, T value ) { diff --git a/include/boost/algorithm/cxx11/is_partitioned.hpp b/include/boost/algorithm/cxx11/is_partitioned.hpp index cdabd97..cb6c71e 100644 --- a/include/boost/algorithm/cxx11/is_partitioned.hpp +++ b/include/boost/algorithm/cxx11/is_partitioned.hpp @@ -12,8 +12,6 @@ #ifndef BOOST_ALGORITHM_IS_PARTITIONED_HPP #define BOOST_ALGORITHM_IS_PARTITIONED_HPP -#include // for std::is_partitioned, if available - #include #include @@ -26,8 +24,6 @@ namespace boost { namespace algorithm { /// \param last One past the end of the input sequence /// \param p The predicate to test the values with /// \note This function is part of the C++2011 standard library. -/// We will use the standard one if it is available, -/// otherwise we have our own implementation. template bool is_partitioned ( InputIterator first, InputIterator last, UnaryPredicate p ) { diff --git a/include/boost/algorithm/cxx11/is_permutation.hpp b/include/boost/algorithm/cxx11/is_permutation.hpp index ec902dc..0098cd5 100644 --- a/include/boost/algorithm/cxx11/is_permutation.hpp +++ b/include/boost/algorithm/cxx11/is_permutation.hpp @@ -12,8 +12,8 @@ #ifndef BOOST_ALGORITHM_IS_PERMUTATION11_HPP #define BOOST_ALGORITHM_IS_PERMUTATION11_HPP -#include // for std::less, tie, mismatch and is_permutation (if available) -#include // for std::make_pair +#include // for std::find_if, count_if, mismatch +#include // for std::pair #include // for std::equal_to #include @@ -108,8 +108,6 @@ namespace detail { /// \param p The predicate to compare elements with /// /// \note This function is part of the C++2011 standard library. -/// We will use the standard one if it is available, -/// otherwise we have our own implementation. template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate > bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, BinaryPredicate p ) @@ -135,8 +133,6 @@ bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, /// \param last2 One past the end of the input sequence /// \param first2 The start of the second sequence /// \note This function is part of the C++2011 standard library. -/// We will use the standard one if it is available, -/// otherwise we have our own implementation. template< class ForwardIterator1, class ForwardIterator2 > bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2 ) { diff --git a/include/boost/algorithm/cxx11/is_sorted.hpp b/include/boost/algorithm/cxx11/is_sorted.hpp index f6062da..f4dbb38 100644 --- a/include/boost/algorithm/cxx11/is_sorted.hpp +++ b/include/boost/algorithm/cxx11/is_sorted.hpp @@ -13,7 +13,6 @@ #ifndef BOOST_ALGORITHM_ORDERED_HPP #define BOOST_ALGORITHM_ORDERED_HPP -#include #include #include diff --git a/include/boost/algorithm/cxx11/none_of.hpp b/include/boost/algorithm/cxx11/none_of.hpp index 67be3d1..36f0aa8 100644 --- a/include/boost/algorithm/cxx11/none_of.hpp +++ b/include/boost/algorithm/cxx11/none_of.hpp @@ -12,7 +12,6 @@ #ifndef BOOST_ALGORITHM_NONE_OF_HPP #define BOOST_ALGORITHM_NONE_OF_HPP -#include // for std::none_of, if available #include #include diff --git a/include/boost/algorithm/cxx11/partition_copy.hpp b/include/boost/algorithm/cxx11/partition_copy.hpp index 2d8c3e9..f347f21 100644 --- a/include/boost/algorithm/cxx11/partition_copy.hpp +++ b/include/boost/algorithm/cxx11/partition_copy.hpp @@ -12,8 +12,7 @@ #ifndef BOOST_ALGORITHM_PARTITION_COPY_HPP #define BOOST_ALGORITHM_PARTITION_COPY_HPP -#include // for std::partition_copy, if available -#include // for make_pair +#include // for std::pair #include #include @@ -34,8 +33,6 @@ namespace boost { namespace algorithm { /// \param p A predicate for dividing the elements of the input sequence. /// /// \note This function is part of the C++2011 standard library. -/// We will use the standard one if it is available, -/// otherwise we have our own implementation. template std::pair diff --git a/include/boost/algorithm/cxx11/partition_point.hpp b/include/boost/algorithm/cxx11/partition_point.hpp index f1310c3..2c2767a 100644 --- a/include/boost/algorithm/cxx11/partition_point.hpp +++ b/include/boost/algorithm/cxx11/partition_point.hpp @@ -12,7 +12,7 @@ #ifndef BOOST_ALGORITHM_PARTITION_POINT_HPP #define BOOST_ALGORITHM_PARTITION_POINT_HPP -#include // for std::partition_point, if available +#include // for std::distance, advance #include #include @@ -27,8 +27,6 @@ namespace boost { namespace algorithm { /// \param last One past the end of the input sequence /// \param p The predicate to test the values with /// \note This function is part of the C++2011 standard library. -/// We will use the standard one if it is available, -/// otherwise we have our own implementation. template ForwardIterator partition_point ( ForwardIterator first, ForwardIterator last, Predicate p ) { From f06dc424dda4823ddee83a65e5b4532563d48a27 Mon Sep 17 00:00:00 2001 From: Kolya Matteo Date: Fri, 29 Apr 2016 16:04:17 -0400 Subject: [PATCH 09/36] In cxx14, remove unnecessary #include and correct some comments --- include/boost/algorithm/cxx14/equal.hpp | 3 ++- include/boost/algorithm/cxx14/is_permutation.hpp | 7 +------ include/boost/algorithm/cxx14/mismatch.hpp | 1 - 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/include/boost/algorithm/cxx14/equal.hpp b/include/boost/algorithm/cxx14/equal.hpp index cfc62d5..f1539f8 100644 --- a/include/boost/algorithm/cxx14/equal.hpp +++ b/include/boost/algorithm/cxx14/equal.hpp @@ -13,7 +13,8 @@ #define BOOST_ALGORITHM_EQUAL_HPP #include // for std::equal -#include // for std::equal_to +#include // for std::binary_function +#include namespace boost { namespace algorithm { diff --git a/include/boost/algorithm/cxx14/is_permutation.hpp b/include/boost/algorithm/cxx14/is_permutation.hpp index 9346881..639446b 100644 --- a/include/boost/algorithm/cxx14/is_permutation.hpp +++ b/include/boost/algorithm/cxx14/is_permutation.hpp @@ -12,8 +12,7 @@ #ifndef BOOST_ALGORITHM_IS_PERMUTATION14_HPP #define BOOST_ALGORITHM_IS_PERMUTATION14_HPP -#include // for std::less, tie, mismatch and is_permutation (if available) -#include // for std::make_pair +#include // for std::pair #include // for std::equal_to #include @@ -31,8 +30,6 @@ namespace boost { namespace algorithm { /// \param first2 The start of the second sequence /// \param last1 One past the end of the second sequence /// \note This function is part of the C++2014 standard library. -/// We will use the standard one if it is available, -/// otherwise we have our own implementation. template< class ForwardIterator1, class ForwardIterator2 > bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2 ) @@ -62,8 +59,6 @@ bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, /// \param pred The predicate to compare elements with /// /// \note This function is part of the C++2014 standard library. -/// We will use the standard one if it is available, -/// otherwise we have our own implementation. template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate > bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, diff --git a/include/boost/algorithm/cxx14/mismatch.hpp b/include/boost/algorithm/cxx14/mismatch.hpp index 926ab19..c3de418 100644 --- a/include/boost/algorithm/cxx14/mismatch.hpp +++ b/include/boost/algorithm/cxx14/mismatch.hpp @@ -12,7 +12,6 @@ #ifndef BOOST_ALGORITHM_MISMATCH_HPP #define BOOST_ALGORITHM_MISMATCH_HPP -#include // for std::mismatch #include // for std::pair namespace boost { namespace algorithm { From e066bfae81c627758aec4440e4ca7adda981091c Mon Sep 17 00:00:00 2001 From: Kolya Matteo Date: Fri, 29 Apr 2016 16:12:49 -0400 Subject: [PATCH 10/36] Fix documentation to reflect commit 4dac507 --- doc/all_of.qbk | 2 +- doc/any_of.qbk | 2 +- doc/is_partitioned.qbk | 2 +- doc/is_permutation.qbk | 2 +- doc/none_of.qbk | 2 +- doc/partition_point.qbk | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/all_of.qbk b/doc/all_of.qbk index 91b7b36..5b0b8af 100644 --- a/doc/all_of.qbk +++ b/doc/all_of.qbk @@ -73,7 +73,7 @@ All of the variants of `all_of` and `all_of_equal` take their parameters by valu [heading Notes] -* The routine `all_of` is part of the C++11 standard. When compiled using a C++11 implementation, the implementation from the standard library will be used. +* The routine `all_of` is also available as part of the C++11 standard. * `all_of` and `all_of_equal` both return true for empty ranges, no matter what is passed to test against. When there are no items in the sequence to test, they all satisfy the condition to be tested against. diff --git a/doc/any_of.qbk b/doc/any_of.qbk index 61a6603..4a50861 100644 --- a/doc/any_of.qbk +++ b/doc/any_of.qbk @@ -73,7 +73,7 @@ All of the variants of `any_of` and `any_of_equal` take their parameters by valu [heading Notes] -* The routine `any_of` is part of the C++11 standard. When compiled using a C++11 implementation, the implementation from the standard library will be used. +* The routine `any_of` is also available as part of the C++11 standard. * `any_of` and `any_of_equal` both return false for empty ranges, no matter what is passed to test against. diff --git a/doc/is_partitioned.qbk b/doc/is_partitioned.qbk index 16dce6a..7a6c458 100644 --- a/doc/is_partitioned.qbk +++ b/doc/is_partitioned.qbk @@ -55,7 +55,7 @@ Both of the variants of `is_partitioned` take their parameters by value or const [heading Notes] -* The iterator-based version of the routine `is_partitioned` is part of the C++11 standard. When compiled using a C++11 implementation, the implementation from the standard library will be used. +* The iterator-based version of the routine `is_partitioned` is also available as part of the C++11 standard. * `is_partitioned` returns true for empty ranges, no matter what predicate is passed to test against. diff --git a/doc/is_permutation.qbk b/doc/is_permutation.qbk index 267bfab..e8753ba 100644 --- a/doc/is_permutation.qbk +++ b/doc/is_permutation.qbk @@ -71,7 +71,7 @@ All of the variants of `is_permutation` take their parameters by value, and do n [heading Notes] -* The three iterator versions of the routine `is_permutation` are part of the C++11 standard. When compiled using a C++11 implementation, the implementation from the standard library will be used. +* The three iterator versions of the routine `is_permutation` are also available as part of the C++11 standard. * The four iterator versions of the routine `is_permutation` are part of the proposed C++14 standard. When C++14 standard libraries become available, the implementation should be changed to use the implementation from the standard library (if available). diff --git a/doc/none_of.qbk b/doc/none_of.qbk index 3cda5f9..cf0b143 100644 --- a/doc/none_of.qbk +++ b/doc/none_of.qbk @@ -74,7 +74,7 @@ All of the variants of `none_of` and `none_of_equal` take their parameters by va [heading Notes] -* The routine `none_of` is part of the C++11 standard. When compiled using a C++11 implementation, the implementation from the standard library will be used. +* The routine `none_of` is also available aspart of the C++11 standard. * `none_of` and `none_of_equal` both return true for empty ranges, no matter what is passed to test against. diff --git a/doc/partition_point.qbk b/doc/partition_point.qbk index 8d1f76c..813a27b 100644 --- a/doc/partition_point.qbk +++ b/doc/partition_point.qbk @@ -54,7 +54,7 @@ Both of the variants of `partition_point` take their parameters by value or cons [heading Notes] -* The iterator-based version of the routine `partition_point` is part of the C++11 standard. When compiled using a C++11 implementation, the implementation from the standard library will be used. +* The iterator-based version of the routine `partition_point` is also available as part of the C++11 standard. * For empty ranges, the partition point is the end of the range. From c11878cd8acb477713cd9b35ef070e8433ed3e89 Mon Sep 17 00:00:00 2001 From: Kolya Matteo Date: Fri, 29 Apr 2016 16:20:43 -0400 Subject: [PATCH 11/36] typo --- doc/none_of.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/none_of.qbk b/doc/none_of.qbk index cf0b143..f0b93b7 100644 --- a/doc/none_of.qbk +++ b/doc/none_of.qbk @@ -74,7 +74,7 @@ All of the variants of `none_of` and `none_of_equal` take their parameters by va [heading Notes] -* The routine `none_of` is also available aspart of the C++11 standard. +* The routine `none_of` is also available as part of the C++11 standard. * `none_of` and `none_of_equal` both return true for empty ranges, no matter what is passed to test against. From 5314d592e3cd69685d6db789df4ab8517a366a2b Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Mon, 16 May 2016 07:47:09 -0700 Subject: [PATCH 12/36] Fix up misleading indentation; Fixes https://svn.boost.org/trac/boost/ticket/12206 --- include/boost/algorithm/cxx11/none_of.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/algorithm/cxx11/none_of.hpp b/include/boost/algorithm/cxx11/none_of.hpp index 36f0aa8..ba13144 100644 --- a/include/boost/algorithm/cxx11/none_of.hpp +++ b/include/boost/algorithm/cxx11/none_of.hpp @@ -28,9 +28,9 @@ namespace boost { namespace algorithm { template bool none_of ( InputIterator first, InputIterator last, Predicate p ) { -for ( ; first != last; ++first ) - if ( p(*first)) - return false; + for ( ; first != last; ++first ) + if ( p(*first)) + return false; return true; } From 9bee197bd8c0224ae5b6efb2745af0baf940ed8d Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Wed, 6 Jul 2016 11:42:18 +0300 Subject: [PATCH 13/36] Added all files to the new repository --- doc/algorithm.qbk | 1 + doc/is_palindrome.qbk | 84 +++++++++++++++++ example/Jamfile.v2 | 2 + example/is_palindrome_example.cpp | 94 +++++++++++++++++++ include/boost/algorithm/is_palindrome.hpp | 107 ++++++++++++++++++++++ test/Jamfile.v2 | 2 + test/is_palindrome_test.cpp | 66 +++++++++++++ 7 files changed, 356 insertions(+) create mode 100644 doc/is_palindrome.qbk create mode 100644 example/is_palindrome_example.cpp create mode 100644 include/boost/algorithm/is_palindrome.hpp create mode 100644 test/is_palindrome_test.cpp diff --git a/doc/algorithm.qbk b/doc/algorithm.qbk index 66971d1..1568fb5 100644 --- a/doc/algorithm.qbk +++ b/doc/algorithm.qbk @@ -66,6 +66,7 @@ Thanks to all the people who have reviewed this library and made suggestions for [include clamp-hpp.qbk] [include gather.qbk] [include hex.qbk] +[include is_palindrome.qbk] [endsect] diff --git a/doc/is_palindrome.qbk b/doc/is_palindrome.qbk new file mode 100644 index 0000000..d1477a2 --- /dev/null +++ b/doc/is_palindrome.qbk @@ -0,0 +1,84 @@ +[/ File is_palindrome.qbk] + +[section:is_palindrome is_palindrome] + +[/license +Copyright (c) 2016 Alexander Zaitsev + +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) +] + +The header file 'is_palindrome.hpp' contains four variants of a single algorithm, is_palindrome. +The algorithm tests the sequence and returns true if the sequence is a palindrome; i.e, it is identical when traversed either backwards or frontwards. + +The routine `is_palindrome` takes a sequence and, optionally, a predicate. It will return true if the predicate returns true for tested elements by algorithm in the sequence. + +The routine come in 4 forms; the first one takes two iterators to define the range. The second form takes two iterators to define the range and a predicate. +The third form takes a single range parameter, and uses Boost.Range to traverse it. And the fourth form takes a single range parameter ( uses Boost.Range to traverse it) and a predicate. + + +[heading interface] + +The function `is_palindrome` returns true if the predicate returns true any tested by algorithm items in the sequence. +There are four versions: +1) takes two iterators. +2) takes two iterators and a predicate. +3) takes a range. +4) takes a range and a predicate. + +`` +template + bool is_palindrome ( BidirectionalIterator begin, BidirectionalIterator end ); +template + bool is_palindrome ( BidirectionalIterator begin, BidirectionalIterator end, Predicate p ); +template + bool is_palindrome ( const Range &r ); +template + bool is_palindrome ( const Range &r, Predicate p ); +`` + + +[heading Examples] + +Given the containers: +const std::list empty, +const std::vector singleElement{'z'}, +int oddNonPalindrome[] = {3,2,2}, +const int evenPalindrome[] = {1,2,2,1}, then +`` + +is_palindrome(empty)) --> true //empty range +is_palindrome(singleElement)) --> true +is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome))) --> false +is_palindrome(std::begin(evenPalindrome), std::end(evenPalindrome))) --> true +is_palindrome(empty.begin(), empty.end(), functorComparator())) --> true //empty range +is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComparator)) --> false +is_palindrome(evenPalindrome, std::equal_to())) --> true +`` + +[heading Iterator Requirements] + +`is_palindrome` work on Bidirectional and RandomAccess iterators. + +[heading Complexity] + +All of the variants of `is_palindrome` run in ['O(N)] (linear) time; that is, they compare against each element in the list once. If any of the comparisons not succeed, the algorithm will terminate immediately, without examining the remaining members of the sequence. + +[heading Exception Safety] + +All of the variants of `is_palindrome` take their parameters by value or const reference, and do not depend upon any global state. Therefore, all the routines in this file provide the strong exception guarantee. + +[heading Notes] + +* `is_palindrome` returns true for empty ranges and for single element ranges. + +* If you use version of 'is_palindrome' without custom predicate, 'is_palindrome' uses default 'operator==' for elements. If you want use custom predicate, you must redefine 'operator=='. + +[endsect] + +[/ File is_palindrome.qbk +Copyright 2016 Alexander Zaitsev +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). +] diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 1d8e3b5..ce067cf 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -20,3 +20,5 @@ project /boost/algorithm/example exe clamp_example : clamp_example.cpp ; exe search_example : search_example.cpp ; +exe is_palindrome_example : is_palindrome_example.cpp; + diff --git a/example/is_palindrome_example.cpp b/example/is_palindrome_example.cpp new file mode 100644 index 0000000..e995a9e --- /dev/null +++ b/example/is_palindrome_example.cpp @@ -0,0 +1,94 @@ +/* + Copyright (c) Alexander Zaitsev , 2016 + + 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) + + For more information, see http://www.boost.org +*/ + +#include +#include +#include +#include +#include + +#include + + +namespace ba = boost::algorithm; + +template +bool funcComparator(const T& v1, const T& v2) +{ + return v1 == v2; +} + +struct functorComparator +{ + template + bool operator()(const T& v1, const T& v2) const + { + return v1 == v2; + } +}; + + +int main ( int /*argc*/, char * /*argv*/ [] ) +{ + //You can this algorithm with iterators(minimum Bidirectional) + std::vector vec{1,2,1}; + if(ba::is_palindrome(vec.begin(), vec.end())) + std::cout << "This container is palindrome" << std::endl; + else + std::cout << "This container is not palindrome" << std::endl; + + + //Of course, you can use const iterators + if(ba::is_palindrome(vec.cbegin(), vec.cend())) + std::cout << "This container is palindrome" << std::endl; + else + std::cout << "This container is not palindrome" << std::endl; + + + //Example with bidirectional iterators + std::list list{1,2,1}; + if(ba::is_palindrome(list.begin(), list.end())) + std::cout << "This container is palindrome" << std::endl; + else + std::cout << "This container is not palindrome" << std::endl; + + + //You can use custom comparators like functions, functors, lambdas + auto lambdaComparator = [](int v1, int v2){ return v1 == v2; }; + auto objFunc = std::function(lambdaComparator); + + if(ba::is_palindrome(vec.begin(), vec.end(), lambdaComparator)) + std::cout << "This container is palindrome" << std::endl; + else + std::cout << "This container is not palindrome" << std::endl; + + if(ba::is_palindrome(vec.begin(), vec.end(), funcComparator)) + std::cout << "This container is palindrome" << std::endl; + else + std::cout << "This container is not palindrome" << std::endl; + + if(ba::is_palindrome(vec.begin(), vec.end(), functorComparator())) + std::cout << "This container is palindrome" << std::endl; + else + std::cout << "This container is not palindrome" << std::endl; + + if(ba::is_palindrome(vec.begin(), vec.end(), objFunc)) + std::cout << "This container is palindrome" << std::endl; + else + std::cout << "This container is not palindrome" << std::endl; + + + //You can use ranges + if(ba::is_palindrome(vec)) + std::cout << "This container is palindrome" << std::endl; + else + std::cout << "This container is not palindrome" << std::endl; + + return 0; +} diff --git a/include/boost/algorithm/is_palindrome.hpp b/include/boost/algorithm/is_palindrome.hpp new file mode 100644 index 0000000..38029bb --- /dev/null +++ b/include/boost/algorithm/is_palindrome.hpp @@ -0,0 +1,107 @@ +/* + Copyright (c) Alexander Zaitsev , 2016 + + 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/ for latest version. +*/ + +/// \file is_palindrome.hpp +/// \brief Checks the input sequence on palindrome. +/// \author Alexander Zaitsev + +#ifndef BOOST_ALGORITHM_is_palindrome_HPP +#define BOOST_ALGORITHM_is_palindrome_HPP + +#include + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn is_palindrome ( BidirectionalIterator begin, BidirectionalIterator end, Predicate p ) +/// \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 p A predicate used to compare the values. +/// +/// \note This function will return true for empty sequences and for palindromes. +/// For other sequences function will return false. +/// Complexity: O(N). +template +bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predicate p) +{ + if(begin == end) + { + return true; + } + + --end; + while(begin != end) + { + if(!p(*begin, *end)) + { + return false; + } + ++begin; + if(begin == end) + { + break; + } + --end; + } + return true; +} + +/// \fn is_palindrome ( BidirectionalIterator begin, BidirectionalIterator end ) +/// \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 +/// +/// \note This function will return true for empty sequences and for palindromes. +/// For other sequences function will return false. +/// Complexity: O(N). +template +bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end) +{ + return is_palindrome(begin, end, + std::equal_to::value_type> ()); +} + +/// \fn is_palindrome ( const R& range ) +/// \return true if the entire sequence is palindrome +/// +/// \param range The range to be tested. +/// +/// \note This function will return true for empty sequences and for palindromes. +/// For other sequences function will return false. +/// Complexity: O(N). +template +bool is_palindrome(const R& range) +{ + return is_palindrome(boost::begin(range), boost::end(range)); +} + +/// \fn is_palindrome ( const R& range, Predicate p ) +/// \return true if the entire sequence is palindrome +/// +/// \param range The range to be tested. +/// \param p A predicate used to compare the values. +/// +/// \note This function will return true for empty sequences and for palindromes. +/// For other sequences function will return false. +/// Complexity: O(N). +template +bool is_palindrome(const R& range, Predicate p) +{ + return is_palindrome(boost::begin(range), boost::end(range), p); +} + +}} + +#endif // BOOST_ALGORITHM_is_palindrome_HPP diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index dd18ef8..fb00843 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -68,6 +68,8 @@ alias unit_test_framework [ run sort_subrange_test.cpp unit_test_framework : : : : sort_subrange_test ] [ run partition_subrange_test.cpp unit_test_framework : : : : partition_subrange_test ] +# Is_palindrome tests + [ run is_palindrome_test.cpp unit_test_framework : : : : is_palindrome_test ] ; } diff --git a/test/is_palindrome_test.cpp b/test/is_palindrome_test.cpp new file mode 100644 index 0000000..673e95b --- /dev/null +++ b/test/is_palindrome_test.cpp @@ -0,0 +1,66 @@ +/* + Copyright (c) Alexander Zaitsev , 2016 + + 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/ for latest version. +*/ + +#include +#include +#include +#include + +#include +#include + +namespace ba = boost::algorithm; + + +template +bool funcComparator(const T& v1, const T& v2) +{ + return v1 == v2; +} + +struct functorComparator +{ + template + bool operator()(const T& v1, const T& v2) const + { + return v1 == v2; + } +}; + + +static void test_is_palindrome() +{ + const std::list empty; + const std::vector singleElement{'z'}; + int oddNonPalindrome[] = {3,2,2}; + const int evenPalindrome[] = {1,2,2,1}; + + // Test a default operator== + BOOST_CHECK ( ba::is_palindrome(empty)); + BOOST_CHECK ( ba::is_palindrome(singleElement)); + BOOST_CHECK (!ba::is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome))); + BOOST_CHECK ( ba::is_palindrome(std::begin(evenPalindrome), std::end(evenPalindrome))); + + //Test the custom comparators + BOOST_CHECK ( ba::is_palindrome(empty.begin(), empty.end(), functorComparator())); + BOOST_CHECK (!ba::is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComparator)); + BOOST_CHECK ( ba::is_palindrome(evenPalindrome, std::equal_to())); + + //Only C++14 or newer + //auto lambdaComparator = [](const auto& v1, const auto& v2){ return v1 == v2; }; + //BOOST_CHECK ( ba::is_palindrome(singleElement, lambdaComparator)); +} + +int test_main( int, char * [] ) +{ + test_is_palindrome(); + + return 0; +} From 1ec1cd304553567a9653c9662e325e9a029e86e4 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Wed, 6 Jul 2016 11:57:05 +0300 Subject: [PATCH 14/36] Fixed is_palindrome_test --- test/is_palindrome_test.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/test/is_palindrome_test.cpp b/test/is_palindrome_test.cpp index 673e95b..ed7b1c4 100644 --- a/test/is_palindrome_test.cpp +++ b/test/is_palindrome_test.cpp @@ -8,13 +8,17 @@ See http://www.boost.org/ for latest version. */ +#include +#include + +#define BOOST_TEST_MAIN +#include + #include #include #include #include -#include -#include namespace ba = boost::algorithm; @@ -35,7 +39,7 @@ struct functorComparator }; -static void test_is_palindrome() +void test_is_palindrome() { const std::list empty; const std::vector singleElement{'z'}; @@ -58,9 +62,7 @@ static void test_is_palindrome() //BOOST_CHECK ( ba::is_palindrome(singleElement, lambdaComparator)); } -int test_main( int, char * [] ) +BOOST_AUTO_TEST_CASE( test_main ) { - test_is_palindrome(); - - return 0; + test_is_palindrome (); } From 366274ff0a196ddbab67d5e2b831dac8434a0988 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 6 Jul 2016 22:56:02 +0300 Subject: [PATCH 15/36] Added new tests to is_palindrome_test Added evenNonPalindrome and oddPalindrome tests. --- test/is_palindrome_test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/is_palindrome_test.cpp b/test/is_palindrome_test.cpp index ed7b1c4..b9279c9 100644 --- a/test/is_palindrome_test.cpp +++ b/test/is_palindrome_test.cpp @@ -44,22 +44,22 @@ void test_is_palindrome() const std::list empty; const std::vector singleElement{'z'}; int oddNonPalindrome[] = {3,2,2}; + const int oddPalindrome[] = {1,2,3,2,1}; const int evenPalindrome[] = {1,2,2,1}; + int evenNonPalindrome[] = {1,4,8,8}; // Test a default operator== BOOST_CHECK ( ba::is_palindrome(empty)); BOOST_CHECK ( ba::is_palindrome(singleElement)); BOOST_CHECK (!ba::is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome))); + BOOST_CHECK ( ba::is_palindrome(std::begin(oddPalindrome), std::end(oddPalindrome))); BOOST_CHECK ( ba::is_palindrome(std::begin(evenPalindrome), std::end(evenPalindrome))); + BOOST_CHECK (!ba::is_palindrome(std::begin(evenNonPalindrome), std::end(evenNonPalindrome))); //Test the custom comparators BOOST_CHECK ( ba::is_palindrome(empty.begin(), empty.end(), functorComparator())); BOOST_CHECK (!ba::is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComparator)); BOOST_CHECK ( ba::is_palindrome(evenPalindrome, std::equal_to())); - - //Only C++14 or newer - //auto lambdaComparator = [](const auto& v1, const auto& v2){ return v1 == v2; }; - //BOOST_CHECK ( ba::is_palindrome(singleElement, lambdaComparator)); } BOOST_AUTO_TEST_CASE( test_main ) From fb964d72d7933b4d7cbb9021625a3907edc81b3d Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 6 Jul 2016 23:00:55 +0300 Subject: [PATCH 16/36] Updated documentation for is_palindrome Added two lines with examples. --- doc/is_palindrome.qbk | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/is_palindrome.qbk b/doc/is_palindrome.qbk index d1477a2..928de6f 100644 --- a/doc/is_palindrome.qbk +++ b/doc/is_palindrome.qbk @@ -45,7 +45,9 @@ Given the containers: const std::list empty, const std::vector singleElement{'z'}, int oddNonPalindrome[] = {3,2,2}, -const int evenPalindrome[] = {1,2,2,1}, then +const int oddPalindrome[] = {1,2,3,2,1}, +const int evenPalindrome[] = {1,2,2,1}, +int evenNonPalindrome[] = {1,4,8,8}, then `` is_palindrome(empty)) --> true //empty range @@ -54,7 +56,9 @@ is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome))) --> fal is_palindrome(std::begin(evenPalindrome), std::end(evenPalindrome))) --> true is_palindrome(empty.begin(), empty.end(), functorComparator())) --> true //empty range is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComparator)) --> false -is_palindrome(evenPalindrome, std::equal_to())) --> true +is_palindrome(std::begin(oddPalindrome), std::end(oddPalindrome)) --> true +is_palindrome(evenPalindrome, std::equal_to())) --> true +is_palindrome(std::begin(evenNonPalindrome), std::end(evenNonPalindrome)) --> false `` [heading Iterator Requirements] From 52f91139afe8c24be08d221c1bc4555a86cbecef Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Sun, 10 Jul 2016 22:52:55 +0300 Subject: [PATCH 17/36] Fix comments --- include/boost/algorithm/is_palindrome.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/algorithm/is_palindrome.hpp b/include/boost/algorithm/is_palindrome.hpp index 38029bb..61acbae 100644 --- a/include/boost/algorithm/is_palindrome.hpp +++ b/include/boost/algorithm/is_palindrome.hpp @@ -12,8 +12,8 @@ /// \brief Checks the input sequence on palindrome. /// \author Alexander Zaitsev -#ifndef BOOST_ALGORITHM_is_palindrome_HPP -#define BOOST_ALGORITHM_is_palindrome_HPP +#ifndef BOOST_ALGORITHM_IS_PALINDROME_HPP +#define BOOST_ALGORITHM_IS_PALINDROME_HPP #include @@ -104,4 +104,4 @@ bool is_palindrome(const R& range, Predicate p) }} -#endif // BOOST_ALGORITHM_is_palindrome_HPP +#endif // BOOST_ALGORITHM_IS_PALINDROME_HPP From 093900a8f3d2608ff28ba009f16e9c3c689640e8 Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 11 Jul 2016 18:25:04 +0300 Subject: [PATCH 18/36] [micro] Replaced constructor of singleElement Replaced bracket initializes constructor to simply constructor with two arguments in std::vector --- test/is_palindrome_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/is_palindrome_test.cpp b/test/is_palindrome_test.cpp index b9279c9..2c0f67a 100644 --- a/test/is_palindrome_test.cpp +++ b/test/is_palindrome_test.cpp @@ -42,7 +42,7 @@ struct functorComparator void test_is_palindrome() { const std::list empty; - const std::vector singleElement{'z'}; + const std::vector singleElement(1, 'z'); int oddNonPalindrome[] = {3,2,2}; const int oddPalindrome[] = {1,2,3,2,1}; const int evenPalindrome[] = {1,2,2,1}; From 1a34a6935b7694178631d0b06d7bfeedf6f89d61 Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 11 Jul 2016 18:26:18 +0300 Subject: [PATCH 19/36] [micro] Added "#include " --- include/boost/algorithm/is_palindrome.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/algorithm/is_palindrome.hpp b/include/boost/algorithm/is_palindrome.hpp index 61acbae..e15e77a 100644 --- a/include/boost/algorithm/is_palindrome.hpp +++ b/include/boost/algorithm/is_palindrome.hpp @@ -16,6 +16,7 @@ #define BOOST_ALGORITHM_IS_PALINDROME_HPP #include +#include #include #include From 71ed4a159f8e733e3a9acc08ab58e8f10c200846 Mon Sep 17 00:00:00 2001 From: Marcel Raad Date: Thu, 14 Jul 2016 11:36:47 +0200 Subject: [PATCH 20/36] Remove unused bad include boost/exception/errinfo_errno.hpp, included in boost/exception/all.hpp, pushes the warning level to 1 on MSVC, but emits a level 1 warning with /sdl. Only exception.hpp and throw_exception.hpp are necessary. --- include/boost/algorithm/hex.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/boost/algorithm/hex.hpp b/include/boost/algorithm/hex.hpp index ad20a20..739e89f 100644 --- a/include/boost/algorithm/hex.hpp +++ b/include/boost/algorithm/hex.hpp @@ -25,7 +25,9 @@ #include #include -#include +#include +#include +#include #include #include From 774fb437f3b8babdb933850fcabab1c8041f7987 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Mon, 15 Aug 2016 04:09:48 +0300 Subject: [PATCH 21/36] Disabled 'is_palindrome' for 'const char*' --- doc/is_palindrome.qbk | 2 ++ include/boost/algorithm/is_palindrome.hpp | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/doc/is_palindrome.qbk b/doc/is_palindrome.qbk index 928de6f..f37ca07 100644 --- a/doc/is_palindrome.qbk +++ b/doc/is_palindrome.qbk @@ -79,6 +79,8 @@ All of the variants of `is_palindrome` take their parameters by value or const r * If you use version of 'is_palindrome' without custom predicate, 'is_palindrome' uses default 'operator==' for elements. If you want use custom predicate, you must redefine 'operator=='. +* Don't use 'const char*' with 'is_palindrome', because 'const char*' is always non-palindromic ('\0' at the end). If you will try to compile 'is_palindrome' with 'const char*', you will get an error. + [endsect] [/ File is_palindrome.qbk diff --git a/include/boost/algorithm/is_palindrome.hpp b/include/boost/algorithm/is_palindrome.hpp index 61acbae..0080e60 100644 --- a/include/boost/algorithm/is_palindrome.hpp +++ b/include/boost/algorithm/is_palindrome.hpp @@ -102,6 +102,22 @@ bool is_palindrome(const R& range, Predicate p) return is_palindrome(boost::begin(range), boost::end(range), p); } +//Disable is_palindrome for const char* because it work not properly. +//Please use string_view for const char* cases. +//Here we use dirty hack to disable 'is_palindrome' with 'const char*' +//URL: http://stackoverflow.com/questions/14637356/static-assert-fails-compilation-even-though-template-function-is-called-nowhere +template +struct foobar : std::false_type +{ }; + +template +bool is_palindrome(const char* str) +{ + static_assert(foobar::value, "Using 'is_palindrome' for 'const char*' is dangerous, because result is always false" + "(reason: '\0' in the end of the string). You can use string_view in this case"); + return false; +} + }} #endif // BOOST_ALGORITHM_IS_PALINDROME_HPP From 3c25ce10903ca0f001bc845c1d0dd01df7e4bbd2 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Tue, 16 Aug 2016 05:14:56 +0300 Subject: [PATCH 22/36] Added C-String support for 'is_palindrome' Updated doc, example and tests. --- doc/is_palindrome.qbk | 25 ++++--- example/is_palindrome_example.cpp | 7 +- include/boost/algorithm/is_palindrome.hpp | 85 ++++++++++++++++++----- test/is_palindrome_test.cpp | 11 +++ 4 files changed, 103 insertions(+), 25 deletions(-) diff --git a/doc/is_palindrome.qbk b/doc/is_palindrome.qbk index f37ca07..b4193e4 100644 --- a/doc/is_palindrome.qbk +++ b/doc/is_palindrome.qbk @@ -9,23 +9,26 @@ 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) ] -The header file 'is_palindrome.hpp' contains four variants of a single algorithm, is_palindrome. +The header file 'is_palindrome.hpp' contains six variants of a single algorithm, is_palindrome. The algorithm tests the sequence and returns true if the sequence is a palindrome; i.e, it is identical when traversed either backwards or frontwards. The routine `is_palindrome` takes a sequence and, optionally, a predicate. It will return true if the predicate returns true for tested elements by algorithm in the sequence. -The routine come in 4 forms; the first one takes two iterators to define the range. The second form takes two iterators to define the range and a predicate. -The third form takes a single range parameter, and uses Boost.Range to traverse it. And the fourth form takes a single range parameter ( uses Boost.Range to traverse it) and a predicate. +The routine come in 6 forms; the first one takes two iterators to define the range. The second form takes two iterators to define the range and a predicate. +The third form takes a single range parameter, and uses Boost.Range to traverse it. The fourth form takes a single range parameter ( uses Boost.Range to traverse it) and a predicate. +The fifth form takes a single C-string and a predicate. The sixth form takes a single C-string. [heading interface] The function `is_palindrome` returns true if the predicate returns true any tested by algorithm items in the sequence. -There are four versions: +There are six versions: 1) takes two iterators. 2) takes two iterators and a predicate. 3) takes a range. 4) takes a range and a predicate. +5) takes a C-string and a predicate. +6) takes a C-string. `` template @@ -36,6 +39,9 @@ template bool is_palindrome ( const Range &r ); template bool is_palindrome ( const Range &r, Predicate p ); +template + bool is_palindrome ( const char* str, Predicate p ); +bool is_palindrome(const char* str); `` @@ -59,6 +65,9 @@ is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComp is_palindrome(std::begin(oddPalindrome), std::end(oddPalindrome)) --> true is_palindrome(evenPalindrome, std::equal_to())) --> true is_palindrome(std::begin(evenNonPalindrome), std::end(evenNonPalindrome)) --> false +is_palindrome(nullptr) --> true +is_palindrome("a") --> true +is_palindrome("aba", std::equal_to()) --> true `` [heading Iterator Requirements] @@ -71,15 +80,15 @@ All of the variants of `is_palindrome` run in ['O(N)] (linear) time; that is, th [heading Exception Safety] -All of the variants of `is_palindrome` take their parameters by value or const reference, and do not depend upon any global state. Therefore, all the routines in this file provide the strong exception guarantee. +All of the variants of `is_palindrome` take their parameters by value, const pointer or const reference, and do not depend upon any global state. Therefore, all the routines in this file provide the strong exception guarantee. [heading Notes] -* `is_palindrome` returns true for empty ranges and for single element ranges. +* `is_palindrome` returns true for empty ranges, null pointers and for single element ranges. -* If you use version of 'is_palindrome' without custom predicate, 'is_palindrome' uses default 'operator==' for elements. If you want use custom predicate, you must redefine 'operator=='. +* If you use version of 'is_palindrome' without custom predicate, 'is_palindrome' uses default 'operator==()' for elements. -* Don't use 'const char*' with 'is_palindrome', because 'const char*' is always non-palindromic ('\0' at the end). If you will try to compile 'is_palindrome' with 'const char*', you will get an error. +* Be careful with using not null pointer 'const char*' without '\0' - if you use it with 'is_palindrome', it's a undefined behaviour. [endsect] diff --git a/example/is_palindrome_example.cpp b/example/is_palindrome_example.cpp index e995a9e..cefc782 100644 --- a/example/is_palindrome_example.cpp +++ b/example/is_palindrome_example.cpp @@ -89,6 +89,11 @@ int main ( int /*argc*/, char * /*argv*/ [] ) std::cout << "This container is palindrome" << std::endl; else std::cout << "This container is not palindrome" << std::endl; - + + //You can use C-strings + if(ba::is_palindrome("aba")) + std::cout << "This C-string is palindrome" << std::endl; + else + std::cout << "This C-string is not palindrome" << std::endl; return 0; } diff --git a/include/boost/algorithm/is_palindrome.hpp b/include/boost/algorithm/is_palindrome.hpp index d341eb7..714c833 100644 --- a/include/boost/algorithm/is_palindrome.hpp +++ b/include/boost/algorithm/is_palindrome.hpp @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include @@ -34,7 +36,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) { @@ -70,8 +72,26 @@ bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predi template bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end) { - return is_palindrome(begin, end, - std::equal_to::value_type> ()); + if(begin == end) + { + return true; + } + + --end; + while(begin != end) + { + if(!(*begin == *end)) + { + return false; + } + ++begin; + if(begin == end) + { + break; + } + --end; + } + return true; } /// \fn is_palindrome ( const R& range ) @@ -82,7 +102,7 @@ bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end) /// \note This function will return true for empty sequences and for palindromes. /// For other sequences function will return false. /// Complexity: O(N). -template +template ::value_type>::type> bool is_palindrome(const R& range) { return is_palindrome(boost::begin(range), boost::end(range)); @@ -97,26 +117,59 @@ bool is_palindrome(const R& range) /// \note This function will return true for empty sequences and for palindromes. /// For other sequences function will return false. /// Complexity: O(N). -template +template ::value_type>::type> bool is_palindrome(const R& range, Predicate p) { return is_palindrome(boost::begin(range), boost::end(range), p); } -//Disable is_palindrome for const char* because it work not properly. -//Please use string_view for const char* cases. -//Here we use dirty hack to disable 'is_palindrome' with 'const char*' -//URL: http://stackoverflow.com/questions/14637356/static-assert-fails-compilation-even-though-template-function-is-called-nowhere -template -struct foobar : std::false_type -{ }; -template +/// \fn is_palindrome ( const char* str ) +/// \return true if the entire sequence is palindrome +/// +/// \param str C-string to be tested. +/// +/// \note This function will return true for empty sequences and for palindromes. +/// For other sequences function will return false. +/// Complexity: O(N). bool is_palindrome(const char* str) { - static_assert(foobar::value, "Using 'is_palindrome' for 'const char*' is dangerous, because result is always false" - "(reason: '\0' in the end of the string). You can use string_view in this case"); - return false; + if(str == nullptr) + { + return true; + } + return is_palindrome(str, str + strlen(str)); +} + + +/// \fn is_palindrome ( const char* str, Predicate p ) +/// \return true if the entire sequence is palindrome +/// +/// \param str C-string to be tested. +/// \param p A predicate used to compare the values. +/// +/// \note This function will return true for empty sequences and for palindromes. +/// For other sequences function will return false. +/// Complexity: O(N). +template +bool is_palindrome(const char* str, Predicate p) +{ + if(str == nullptr) + { + return true; + } + return is_palindrome(str, str + strlen(str), p); +} + +bool is_palindrome (nullptr_t) +{ + return true; +} + +template +bool is_palindrome (T) +{ + return true; } }} diff --git a/test/is_palindrome_test.cpp b/test/is_palindrome_test.cpp index 2c0f67a..69ddfbc 100644 --- a/test/is_palindrome_test.cpp +++ b/test/is_palindrome_test.cpp @@ -47,6 +47,7 @@ void test_is_palindrome() const int oddPalindrome[] = {1,2,3,2,1}; const int evenPalindrome[] = {1,2,2,1}; int evenNonPalindrome[] = {1,4,8,8}; + const char* stringNullPtr = nullptr; // Test a default operator== BOOST_CHECK ( ba::is_palindrome(empty)); @@ -60,6 +61,16 @@ void test_is_palindrome() BOOST_CHECK ( ba::is_palindrome(empty.begin(), empty.end(), functorComparator())); BOOST_CHECK (!ba::is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComparator)); BOOST_CHECK ( ba::is_palindrome(evenPalindrome, std::equal_to())); + + //Test C-strings like cases + BOOST_CHECK ( ba::is_palindrome(nullptr)); + BOOST_CHECK ( ba::is_palindrome(0)); + BOOST_CHECK ( ba::is_palindrome(stringNullPtr)); + BOOST_CHECK ( ba::is_palindrome("")); + BOOST_CHECK ( ba::is_palindrome("a")); + BOOST_CHECK ( ba::is_palindrome("abacaba"), std::equal_to()); + BOOST_CHECK ( ba::is_palindrome("abba")); + BOOST_CHECK ( ba::is_palindrome("acab")); } BOOST_AUTO_TEST_CASE( test_main ) From 42bbfdeb4c18cc3d816932cb27bdfbaddd1fa602 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 16 Aug 2016 16:18:21 +0300 Subject: [PATCH 23/36] Deleted support for nullptr, NULL and 0. I think user shouldn't send to 'is_palindrome' zero, NULL or nullptr as parameter. As value of const char* it's possible, of course. But cases 'is_palindrome(0)', 'is_palindrome(NULL)' and 'is_palindrome(nullptr)' is silly and it should be restricted by design. --- include/boost/algorithm/is_palindrome.hpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/include/boost/algorithm/is_palindrome.hpp b/include/boost/algorithm/is_palindrome.hpp index 714c833..8649ad6 100644 --- a/include/boost/algorithm/is_palindrome.hpp +++ b/include/boost/algorithm/is_palindrome.hpp @@ -102,7 +102,7 @@ bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end) /// \note This function will return true for empty sequences and for palindromes. /// For other sequences function will return false. /// Complexity: O(N). -template ::value_type>::type> +template bool is_palindrome(const R& range) { return is_palindrome(boost::begin(range), boost::end(range)); @@ -117,7 +117,7 @@ bool is_palindrome(const R& range) /// \note This function will return true for empty sequences and for palindromes. /// For other sequences function will return false. /// Complexity: O(N). -template ::value_type>::type> +template bool is_palindrome(const R& range, Predicate p) { return is_palindrome(boost::begin(range), boost::end(range), p); @@ -161,17 +161,6 @@ bool is_palindrome(const char* str, Predicate p) return is_palindrome(str, str + strlen(str), p); } -bool is_palindrome (nullptr_t) -{ - return true; -} - -template -bool is_palindrome (T) -{ - return true; -} - }} #endif // BOOST_ALGORITHM_IS_PALINDROME_HPP From a53b0121b9122e20506911396e88ec5c94115ecb Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 16 Aug 2016 16:20:22 +0300 Subject: [PATCH 24/36] Updated documentation for is_palindrome --- doc/is_palindrome.qbk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/is_palindrome.qbk b/doc/is_palindrome.qbk index b4193e4..783305f 100644 --- a/doc/is_palindrome.qbk +++ b/doc/is_palindrome.qbk @@ -65,7 +65,6 @@ is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComp is_palindrome(std::begin(oddPalindrome), std::end(oddPalindrome)) --> true is_palindrome(evenPalindrome, std::equal_to())) --> true is_palindrome(std::begin(evenNonPalindrome), std::end(evenNonPalindrome)) --> false -is_palindrome(nullptr) --> true is_palindrome("a") --> true is_palindrome("aba", std::equal_to()) --> true `` @@ -84,7 +83,7 @@ All of the variants of `is_palindrome` take their parameters by value, const poi [heading Notes] -* `is_palindrome` returns true for empty ranges, null pointers and for single element ranges. +* `is_palindrome` returns true for empty ranges, const char* null pointers and for single element ranges. * If you use version of 'is_palindrome' without custom predicate, 'is_palindrome' uses default 'operator==()' for elements. From ff79a9c2db5bd59b70d53b4ff96f8072203088b7 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 16 Aug 2016 16:22:01 +0300 Subject: [PATCH 25/36] Updated tests --- test/is_palindrome_test.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/is_palindrome_test.cpp b/test/is_palindrome_test.cpp index 69ddfbc..e15668f 100644 --- a/test/is_palindrome_test.cpp +++ b/test/is_palindrome_test.cpp @@ -63,14 +63,12 @@ void test_is_palindrome() BOOST_CHECK ( ba::is_palindrome(evenPalindrome, std::equal_to())); //Test C-strings like cases - BOOST_CHECK ( ba::is_palindrome(nullptr)); - BOOST_CHECK ( ba::is_palindrome(0)); BOOST_CHECK ( ba::is_palindrome(stringNullPtr)); BOOST_CHECK ( ba::is_palindrome("")); BOOST_CHECK ( ba::is_palindrome("a")); BOOST_CHECK ( ba::is_palindrome("abacaba"), std::equal_to()); BOOST_CHECK ( ba::is_palindrome("abba")); - BOOST_CHECK ( ba::is_palindrome("acab")); + BOOST_CHECK (!ba::is_palindrome("acab")); } BOOST_AUTO_TEST_CASE( test_main ) From f1e9d3140cf9bf8c48de7833e0af7b91d8c12811 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Wed, 17 Aug 2016 13:49:16 -0700 Subject: [PATCH 26/36] Made is_palindrome work for C++03 --- include/boost/algorithm/is_palindrome.hpp | 13 ++++--------- test/is_palindrome_test.cpp | 16 +++++++++------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/include/boost/algorithm/is_palindrome.hpp b/include/boost/algorithm/is_palindrome.hpp index 8649ad6..cc63e18 100644 --- a/include/boost/algorithm/is_palindrome.hpp +++ b/include/boost/algorithm/is_palindrome.hpp @@ -17,7 +17,6 @@ #include #include -#include #include #include @@ -134,10 +133,8 @@ bool is_palindrome(const R& range, Predicate p) /// Complexity: O(N). bool is_palindrome(const char* str) { - if(str == nullptr) - { - return true; - } + if(!str) + return true; return is_palindrome(str, str + strlen(str)); } @@ -154,10 +151,8 @@ bool is_palindrome(const char* str) template bool is_palindrome(const char* str, Predicate p) { - if(str == nullptr) - { - return true; - } + if(!str) + return true; return is_palindrome(str, str + strlen(str), p); } diff --git a/test/is_palindrome_test.cpp b/test/is_palindrome_test.cpp index e15668f..c668e9d 100644 --- a/test/is_palindrome_test.cpp +++ b/test/is_palindrome_test.cpp @@ -38,6 +38,8 @@ struct functorComparator } }; +#define Begin(arr) (arr) +#define End(arr) (arr+(sizeof(arr)/(sizeof(arr[0])))) void test_is_palindrome() { @@ -47,26 +49,26 @@ void test_is_palindrome() const int oddPalindrome[] = {1,2,3,2,1}; const int evenPalindrome[] = {1,2,2,1}; int evenNonPalindrome[] = {1,4,8,8}; - const char* stringNullPtr = nullptr; + const char* stringNullPtr = NULL; // Test a default operator== BOOST_CHECK ( ba::is_palindrome(empty)); BOOST_CHECK ( ba::is_palindrome(singleElement)); - BOOST_CHECK (!ba::is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome))); - BOOST_CHECK ( ba::is_palindrome(std::begin(oddPalindrome), std::end(oddPalindrome))); - BOOST_CHECK ( ba::is_palindrome(std::begin(evenPalindrome), std::end(evenPalindrome))); - BOOST_CHECK (!ba::is_palindrome(std::begin(evenNonPalindrome), std::end(evenNonPalindrome))); + BOOST_CHECK (!ba::is_palindrome(Begin(oddNonPalindrome), End(oddNonPalindrome))); + BOOST_CHECK ( ba::is_palindrome(Begin(oddPalindrome), End(oddPalindrome))); + BOOST_CHECK ( ba::is_palindrome(Begin(evenPalindrome), End(evenPalindrome))); + BOOST_CHECK (!ba::is_palindrome(Begin(evenNonPalindrome), End(evenNonPalindrome))); //Test the custom comparators BOOST_CHECK ( ba::is_palindrome(empty.begin(), empty.end(), functorComparator())); - BOOST_CHECK (!ba::is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComparator)); + BOOST_CHECK (!ba::is_palindrome(Begin(oddNonPalindrome), End(oddNonPalindrome), funcComparator)); BOOST_CHECK ( ba::is_palindrome(evenPalindrome, std::equal_to())); //Test C-strings like cases BOOST_CHECK ( ba::is_palindrome(stringNullPtr)); BOOST_CHECK ( ba::is_palindrome("")); BOOST_CHECK ( ba::is_palindrome("a")); - BOOST_CHECK ( ba::is_palindrome("abacaba"), std::equal_to()); + BOOST_CHECK ( ba::is_palindrome("abacaba", std::equal_to())); BOOST_CHECK ( ba::is_palindrome("abba")); BOOST_CHECK (!ba::is_palindrome("acab")); } From b3dabe10e4c6c1ec48f95158f555fe44a63e59b4 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Wed, 17 Aug 2016 13:54:58 -0700 Subject: [PATCH 27/36] Add missing error_info include --- test/hex_test4.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hex_test4.cpp b/test/hex_test4.cpp index df6e8d8..ba1ee34 100644 --- a/test/hex_test4.cpp +++ b/test/hex_test4.cpp @@ -11,6 +11,7 @@ Try ostream_iterators #include #include +#include #define BOOST_TEST_MAIN #include From eccac19108e555b48454db171422e74e6904dcb9 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Fri, 7 Oct 2016 23:03:40 -0500 Subject: [PATCH 28/36] Add, and update, documentation build targets. --- doc/Jamfile.v2 | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 6af1129..ef482ec 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -44,3 +44,13 @@ boostbook standalone toc.max.depth=2 generate.section.toc.level=1 ; + +############################################################################### +alias boostdoc + : algorithm ../string/doc/string_algo.xml + : + : autodoc ../string/doc//autodoc + : ; +explicit boostdoc ; +alias boostrelease ; +explicit boostrelease ; From 303ff13b863c95a11f8befac18ff13783ac214b1 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 12 Oct 2016 22:22:30 +0300 Subject: [PATCH 29/36] Delete duplicate version os is_palindrome --- include/boost/algorithm/is_palindrome.hpp | 41 +++++------------------ 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/include/boost/algorithm/is_palindrome.hpp b/include/boost/algorithm/is_palindrome.hpp index 8649ad6..bd8b9f9 100644 --- a/include/boost/algorithm/is_palindrome.hpp +++ b/include/boost/algorithm/is_palindrome.hpp @@ -36,7 +36,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) { @@ -64,7 +64,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. @@ -72,26 +72,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 ) @@ -123,7 +105,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 /// @@ -134,14 +115,11 @@ bool is_palindrome(const R& range, Predicate p) /// Complexity: O(N). bool is_palindrome(const char* str) { - if(str == nullptr) - { - return true; - } + if(!str) + return true; return is_palindrome(str, str + strlen(str)); } - /// \fn is_palindrome ( const char* str, Predicate p ) /// \return true if the entire sequence is palindrome /// @@ -154,13 +132,10 @@ bool is_palindrome(const char* str) template bool is_palindrome(const char* str, Predicate p) { - if(str == nullptr) - { - return true; - } + if(!str) + return true; return is_palindrome(str, str + strlen(str), p); } - }} #endif // BOOST_ALGORITHM_IS_PALINDROME_HPP From efd7a8b54426e7d5e1eb0e572103875e1981c7c3 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Wed, 26 Oct 2016 11:22:37 -0700 Subject: [PATCH 30/36] Updated the docs for the searchers to reflect the new interface, and added rationale for the change. --- doc/boyer_moore.qbk | 20 +++++++++++++++++--- doc/boyer_moore_horspool.qbk | 20 +++++++++++++++++--- doc/knuth_morris_pratt.qbk | 19 ++++++++++++++++--- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/doc/boyer_moore.qbk b/doc/boyer_moore.qbk index 13c9666..1651133 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 3a10c32..5b8491a 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 7b184cf..b2620f1 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. From 7977bd0cdc4dd62cd928ea60ce9b670ba815a08a Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Sun, 20 Nov 2016 17:02:49 -0800 Subject: [PATCH 31/36] Remove all mentions of (unary|binary)_function; not needed and they have been removed for C++17 --- include/boost/algorithm/cxx14/equal.hpp | 3 +-- include/boost/algorithm/string/detail/case_conv.hpp | 8 ++++++-- include/boost/algorithm/string/detail/util.hpp | 5 +++-- test/all_of_test.cpp | 2 +- test/any_of_test.cpp | 2 +- test/none_of_test.cpp | 2 +- test/one_of_test.cpp | 2 +- 7 files changed, 14 insertions(+), 10 deletions(-) diff --git a/include/boost/algorithm/cxx14/equal.hpp b/include/boost/algorithm/cxx14/equal.hpp index f1539f8..9f97be1 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/string/detail/case_conv.hpp b/include/boost/algorithm/string/detail/case_conv.hpp index 42621c7..233912c 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/util.hpp b/include/boost/algorithm/string/detail/util.hpp index cf4a8b1..7844b67 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 36918d5..b90eb27 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 a3267c5..f576a3c 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 fc74945..b9b40c6 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 9422881..ccc3a97 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; } From 9b19fc00c22bad292977b3e85130974fb9812cdf Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Sun, 20 Nov 2016 17:24:19 -0800 Subject: [PATCH 32/36] use std::shuffle instead of random_shuffle in C++11 and later --- test/partition_subrange_test.cpp | 34 ++++++++++++++++++++++---------- test/sort_subrange_test.cpp | 34 ++++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/test/partition_subrange_test.cpp b/test/partition_subrange_test.cpp index 018f140..c33fb46 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 4c1192e..de6a3fa 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()); } From 42db8a44037c8492d9c7a7e1a09b3c8831fdad23 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Fri, 25 Nov 2016 08:11:01 -0800 Subject: [PATCH 33/36] Change name of parameter; fixes 'shadowing' warning (Trac #12623) --- include/boost/algorithm/searching/boyer_moore.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/algorithm/searching/boyer_moore.hpp b/include/boost/algorithm/searching/boyer_moore.hpp index 65a809d..a72a40e 100644 --- a/include/boost/algorithm/searching/boyer_moore.hpp +++ b/include/boost/algorithm/searching/boyer_moore.hpp @@ -172,15 +172,15 @@ Requirements: } } - 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 ); From e442420d496c7ae6424d418cb19520026537f0a5 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Fri, 25 Nov 2016 20:50:53 -0800 Subject: [PATCH 34/36] Change name of (another) parameter; fixes 'shadowing' warning (Trac #12623) --- include/boost/algorithm/searching/boyer_moore.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/algorithm/searching/boyer_moore.hpp b/include/boost/algorithm/searching/boyer_moore.hpp index a72a40e..192d4de 100644 --- a/include/boost/algorithm/searching/boyer_moore.hpp +++ b/include/boost/algorithm/searching/boyer_moore.hpp @@ -152,8 +152,8 @@ Requirements: 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,12 +161,12 @@ Requirements: 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; } From 25d54bd1e8833666d9a7c2ecd4a5b576429afd78 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 13 Dec 2016 19:36:43 +0000 Subject: [PATCH 35/36] Build the algorithm documentation standalone. --- doc/Jamfile.v2 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index ef482ec..360b973 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 ; From d22c60c2d4c1e5b3e29f978fba59aa53fdcd07bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Hunold?= Date: Fri, 6 Jan 2017 09:59:12 +0100 Subject: [PATCH 36/36] Remove trailing ";" clang warning: extra ';' after member function definition [-Wextra-semi] --- include/boost/algorithm/string/detail/find_iterator.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/algorithm/string/detail/find_iterator.hpp b/include/boost/algorithm/string/detail/find_iterator.hpp index 9b78a0f..4f90a98 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) {}