diff --git a/doc/is_palindrome.qbk b/doc/is_palindrome.qbk index 928de6f..783305f 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,8 @@ 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("a") --> true +is_palindrome("aba", std::equal_to()) --> true `` [heading Iterator Requirements] @@ -71,13 +79,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, 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. 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. + +* 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 e15e77a..cc63e18 100644 --- a/include/boost/algorithm/is_palindrome.hpp +++ b/include/boost/algorithm/is_palindrome.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -34,7 +35,7 @@ namespace boost { namespace algorithm { /// For other sequences function will return false. /// Complexity: O(N). template -bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predicate p) +bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predicate p ) { if(begin == end) { @@ -70,8 +71,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 ) @@ -103,6 +122,40 @@ 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 +/// +/// \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) +{ + 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 +/// +/// \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) + return true; + return is_palindrome(str, str + strlen(str), p); +} + }} #endif // BOOST_ALGORITHM_IS_PALINDROME_HPP 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 diff --git a/test/is_palindrome_test.cpp b/test/is_palindrome_test.cpp index 2c0f67a..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,19 +49,28 @@ 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 = 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("abba")); + BOOST_CHECK (!ba::is_palindrome("acab")); } BOOST_AUTO_TEST_CASE( test_main )