mirror of
https://github.com/boostorg/algorithm.git
synced 2025-07-06 09:16:33 +02:00
Added C-String support for 'is_palindrome'
Updated doc, example and tests.
This commit is contained in:
@ -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)
|
(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 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 `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 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. And the fourth form takes a single range parameter ( uses Boost.Range to traverse it) 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]
|
[heading interface]
|
||||||
|
|
||||||
The function `is_palindrome` returns true if the predicate returns true any tested by algorithm items in the sequence.
|
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.
|
1) takes two iterators.
|
||||||
2) takes two iterators and a predicate.
|
2) takes two iterators and a predicate.
|
||||||
3) takes a range.
|
3) takes a range.
|
||||||
4) takes a range and a predicate.
|
4) takes a range and a predicate.
|
||||||
|
5) takes a C-string and a predicate.
|
||||||
|
6) takes a C-string.
|
||||||
|
|
||||||
``
|
``
|
||||||
template<typename BidirectionalIterator>
|
template<typename BidirectionalIterator>
|
||||||
@ -36,6 +39,9 @@ template<typename Range>
|
|||||||
bool is_palindrome ( const Range &r );
|
bool is_palindrome ( const Range &r );
|
||||||
template<typename Range, typename Predicate>
|
template<typename Range, typename Predicate>
|
||||||
bool is_palindrome ( const Range &r, Predicate p );
|
bool is_palindrome ( const Range &r, Predicate p );
|
||||||
|
template<typename Predicate>
|
||||||
|
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(std::begin(oddPalindrome), std::end(oddPalindrome)) --> true
|
||||||
is_palindrome(evenPalindrome, std::equal_to<int>())) --> true
|
is_palindrome(evenPalindrome, std::equal_to<int>())) --> true
|
||||||
is_palindrome(std::begin(evenNonPalindrome), std::end(evenNonPalindrome)) --> false
|
is_palindrome(std::begin(evenNonPalindrome), std::end(evenNonPalindrome)) --> false
|
||||||
|
is_palindrome(nullptr) --> true
|
||||||
|
is_palindrome("a") --> true
|
||||||
|
is_palindrome("aba", std::equal_to<char>()) --> true
|
||||||
``
|
``
|
||||||
|
|
||||||
[heading Iterator Requirements]
|
[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]
|
[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]
|
[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]
|
[endsect]
|
||||||
|
|
||||||
|
@ -90,5 +90,10 @@ int main ( int /*argc*/, char * /*argv*/ [] )
|
|||||||
else
|
else
|
||||||
std::cout << "This container is not palindrome" << std::endl;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include <boost/range/begin.hpp>
|
#include <boost/range/begin.hpp>
|
||||||
#include <boost/range/end.hpp>
|
#include <boost/range/end.hpp>
|
||||||
@ -70,8 +72,26 @@ bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predi
|
|||||||
template <typename BidirectionalIterator>
|
template <typename BidirectionalIterator>
|
||||||
bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end)
|
bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end)
|
||||||
{
|
{
|
||||||
return is_palindrome(begin, end,
|
if(begin == end)
|
||||||
std::equal_to<typename std::iterator_traits<BidirectionalIterator>::value_type> ());
|
{
|
||||||
|
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 )
|
/// \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.
|
/// \note This function will return true for empty sequences and for palindromes.
|
||||||
/// For other sequences function will return false.
|
/// For other sequences function will return false.
|
||||||
/// Complexity: O(N).
|
/// Complexity: O(N).
|
||||||
template <typename R>
|
template <typename R, typename std::enable_if<!std::is_integral<R>::value_type>::type>
|
||||||
bool is_palindrome(const R& range)
|
bool is_palindrome(const R& range)
|
||||||
{
|
{
|
||||||
return is_palindrome(boost::begin(range), boost::end(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.
|
/// \note This function will return true for empty sequences and for palindromes.
|
||||||
/// For other sequences function will return false.
|
/// For other sequences function will return false.
|
||||||
/// Complexity: O(N).
|
/// Complexity: O(N).
|
||||||
template <typename R, typename Predicate>
|
template <typename R, typename Predicate, typename std::enable_if<!std::is_integral<R>::value_type>::type>
|
||||||
bool is_palindrome(const R& range, Predicate p)
|
bool is_palindrome(const R& range, Predicate p)
|
||||||
{
|
{
|
||||||
return is_palindrome(boost::begin(range), boost::end(range), 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<typename T>
|
|
||||||
struct foobar : std::false_type
|
|
||||||
{ };
|
|
||||||
|
|
||||||
template<typename T = int>
|
/// \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)
|
bool is_palindrome(const char* str)
|
||||||
{
|
{
|
||||||
static_assert(foobar<T>::value, "Using 'is_palindrome' for 'const char*' is dangerous, because result is always false"
|
if(str == nullptr)
|
||||||
"(reason: '\0' in the end of the string). You can use string_view in this case");
|
{
|
||||||
return false;
|
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<typename Predicate>
|
||||||
|
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<typename T>
|
||||||
|
bool is_palindrome (T)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
@ -47,6 +47,7 @@ void test_is_palindrome()
|
|||||||
const int oddPalindrome[] = {1,2,3,2,1};
|
const int oddPalindrome[] = {1,2,3,2,1};
|
||||||
const int evenPalindrome[] = {1,2,2,1};
|
const int evenPalindrome[] = {1,2,2,1};
|
||||||
int evenNonPalindrome[] = {1,4,8,8};
|
int evenNonPalindrome[] = {1,4,8,8};
|
||||||
|
const char* stringNullPtr = nullptr;
|
||||||
|
|
||||||
// Test a default operator==
|
// Test a default operator==
|
||||||
BOOST_CHECK ( ba::is_palindrome(empty));
|
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(empty.begin(), empty.end(), functorComparator()));
|
||||||
BOOST_CHECK (!ba::is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComparator<int>));
|
BOOST_CHECK (!ba::is_palindrome(std::begin(oddNonPalindrome), std::end(oddNonPalindrome), funcComparator<int>));
|
||||||
BOOST_CHECK ( ba::is_palindrome(evenPalindrome, std::equal_to<int>()));
|
BOOST_CHECK ( ba::is_palindrome(evenPalindrome, std::equal_to<int>()));
|
||||||
|
|
||||||
|
//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<char>());
|
||||||
|
BOOST_CHECK ( ba::is_palindrome("abba"));
|
||||||
|
BOOST_CHECK ( ba::is_palindrome("acab"));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( test_main )
|
BOOST_AUTO_TEST_CASE( test_main )
|
||||||
|
Reference in New Issue
Block a user