From fe03162e75dece5a8106762a882869750d1682d4 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 11 Dec 2020 04:18:04 +0700 Subject: [PATCH] rewrite tests and simplify curry impl --- headers/kari.hpp/kari.hpp | 47 ++-- untests/kari_ext_tests.cpp | 94 ++++++++ untests/kari_tests.cpp | 461 +++++++++++++++++++++++++++++++++++++ 3 files changed, 572 insertions(+), 30 deletions(-) diff --git a/headers/kari.hpp/kari.hpp b/headers/kari.hpp/kari.hpp index 8408ba1..2d9047a 100644 --- a/headers/kari.hpp/kari.hpp +++ b/headers/kari.hpp/kari.hpp @@ -12,8 +12,8 @@ namespace kari_hpp { - template < typename F, typename... Args > - struct curry_t; + template < typename F, typename... As > + class curry_t; namespace impl { @@ -21,8 +21,8 @@ namespace kari_hpp struct is_curried_impl : std::false_type {}; - template < typename F, typename... Args > - struct is_curried_impl> + template < typename F, typename... As > + struct is_curried_impl> : std::true_type {}; } @@ -44,40 +44,31 @@ namespace kari_hpp::detail return curry_t, Args...>(std::forward(f), std::move(args)); } } - - template < typename F > - constexpr auto curry_or_apply(F&& f) { - return curry_or_apply(std::forward(f), std::make_tuple()); - } } namespace kari_hpp { template < typename F, typename... Args > - struct curry_t final { - template < typename U > - constexpr curry_t(U&& u, std::tuple&& args) - : f_(std::forward(u)) + class curry_t final { + constexpr curry_t(F f, std::tuple args) + : f_(std::move(f)) , args_(std::move(args)) {} - // recurry + template < typename U, typename... As > + friend class curry_t; - constexpr auto recurry() && { + template < typename U, typename... As > + friend constexpr auto detail::curry_or_apply(U&&, std::tuple&&); + public: + constexpr curry_t(F f) + : f_(std::move(f)) {} + + constexpr auto operator()() && { return detail::curry_or_apply( std::move(f_), std::move(args_)); } - constexpr auto recurry() const & { - return std::move(curry_t(*this)).recurry(); - } - - // operator(As&&...) - - constexpr auto operator()() && { - return std::move(*this).template recurry<0>(); - } - template < typename A > constexpr auto operator()(A&& a) && { return detail::curry_or_apply( @@ -104,16 +95,12 @@ namespace kari_hpp namespace kari_hpp { - // - // curry - // - template < typename F > constexpr auto curry(F&& f) { if constexpr ( is_curried_v> ) { return std::forward(f); } else { - return detail::curry_or_apply(std::forward(f)); + return detail::curry_or_apply(std::forward(f), {}); } } diff --git a/untests/kari_ext_tests.cpp b/untests/kari_ext_tests.cpp index c4ba322..4cf04da 100644 --- a/untests/kari_ext_tests.cpp +++ b/untests/kari_ext_tests.cpp @@ -10,4 +10,98 @@ using namespace kari_hpp; TEST_CASE("kari_ext") { + struct box final { + int v; + constexpr box(int v): v(v) {} + }; + + SUBCASE("fid") { + STATIC_REQUIRE(fid(box(10)).v == 10); + } + + SUBCASE("fconst") { + STATIC_REQUIRE(fconst(box(10), 20).v == 10); + { + constexpr auto f = fconst(box(10)); + STATIC_REQUIRE(f(20).v == 10); + } + } + + SUBCASE("fflip") { + using namespace underscore; + STATIC_REQUIRE(fflip(_ - _)(10, 20) == 10); + } + + SUBCASE("fpipe") { + using namespace underscore; + STATIC_REQUIRE(fpipe(_+2, _*2, 4) == 12); + STATIC_REQUIRE(((_+2) | (_*2) | 4) == 12); + STATIC_REQUIRE((4 | (_+2) | (_*2)) == 12); + } + + SUBCASE("fcompose") { + using namespace underscore; + STATIC_REQUIRE(fcompose(_+2, _*2, 4) == 10); + STATIC_REQUIRE((_+2) * (_*2) * 4 == 10); + STATIC_REQUIRE(4 * (_+2) * (_*2) == 12); + { + constexpr auto s3 = [](int v1, int v2, int v3){ + return v1 + v2 + v3; + }; + constexpr auto c = curry(s3) * (_*2) * 10 * 20 * 30; + STATIC_REQUIRE(c == 70); + } + { + // (. (+2)) (*2) $ 10 == 24 + constexpr int i = fflip(fcompose)(_+2, _*2, 10); + constexpr int j = (_*(_+2))(_*2)(10); + STATIC_REQUIRE(i == 24); + STATIC_REQUIRE(j == 24); + } + { + // ((+2) .) (*2) $ 10 == 24 + constexpr int i = fcompose(_+2)(_*2, 10); + constexpr int j = ((_+2) * _)(_*2)(10); + STATIC_REQUIRE(i == 22); + STATIC_REQUIRE(j == 22); + } + } + + SUBCASE("underscore") { + using namespace underscore; + STATIC_REQUIRE((-_)(40) == -40); + + STATIC_REQUIRE((_ + 40)(2) == 42); + STATIC_REQUIRE((_ - 2)(44) == 42); + STATIC_REQUIRE((_ * 21)(2) == 42); + STATIC_REQUIRE((_ / 2)(84) == 42); + STATIC_REQUIRE((_ % 100)(142) == 42); + + STATIC_REQUIRE((_ == 42)(42)); + STATIC_REQUIRE((_ != 42)(40)); + STATIC_REQUIRE_FALSE((_ == 42)(40)); + STATIC_REQUIRE_FALSE((_ != 42)(42)); + + STATIC_REQUIRE((40 + _)(2) == 42); + STATIC_REQUIRE((44 - _)(2) == 42); + STATIC_REQUIRE((21 * _)(2) == 42); + STATIC_REQUIRE((84 / _)(2) == 42); + STATIC_REQUIRE((142 % _)(100) == 42); + + STATIC_REQUIRE((42 == _)(42)); + STATIC_REQUIRE((42 != _)(40)); + STATIC_REQUIRE_FALSE((42 == _)(40)); + STATIC_REQUIRE_FALSE((42 != _)(42)); + + STATIC_REQUIRE((_ + _)(40,2) == 42); + STATIC_REQUIRE((_ - _)(44,2) == 42); + STATIC_REQUIRE((_ * _)(21,2) == 42); + STATIC_REQUIRE((_ / _)(84,2) == 42); + STATIC_REQUIRE((_ % _)(142,100) == 42); + + STATIC_REQUIRE((_ == _)(42,42)); + STATIC_REQUIRE((_ != _)(42,40)); + STATIC_REQUIRE_FALSE((_ == _)(42,40)); + STATIC_REQUIRE_FALSE((_ != _)(42,42)); + } } diff --git a/untests/kari_tests.cpp b/untests/kari_tests.cpp index 3c10455..68ffce8 100644 --- a/untests/kari_tests.cpp +++ b/untests/kari_tests.cpp @@ -7,7 +7,468 @@ #include #include "doctest/doctest.hpp" +#include + using namespace kari_hpp; TEST_CASE("kari") { + SUBCASE("ctor") { + { + constexpr curry_t f = [](){ + return 1; + }; + + STATIC_REQUIRE(f() == 1); + } + { + constexpr curry_t f = [](auto a){ + return a; + }; + + STATIC_REQUIRE(f(1) == 1); + STATIC_REQUIRE(f()(1) == 1); + } + { + constexpr curry_t f = [](auto a, auto b){ + return a + b; + }; + + STATIC_REQUIRE(f(1,2) == 3); + STATIC_REQUIRE(f()(1,2) == 3); + + STATIC_REQUIRE(f(1)(2) == 3); + STATIC_REQUIRE(f()(1)(2) == 3); + STATIC_REQUIRE(f(1)()(2) == 3); + STATIC_REQUIRE(f()(1)()(2) == 3); + } + { + constexpr curry_t f = [](auto a, auto b, auto c){ + return a + b + c; + }; + + STATIC_REQUIRE(f(1,2,3) == 6); + STATIC_REQUIRE(f()(1,2,3) == 6); + + STATIC_REQUIRE(f(1)(2,3) == 6); + STATIC_REQUIRE(f()(1)(2,3) == 6); + STATIC_REQUIRE(f(1)()(2,3) == 6); + STATIC_REQUIRE(f()(1)()(2,3) == 6); + + STATIC_REQUIRE(f(1,2)(3) == 6); + STATIC_REQUIRE(f()(1,2)(3) == 6); + STATIC_REQUIRE(f(1,2)()(3) == 6); + STATIC_REQUIRE(f()(1,2)()(3) == 6); + + STATIC_REQUIRE(f(1)(2)(3) == 6); + STATIC_REQUIRE(f()(1)(2)(3) == 6); + STATIC_REQUIRE(f(1)()(2)(3) == 6); + STATIC_REQUIRE(f(1)(2)()(3) == 6); + STATIC_REQUIRE(f()(1)()(2)(3) == 6); + STATIC_REQUIRE(f(1)()(2)()(3) == 6); + STATIC_REQUIRE(f()(1)()(2)()(3) == 6); + } + } + + SUBCASE("nested ctor") { + { + constexpr auto f = curry_t([](auto a){ + return curry_t([a](auto b, auto c){ + return a + b + c; + }); + }); + + STATIC_REQUIRE(f(1,2,3) == 6); + STATIC_REQUIRE(f()(1,2,3) == 6); + + STATIC_REQUIRE(f(1)(2,3) == 6); + STATIC_REQUIRE(f()(1)(2,3) == 6); + STATIC_REQUIRE(f(1)()(2,3) == 6); + STATIC_REQUIRE(f()(1)()(2,3) == 6); + + STATIC_REQUIRE(f(1,2)(3) == 6); + STATIC_REQUIRE(f()(1,2)(3) == 6); + STATIC_REQUIRE(f(1,2)()(3) == 6); + STATIC_REQUIRE(f()(1,2)()(3) == 6); + + STATIC_REQUIRE(f(1)(2)(3) == 6); + STATIC_REQUIRE(f()(1)(2)(3) == 6); + STATIC_REQUIRE(f(1)()(2)(3) == 6); + STATIC_REQUIRE(f(1)(2)()(3) == 6); + STATIC_REQUIRE(f()(1)()(2)(3) == 6); + STATIC_REQUIRE(f(1)()(2)()(3) == 6); + STATIC_REQUIRE(f()(1)()(2)()(3) == 6); + } + { + constexpr auto f = curry_t([](auto a, auto b){ + return curry_t([a, b](auto c){ + return a + b + c; + }); + }); + + STATIC_REQUIRE(f(1,2,3) == 6); + STATIC_REQUIRE(f()(1,2,3) == 6); + + STATIC_REQUIRE(f(1)(2,3) == 6); + STATIC_REQUIRE(f()(1)(2,3) == 6); + STATIC_REQUIRE(f(1)()(2,3) == 6); + STATIC_REQUIRE(f()(1)()(2,3) == 6); + + STATIC_REQUIRE(f(1,2)(3) == 6); + STATIC_REQUIRE(f()(1,2)(3) == 6); + STATIC_REQUIRE(f(1,2)()(3) == 6); + STATIC_REQUIRE(f()(1,2)()(3) == 6); + + STATIC_REQUIRE(f(1)(2)(3) == 6); + STATIC_REQUIRE(f()(1)(2)(3) == 6); + STATIC_REQUIRE(f(1)()(2)(3) == 6); + STATIC_REQUIRE(f(1)(2)()(3) == 6); + STATIC_REQUIRE(f()(1)()(2)(3) == 6); + STATIC_REQUIRE(f(1)()(2)()(3) == 6); + STATIC_REQUIRE(f()(1)()(2)()(3) == 6); + } + } + + SUBCASE("curry") { + { + constexpr auto f = curry([](){ + return 1; + }); + + STATIC_REQUIRE(f == 1); + } + { + { + constexpr auto f = curry([](auto a){ + return a; + }); + + STATIC_REQUIRE(f(1) == 1); + STATIC_REQUIRE(f()(1) == 1); + } + { + constexpr auto f = curry([](auto a){ + return a; + }, 1); + + STATIC_REQUIRE(f == 1); + } + } + { + { + constexpr auto f = curry([](auto a, auto b){ + return a + b; + }); + + STATIC_REQUIRE(f(1,2) == 3); + STATIC_REQUIRE(f()(1,2) == 3); + + STATIC_REQUIRE(f(1)(2) == 3); + STATIC_REQUIRE(f()(1)(2) == 3); + STATIC_REQUIRE(f(1)()(2) == 3); + STATIC_REQUIRE(f()(1)()(2) == 3); + } + { + constexpr auto f = curry([](auto a, auto b){ + return a + b; + }, 1); + + STATIC_REQUIRE(f(2) == 3); + STATIC_REQUIRE(f()(2) == 3); + } + { + constexpr auto f = curry([](auto a, auto b){ + return a + b; + }, 1, 2); + + STATIC_REQUIRE(f == 3); + } + } + { + { + constexpr auto f = curry([](auto a, auto b, auto c){ + return a + b + c; + }); + + STATIC_REQUIRE(f(1,2,3) == 6); + STATIC_REQUIRE(f()(1,2,3) == 6); + + STATIC_REQUIRE(f(1)(2,3) == 6); + STATIC_REQUIRE(f()(1)(2,3) == 6); + STATIC_REQUIRE(f(1)()(2,3) == 6); + STATIC_REQUIRE(f()(1)()(2,3) == 6); + + STATIC_REQUIRE(f(1,2)(3) == 6); + STATIC_REQUIRE(f()(1,2)(3) == 6); + STATIC_REQUIRE(f(1,2)()(3) == 6); + STATIC_REQUIRE(f()(1,2)()(3) == 6); + + STATIC_REQUIRE(f(1)(2)(3) == 6); + STATIC_REQUIRE(f()(1)(2)(3) == 6); + STATIC_REQUIRE(f(1)()(2)(3) == 6); + STATIC_REQUIRE(f(1)(2)()(3) == 6); + STATIC_REQUIRE(f()(1)()(2)(3) == 6); + STATIC_REQUIRE(f(1)()(2)()(3) == 6); + STATIC_REQUIRE(f()(1)()(2)()(3) == 6); + } + { + constexpr auto f = curry([](auto a, auto b, auto c){ + return a + b + c; + }, 1); + + STATIC_REQUIRE(f(2,3) == 6); + STATIC_REQUIRE(f()(2,3) == 6); + + STATIC_REQUIRE(f(2)(3) == 6); + STATIC_REQUIRE(f()(2)(3) == 6); + STATIC_REQUIRE(f(2)()(3) == 6); + STATIC_REQUIRE(f()(2)()(3) == 6); + } + { + constexpr auto f = curry([](auto a, auto b, auto c){ + return a + b + c; + }, 1, 2); + + STATIC_REQUIRE(f(3) == 6); + STATIC_REQUIRE(f()(3) == 6); + } + { + constexpr auto f = curry([](auto a, auto b, auto c){ + return a + b + c; + }, 1, 2, 3); + + STATIC_REQUIRE(f == 6); + } + } + } + + SUBCASE("nested curry") { + { + constexpr auto f = curry([](auto a){ + return curry([a](auto b, auto c){ + return a + b + c; + }); + }); + + STATIC_REQUIRE(f(1,2,3) == 6); + STATIC_REQUIRE(f()(1,2,3) == 6); + + STATIC_REQUIRE(f(1)(2,3) == 6); + STATIC_REQUIRE(f()(1)(2,3) == 6); + STATIC_REQUIRE(f(1)()(2,3) == 6); + STATIC_REQUIRE(f()(1)()(2,3) == 6); + + STATIC_REQUIRE(f(1,2)(3) == 6); + STATIC_REQUIRE(f()(1,2)(3) == 6); + STATIC_REQUIRE(f(1,2)()(3) == 6); + STATIC_REQUIRE(f()(1,2)()(3) == 6); + + STATIC_REQUIRE(f(1)(2)(3) == 6); + STATIC_REQUIRE(f()(1)(2)(3) == 6); + STATIC_REQUIRE(f(1)()(2)(3) == 6); + STATIC_REQUIRE(f(1)(2)()(3) == 6); + STATIC_REQUIRE(f()(1)()(2)(3) == 6); + STATIC_REQUIRE(f(1)()(2)()(3) == 6); + STATIC_REQUIRE(f()(1)()(2)()(3) == 6); + } + { + constexpr auto f = curry([](auto a, auto b){ + return curry([a, b](auto c){ + return a + b + c; + }); + }); + + STATIC_REQUIRE(f(1,2,3) == 6); + STATIC_REQUIRE(f()(1,2,3) == 6); + + STATIC_REQUIRE(f(1)(2,3) == 6); + STATIC_REQUIRE(f()(1)(2,3) == 6); + STATIC_REQUIRE(f(1)()(2,3) == 6); + STATIC_REQUIRE(f()(1)()(2,3) == 6); + + STATIC_REQUIRE(f(1,2)(3) == 6); + STATIC_REQUIRE(f()(1,2)(3) == 6); + STATIC_REQUIRE(f(1,2)()(3) == 6); + STATIC_REQUIRE(f()(1,2)()(3) == 6); + + STATIC_REQUIRE(f(1)(2)(3) == 6); + STATIC_REQUIRE(f()(1)(2)(3) == 6); + STATIC_REQUIRE(f(1)()(2)(3) == 6); + STATIC_REQUIRE(f(1)(2)()(3) == 6); + STATIC_REQUIRE(f()(1)()(2)(3) == 6); + STATIC_REQUIRE(f(1)()(2)()(3) == 6); + STATIC_REQUIRE(f()(1)()(2)()(3) == 6); + } + } + + SUBCASE("member functions ctor") { + struct box final { + int v_; + + constexpr box(int v) + : v_(v) {} + + constexpr auto add_v(int add) { + v_ += add; + return v_; + } + + constexpr int get_v() const { + return v_; + } + }; + { + constexpr auto get_v = curry_t(&box::get_v); + constexpr auto add_v = curry_t(&box::add_v); + + STATIC_REQUIRE(get_v(box(1)) == 1); + STATIC_REQUIRE(add_v(box(1), 2) == 3); + } + { + constexpr auto get_v = curry_t(&box::get_v); + constexpr auto add_v = curry_t(&box::add_v); + { + box b{1}; + REQUIRE(add_v(&b, 2) == 3); + REQUIRE(get_v(&b) == 3); + } + { + box b{1}; + REQUIRE(add_v(std::ref(b), 2) == 3); + REQUIRE(get_v(std::cref(b)) == 3); + } + } + } + + SUBCASE("members functions curry") { + struct box final { + int v_; + + constexpr box(int v) + : v_(v) {} + + constexpr auto add_v(int add) { + v_ += add; + return v_; + } + + constexpr int get_v() const { + return v_; + } + }; + { + constexpr auto get_v = curry(&box::get_v); + constexpr auto add_v = curry(&box::add_v); + + STATIC_REQUIRE(get_v(box(1)) == 1); + STATIC_REQUIRE(add_v(box(1), 2) == 3); + + { + box b{1}; + REQUIRE(add_v(std::ref(b), 2) == 3); + REQUIRE(get_v(std::cref(b)) == 3); + REQUIRE(add_v(std::ref(b), 2) == 5); + REQUIRE(get_v(std::cref(b)) == 5); + } + { + box b{1}; + REQUIRE(add_v(std::ref(b), 2) == 3); + REQUIRE(get_v(std::cref(b)) == 3); + } + } + { + box b{1}; + const int get_v = curry(&box::get_v, std::cref(b)); + const auto add_v = curry(&box::add_v, std::ref(b)); + + REQUIRE(get_v == 1); + REQUIRE(add_v(2) == 3); + REQUIRE(b.get_v() == 3); + REQUIRE(add_v(2) == 5); + REQUIRE(b.get_v() == 5); + } + { + box b{1}; + const auto add_v = curry(&box::add_v, std::ref(b), 2); + + REQUIRE(add_v == 3); + REQUIRE(b.get_v() == 3); + } + } + + SUBCASE("members objects ctor") { + struct box final { + int v_; + constexpr box(int v) + : v_(v) {} + }; + { + constexpr auto f = curry_t(&box::v_); + STATIC_REQUIRE(f(box(1)) == 1); + } + { + constexpr auto f = curry_t(&box::v_); + box b{1}; + REQUIRE(f(b) == 1); + REQUIRE(f(&b) == 1); + REQUIRE(f(std::cref(b)) == 1); + } + } + + SUBCASE("members objects curry") { + struct box final { + int v_; + constexpr box(int v) + : v_(v) {} + }; + { + constexpr auto f = curry(&box::v_); + STATIC_REQUIRE(f(box(1)) == 1); + } + { + constexpr auto f = curry(&box::v_, box(1)); + STATIC_REQUIRE(f == 1); + } + { + const box b{1}; + const auto f = curry(&box::v_, b); + REQUIRE(f == 1); + } + } + + SUBCASE("ref forwarding") { + { + int i = 42; + const int& g = curry([](int& v, int){ + return std::ref(v); + }, std::ref(i), 0); + REQUIRE(&i == &g); + } + { + const int i = 42; + const int& g = curry([](const int& v, int){ + return std::ref(v); + }, std::cref(i), 0); + REQUIRE(&i == &g); + } + } + + SUBCASE("args forwarding") { + struct box final { + int v_; + constexpr box(int v) + : v_(v) {} + + box(box&&) = default; + box& operator=(box&&) = default; + + box(const box&) = delete; + box& operator=(const box&) = delete; + }; + + constexpr auto b = curry([](auto&& v1, auto&& v2, auto&& v3){ + return box(v1.v_ + v2.v_ + v3.v_); + })(box(1),box(2))(box(3)); + + STATIC_REQUIRE(b.v_ == 6); + } }