diff --git a/include/forfun/palindrome.hpp b/include/forfun/palindrome.hpp index b8f419a..b759276 100644 --- a/include/forfun/palindrome.hpp +++ b/include/forfun/palindrome.hpp @@ -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 #include -#include -#include - -template -[[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(*begin)) - != std::tolower(static_cast(*end))) { +#include +#include + +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(s[i])) + != std::tolower(static_cast(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((*lower))) + != std::tolower(static_cast((*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(a)) + == std::tolower(static_cast(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_ diff --git a/test/palindrome.cpp b/test/palindrome.cpp index 3ae124f..a7826c2 100644 --- a/test/palindrome.cpp +++ b/test/palindrome.cpp @@ -7,54 +7,78 @@ #include "forfun/palindrome.hpp" #include +#include +#include -int main() { +using is_palindrome_func_t = std::function; + +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; }