Skip to content

Commit 3c25ce1

Browse files
committed
Added C-String support for 'is_palindrome'
Updated doc, example and tests.
1 parent 0f5136d commit 3c25ce1

File tree

4 files changed

+103
-25
lines changed

4 files changed

+103
-25
lines changed

doc/is_palindrome.qbk

+17-8
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,26 @@ Distributed under the Boost Software License, Version 1.0.
99
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
1010
]
1111

12-
The header file 'is_palindrome.hpp' contains four variants of a single algorithm, is_palindrome.
12+
The header file 'is_palindrome.hpp' contains six variants of a single algorithm, is_palindrome.
1313
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.
1414

1515
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.
1616

17-
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.
18-
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.
17+
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.
18+
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.
19+
The fifth form takes a single C-string and a predicate. The sixth form takes a single C-string.
1920

2021

2122
[heading interface]
2223

2324
The function `is_palindrome` returns true if the predicate returns true any tested by algorithm items in the sequence.
24-
There are four versions:
25+
There are six versions:
2526
1) takes two iterators.
2627
2) takes two iterators and a predicate.
2728
3) takes a range.
2829
4) takes a range and a predicate.
30+
5) takes a C-string and a predicate.
31+
6) takes a C-string.
2932

3033
``
3134
template<typename BidirectionalIterator>
@@ -36,6 +39,9 @@ template<typename Range>
3639
bool is_palindrome ( const Range &r );
3740
template<typename Range, typename Predicate>
3841
bool is_palindrome ( const Range &r, Predicate p );
42+
template<typename Predicate>
43+
bool is_palindrome ( const char* str, Predicate p );
44+
bool is_palindrome(const char* str);
3945
``
4046

4147

@@ -59,6 +65,9 @@ is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComp
5965
is_palindrome(std::begin(oddPalindrome), std::end(oddPalindrome)) --> true
6066
is_palindrome(evenPalindrome, std::equal_to<int>())) --> true
6167
is_palindrome(std::begin(evenNonPalindrome), std::end(evenNonPalindrome)) --> false
68+
is_palindrome(nullptr) --> true
69+
is_palindrome("a") --> true
70+
is_palindrome("aba", std::equal_to<char>()) --> true
6271
``
6372

6473
[heading Iterator Requirements]
@@ -71,15 +80,15 @@ All of the variants of `is_palindrome` run in ['O(N)] (linear) time; that is, th
7180

7281
[heading Exception Safety]
7382

74-
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.
83+
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.
7584

7685
[heading Notes]
7786

78-
* `is_palindrome` returns true for empty ranges and for single element ranges.
87+
* `is_palindrome` returns true for empty ranges, null pointers and for single element ranges.
7988

80-
* 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=='.
89+
* If you use version of 'is_palindrome' without custom predicate, 'is_palindrome' uses default 'operator==()' for elements.
8190

82-
* 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.
91+
* Be careful with using not null pointer 'const char*' without '\0' - if you use it with 'is_palindrome', it's a undefined behaviour.
8392

8493
[endsect]
8594

example/is_palindrome_example.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ int main ( int /*argc*/, char * /*argv*/ [] )
8989
std::cout << "This container is palindrome" << std::endl;
9090
else
9191
std::cout << "This container is not palindrome" << std::endl;
92-
92+
93+
//You can use C-strings
94+
if(ba::is_palindrome("aba"))
95+
std::cout << "This C-string is palindrome" << std::endl;
96+
else
97+
std::cout << "This C-string is not palindrome" << std::endl;
9398
return 0;
9499
}

include/boost/algorithm/is_palindrome.hpp

+69-16
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
#include <iterator>
1919
#include <functional>
20+
#include <type_traits>
21+
#include <cstring>
2022

