rewrite tests and simplify curry impl

This commit is contained in:
BlackMATov
2020-12-11 04:18:04 +07:00
parent 7d5342ff4e
commit fe03162e75
3 changed files with 572 additions and 30 deletions

View File

@@ -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<curry_t<F, Args...>>
template < typename F, typename... As >
struct is_curried_impl<curry_t<F, As...>>
: std::true_type {};
}
@@ -44,40 +44,31 @@ namespace kari_hpp::detail
return curry_t<std::decay_t<F>, Args...>(std::forward<F>(f), std::move(args));
}
}
template < typename F >
constexpr auto curry_or_apply(F&& f) {
return curry_or_apply(std::forward<F>(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...>&& args)
: f_(std::forward<U>(u))
class curry_t final {
constexpr curry_t(F f, std::tuple<Args...> 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<As...>&&);
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<std::decay_t<F>> ) {
return std::forward<F>(f);
} else {
return detail::curry_or_apply(std::forward<F>(f));
return detail::curry_or_apply(std::forward<F>(f), {});
}
}

View File

@@ -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));
}
}

View File

@@ -7,7 +7,468 @@
#include <kari.hpp/kari.hpp>
#include "doctest/doctest.hpp"
#include <functional>
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);
}
}