diff --git a/benchmark/palindrome_benchmark.cpp b/benchmark/palindrome_benchmark.cpp index 4aec403..ce0e2c3 100644 --- a/benchmark/palindrome_benchmark.cpp +++ b/benchmark/palindrome_benchmark.cpp @@ -69,7 +69,8 @@ TEST_CASE("Palindrome benchmarking", "[benchmark][palindrome]") .run( NAMEOF_RAW(raw::is_palindrome).c_str(), [&palindrome]() { - auto const r{raw::is_palindrome(palindrome)}; + auto const r{raw::is_palindrome( + palindrome.data(), palindrome.length())}; ankerl::nanobench::doNotOptimizeAway(r); }) diff --git a/include/forfun/palindrome.hpp b/include/forfun/palindrome.hpp index e26040b..9552686 100644 --- a/include/forfun/palindrome.hpp +++ b/include/forfun/palindrome.hpp @@ -12,21 +12,23 @@ #include #include +#include #include #include +#include namespace forfun::palindrome { namespace raw { -template +template [[clang::no_sanitize("unsigned-integer-overflow")]] [[nodiscard]] -constexpr auto -is_palindrome(std::basic_string_view const s) noexcept -> bool +constexpr auto is_palindrome( + typename std::basic_string_view::const_pointer const s, + typename std::basic_string_view::size_type const length) noexcept + -> bool { - using SizeType = decltype(s)::size_type; - - auto const length{s.length()}; + using SizeType = std::remove_const_t; auto end{length - 1}; auto const mid{length / 2}; @@ -64,7 +66,7 @@ inline auto is_palindrome_ci(std::string_view const s) noexcept -> bool namespace iterator_based { -template +template [[nodiscard]] constexpr auto is_palindrome(std::basic_string_view const s) noexcept -> bool @@ -119,7 +121,7 @@ namespace functional { /// Adapted from original source: /// https://en.cppreference.com/w/cpp/algorithm/equal -template +template [[nodiscard]] constexpr auto is_palindrome(std::basic_string_view const s) noexcept -> bool @@ -135,7 +137,7 @@ namespace bloated { /// Adapted from original source: /// https://en.cppreference.com/w/cpp/algorithm/equal -template +template [[nodiscard]] constexpr auto is_palindrome(std::basic_string_view const s) noexcept -> bool diff --git a/test/palindrome_test.cpp b/test/palindrome_test.cpp index a4c116f..ffbe345 100644 --- a/test/palindrome_test.cpp +++ b/test/palindrome_test.cpp @@ -4,7 +4,9 @@ // SPDX-License-Identifier: MIT +#include #include +#include #include #include @@ -16,16 +18,27 @@ namespace { -[[nodiscard]] inline auto -is_palindrome_wrapper(std::string_view const s) noexcept -> bool +template +[[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) + { + return std::invoke( + std::forward(func), std::forward(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(func), + std::forward(s.data()), + std::forward(s.length())); + } } } // namespace @@ -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), (forfun::palindrome::functional::bloated::is_palindrome), (forfun::palindrome::iterator_based::is_palindrome), @@ -59,7 +72,7 @@ TEMPLATE_TEST_CASE_SIG( CAPTURE(s); - REQUIRE(is_palindrome(s)); + REQUIRE(is_palindrome_test_wrapper(is_palindrome, s)); } SECTION("Negative") @@ -78,7 +91,7 @@ TEMPLATE_TEST_CASE_SIG( CAPTURE(s); - REQUIRE_FALSE(is_palindrome(s)); + REQUIRE_FALSE(is_palindrome_test_wrapper(is_palindrome, s)); } } @@ -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") @@ -130,7 +143,7 @@ TEMPLATE_TEST_CASE_SIG( CAPTURE(s); - REQUIRE_FALSE(is_palindrome(s)); + REQUIRE_FALSE(is_palindrome_test_wrapper(is_palindrome, s)); } } @@ -138,7 +151,7 @@ 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)) @@ -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") @@ -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)); } }