basedOpinionated utility library |
git clone git://git.dimitrijedobrota.com/based.git |
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |
commit | ce9865aca018985b89bf4f640e42744805df879a |
parent | 630d79b6b927b251d8d4b2bd975cf8d2533bcc49 |
author | Dimitrije Dobrota < mail@dimitrijedobrota.com > |
date | Thu, 1 May 2025 18:29:12 +0200 |
Functional curry with tests
M | include/based/functional.hpp | | | +++++++++++++++++++++++++++++++++++++++++ |
M | test/CMakeLists.txt | | | ++++ |
A | test/source/curry_test.cpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 115 insertions(+), 0 deletions(-)
diff --git a/ include/based/functional.hpp b/ include/based/functional.hpp
@@ -7,6 +7,47 @@
namespace based
{
template<typename Function, typename... CapturedArgs>
class curried
{
template<typename FFunction, typename... FCapturedArgs>
friend class curried;
Function m_function;
std::tuple<CapturedArgs...> m_captured;
curried(Function function, std::tuple<CapturedArgs...> args)
: m_function(function)
, m_captured(std::move(args))
{
}
public:
curried(Function function, CapturedArgs&&... args) // NOLINT explicit
: m_function(function)
, m_captured(std::forward<CapturedArgs>(args)...)
{
}
template<typename... NewArgs>
auto operator()(NewArgs&&... args) const
{
auto all_args = std::tuple_cat(
m_captured, std::make_tuple(std::forward<NewArgs>(args)...)
);
if constexpr (std::is_invocable_v<Function, CapturedArgs..., NewArgs...>) {
return std::apply(m_function, std::move(all_args));
} else {
return curried<Function, CapturedArgs..., NewArgs...> {
m_function, std::move(all_args)
};
}
}
};
/* ----- Relation modifiers ----- */
template<typename T, Relation<T> Rel>
auto complement(Rel rel)
{
diff --git a/ test/CMakeLists.txt b/ test/CMakeLists.txt
@@ -74,6 +74,10 @@
add_test(buffer_test)
add_test(function_test)
add_test(scopeguard_test)
# ----- Functional -----
add_test(curry_test)
# ---- End-of-file commands ----
add_folders(Test)
diff --git a/ test/source/curry_test.cpp b/ test/source/curry_test.cpp
@@ -0,0 +1,70 @@
#include <catch2/catch_test_macros.hpp>
#include "based/functional.hpp"
// NOLINTBEGIN congnitive-complexity magic-number
auto free_func(int a, double b, int c, double d)
{
return static_cast<int>(a + b + c + d);
};
TEST_CASE("free function", "[functional/curry]")
{
const based::curried curried = free_func;
REQUIRE(curried(1)(2.0)(3)(4.0) == 10);
REQUIRE(curried(1)(2.0, 3)(4.0) == 10);
REQUIRE(curried(1)(2.0, 3, 4.0) == 10);
REQUIRE(curried(1, 2.0)(3, 4.0) == 10);
REQUIRE(curried(1, 2.0, 3)(4.0) == 10);
REQUIRE(curried(1, 2.0, 3, 4.0) == 10);
}
TEST_CASE("lambda", "[functional/curry]")
{
const based::curried curried = [](int a, double b, int c, double d)
{
return static_cast<int>(a + b + c + d);
};
REQUIRE(curried(1)(2.0)(3)(4.0) == 10);
REQUIRE(curried(1)(2.0)(3, 4.0) == 10);
REQUIRE(curried(1)(2.0, 3)(4.0) == 10);
REQUIRE(curried(1)(2.0, 3, 4.0) == 10);
REQUIRE(curried(1, 2.0)(3)(4.0) == 10);
REQUIRE(curried(1, 2.0)(3, 4.0) == 10);
REQUIRE(curried(1, 2.0, 3)(4.0) == 10);
REQUIRE(curried(1, 2.0, 3, 4.0) == 10);
}
TEST_CASE("member function", "[functional/curry]")
{
struct test
{
auto func(int a, double b, int c, double d) const
{
return static_cast<int>(a + b + c + d);
}
};
const based::curried curried = &test::func;
test t;
REQUIRE(curried(std::ref(t))(1)(2.0)(3)(4.0) == 10);
REQUIRE(curried(std::ref(t))(1)(2.0)(3, 4.0) == 10);
REQUIRE(curried(std::ref(t))(1)(2.0, 3)(4.0) == 10);
REQUIRE(curried(std::ref(t))(1)(2.0, 3, 4.0) == 10);
REQUIRE(curried(std::ref(t))(1, 2.0)(3)(4.0) == 10);
REQUIRE(curried(std::ref(t))(1, 2.0)(3, 4.0) == 10);
REQUIRE(curried(std::ref(t))(1, 2.0, 3)(4.0) == 10);
REQUIRE(curried(std::ref(t))(1, 2.0, 3, 4.0) == 10);
REQUIRE(curried(std::ref(t), 1)(2.0)(3)(4.0) == 10);
REQUIRE(curried(std::ref(t), 1)(2.0, 3)(4.0) == 10);
REQUIRE(curried(std::ref(t), 1, 2.0)(3)(4.0) == 10);
REQUIRE(curried(std::ref(t), 1, 2.0, 3)(4.0) == 10);
REQUIRE(curried(std::ref(t), 1, 2.0, 3, 4.0) == 10);
REQUIRE(curried(std::ref(t), 1, 2.0, 3, 4.0) == 10);
}
// NOLINTEND congnitive-complexity magic-number