Skip to content

Commit

Permalink
refactor: Update palindrome interface
Browse files Browse the repository at this point in the history
  • Loading branch information
oboukli committed Jul 1, 2024
1 parent 1d16c94 commit d6b55cc
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 29 deletions.
3 changes: 2 additions & 1 deletion benchmark/palindrome_benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ TEST_CASE("Palindrome benchmarking", "[benchmark][palindrome]")
.run(
NAMEOF_RAW(raw::is_palindrome<char>).c_str(),
[&palindrome]() {
auto const r{raw::is_palindrome(palindrome)};
auto const r{raw::is_palindrome<char>(
palindrome.data(), palindrome.length())};

ankerl::nanobench::doNotOptimizeAway(r);
})
Expand Down
20 changes: 11 additions & 9 deletions include/forfun/palindrome.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,23 @@

#include <algorithm>
#include <cctype>
#include <concepts>
#include <iterator>
#include <string_view>
#include <type_traits>

namespace forfun::palindrome {

namespace raw {

template <typename CharT>
template <std::integral CharT>
[[clang::no_sanitize("unsigned-integer-overflow")]] [[nodiscard]]
constexpr auto
is_palindrome(std::basic_string_view<CharT> const s) noexcept -> bool
constexpr auto is_palindrome(
typename std::basic_string_view<CharT>::const_pointer const s,
typename std::basic_string_view<CharT>::size_type const length) noexcept
-> bool
{
using SizeType = decltype(s)::size_type;

auto const length{s.length()};
using SizeType = std::remove_const_t<decltype(length)>;

auto end{length - 1};
auto const mid{length / 2};
Expand Down Expand Up @@ -64,7 +66,7 @@ inline auto is_palindrome_ci(std::string_view const s) noexcept -> bool

namespace iterator_based {

template <typename CharT>
template <std::integral CharT>
[[nodiscard]]
constexpr auto
is_palindrome(std::basic_string_view<CharT> const s) noexcept -> bool
Expand Down Expand Up @@ -119,7 +121,7 @@ namespace functional {

/// Adapted from original source:
/// https://en.cppreference.com/w/cpp/algorithm/equal
template <typename CharT>
template <std::integral CharT>
[[nodiscard]]
constexpr auto
is_palindrome(std::basic_string_view<CharT> const s) noexcept -> bool
Expand All @@ -135,7 +137,7 @@ namespace bloated {

/// Adapted from original source:
/// https://en.cppreference.com/w/cpp/algorithm/equal
template <typename CharT>
template <std::integral CharT>
[[nodiscard]]
constexpr auto
is_palindrome(std::basic_string_view<CharT> const s) noexcept -> bool
Expand Down
51 changes: 32 additions & 19 deletions test/palindrome_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

// SPDX-License-Identifier: MIT

#include <functional>
#include <string_view>
#include <utility>

#include <catch2/catch_message.hpp>
#include <catch2/catch_template_test_macros.hpp>
Expand All @@ -16,16 +18,27 @@

namespace {

[[nodiscard]] inline auto
is_palindrome_wrapper(std::string_view const s) noexcept -> bool
template <typename Func, typename BasicStringView>
[[nodiscard]] constexpr auto is_palindrome_test_wrapper(
Func&& func, BasicStringView const s) noexcept -> bool
{
return ::is_palindrome(s.data(), s.size()) != 0;
}

[[nodiscard]] inline auto
is_palindrome_ci_wrapper(std::string_view const s) noexcept -> bool
{
return ::is_palindrome_ci(s.data(), s.size()) != 0;
if constexpr (std::is_invocable_v<decltype(func), decltype(s)>)
{
return std::invoke(
std::forward<decltype(func)>(func), std::forward<decltype(s)>(s));
}
// clang-format off
else if constexpr (std::is_invocable_v<
decltype(func),
typename decltype(s)::pointer,
typename decltype(s)::size_type>)
// clang-format on
{
return std::invoke(
std::forward<decltype(func)>(func),
std::forward<decltype(s.data())>(s.data()),
std::forward<decltype(s.length())>(s.length()));
}
}

} // namespace
Expand All @@ -36,7 +49,7 @@ TEMPLATE_TEST_CASE_SIG(
"Case-sensitive palindrome check",
"[palindrome]",
((auto is_palindrome), is_palindrome),
(is_palindrome_wrapper),
(::is_palindrome),
(forfun::palindrome::functional::is_palindrome<char>),
(forfun::palindrome::functional::bloated::is_palindrome<char>),
(forfun::palindrome::iterator_based::is_palindrome<char>),
Expand All @@ -59,7 +72,7 @@ TEMPLATE_TEST_CASE_SIG(

CAPTURE(s);

REQUIRE(is_palindrome(s));
REQUIRE(is_palindrome_test_wrapper(is_palindrome, s));
}

SECTION("Negative")
Expand All @@ -78,7 +91,7 @@ TEMPLATE_TEST_CASE_SIG(

CAPTURE(s);

REQUIRE_FALSE(is_palindrome(s));
REQUIRE_FALSE(is_palindrome_test_wrapper(is_palindrome, s));
}
}

Expand All @@ -104,13 +117,13 @@ TEMPLATE_TEST_CASE_SIG(
U"ABBA"sv,
U"Xyz 8 zyX"sv,
U"step on no pets"sv,
U"باب"sv,
U"亞細亞"sv,
U"باب"sv, // Door, in Arabic
U"亞細亞"sv, // Asia, in Chinese
U"19/9/91"sv)};

CAPTURE(s);

REQUIRE(is_palindrome(s));
REQUIRE(is_palindrome_test_wrapper(is_palindrome, s));
}

SECTION("Negative")
Expand All @@ -130,15 +143,15 @@ TEMPLATE_TEST_CASE_SIG(

CAPTURE(s);

REQUIRE_FALSE(is_palindrome(s));
REQUIRE_FALSE(is_palindrome_test_wrapper(is_palindrome, s));
}
}

TEMPLATE_TEST_CASE_SIG(
"Case-insensitive palindrome check",
"[palindrome]",
((auto is_palindrome_ci), is_palindrome_ci),
(is_palindrome_ci_wrapper),
(::is_palindrome_ci),
(forfun::palindrome::functional::bloated::is_palindrome_ci),
(forfun::palindrome::iterator_based::is_palindrome_ci),
(forfun::palindrome::raw::is_palindrome_ci))
Expand All @@ -164,7 +177,7 @@ TEMPLATE_TEST_CASE_SIG(

CAPTURE(s);

REQUIRE(is_palindrome_ci(s));
REQUIRE(is_palindrome_test_wrapper(is_palindrome_ci, s));
}

SECTION("Negative")
Expand All @@ -180,6 +193,6 @@ TEMPLATE_TEST_CASE_SIG(

CAPTURE(s);

REQUIRE_FALSE(is_palindrome_ci(s));
REQUIRE_FALSE(is_palindrome_test_wrapper(is_palindrome_ci, s));
}
}

0 comments on commit d6b55cc

Please sign in to comment.