From 774fb437f3b8babdb933850fcabab1c8041f7987 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Mon, 15 Aug 2016 04:09:48 +0300 Subject: [PATCH 1/7] Disabled 'is_palindrome' for 'const char*' --- doc/is_palindrome.qbk | 2 ++ include/boost/algorithm/is_palindrome.hpp | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/doc/is_palindrome.qbk b/doc/is_palindrome.qbk index 928de6f..f37ca07 100644 --- a/doc/is_palindrome.qbk +++ b/doc/is_palindrome.qbk @@ -79,6 +79,8 @@ All of the variants of `is_palindrome` take their parameters by value or const r * If you use version of 'is_palindrome' without custom predicate, 'is_palindrome' uses default 'operator==' for elements. If you want use custom predicate, you must redefine 'operator=='. +* Don't use 'const char*' with 'is_palindrome', because 'const char*' is always non-palindromic ('\0' at the end). If you will try to compile 'is_palindrome' with 'const char*', you will get an error. + [endsect] [/ File is_palindrome.qbk diff --git a/include/boost/algorithm/is_palindrome.hpp b/include/boost/algorithm/is_palindrome.hpp index 61acbae..0080e60 100644 --- a/include/boost/algorithm/is_palindrome.hpp +++ b/include/boost/algorithm/is_palindrome.hpp @@ -102,6 +102,22 @@ bool is_palindrome(const R& range, Predicate p) return is_palindrome(boost::begin(range), boost::end(range), p); } +//Disable is_palindrome for const char* because it work not properly. +//Please use string_view for const char* cases. +//Here we use dirty hack to disable 'is_palindrome' with 'const char*' +//URL: http://stackoverflow.com/questions/14637356/static-assert-fails-compilation-even-though-template-function-is-called-nowhere +template +struct foobar : std::false_type +{ }; + +template +bool is_palindrome(const char* str) +{ + static_assert(foobar::value, "Using 'is_palindrome' for 'const char*' is dangerous, because result is always false" + "(reason: '\0' in the end of the string). You can use string_view in this case"); + return false; +} + }} #endif // BOOST_ALGORITHM_IS_PALINDROME_HPP From 3c25ce10903ca0f001bc845c1d0dd01df7e4bbd2 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Tue, 16 Aug 2016 05:14:56 +0300 Subject: [PATCH 2/7] Added C-String support for 'is_palindrome' Updated doc, example and tests. --- doc/is_palindrome.qbk | 25 ++++--- example/is_palindrome_example.cpp | 7 +- include/boost/algorithm/is_palindrome.hpp | 85 ++++++++++++++++++----- test/is_palindrome_test.cpp | 11 +++ 4 files changed, 103 insertions(+), 25 deletions(-) diff --git a/doc/is_palindrome.qbk b/doc/is_palindrome.qbk index f37ca07..b4193e4 100644 --- a/doc/is_palindrome.qbk +++ b/doc/is_palindrome.qbk @@ -9,23 +9,26 @@ Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -The header file 'is_palindrome.hpp' contains four variants of a single algorithm, is_palindrome. +The header file 'is_palindrome.hpp' contains six variants of a single algorithm, is_palindrome. The algorithm tests the sequence and returns true if the sequence is a palindrome; i.e, it is identical when traversed either backwards or frontwards. The routine `is_palindrome` takes a sequence and, optionally, a predicate. It will return true if the predicate returns true for tested elements by algorithm in the sequence. -The routine come in 4 forms; the first one takes two iterators to define the range. The second form takes two iterators to define the range and a predicate. -The third form takes a single range parameter, and uses Boost.Range to traverse it. And the fourth form takes a single range parameter ( uses Boost.Range to traverse it) and a predicate. +The routine come in 6 forms; the first one takes two iterators to define the range. The second form takes two iterators to define the range and a predicate. +The third form takes a single range parameter, and uses Boost.Range to traverse it. The fourth form takes a single range parameter ( uses Boost.Range to traverse it) and a predicate. +The fifth form takes a single C-string and a predicate. The sixth form takes a single C-string. [heading interface] The function `is_palindrome` returns true if the predicate returns true any tested by algorithm items in the sequence. -There are four versions: +There are six versions: 1) takes two iterators. 2) takes two iterators and a predicate. 3) takes a range. 4) takes a range and a predicate. +5) takes a C-string and a predicate. +6) takes a C-string. `` template @@ -36,6 +39,9 @@ template bool is_palindrome ( const Range &r ); template bool is_palindrome ( const Range &r, Predicate p ); +template + bool is_palindrome ( const char* str, Predicate p ); +bool is_palindrome(const char* str); `` @@ -59,6 +65,9 @@ is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComp is_palindrome(std::begin(oddPalindrome), std::end(oddPalindrome)) --> true is_palindrome(evenPalindrome, std::equal_to())) --> true is_palindrome(std::begin(evenNonPalindrome), std::end(evenNonPalindrome)) --> false +is_palindrome(nullptr) --> true +is_palindrome("a") --> true +is_palindrome("aba", std::equal_to()) --> true `` [heading Iterator Requirements] @@ -71,15 +80,15 @@ All of the variants of `is_palindrome` run in ['O(N)] (linear) time; that is, th [heading Exception Safety] -All of the variants of `is_palindrome` take their parameters by value or const reference, and do not depend upon any global state. Therefore, all the routines in this file provide the strong exception guarantee. +All of the variants of `is_palindrome` take their parameters by value, const pointer or const reference, and do not depend upon any global state. Therefore, all the routines in this file provide the strong exception guarantee. [heading Notes] -* `is_palindrome` returns true for empty ranges and for single element ranges. +* `is_palindrome` returns true for empty ranges, null pointers and for single element ranges. -* If you use version of 'is_palindrome' without custom predicate, 'is_palindrome' uses default 'operator==' for elements. If you want use custom predicate, you must redefine 'operator=='. +* If you use version of 'is_palindrome' without custom predicate, 'is_palindrome' uses default 'operator==()' for elements. -* Don't use 'const char*' with 'is_palindrome', because 'const char*' is always non-palindromic ('\0' at the end). If you will try to compile 'is_palindrome' with 'const char*', you will get an error. +* Be careful with using not null pointer 'const char*' without '\0' - if you use it with 'is_palindrome', it's a undefined behaviour. [endsect] diff --git a/example/is_palindrome_example.cpp b/example/is_palindrome_example.cpp index e995a9e..cefc782 100644 --- a/example/is_palindrome_example.cpp +++ b/example/is_palindrome_example.cpp @@ -89,6 +89,11 @@ int main ( int /*argc*/, char * /*argv*/ [] ) std::cout << "This container is palindrome" << std::endl; else std::cout << "This container is not palindrome" << std::endl; - + + //You can use C-strings + if(ba::is_palindrome("aba")) + std::cout << "This C-string is palindrome" << std::endl; + else + std::cout << "This C-string is not palindrome" << std::endl; return 0; } diff --git a/include/boost/algorithm/is_palindrome.hpp b/include/boost/algorithm/is_palindrome.hpp index d341eb7..714c833 100644 --- a/include/boost/algorithm/is_palindrome.hpp +++ b/include/boost/algorithm/is_palindrome.hpp @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include @@ -34,7 +36,7 @@ namespace boost { namespace algorithm { /// For other sequences function will return false. /// Complexity: O(N). template -bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predicate p) +bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predicate p ) { if(begin == end) { @@ -70,8 +72,26 @@ bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predi template bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end) { - return is_palindrome(begin, end, - std::equal_to::value_type> ()); + if(begin == end) + { + return true; + } + + --end; + while(begin != end) + { + if(!(*begin == *end)) + { + return false; + } + ++begin; + if(begin == end) + { + break; + } + --end; + } + return true; } /// \fn is_palindrome ( const R& range ) @@ -82,7 +102,7 @@ bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end) /// \note This function will return true for empty sequences and for palindromes. /// For other sequences function will return false. /// Complexity: O(N). -template +template ::value_type>::type> bool is_palindrome(const R& range) { return is_palindrome(boost::begin(range), boost::end(range)); @@ -97,26 +117,59 @@ bool is_palindrome(const R& range) /// \note This function will return true for empty sequences and for palindromes. /// For other sequences function will return false. /// Complexity: O(N). -template +template ::value_type>::type> bool is_palindrome(const R& range, Predicate p) { return is_palindrome(boost::begin(range), boost::end(range), p); } -//Disable is_palindrome for const char* because it work not properly. -//Please use string_view for const char* cases. -//Here we use dirty hack to disable 'is_palindrome' with 'const char*' -//URL: http://stackoverflow.com/questions/14637356/static-assert-fails-compilation-even-though-template-function-is-called-nowhere -template -struct foobar : std::false_type -{ }; -template +/// \fn is_palindrome ( const char* str ) +/// \return true if the entire sequence is palindrome +/// +/// \param str C-string to be tested. +/// +/// \note This function will return true for empty sequences and for palindromes. +/// For other sequences function will return false. +/// Complexity: O(N). bool is_palindrome(const char* str) { - static_assert(foobar::value, "Using 'is_palindrome' for 'const char*' is dangerous, because result is always false" - "(reason: '\0' in the end of the string). You can use string_view in this case"); - return false; + if(str == nullptr) + { + return true; + } + return is_palindrome(str, str + strlen(str)); +} + + +/// \fn is_palindrome ( const char* str, Predicate p ) +/// \return true if the entire sequence is palindrome +/// +/// \param str C-string to be tested. +/// \param p A predicate used to compare the values. +/// +/// \note This function will return true for empty sequences and for palindromes. +/// For other sequences function will return false. +/// Complexity: O(N). +template +bool is_palindrome(const char* str, Predicate p) +{ + if(str == nullptr) + { + return true; + } + return is_palindrome(str, str + strlen(str), p); +} + +bool is_palindrome (nullptr_t) +{ + return true; +} + +template +bool is_palindrome (T) +{ + return true; } }} diff --git a/test/is_palindrome_test.cpp b/test/is_palindrome_test.cpp index 2c0f67a..69ddfbc 100644 --- a/test/is_palindrome_test.cpp +++ b/test/is_palindrome_test.cpp @@ -47,6 +47,7 @@ void test_is_palindrome() const int oddPalindrome[] = {1,2,3,2,1}; const int evenPalindrome[] = {1,2,2,1}; int evenNonPalindrome[] = {1,4,8,8}; + const char* stringNullPtr = nullptr; // Test a default operator== BOOST_CHECK ( ba::is_palindrome(empty)); @@ -60,6 +61,16 @@ void test_is_palindrome() BOOST_CHECK ( ba::is_palindrome(empty.begin(), empty.end(), functorComparator())); BOOST_CHECK (!ba::is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComparator)); BOOST_CHECK ( ba::is_palindrome(evenPalindrome, std::equal_to())); + + //Test C-strings like cases + BOOST_CHECK ( ba::is_palindrome(nullptr)); + BOOST_CHECK ( ba::is_palindrome(0)); + BOOST_CHECK ( ba::is_palindrome(stringNullPtr)); + BOOST_CHECK ( ba::is_palindrome("")); + BOOST_CHECK ( ba::is_palindrome("a")); + BOOST_CHECK ( ba::is_palindrome("abacaba"), std::equal_to()); + BOOST_CHECK ( ba::is_palindrome("abba")); + BOOST_CHECK ( ba::is_palindrome("acab")); } BOOST_AUTO_TEST_CASE( test_main ) From 42bbfdeb4c18cc3d816932cb27bdfbaddd1fa602 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 16 Aug 2016 16:18:21 +0300 Subject: [PATCH 3/7] Deleted support for nullptr, NULL and 0. I think user shouldn't send to 'is_palindrome' zero, NULL or nullptr as parameter. As value of const char* it's possible, of course. But cases 'is_palindrome(0)', 'is_palindrome(NULL)' and 'is_palindrome(nullptr)' is silly and it should be restricted by design. --- include/boost/algorithm/is_palindrome.hpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/include/boost/algorithm/is_palindrome.hpp b/include/boost/algorithm/is_palindrome.hpp index 714c833..8649ad6 100644 --- a/include/boost/algorithm/is_palindrome.hpp +++ b/include/boost/algorithm/is_palindrome.hpp @@ -102,7 +102,7 @@ bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end) /// \note This function will return true for empty sequences and for palindromes. /// For other sequences function will return false. /// Complexity: O(N). -template ::value_type>::type> +template bool is_palindrome(const R& range) { return is_palindrome(boost::begin(range), boost::end(range)); @@ -117,7 +117,7 @@ bool is_palindrome(const R& range) /// \note This function will return true for empty sequences and for palindromes. /// For other sequences function will return false. /// Complexity: O(N). -template ::value_type>::type> +template bool is_palindrome(const R& range, Predicate p) { return is_palindrome(boost::begin(range), boost::end(range), p); @@ -161,17 +161,6 @@ bool is_palindrome(const char* str, Predicate p) return is_palindrome(str, str + strlen(str), p); } -bool is_palindrome (nullptr_t) -{ - return true; -} - -template -bool is_palindrome (T) -{ - return true; -} - }} #endif // BOOST_ALGORITHM_IS_PALINDROME_HPP From a53b0121b9122e20506911396e88ec5c94115ecb Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 16 Aug 2016 16:20:22 +0300 Subject: [PATCH 4/7] Updated documentation for is_palindrome --- doc/is_palindrome.qbk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/is_palindrome.qbk b/doc/is_palindrome.qbk index b4193e4..783305f 100644 --- a/doc/is_palindrome.qbk +++ b/doc/is_palindrome.qbk @@ -65,7 +65,6 @@ is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComp is_palindrome(std::begin(oddPalindrome), std::end(oddPalindrome)) --> true is_palindrome(evenPalindrome, std::equal_to())) --> true is_palindrome(std::begin(evenNonPalindrome), std::end(evenNonPalindrome)) --> false -is_palindrome(nullptr) --> true is_palindrome("a") --> true is_palindrome("aba", std::equal_to()) --> true `` @@ -84,7 +83,7 @@ All of the variants of `is_palindrome` take their parameters by value, const poi [heading Notes] -* `is_palindrome` returns true for empty ranges, null pointers and for single element ranges. +* `is_palindrome` returns true for empty ranges, const char* null pointers and for single element ranges. * If you use version of 'is_palindrome' without custom predicate, 'is_palindrome' uses default 'operator==()' for elements. From ff79a9c2db5bd59b70d53b4ff96f8072203088b7 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 16 Aug 2016 16:22:01 +0300 Subject: [PATCH 5/7] Updated tests --- test/is_palindrome_test.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/is_palindrome_test.cpp b/test/is_palindrome_test.cpp index 69ddfbc..e15668f 100644 --- a/test/is_palindrome_test.cpp +++ b/test/is_palindrome_test.cpp @@ -63,14 +63,12 @@ void test_is_palindrome() BOOST_CHECK ( ba::is_palindrome(evenPalindrome, std::equal_to())); //Test C-strings like cases - BOOST_CHECK ( ba::is_palindrome(nullptr)); - BOOST_CHECK ( ba::is_palindrome(0)); BOOST_CHECK ( ba::is_palindrome(stringNullPtr)); BOOST_CHECK ( ba::is_palindrome("")); BOOST_CHECK ( ba::is_palindrome("a")); BOOST_CHECK ( ba::is_palindrome("abacaba"), std::equal_to()); BOOST_CHECK ( ba::is_palindrome("abba")); - BOOST_CHECK ( ba::is_palindrome("acab")); + BOOST_CHECK (!ba::is_palindrome("acab")); } BOOST_AUTO_TEST_CASE( test_main ) From f1e9d3140cf9bf8c48de7833e0af7b91d8c12811 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Wed, 17 Aug 2016 13:49:16 -0700 Subject: [PATCH 6/7] Made is_palindrome work for C++03 --- include/boost/algorithm/is_palindrome.hpp | 13 ++++--------- test/is_palindrome_test.cpp | 16 +++++++++------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/include/boost/algorithm/is_palindrome.hpp b/include/boost/algorithm/is_palindrome.hpp index 8649ad6..cc63e18 100644 --- a/include/boost/algorithm/is_palindrome.hpp +++ b/include/boost/algorithm/is_palindrome.hpp @@ -17,7 +17,6 @@ #include #include -#include #include #include @@ -134,10 +133,8 @@ bool is_palindrome(const R& range, Predicate p) /// Complexity: O(N). bool is_palindrome(const char* str) { - if(str == nullptr) - { - return true; - } + if(!str) + return true; return is_palindrome(str, str + strlen(str)); } @@ -154,10 +151,8 @@ bool is_palindrome(const char* str) template bool is_palindrome(const char* str, Predicate p) { - if(str == nullptr) - { - return true; - } + if(!str) + return true; return is_palindrome(str, str + strlen(str), p); } diff --git a/test/is_palindrome_test.cpp b/test/is_palindrome_test.cpp index e15668f..c668e9d 100644 --- a/test/is_palindrome_test.cpp +++ b/test/is_palindrome_test.cpp @@ -38,6 +38,8 @@ struct functorComparator } }; +#define Begin(arr) (arr) +#define End(arr) (arr+(sizeof(arr)/(sizeof(arr[0])))) void test_is_palindrome() { @@ -47,26 +49,26 @@ void test_is_palindrome() const int oddPalindrome[] = {1,2,3,2,1}; const int evenPalindrome[] = {1,2,2,1}; int evenNonPalindrome[] = {1,4,8,8}; - const char* stringNullPtr = nullptr; + const char* stringNullPtr = NULL; // Test a default operator== BOOST_CHECK ( ba::is_palindrome(empty)); BOOST_CHECK ( ba::is_palindrome(singleElement)); - BOOST_CHECK (!ba::is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome))); - BOOST_CHECK ( ba::is_palindrome(std::begin(oddPalindrome), std::end(oddPalindrome))); - BOOST_CHECK ( ba::is_palindrome(std::begin(evenPalindrome), std::end(evenPalindrome))); - BOOST_CHECK (!ba::is_palindrome(std::begin(evenNonPalindrome), std::end(evenNonPalindrome))); + BOOST_CHECK (!ba::is_palindrome(Begin(oddNonPalindrome), End(oddNonPalindrome))); + BOOST_CHECK ( ba::is_palindrome(Begin(oddPalindrome), End(oddPalindrome))); + BOOST_CHECK ( ba::is_palindrome(Begin(evenPalindrome), End(evenPalindrome))); + BOOST_CHECK (!ba::is_palindrome(Begin(evenNonPalindrome), End(evenNonPalindrome))); //Test the custom comparators BOOST_CHECK ( ba::is_palindrome(empty.begin(), empty.end(), functorComparator())); - BOOST_CHECK (!ba::is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComparator)); + BOOST_CHECK (!ba::is_palindrome(Begin(oddNonPalindrome), End(oddNonPalindrome), funcComparator)); BOOST_CHECK ( ba::is_palindrome(evenPalindrome, std::equal_to())); //Test C-strings like cases BOOST_CHECK ( ba::is_palindrome(stringNullPtr)); BOOST_CHECK ( ba::is_palindrome("")); BOOST_CHECK ( ba::is_palindrome("a")); - BOOST_CHECK ( ba::is_palindrome("abacaba"), std::equal_to()); + BOOST_CHECK ( ba::is_palindrome("abacaba", std::equal_to())); BOOST_CHECK ( ba::is_palindrome("abba")); BOOST_CHECK (!ba::is_palindrome("acab")); } From b3dabe10e4c6c1ec48f95158f555fe44a63e59b4 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Wed, 17 Aug 2016 13:54:58 -0700 Subject: [PATCH 7/7] Add missing error_info include --- test/hex_test4.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hex_test4.cpp b/test/hex_test4.cpp index df6e8d8..ba1ee34 100644 --- a/test/hex_test4.cpp +++ b/test/hex_test4.cpp @@ -11,6 +11,7 @@ Try ostream_iterators #include #include +#include #define BOOST_TEST_MAIN #include