2123
#include <boost/range/begin.hpp>
2224
#include <boost/range/end.hpp>
@@ -34,7 +36,7 @@ namespace boost { namespace algorithm {
3436
/// For other sequences function will return false.
3537
/// Complexity: O(N).
3638
template <typename BidirectionalIterator, typename Predicate>
37-
bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predicate p)
39+
bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predicate p )
3840
{
3941
if(begin == end)
4042
{
@@ -70,8 +72,26 @@ bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predi
7072
template <typename BidirectionalIterator>
7173
bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end)
7274
{
73-
return is_palindrome(begin, end,
74-
std::equal_to<typename std::iterator_traits<BidirectionalIterator>::value_type> ());
75+
if(begin == end)
76+
{
77+
return true;
78+
}
79+
80+
--end;
81+
while(begin != end)
82+
{
83+
if(!(*begin == *end))
84+
{
85+
return false;
86+
}
87+
++begin;
88+
if(begin == end)
89+
{
90+
break;
91+
}
92+
--end;
93+
}
94+
return true;
7595
}
7696

7797
/// \fn is_palindrome ( const R& range )
@@ -82,7 +102,7 @@ bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end)
82102
/// \note This function will return true for empty sequences and for palindromes.
83103
/// For other sequences function will return false.
84104
/// Complexity: O(N).
85-
template <typename R>
105+
template <typename R, typename std::enable_if<!std::is_integral<R>::value_type>::type>
86106
bool is_palindrome(const R& range)
87107
{
88108
return is_palindrome(boost::begin(range), boost::end(range));
@@ -97,26 +117,59 @@ bool is_palindrome(const R& range)
97117
/// \note This function will return true for empty sequences and for palindromes.
98118
/// For other sequences function will return false.
99119
/// Complexity: O(N).
100-
template <typename R, typename Predicate>
120+
template <typename R, typename Predicate, typename std::enable_if<!std::is_integral<R>::value_type>::type>
101121
bool is_palindrome(const R& range, Predicate p)
102122
{
103123
return is_palindrome(boost::begin(range), boost::end(range), p);
104124
}
105125

106-
//Disable is_palindrome for const char* because it work not properly.
107-
//Please use string_view for const char* cases.
108-
//Here we use dirty hack to disable 'is_palindrome' with 'const char*'
109-
//URL: http://stackoverflow.com/questions/14637356/static-assert-fails-compilation-even-though-template-function-is-called-nowhere
110-
template<typename T>
111-
struct foobar : std::false_type
112-
{ };
113126

114-
template<typename T = int>
127+
/// \fn is_palindrome ( const char* str )
128+
/// \return true if the entire sequence is palindrome
129+
///
130+
/// \param str C-string to be tested.
131+
///
132+
/// \note This function will return true for empty sequences and for palindromes.
133+
/// For other sequences function will return false.
134+
/// Complexity: O(N).
115135
bool is_palindrome(const char* str)
116136
{
117-
static_assert(foobar<T>::value, "Using 'is_palindrome' for 'const char*' is dangerous, because result is always false"
118-
"(reason: '\0' in the end of the string). You can use string_view in this case");
119-
return false;
137+
if(str == nullptr)
138+
{
139+
return true;
140+
}
141+
return is_palindrome(str, str + strlen(str));
142+
}
143+
144+
145+
/// \fn is_palindrome ( const char* str, Predicate p )
146+
/// \return true if the entire sequence is palindrome
147+
///
148+
/// \param str C-string to be tested.
149+
/// \param p A predicate used to compare the values.
150+
///
151+
/// \note This function will return true for empty sequences and for palindromes.
152+
/// For other sequences function will return false.
153+
/// Complexity: O(N).
154+
template<typename Predicate>
155+
bool is_palindrome(const char* str, Predicate p)
156+
{
157+
if(str == nullptr)
158+
{
159+
return true;
160+
}
161+
return is_palindrome(str, str + strlen(str), p);
162+
}
163+
164+
bool is_palindrome (nullptr_t)
165+
{
166+
return true;
167+
}
168+
169+
template<typename T>
170+
bool is_palindrome (T)
171+
{
172+
return true;
120173
}
121174

122175
}}

test/is_palindrome_test.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ void test_is_palindrome()
4747
const int oddPalindrome[] = {1,2,3,2,1};
4848
const int evenPalindrome[] = {1,2,2,1};
4949
int evenNonPalindrome[] = {1,4,8,8};
50+
const char* stringNullPtr = nullptr;
5051

5152
// Test a default operator==
5253
BOOST_CHECK ( ba::is_palindrome(empty));
@@ -60,6 +61,16 @@ void test_is_palindrome()
6061
BOOST_CHECK ( ba::is_palindrome(empty.begin(), empty.end(), functorComparator()));
6162
BOOST_CHECK (!ba::is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComparator<int>));
6263
BOOST_CHECK ( ba::is_palindrome(evenPalindrome, std::equal_to<int>()));
64+
65+
//Test C-strings like cases
66+
BOOST_CHECK ( ba::is_palindrome(nullptr));
67+
BOOST_CHECK ( ba::is_palindrome(0));
68+
BOOST_CHECK ( ba::is_palindrome(stringNullPtr));
69+
BOOST_CHECK ( ba::is_palindrome(""));
70+
BOOST_CHECK ( ba::is_palindrome("a"));
71+
BOOST_CHECK ( ba::is_palindrome("abacaba"), std::equal_to<char>());
72+
BOOST_CHECK ( ba::is_palindrome("abba"));
73+
BOOST_CHECK ( ba::is_palindrome("acab"));
6374
}
6475

6576
BOOST_AUTO_TEST_CASE( test_main )

0 commit comments

Comments
 (0)