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/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/clamp-hpp.qbk b/doc/clamp-hpp.qbk index 9c80a8e..7fb9264 100644 --- a/doc/clamp-hpp.qbk +++ b/doc/clamp-hpp.qbk @@ -27,11 +27,11 @@ Note: using `clamp` with floating point numbers may give unexpected results if o There is also a version that allows the caller to specify a comparison predicate to use instead of `operator <`. `` -template -V clamp ( V val, V lo, V hi ); +template +const T& clamp ( const T& val, const T& lo, const T& hi ); -template -V clamp ( V val, V lo, V hi, Pred p ); +template +const T& clamp ( const T& val, const T& lo, const T& hi, Pred p ); `` The following code: `` diff --git a/doc/is_palindrome.qbk b/doc/is_palindrome.qbk new file mode 100644 index 0000000..928de6f --- /dev/null +++ b/doc/is_palindrome.qbk @@ -0,0 +1,88 @@ +[/ 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 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 +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(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] + +`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/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..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 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 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. 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. 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/algorithm.hpp b/include/boost/algorithm/algorithm.hpp index 0cf6c45..ab0d4af 100644 --- a/include/boost/algorithm/algorithm.hpp +++ b/include/boost/algorithm/algorithm.hpp @@ -17,6 +17,8 @@ #ifndef BOOST_ALGORITHM_HPP #define BOOST_ALGORITHM_HPP +#include // for plus and multiplies + #include // for boost::disable_if #include @@ -56,7 +58,7 @@ power (T x, Integer n) { /// \fn power ( T x, Integer n, Operation op ) /// \return the value "x" raised to the power "n" -/// using the operaton "op". +/// using the operation "op". /// /// \param x The value to be exponentiated /// \param n The exponent (must be >= 0) 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..ba13144 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 @@ -29,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; } 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 ) { 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 { diff --git a/include/boost/algorithm/hex.hpp b/include/boost/algorithm/hex.hpp index 145a414..739e89f 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 @@ -25,7 +25,9 @@ #include #include -#include +#include +#include +#include #include #include @@ -33,17 +35,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 +56,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 +108,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 +126,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 +140,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 +150,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 +183,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 +218,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 +250,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 +268,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 +281,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 @@ -242,9 +292,24 @@ 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. -/// +/// /// \param input A container to be converted /// \return A container with the decoded text template diff --git a/include/boost/algorithm/is_palindrome.hpp b/include/boost/algorithm/is_palindrome.hpp new file mode 100644 index 0000000..e15e77a --- /dev/null +++ b/include/boost/algorithm/is_palindrome.hpp @@ -0,0 +1,108 @@ +/* + 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 +#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/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/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 ); } 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/include/boost/algorithm/sort_subrange.hpp b/include/boost/algorithm/sort_subrange.hpp new file mode 100644 index 0000000..7fb2cb5 --- /dev/null +++ b/include/boost/algorithm/sort_subrange.hpp @@ -0,0 +1,109 @@ +/* + Copyright (c) Marshall Clow 2008-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) + + Revision history: + 28 Sep 2015 mtc First version + +*/ + +/// \file sort_subrange.hpp +/// \brief Sort a subrange +/// \author Marshall Clow +/// +/// Suggested by Sean Parent in his CppCon 2015 keynote + +#ifndef BOOST_ALGORITHM_SORT_SUBRANGE_HPP +#define BOOST_ALGORITHM_SORT_SUBRANGE_HPP + +#include // For std::less +#include // For std::iterator_traits +#include // For nth_element and partial_sort + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn sort_subrange ( T const& val, +/// Iterator first, Iterator last, +/// Iterator sub_first, Iterator sub_last, +/// Pred p ) +/// \brief Sort the subrange [sub_first, sub_last) that is inside +/// the range [first, last) as if you had sorted the entire range. +/// +/// \param first The start of the larger range +/// \param last The end of the larger range +/// \param sub_first The start of the sub range +/// \param sub_last The end of the sub range +/// \param p A predicate to use to compare the values. +/// p ( a, b ) returns a boolean. +/// + template + void sort_subrange ( + Iterator first, Iterator last, + Iterator sub_first, Iterator sub_last, + Pred p) + { + if (sub_first == sub_last) return; // the empty sub-range is already sorted. + + if (sub_first != first) { // sub-range is at the start, don't need to partition + (void) std::nth_element(first, sub_first, last, p); + ++sub_first; + } + std::partial_sort(sub_first, sub_last, last, p); + } + + + + template + void sort_subrange (Iterator first, Iterator last, Iterator sub_first, Iterator sub_last) + { + typedef typename std::iterator_traits::value_type value_type; + return sort_subrange(first, last, sub_first, sub_last, std::less()); + } + +/// range versions? + + +/// \fn partition_subrange ( T const& val, +/// Iterator first, Iterator last, +/// Iterator sub_first, Iterator sub_last, +/// Pred p ) +/// \brief Gather the elements of the subrange [sub_first, sub_last) that is +/// inside the range [first, last) as if you had sorted the entire range. +/// +/// \param first The start of the larger range +/// \param last The end of the larger range +/// \param sub_first The start of the sub range +/// \param sub_last The end of the sub range +/// \param p A predicate to use to compare the values. +/// p ( a, b ) returns a boolean. +/// + template + void partition_subrange ( + Iterator first, Iterator last, + Iterator sub_first, Iterator sub_last, + Pred p) + { + if (sub_first != first) { + (void) std::nth_element(first, sub_first, last, p); + ++sub_first; + } + + if (sub_last != last) + (void) std::nth_element(sub_first, sub_last, last, p); + } + + template + void partition_subrange (Iterator first, Iterator last, Iterator sub_first, Iterator sub_last) + { + typedef typename std::iterator_traits::value_type value_type; + return partition_subrange(first, last, sub_first, sub_last, std::less()); + } + +}} + +#endif // BOOST_ALGORITHM_SORT_SUBRANGE_HPP 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( 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 diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 9b5d30b..fb00843 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -64,6 +64,12 @@ alias unit_test_framework [ run gather_test1.cpp unit_test_framework : : : : gather_test1 ] [ compile-fail gather_fail1.cpp ] +# SortSubrange tests + [ 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/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/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 ); } diff --git a/test/is_palindrome_test.cpp b/test/is_palindrome_test.cpp new file mode 100644 index 0000000..2c0f67a --- /dev/null +++ b/test/is_palindrome_test.cpp @@ -0,0 +1,68 @@ +/* + 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 + +#define BOOST_TEST_MAIN +#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; + } +}; + + +void test_is_palindrome() +{ + const std::list empty; + 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}; + 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())); +} + +BOOST_AUTO_TEST_CASE( test_main ) +{ + test_is_palindrome (); +} diff --git a/test/partition_subrange_test.cpp b/test/partition_subrange_test.cpp new file mode 100644 index 0000000..018f140 --- /dev/null +++ b/test/partition_subrange_test.cpp @@ -0,0 +1,156 @@ +#include +#include +#include + +#define BOOST_TEST_MAIN +#include + +#include +#include +namespace ba = boost::algorithm; + +template +void check_sequence ( Iter first, Iter last, Iter sf, Iter sl ) +{ +// for (Iter i = first; i < last; ++i) { +// if (i != first) std::cout << ' '; +// if (i == sf) std::cout << ">"; +// std::cout << *i; +// if (i == sl) std::cout << "<"; +// } +// if (sl == last) std::cout << "<"; +// std::cout << '\n'; + + if (sf == sl) return; + for (Iter i = first; i < sf; ++i) + BOOST_CHECK(*i < *sf); + for (Iter i = sf; i < sl; ++i) { + if (first != sf) // if there is an element before the subrange + BOOST_CHECK(*i > *(sf-1)); + if (last != sl) // if there is an element after the subrange + BOOST_CHECK(*i < *sl); + } + for (Iter i = sl; i < last; ++i) + BOOST_CHECK(*(sl-1) < *i); +} + +template +void check_sequence ( Iter first, Iter last, Iter sf, Iter sl, Pred p ) +{ + if (sf == sl) return; + for (Iter i = first; i < sf; ++i) + BOOST_CHECK(p(*i, *sf)); + for (Iter i = sf; i < sl; ++i) { + if (first != sf) // if there is an element before the subrange + BOOST_CHECK(p(*(sf-1), *i)); + if (last != sl) // if there is an element after the subrange + BOOST_CHECK(p(*i, *sl)); + } + for (Iter i = sl; i < last; ++i) + BOOST_CHECK(p(*(sl-1), *i)); + +} + +// for ( int i = 0; i < v.size(); ++i ) +// std::cout << v[i] << ' '; +// std::cout << std::endl; + + +BOOST_AUTO_TEST_CASE( test_main ) +{ + { + std::vector v; + for ( int i = 0; i < 10; ++i ) + v.push_back(i); + + const std::vector::iterator b = v.begin(); + ba::partition_subrange(b, v.end(), b + 3, b + 6); + check_sequence (b, v.end(), b + 3, b + 6); + +// BOOST_CHECK_EQUAL(v[3], 3); +// BOOST_CHECK_EQUAL(v[4], 4); +// BOOST_CHECK_EQUAL(v[5], 5); + +// Mix them up and try again - single element + std::random_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()); + ba::partition_subrange(b, v.end(), b + 7, v.end()); + check_sequence (b, v.end(), b + 7, v.end()); + +// BOOST_CHECK_EQUAL(v[7], 7); +// BOOST_CHECK_EQUAL(v[8], 8); +// BOOST_CHECK_EQUAL(v[9], 9); + +// Mix them up and try again - at the beginning + std::random_shuffle(v.begin(), v.end()); + ba::partition_subrange(b, v.end(), b, b + 2); + check_sequence (b, v.end(), b, b + 2); + +// BOOST_CHECK_EQUAL(v[0], 0); +// BOOST_CHECK_EQUAL(v[1], 1); + +// Mix them up and try again - empty subrange + std::random_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()); + ba::partition_subrange(b, v.end(), b, v.end()); + check_sequence (b, v.end(), b, v.end()); + } + + { + std::vector v; + for ( int i = 0; i < 10; ++i ) + v.push_back(i); + + const std::vector::iterator b = v.begin(); + ba::partition_subrange(b, v.end(), b + 3, b + 6, std::greater()); + check_sequence (b, v.end(), b + 3, b + 6, std::greater()); + +// BOOST_CHECK_EQUAL(v[3], 6); +// BOOST_CHECK_EQUAL(v[4], 5); +// BOOST_CHECK_EQUAL(v[5], 4); + +// Mix them up and try again - single element + std::random_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()); + ba::partition_subrange(b, v.end(), b + 7, v.end(), std::greater()); + check_sequence (b, v.end(), b + 7, v.end(), std::greater()); + +// BOOST_CHECK_EQUAL(v[7], 2); +// BOOST_CHECK_EQUAL(v[8], 1); +// BOOST_CHECK_EQUAL(v[9], 0); + +// Mix them up and try again - at the beginning + std::random_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()); + +// BOOST_CHECK_EQUAL(v[0], 9); +// BOOST_CHECK_EQUAL(v[1], 8); + +// Mix them up and try again - empty subrange + std::random_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()); + 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/power_test.cpp b/test/power_test.cpp index 20204c1..c1d5c23 100644 --- a/test/power_test.cpp +++ b/test/power_test.cpp @@ -8,6 +8,7 @@ */ #include +#include #include #include 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" ); } diff --git a/test/sort_subrange_test.cpp b/test/sort_subrange_test.cpp new file mode 100644 index 0000000..4c1192e --- /dev/null +++ b/test/sort_subrange_test.cpp @@ -0,0 +1,137 @@ +#include +#include +#include + +#define BOOST_TEST_MAIN +#include + +#include +#include +namespace ba = boost::algorithm; + +template +void check_sequence ( Iter first, Iter last, Iter sf, Iter sl ) +{ + if (sf == sl) return; + for (Iter i = first; i < sf; ++i) + BOOST_CHECK(*i < *sf); + BOOST_CHECK(ba::is_sorted(sf, sl)); + for (Iter i = sl; i < last; ++i) + BOOST_CHECK(*(sl-1) < *i); +} + +template +void check_sequence ( Iter first, Iter last, Iter sf, Iter sl, Pred p ) +{ + if (sf == sl) return; + for (Iter i = first; i < sf; ++i) + BOOST_CHECK(p(*i, *sf)); + BOOST_CHECK(ba::is_sorted(sf, sl, p)); + for (Iter i = sl; i < last; ++i) + BOOST_CHECK(p(*(sl-1), *i)); + +} + +// for ( int i = 0; i < v.size(); ++i ) +// std::cout << v[i] << ' '; +// std::cout << std::endl; + + +BOOST_AUTO_TEST_CASE( test_main ) +{ + { + std::vector v; + for ( int i = 0; i < 10; ++i ) + v.push_back(i); + + const std::vector::iterator b = v.begin(); + ba::sort_subrange(b, v.end(), b + 3, b + 6); + check_sequence (b, v.end(), b + 3, b + 6); + + BOOST_CHECK_EQUAL(v[3], 3); + BOOST_CHECK_EQUAL(v[4], 4); + BOOST_CHECK_EQUAL(v[5], 5); + +// Mix them up and try again - single element + std::random_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()); + ba::sort_subrange(b, v.end(), b + 7, v.end()); + check_sequence (b, v.end(), b + 7, v.end()); + + BOOST_CHECK_EQUAL(v[7], 7); + BOOST_CHECK_EQUAL(v[8], 8); + BOOST_CHECK_EQUAL(v[9], 9); + +// Mix them up and try again - at the beginning + std::random_shuffle(v.begin(), v.end()); + ba::sort_subrange(b, v.end(), b, b + 2); + check_sequence (b, v.end(), b, b + 2); + + BOOST_CHECK_EQUAL(v[0], 0); + BOOST_CHECK_EQUAL(v[1], 1); + +// Mix them up and try again - empty subrange + std::random_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()); + ba::sort_subrange(b, v.end(), b, v.end()); + check_sequence (b, v.end(), b, v.end()); + } + + { + std::vector v; + for ( int i = 0; i < 10; ++i ) + v.push_back(i); + + const std::vector::iterator b = v.begin(); + ba::sort_subrange(b, v.end(), b + 3, b + 6, std::greater()); + check_sequence (b, v.end(), b + 3, b + 6, std::greater()); + + BOOST_CHECK_EQUAL(v[3], 6); + BOOST_CHECK_EQUAL(v[4], 5); + BOOST_CHECK_EQUAL(v[5], 4); + +// Mix them up and try again - single element + std::random_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()); + ba::sort_subrange(b, v.end(), b + 7, v.end(), std::greater()); + check_sequence (b, v.end(), b + 7, v.end(), std::greater()); + + BOOST_CHECK_EQUAL(v[7], 2); + BOOST_CHECK_EQUAL(v[8], 1); + BOOST_CHECK_EQUAL(v[9], 0); + +// Mix them up and try again - at the beginning + std::random_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()); + + BOOST_CHECK_EQUAL(v[0], 9); + BOOST_CHECK_EQUAL(v[1], 8); + +// Mix them up and try again - empty subrange + std::random_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()); + ba::sort_subrange(b, v.end(), b, v.end(), std::greater()); + check_sequence (b, v.end(), b, v.end(), std::greater()); + } +}