Skip to content

Adding is_palindromic() algo to Boost.Algorithm #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions boost/algorithm/is_palindrome.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
Copyright (c) Alexander Zaitsev <[email protected]>, 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 <iterator>

#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>

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 <typename BidirectionalIterator, typename Predicate>
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 <typename BidirectionalIterator>
bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end)
{
return is_palindrome(begin, end,
std::equal_to<typename std::iterator_traits<BidirectionalIterator>::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 <typename R>
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 <typename R, typename Predicate>
bool is_palindrome(const R& range, Predicate p)
{
return is_palindrome(boost::begin(range), boost::end(range), p);
}

}}

#endif // BOOST_ALGORITHM_is_palindrome_HPP
1 change: 1 addition & 0 deletions libs/algorithm/doc/algorithm.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Thanks to all the people who have reviewed this library and made suggestions for
[include one_of.qbk]
[include is_partitioned.qbk]
[include partition_point.qbk]
[include is_palindrome.qbk]

[xinclude autodoc.xml]

Expand Down
84 changes: 84 additions & 0 deletions libs/algorithm/doc/is_palindrome.qbk
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
[/ 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<typename BidirectionalIterator>
bool is_palindrome ( BidirectionalIterator begin, BidirectionalIterator end );
template<typename BidirectionalIterator, typename Predicate>
bool is_palindrome ( BidirectionalIterator begin, BidirectionalIterator end, Predicate p );
template<typename Range>
bool is_palindrome ( const Range &r );
template<typename Range, typename Predicate>
bool is_palindrome ( const Range &r, Predicate p );
``


[heading Examples]

Given the containers:
const std::list<int> empty,
const std::vector<char> singleElement{'z'},
int oddNonPalindrome[] = {3,2,2},
const int evenPalindrome[] = {1,2,2,1}, 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<int>)) --> false
is_palindrome(evenPalindrome, std::equal_to<int>())) --> true
``

[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).
]
1 change: 1 addition & 0 deletions libs/algorithm/example/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ exe ordered_example : ordered_example.cpp ;
exe clamp_example : clamp_example.cpp ;
exe all_example : all_example.cpp ;
exe search_example : search_example.cpp ;
exe is_palindrome_example : is_palindrome_example.cpp;
94 changes: 94 additions & 0 deletions libs/algorithm/example/is_palindrome_example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
Copyright (c) Alexander Zaitsev <[email protected]>, 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 <vector>
#include <list>
#include <iterator>
#include <functional>
#include <iostream>

#include <boost/algorithm/is_palindrome.hpp>


namespace ba = boost::algorithm;

template <typename T>
bool funcComparator(const T& v1, const T& v2)
{
return v1 == v2;
}

struct functorComparator
{
template <typename T>
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<int> 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<int> 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<bool(int, int)>(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<int>))
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;
}
2 changes: 2 additions & 0 deletions libs/algorithm/test/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,5 @@ run is_partitioned_test1.cpp ;
run partition_copy_test1.cpp ;

run find_if_not_test1.cpp ;

run is_palindrome_test.cpp ;
66 changes: 66 additions & 0 deletions libs/algorithm/test/is_palindrome_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
Copyright (c) Alexander Zaitsev <[email protected]>, 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 <algorithm>
#include <iostream>
#include <list>
#include <vector>

#include <boost/algorithm/is_palindrome.hpp>
#include <boost/test/included/test_exec_monitor.hpp>

namespace ba = boost::algorithm;


template <typename T>
bool funcComparator(const T& v1, const T& v2)
{
return v1 == v2;
}

struct functorComparator
{
template <typename T>
bool operator()(const T& v1, const T& v2) const
{
return v1 == v2;
}
};


static void test_is_palindrome()
{
const std::list<int> empty;
const std::vector<char> singleElement{'z'};
int oddNonPalindrome[] = {3,2,2};
const int evenPalindrome[] = {1,2,2,1};

// 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(evenPalindrome), std::end(evenPalindrome)));

//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<int>));
BOOST_CHECK ( ba::is_palindrome(evenPalindrome, std::equal_to<int>()));

//Only C++14 or newer
//auto lambdaComparator = [](const auto& v1, const auto& v2){ return v1 == v2; };
//BOOST_CHECK ( ba::is_palindrome(singleElement, lambdaComparator));
}

int test_main( int, char * [] )
{
test_is_palindrome();

return 0;
}