Skip to content

Commit

Permalink
Add more is_palindrome implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
oboukli committed Jun 24, 2023
1 parent 85069eb commit d97a567
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 26 deletions.
125 changes: 110 additions & 15 deletions include/forfun/palindrome.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,128 @@

// SPDX-License-Identifier: MIT

/// Problem source:
/// Problem reference:
/// https://en.wikipedia.org/wiki/Palindrome

#ifndef FORFUN_PALINDROME_HPP_
#define FORFUN_PALINDROME_HPP_

#include <algorithm>
#include <cctype>
#include <concepts>
#include <string>

template <typename T = std::string, std::integral Tsize = typename T::size_type>
[[nodiscard]] bool is_palindrome(T const& s) noexcept {
Tsize const len = (s.length()) / Tsize{2};
auto begin = s.cbegin();
auto end = --(s.cend());

for (Tsize i{0}; i < len; ++i) {
if (std::tolower(static_cast<unsigned char>(*begin))
!= std::tolower(static_cast<unsigned char>(*end))) {
#include <cstddef>
#include <string_view>

namespace forfun::palindrome {

namespace raw {

[[nodiscard]] constexpr inline bool
is_palindrome(std::string_view const& s) noexcept {
auto const end{s.length() - 1};
auto const mid{s.length() / 2};

for (std::size_t i{0}; i < mid; ++i) {
if (s[i] != s[end - i]) {
return false;
}
}

return true;
}

[[nodiscard]] constexpr inline bool
is_palindrome_ci(std::string_view const& s) noexcept {
auto const end{s.length() - 1};
auto const mid{s.length() / 2};

++begin;
--end;
for (std::size_t i{0}; i < mid; ++i) {
if (std::tolower(static_cast<unsigned char>(s[i]))
!= std::tolower(static_cast<unsigned char>(s[end - i]))) {
return false;
}
}

return true;
}

} // namespace raw

namespace fast {

[[nodiscard]] constexpr inline bool
is_palindrome(std::string_view const& s) noexcept {
auto upper{s.cend() - 1};
auto const mid{s.cbegin() + (s.length() / 2)};

for (auto lower{s.cbegin()}; lower < mid; ++lower) {
if ((*lower) != (*upper)) {
return false;
}

--upper;
}

return true;
}

[[nodiscard]] constexpr inline bool
is_palindrome_ci(std::string_view const& s) noexcept {
auto upper{s.cend() - 1};
auto const mid{s.cbegin() + (s.length() / 2)};

for (auto lower{s.cbegin()}; lower < mid; ++lower) {
if (std::tolower(static_cast<unsigned char>((*lower)))
!= std::tolower(static_cast<unsigned char>((*upper)))) {
return false;
}

--upper;
}

return true;
}

} // namespace fast

namespace stl_bloated {

/// Adapted from original source:
/// https://en.cppreference.com/w/cpp/algorithm/equal
[[nodiscard]] constexpr inline bool
is_palindrome(std::string_view const& s) noexcept {
return std::equal(
s.cbegin(), std::next(s.cbegin(), s.size() / 2), s.crbegin());
}

namespace {
[[nodiscard]] constexpr inline bool
equal_case_insensitive(char const a, char const b) noexcept {
return std::tolower(static_cast<unsigned char>(a))
== std::tolower(static_cast<unsigned char>(b));
}
} // namespace

[[nodiscard]] constexpr inline bool
is_palindrome_ci(std::string_view const& s) noexcept {
return std::equal(
s.cbegin(), std::next(s.cbegin(), s.size() / 2), s.crbegin(),
equal_case_insensitive);
}

} // namespace stl_bloated

namespace stl_fast {

/// Adapted from original source:
/// https://en.cppreference.com/w/cpp/algorithm/equal
[[nodiscard]] constexpr inline bool
is_palindrome(std::string_view const& s) noexcept {
auto const begin{s.cbegin()};
return std::equal(begin, begin + (s.size() / 2), s.crbegin());
}

} // namespace stl_fast

} // namespace forfun::palindrome

#endif // FORFUN_PALINDROME_HPP_
46 changes: 35 additions & 11 deletions test/palindrome.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,78 @@
#include "forfun/palindrome.hpp"

#include <cassert>
#include <string>
#include <string_view>

int main() {
using is_palindrome_func_t = std::function<bool(std::string_view const&)>;

void test_palindrome(is_palindrome_func_t is_palindrome_func) {
using namespace std::string_literals;

{
bool const f_palindrome{is_palindrome(""s)};
bool const f_palindrome{is_palindrome_func(""s)};
assert(f_palindrome);
}

{
bool const f_palindrome{is_palindrome("\xb8Y\xb8"s)};
bool const f_palindrome{is_palindrome_func("\xb8Y\xb8"s)};
assert(f_palindrome);
}

{
bool const f_palindrome{is_palindrome("aa"s)};
bool const f_palindrome{is_palindrome_func("aa"s)};
assert(f_palindrome);
}

{
bool const f_palindrome{is_palindrome("aba"s)};
bool const f_palindrome{is_palindrome_func("aba"s)};
assert(f_palindrome);
}

{
bool const f_palindrome{is_palindrome("a b a"s)};
bool const f_palindrome{is_palindrome_func("a b a"s)};
assert(f_palindrome);
}

{
bool const f_palindrome{is_palindrome("101"s)};
bool const f_palindrome{is_palindrome_func("101"s)};
assert(f_palindrome);
}

{
bool const f_palindrome{is_palindrome("Aa"s)};
bool const f_palindrome{is_palindrome_func("tattarrattat"s)};
assert(f_palindrome);
}

{
bool const f_palindrome{is_palindrome("Aab4'{x{'4BaA"s)};
bool const f_palindrome{is_palindrome_func("dummy"s)};
assert(f_palindrome == false);
}
}

void test_palindrome_ci(is_palindrome_func_t is_palindrome_func) {
using namespace std::string_literals;

{
bool const f_palindrome{is_palindrome_func("Aa"s)};
assert(f_palindrome);
}

{
bool const f_palindrome{is_palindrome("dummy"s)};
assert(f_palindrome == false);
bool const f_palindrome{is_palindrome_func("Aab4'{x{'4BaA"s)};
assert(f_palindrome);
}
}

int main() {
test_palindrome(forfun::palindrome::raw::is_palindrome);
test_palindrome(forfun::palindrome::fast::is_palindrome);
test_palindrome(forfun::palindrome::stl_bloated::is_palindrome);
test_palindrome(forfun::palindrome::stl_fast::is_palindrome);

test_palindrome_ci(forfun::palindrome::raw::is_palindrome_ci);
test_palindrome_ci(forfun::palindrome::fast::is_palindrome_ci);
test_palindrome_ci(forfun::palindrome::stl_bloated::is_palindrome_ci);

return 0;
}

0 comments on commit d97a567

Please sign in to comment.