mirror of
https://github.com/BlackMATov/kari.hpp.git
synced 2025-12-15 13:29:49 +07:00
This commit is contained in:
8
CMakeLists.txt
Normal file
8
CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(kari)
|
||||
file(GLOB kari_src "*.cpp" "*.hpp")
|
||||
add_executable(${PROJECT_NAME} ${kari_src})
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
CXX_STANDARD 14
|
||||
CXX_STANDARD_REQUIRED YES
|
||||
CXX_EXTENSIONS NO)
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Matvey Cherevko
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
507
kari.hpp
Normal file
507
kari.hpp
Normal file
@@ -0,0 +1,507 @@
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace kari
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace std_ext
|
||||
{
|
||||
//
|
||||
// void_t
|
||||
//
|
||||
|
||||
template < typename... Ts >
|
||||
struct make_void {
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template < typename... Ts >
|
||||
using void_t = typename make_void<Ts...>::type;
|
||||
|
||||
//
|
||||
// apply
|
||||
//
|
||||
|
||||
template < typename F, typename Tuple, std::size_t... I >
|
||||
constexpr decltype(auto) apply_impl(F&& f, Tuple&& args, std::index_sequence<I...>) {
|
||||
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(args))...);
|
||||
}
|
||||
|
||||
template < typename F, typename Tuple >
|
||||
constexpr decltype(auto) apply(F&& f, Tuple&& args) {
|
||||
return apply_impl(
|
||||
std::forward<F>(f),
|
||||
std::forward<Tuple>(args),
|
||||
std::make_index_sequence<std::tuple_size<Tuple>::value>());
|
||||
}
|
||||
|
||||
//
|
||||
// is_invocable, is_invocable_v
|
||||
//
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template < typename F, typename = void >
|
||||
struct is_invocable_impl
|
||||
: std::false_type {};
|
||||
|
||||
template < typename F, typename... Args >
|
||||
struct is_invocable_impl<
|
||||
F(Args...),
|
||||
void_t<decltype(std::declval<F>()(std::declval<Args>()...))>
|
||||
> : std::true_type {};
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
struct is_invocable
|
||||
: detail::is_invocable_impl<F(Args...)> {};
|
||||
|
||||
template < typename F, typename... Args >
|
||||
constexpr bool is_invocable_v = is_invocable<F, Args...>::value;
|
||||
|
||||
//
|
||||
// conjunction, conjunction_v
|
||||
//
|
||||
|
||||
template < typename... >
|
||||
struct conjunction
|
||||
: std::true_type {};
|
||||
|
||||
template < typename B >
|
||||
struct conjunction<B>
|
||||
: B {};
|
||||
|
||||
template < typename B, typename... Bs>
|
||||
struct conjunction<B, Bs...>
|
||||
: std::conditional_t<bool(B::value), conjunction<Bs...>, B> {};
|
||||
|
||||
template < typename... Bs >
|
||||
constexpr bool conjunction_v = conjunction<Bs...>::value;
|
||||
|
||||
//
|
||||
// disjunction, disjunction_v
|
||||
//
|
||||
|
||||
template < typename... >
|
||||
struct disjunction
|
||||
: std::false_type {};
|
||||
|
||||
template < typename B >
|
||||
struct disjunction<B>
|
||||
: B {};
|
||||
|
||||
template < typename B, typename... Bs>
|
||||
struct disjunction<B, Bs...>
|
||||
: std::conditional_t<bool(B::value), B, disjunction<Bs...>> {};
|
||||
|
||||
template < typename... Bs >
|
||||
constexpr bool disjunction_v = disjunction<Bs...>::value;
|
||||
|
||||
//
|
||||
// bool_constant
|
||||
//
|
||||
|
||||
template < bool B >
|
||||
using bool_constant = std::integral_constant<bool, B>;
|
||||
|
||||
//
|
||||
// negation, negation_v
|
||||
//
|
||||
|
||||
template < typename B >
|
||||
struct negation
|
||||
: bool_constant<!bool(B::value)> {};
|
||||
|
||||
template < typename B >
|
||||
constexpr bool negation_v = negation<B>::value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace kari
|
||||
{
|
||||
template < std::size_t N, typename F, typename... Args >
|
||||
struct curry_t;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template
|
||||
<
|
||||
std::size_t N, typename F, typename... Args,
|
||||
typename std::enable_if<std_ext::conjunction_v<
|
||||
std_ext::bool_constant<(N == 0)>,
|
||||
std_ext::is_invocable<F, Args...>
|
||||
>, int>::type = 0
|
||||
>
|
||||
constexpr auto make_curry(F&& f, std::tuple<Args...>&& args) {
|
||||
return std_ext::apply(std::forward<F>(f), std::move(args));
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
std::size_t N, typename F, typename... Args,
|
||||
typename std::enable_if<std_ext::disjunction_v<
|
||||
std_ext::bool_constant<(N > 0)>,
|
||||
std_ext::negation<std_ext::is_invocable<F, Args...>>
|
||||
>, int>::type = 0
|
||||
>
|
||||
constexpr decltype(auto) make_curry(F&& f, std::tuple<Args...>&& args) {
|
||||
return curry_t<
|
||||
N,
|
||||
std::decay_t<F>,
|
||||
Args...
|
||||
>(std::forward<F>(f), std::move(args));
|
||||
}
|
||||
|
||||
template < std::size_t N, typename F >
|
||||
constexpr decltype(auto) make_curry(F&& f) {
|
||||
return make_curry<N>(std::forward<F>(f), std::make_tuple());
|
||||
}
|
||||
}
|
||||
|
||||
template < std::size_t N, 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))
|
||||
, args_(std::move(args)) {}
|
||||
|
||||
// min_arity
|
||||
|
||||
constexpr std::size_t min_arity() const noexcept {
|
||||
return N;
|
||||
}
|
||||
|
||||
// recurry
|
||||
|
||||
template < std::size_t M >
|
||||
constexpr decltype(auto) recurry() && {
|
||||
return detail::make_curry<M>(
|
||||
std::move(f_),
|
||||
std::move(args_));
|
||||
}
|
||||
|
||||
template < std::size_t M >
|
||||
constexpr decltype(auto) recurry() const & {
|
||||
auto self_copy = *this;
|
||||
return std::move(self_copy).template recurry<M>();
|
||||
}
|
||||
|
||||
// operator(As&&...)
|
||||
|
||||
constexpr decltype(auto) operator()() && {
|
||||
return std::move(*this).template recurry<0>();
|
||||
}
|
||||
|
||||
template < typename A >
|
||||
constexpr decltype(auto) operator()(A&& a) && {
|
||||
return detail::make_curry<(N > 0 ? N - 1 : 0)>(
|
||||
std::move(f_),
|
||||
std::tuple_cat(
|
||||
std::move(args_),
|
||||
std::make_tuple(std::forward<A>(a))));
|
||||
}
|
||||
|
||||
template < typename A, typename... As >
|
||||
constexpr decltype(auto) operator()(A&& a, As&&... as) && {
|
||||
return std::move(*this)(std::forward<A>(a))(std::forward<As>(as)...);
|
||||
}
|
||||
|
||||
template < typename... As >
|
||||
constexpr decltype(auto) operator()(As&&... as) const & {
|
||||
auto self_copy = *this;
|
||||
return std::move(self_copy)(std::forward<As>(as)...);
|
||||
}
|
||||
private:
|
||||
F f_;
|
||||
std::tuple<Args...> args_;
|
||||
};
|
||||
|
||||
//
|
||||
// is_curried, is_curried_v
|
||||
//
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template < typename F >
|
||||
struct is_curried_impl
|
||||
: std::false_type {};
|
||||
|
||||
template < std::size_t N, typename F, typename... Args >
|
||||
struct is_curried_impl<curry_t<N, F, Args...>>
|
||||
: std::true_type {};
|
||||
}
|
||||
|
||||
template < typename F >
|
||||
struct is_curried
|
||||
: detail::is_curried_impl<std::remove_cv_t<std::remove_reference_t<F>>> {};
|
||||
|
||||
template < typename F >
|
||||
constexpr bool is_curried_v = is_curried<F>::value;
|
||||
|
||||
//
|
||||
// curry
|
||||
//
|
||||
|
||||
template
|
||||
<
|
||||
typename F,
|
||||
typename std::enable_if<is_curried_v<F>, int>::type = 0
|
||||
>
|
||||
constexpr decltype(auto) curry(F&& f) {
|
||||
return std::forward<F>(f);
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
typename F,
|
||||
typename std::enable_if<!is_curried_v<F>, int>::type = 0
|
||||
>
|
||||
constexpr decltype(auto) curry(F&& f) {
|
||||
return detail::make_curry<0>(std::forward<F>(f));
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
constexpr decltype(auto) curry(F&& f, Args&&... args) {
|
||||
return curry(std::forward<F>(f))(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
//
|
||||
// curryV
|
||||
//
|
||||
|
||||
template
|
||||
<
|
||||
typename F,
|
||||
typename std::enable_if<is_curried_v<F>, int>::type = 0
|
||||
>
|
||||
constexpr decltype(auto) curryV(F&& f) {
|
||||
constexpr auto n = std::numeric_limits<std::size_t>::max();
|
||||
return std::forward<F>(f).template recurry<n>();
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
typename F,
|
||||
typename std::enable_if<!is_curried_v<F>, int>::type = 0
|
||||
>
|
||||
constexpr decltype(auto) curryV(F&& f) {
|
||||
constexpr auto n = std::numeric_limits<std::size_t>::max();
|
||||
return detail::make_curry<n>(std::forward<F>(f));
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
constexpr decltype(auto) curryV(F&& f, Args&&... args) {
|
||||
return curryV(std::forward<F>(f))(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
//
|
||||
// curryN
|
||||
//
|
||||
|
||||
template
|
||||
<
|
||||
std::size_t N, typename F,
|
||||
typename std::enable_if<is_curried_v<F>, int>::type = 0
|
||||
>
|
||||
constexpr decltype(auto) curryN(F&& f) {
|
||||
return std::forward<F>(f).template recurry<N>();
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
std::size_t N, typename F,
|
||||
typename std::enable_if<!is_curried_v<F>, int>::type = 0
|
||||
>
|
||||
constexpr decltype(auto) curryN(F&& f) {
|
||||
return detail::make_curry<N>(std::forward<F>(f));
|
||||
}
|
||||
|
||||
template < std::size_t N, typename F, typename... Args >
|
||||
constexpr decltype(auto) curryN(F&& f, Args&&... args) {
|
||||
static_assert(
|
||||
std::numeric_limits<std::size_t>::max() - sizeof...(Args) >= N,
|
||||
"N too big");
|
||||
return curryN<N + sizeof...(Args)>(std::forward<F>(f))(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
namespace kari
|
||||
{
|
||||
//
|
||||
// fid
|
||||
//
|
||||
|
||||
struct fid_t {
|
||||
template < typename A >
|
||||
constexpr decltype(auto) operator()(A&& a) const {
|
||||
return std::forward<A>(a);
|
||||
}
|
||||
};
|
||||
constexpr auto fid = curry(fid_t{});
|
||||
|
||||
//
|
||||
// fconst
|
||||
//
|
||||
|
||||
struct fconst_t {
|
||||
template < typename A, typename B >
|
||||
decltype(auto) operator()(A&& a, B&& b) const {
|
||||
(void)b;
|
||||
return std::forward<A>(a);
|
||||
}
|
||||
};
|
||||
constexpr auto fconst = curry(fconst_t{});
|
||||
|
||||
//
|
||||
// fflip
|
||||
//
|
||||
|
||||
struct fflip_t {
|
||||
template < typename F, typename A, typename B >
|
||||
constexpr decltype(auto) operator()(F&& f, A&& a, B&& b) const {
|
||||
return curry(
|
||||
std::forward<F>(f),
|
||||
std::forward<B>(b),
|
||||
std::forward<A>(a));
|
||||
}
|
||||
};
|
||||
constexpr auto fflip = curry(fflip_t{});
|
||||
|
||||
//
|
||||
// fcompose
|
||||
//
|
||||
|
||||
struct fcompose_t {
|
||||
template < typename G, typename F, typename A >
|
||||
constexpr decltype(auto) operator()(G&& g, F&& f, A&& a) const {
|
||||
return curry(
|
||||
std::forward<G>(g),
|
||||
curry(
|
||||
std::forward<F>(f),
|
||||
std::forward<A>(a)));
|
||||
}
|
||||
};
|
||||
constexpr auto fcompose = curry(fcompose_t{});
|
||||
|
||||
//
|
||||
// fcompose operators
|
||||
//
|
||||
|
||||
template
|
||||
<
|
||||
typename G, typename F,
|
||||
typename std::enable_if<is_curried_v<G>, int>::type = 0,
|
||||
typename std::enable_if<is_curried_v<F>, int>::type = 0
|
||||
>
|
||||
constexpr decltype(auto) operator*(G&& g, F&& f) {
|
||||
return fcompose(
|
||||
std::forward<G>(g),
|
||||
std::forward<F>(f));
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
typename F, typename A,
|
||||
typename std::enable_if< is_curried_v<F>, int>::type = 0,
|
||||
typename std::enable_if<!is_curried_v<A>, int>::type = 0
|
||||
>
|
||||
constexpr decltype(auto) operator*(F&& f, A&& a) {
|
||||
return std::forward<F>(f)(std::forward<A>(a));
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
typename A, typename F,
|
||||
typename std::enable_if<!is_curried_v<A>, int>::type = 0,
|
||||
typename std::enable_if< is_curried_v<F>, int>::type = 0
|
||||
>
|
||||
constexpr decltype(auto) operator*(A&& a, F&& f) {
|
||||
return std::forward<F>(f)(std::forward<A>(a));
|
||||
}
|
||||
}
|
||||
|
||||
namespace kari
|
||||
{
|
||||
namespace underscore
|
||||
{
|
||||
struct us_t {};
|
||||
constexpr us_t _{};
|
||||
|
||||
// `op` _
|
||||
|
||||
constexpr auto operator - (us_t) { return curry(std::negate<>()); }
|
||||
constexpr auto operator ~ (us_t) { return curry(std::bit_not<>()); }
|
||||
constexpr auto operator ! (us_t) { return curry(std::logical_not<>()); }
|
||||
|
||||
// _ `op` _
|
||||
|
||||
constexpr auto operator + (us_t, us_t) { return curry(std::plus<>()); }
|
||||
constexpr auto operator - (us_t, us_t) { return curry(std::minus<>()); }
|
||||
constexpr auto operator * (us_t, us_t) { return curry(std::multiplies<>()); }
|
||||
constexpr auto operator / (us_t, us_t) { return curry(std::divides<>()); }
|
||||
constexpr auto operator % (us_t, us_t) { return curry(std::modulus<>()); }
|
||||
|
||||
constexpr auto operator < (us_t, us_t) { return curry(std::less<>()); }
|
||||
constexpr auto operator > (us_t, us_t) { return curry(std::greater<>()); }
|
||||
constexpr auto operator <= (us_t, us_t) { return curry(std::less_equal<>()); }
|
||||
constexpr auto operator >= (us_t, us_t) { return curry(std::greater_equal<>()); }
|
||||
|
||||
constexpr auto operator | (us_t, us_t) { return curry(std::bit_or<>()); }
|
||||
constexpr auto operator & (us_t, us_t) { return curry(std::bit_and<>()); }
|
||||
constexpr auto operator ^ (us_t, us_t) { return curry(std::bit_xor<>()); }
|
||||
|
||||
constexpr auto operator || (us_t, us_t) { return curry(std::logical_or<>()); }
|
||||
constexpr auto operator && (us_t, us_t) { return curry(std::logical_and<>()); }
|
||||
|
||||
// A `op` _
|
||||
|
||||
template < typename A > constexpr auto operator + (A&& a, us_t) { return (_ + _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator - (A&& a, us_t) { return (_ - _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator * (A&& a, us_t) { return (_ * _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator / (A&& a, us_t) { return (_ / _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator % (A&& a, us_t) { return (_ % _)(std::forward<A>(a)); }
|
||||
|
||||
template < typename A > constexpr auto operator < (A&& a, us_t) { return (_ < _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator > (A&& a, us_t) { return (_ > _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator <= (A&& a, us_t) { return (_ <= _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator >= (A&& a, us_t) { return (_ >= _)(std::forward<A>(a)); }
|
||||
|
||||
template < typename A > constexpr auto operator | (A&& a, us_t) { return (_ | _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator & (A&& a, us_t) { return (_ & _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator ^ (A&& a, us_t) { return (_ ^ _)(std::forward<A>(a)); }
|
||||
|
||||
template < typename A > constexpr auto operator || (A&& a, us_t) { return (_ || _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator && (A&& a, us_t) { return (_ && _)(std::forward<A>(a)); }
|
||||
|
||||
// _ `op` A
|
||||
|
||||
template < typename A > constexpr auto operator + (us_t, A&& a) { return fflip(_ + _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator - (us_t, A&& a) { return fflip(_ - _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator * (us_t, A&& a) { return fflip(_ * _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator / (us_t, A&& a) { return fflip(_ / _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator % (us_t, A&& a) { return fflip(_ % _)(std::forward<A>(a)); }
|
||||
|
||||
template < typename A > constexpr auto operator < (us_t, A&& a) { return fflip(_ < _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator > (us_t, A&& a) { return fflip(_ > _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator <= (us_t, A&& a) { return fflip(_ <= _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator >= (us_t, A&& a) { return fflip(_ >= _)(std::forward<A>(a)); }
|
||||
|
||||
template < typename A > constexpr auto operator | (us_t, A&& a) { return fflip(_ | _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator & (us_t, A&& a) { return fflip(_ & _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator ^ (us_t, A&& a) { return fflip(_ ^ _)(std::forward<A>(a)); }
|
||||
|
||||
template < typename A > constexpr auto operator || (us_t, A&& a) { return fflip(_ || _)(std::forward<A>(a)); }
|
||||
template < typename A > constexpr auto operator && (us_t, A&& a) { return fflip(_ && _)(std::forward<A>(a)); }
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
657
tests.cpp
Normal file
657
tests.cpp
Normal file
@@ -0,0 +1,657 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "kari.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
namespace
|
||||
{
|
||||
const auto _42_tl = []() {
|
||||
return 42;
|
||||
};
|
||||
|
||||
const auto id_tl = [](int v) {
|
||||
return v;
|
||||
};
|
||||
|
||||
const auto minus2_tl = [](int v1, int v2) {
|
||||
return v1 - v2;
|
||||
};
|
||||
|
||||
const auto minus3_tl = [](int v1, int v2, int v3) {
|
||||
return v1 - v2 - v3;
|
||||
};
|
||||
|
||||
const auto minus4_tl = [](int v1, int v2, int v3, int v4) {
|
||||
return v1 - v2 - v3 - v4;
|
||||
};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const auto id_gl = [](auto&& v) {
|
||||
return v;
|
||||
};
|
||||
|
||||
const auto minus2_gl = [](auto&& v1, auto&& v2) {
|
||||
return v1 - v2;
|
||||
};
|
||||
|
||||
const auto minus3_gl = [](auto&& v1, auto&& v2, auto&& v3) {
|
||||
return v1 - v2 - v3;
|
||||
};
|
||||
|
||||
const auto minus4_gl = [](auto&& v1, auto&& v2, auto&& v3, auto&& v4) {
|
||||
return v1 - v2 - v3 - v4;
|
||||
};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct id_gf {
|
||||
template < typename T >
|
||||
constexpr auto operator()(T&& v) const {
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
struct minus2_gf {
|
||||
template < typename T1, typename T2 >
|
||||
constexpr auto operator()(T1&& v1, T2&& v2) const {
|
||||
return v1 - v2;
|
||||
}
|
||||
};
|
||||
|
||||
struct minus3_gf {
|
||||
template < typename T1, typename T2, typename T3 >
|
||||
constexpr auto operator()(T1&& v1, T2&& v2, T3&& v3) const {
|
||||
return v1 - v2 - v3;
|
||||
}
|
||||
};
|
||||
|
||||
struct plusV_gf {
|
||||
template < typename A >
|
||||
constexpr decltype(auto) operator()(A&& a) const {
|
||||
return std::forward<A>(a);
|
||||
}
|
||||
|
||||
template < typename A, typename B >
|
||||
constexpr decltype(auto) operator()(A&& a, B&& b) const {
|
||||
return std::forward<A>(a) + std::forward<B>(b);
|
||||
}
|
||||
|
||||
template < typename A, typename B, typename... Cs >
|
||||
constexpr decltype(auto) operator()(A&& a, B&& b, Cs&&... cs) const {
|
||||
return (*this)(
|
||||
(*this)(std::forward<A>(a), std::forward<B>(b)),
|
||||
std::forward<Cs>(cs)...);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr auto f = kari::curry(minus2_gf{}, 10, 20);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct box {
|
||||
box(int v) : v_(v) {}
|
||||
~box() {
|
||||
v_ = 100500;
|
||||
}
|
||||
|
||||
box(box&& o) : v_(o.v_) {
|
||||
o.v_ = 100500;
|
||||
++moveCount_;
|
||||
}
|
||||
|
||||
box(const box& o) : v_(o.v_) {
|
||||
++copyCount_;
|
||||
}
|
||||
|
||||
box& operator=(box&& o) = delete;
|
||||
box& operator=(const box&) = delete;
|
||||
|
||||
int v() const { return v_; }
|
||||
|
||||
int addV(int add) {
|
||||
v_ += add;
|
||||
return v_;
|
||||
}
|
||||
|
||||
static void resetCounters() {
|
||||
moveCount_ = 0;
|
||||
copyCount_ = 0;
|
||||
}
|
||||
|
||||
static int moveCount() {
|
||||
return moveCount_;
|
||||
}
|
||||
|
||||
static int copyCount() {
|
||||
return copyCount_;
|
||||
}
|
||||
private:
|
||||
int v_;
|
||||
static int moveCount_;
|
||||
static int copyCount_;
|
||||
};
|
||||
|
||||
int box::moveCount_;
|
||||
int box::copyCount_;
|
||||
|
||||
static box operator+(const box& lhs, const box& rhs) {
|
||||
return box(lhs.v() + rhs.v());
|
||||
}
|
||||
|
||||
static box operator-(const box& lhs, const box& rhs) {
|
||||
return box(lhs.v() - rhs.v());
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct box_without_move {
|
||||
box_without_move(int v) : v_(v) {}
|
||||
~box_without_move() {
|
||||
v_ = 100500;
|
||||
}
|
||||
|
||||
box_without_move(const box_without_move& o) : v_(o.v_) {
|
||||
++copyCount_;
|
||||
}
|
||||
|
||||
box_without_move& operator=(const box_without_move&) = delete;
|
||||
|
||||
int v() const { return v_; }
|
||||
|
||||
int addV(int add) {
|
||||
v_ += add;
|
||||
return v_;
|
||||
}
|
||||
|
||||
static void resetCounters() {
|
||||
copyCount_ = 0;
|
||||
}
|
||||
|
||||
static int copyCount() {
|
||||
return copyCount_;
|
||||
}
|
||||
private:
|
||||
int v_;
|
||||
static int copyCount_;
|
||||
};
|
||||
|
||||
int box_without_move::copyCount_;
|
||||
|
||||
static box_without_move operator+(const box_without_move& lhs, const box_without_move& rhs) {
|
||||
return box_without_move(lhs.v() + rhs.v());
|
||||
}
|
||||
|
||||
static box_without_move operator-(const box_without_move& lhs, const box_without_move& rhs) {
|
||||
return box_without_move(lhs.v() - rhs.v());
|
||||
}
|
||||
}
|
||||
|
||||
using namespace kari;
|
||||
|
||||
TEST_CASE("kari_feature") {
|
||||
SECTION("underscore") {
|
||||
using namespace kari::underscore;
|
||||
REQUIRE((-_)(40) == -40);
|
||||
|
||||
REQUIRE((_ + 40)(2) == 42);
|
||||
REQUIRE((_ - 2)(44) == 42);
|
||||
REQUIRE((_ * 21)(2) == 42);
|
||||
REQUIRE((_ / 2)(84) == 42);
|
||||
REQUIRE((_ % 100)(142) == 42);
|
||||
|
||||
REQUIRE((40 + _)(2) == 42);
|
||||
REQUIRE((44 - _)(2) == 42);
|
||||
REQUIRE((21 * _)(2) == 42);
|
||||
REQUIRE((84 / _)(2) == 42);
|
||||
REQUIRE((142 % _)(100) == 42);
|
||||
|
||||
REQUIRE((_ + _)(40,2) == 42);
|
||||
REQUIRE((_ - _)(44,2) == 42);
|
||||
REQUIRE((_ * _)(21,2) == 42);
|
||||
REQUIRE((_ / _)(84,2) == 42);
|
||||
REQUIRE((_ % _)(142,100) == 42);
|
||||
}
|
||||
SECTION("ref_functor") {
|
||||
REQUIRE(curry(minus3_gf())(1,2,3) == -4);
|
||||
{
|
||||
auto gf1 = id_gf();
|
||||
REQUIRE(curry(gf1)(1) == 1);
|
||||
auto gf2 = minus2_gf();
|
||||
REQUIRE(curry(gf2)(1,2) == -1);
|
||||
auto gf3 = minus3_gf();
|
||||
REQUIRE(curry(gf3)(1,2,3) == -4);
|
||||
}
|
||||
{
|
||||
const auto gf1 = id_gf();
|
||||
REQUIRE(curry(gf1)(1) == 1);
|
||||
const auto gf2 = minus2_gf();
|
||||
REQUIRE(curry(gf2)(1,2) == -1);
|
||||
const auto gf3 = minus3_gf();
|
||||
REQUIRE(curry(gf3)(1,2,3) == -4);
|
||||
}
|
||||
}
|
||||
SECTION("ref_forwarding") {
|
||||
{
|
||||
int i = 42;
|
||||
const int& g = curry([](const int& v, int){
|
||||
return std::ref(v);
|
||||
}, std::ref(i), 0);
|
||||
REQUIRE(&i == &g);
|
||||
}
|
||||
{
|
||||
int i = 42;
|
||||
const int& g = curry([](int& v, int){
|
||||
return std::ref(v);
|
||||
}, std::ref(i), 0);
|
||||
REQUIRE(&i == &g);
|
||||
}
|
||||
}
|
||||
SECTION("move_vs_copy") {
|
||||
{
|
||||
box::resetCounters();
|
||||
const auto b1 = box(1);
|
||||
const auto b2 = box(2);
|
||||
const auto b3 = box(3);
|
||||
const auto b4 = box(4);
|
||||
const auto b5 = box(5);
|
||||
curry([](auto&& v1, auto&& v2, auto&& v3, auto&& v4, auto&& v5){
|
||||
return v1 + v2 + v3 + v4 + v5;
|
||||
})(std::move(b1))(std::move(b2))(std::move(b3))(std::move(b4))(std::move(b5));
|
||||
REQUIRE(box::moveCount() == 25);
|
||||
REQUIRE(box::copyCount() == 5);
|
||||
}
|
||||
{
|
||||
box::resetCounters();
|
||||
auto b1 = box(1);
|
||||
auto b2 = box(2);
|
||||
auto b3 = box(3);
|
||||
auto b4 = box(4);
|
||||
auto b5 = box(5);
|
||||
curry([](auto&& v1, auto&& v2, auto&& v3, auto&& v4, auto&& v5){
|
||||
return v1 + v2 + v3 + v4 + v5;
|
||||
})(std::move(b1))(std::move(b2))(std::move(b3))(std::move(b4))(std::move(b5));
|
||||
REQUIRE(box::moveCount() == 30);
|
||||
REQUIRE(box::copyCount() == 0);
|
||||
}
|
||||
{
|
||||
box::resetCounters();
|
||||
curry([](auto&& v1, auto&& v2, auto&& v3, auto&& v4, auto&& v5){
|
||||
return v1 + v2 + v3 + v4 + v5;
|
||||
})(box(1))(box(2))(box(3))(box(4))(box(5));
|
||||
REQUIRE(box::moveCount() == 30);
|
||||
REQUIRE(box::copyCount() == 0);
|
||||
}
|
||||
{
|
||||
box::resetCounters();
|
||||
curry([](auto&& v1, auto&& v2, auto&& v3, auto&& v4, auto&& v5){
|
||||
return v1 + v2 + v3 + v4 + v5;
|
||||
})(box(1),box(2))(box(3),box(4))(box(5));
|
||||
REQUIRE(box::moveCount() == 30);
|
||||
REQUIRE(box::copyCount() == 0);
|
||||
}
|
||||
{
|
||||
box::resetCounters();
|
||||
curry([](auto&& v1, auto&& v2, auto&& v3, auto&& v4, auto&& v5){
|
||||
return v1 + v2 + v3 + v4 + v5;
|
||||
})(box(1),box(2),box(3),box(4),box(5));
|
||||
REQUIRE(box::moveCount() == 30);
|
||||
REQUIRE(box::copyCount() == 0);
|
||||
}
|
||||
{
|
||||
box::resetCounters();
|
||||
const auto c0 = curry([](auto&& v1, auto&& v2, auto&& v3, auto&& v4, auto&& v5){
|
||||
return v1 + v2 + v3 + v4 + v5;
|
||||
});
|
||||
const auto c1 = c0(box(1));
|
||||
const auto c2 = c1(box(2));
|
||||
const auto c3 = c2(box(3));
|
||||
const auto c4 = c3(box(4));
|
||||
const auto c5 = c4(box(5));
|
||||
REQUIRE(c5.v() == 15);
|
||||
REQUIRE(box::moveCount() == 30);
|
||||
REQUIRE(box::copyCount() == 10);
|
||||
}
|
||||
{
|
||||
box_without_move::resetCounters();
|
||||
const auto c0 = curry([](auto&& v1, auto&& v2, auto&& v3, auto&& v4, auto&& v5){
|
||||
return v1 + v2 + v3 + v4 + v5;
|
||||
});
|
||||
const auto c1 = c0(box_without_move(1));
|
||||
const auto c2 = c1(box_without_move(2));
|
||||
const auto c3 = c2(box_without_move(3));
|
||||
const auto c4 = c3(box_without_move(4));
|
||||
const auto c5 = c4(box_without_move(5));
|
||||
REQUIRE(c5.v() == 15);
|
||||
REQUIRE(box_without_move::copyCount() == 40);
|
||||
}
|
||||
{
|
||||
box::resetCounters();
|
||||
curryV(plusV_gf())(box(1),box(2),box(3),box(4),box(5))();
|
||||
REQUIRE(box::moveCount() == 35);
|
||||
REQUIRE(box::copyCount() == 0);
|
||||
}
|
||||
{
|
||||
box::resetCounters();
|
||||
const auto c0 = curryV(plusV_gf());
|
||||
const auto c1 = c0(box(1));
|
||||
const auto c2 = c1(box(2));
|
||||
const auto c3 = c2(box(3));
|
||||
const auto c4 = c3(box(4));
|
||||
const auto c5 = c4(box(5));
|
||||
REQUIRE(c5().v() == 15);
|
||||
REQUIRE(box::moveCount() == 35);
|
||||
REQUIRE(box::copyCount() == 15);
|
||||
}
|
||||
}
|
||||
SECTION("persistent") {
|
||||
auto c = curry(minus3_gl);
|
||||
|
||||
auto c10 = c(box(10));
|
||||
auto c10_2 = c10(box(2));
|
||||
auto c10_2_3 = c10_2(box(3));
|
||||
auto c10_2_3d = c10_2(box(3));
|
||||
REQUIRE(c10_2_3.v() == 5);
|
||||
REQUIRE(c10_2_3.v() == c10_2_3d.v());
|
||||
|
||||
auto c9 = c(box(9));
|
||||
auto c9_1 = c9(box(1));
|
||||
auto c9_1_2 = c9_1(box(2));
|
||||
auto c9_1_2d = c9_1(box(2));
|
||||
REQUIRE(c9_1_2.v() == 6);
|
||||
REQUIRE(c9_1_2.v() == c9_1_2d.v());
|
||||
|
||||
auto c10_3 = c10(box(3));
|
||||
auto c10_3_5 = c10_3(box(5));
|
||||
auto c10_3_5d = c10_3(box(5));
|
||||
REQUIRE(c10_3_5.v() == 2);
|
||||
REQUIRE(c10_3_5.v() == c10_3_5d.v());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("kari") {
|
||||
SECTION("arity/min_arity") {
|
||||
REQUIRE(curry(minus3_gl).min_arity() == 0);
|
||||
REQUIRE(curryV(plusV_gf()).min_arity() == std::numeric_limits<std::size_t>::max());
|
||||
REQUIRE(curryN<3>(plusV_gf()).min_arity() == 3);
|
||||
REQUIRE(curryN<3>(plusV_gf())(1).min_arity() == 2);
|
||||
REQUIRE(curryN<3>(plusV_gf())(1)(2).min_arity() == 1);
|
||||
}
|
||||
SECTION("arity/recurring") {
|
||||
constexpr auto max_size_t = std::numeric_limits<std::size_t>::max();
|
||||
{
|
||||
REQUIRE(curry(curry(minus3_gl)).min_arity() == 0);
|
||||
REQUIRE(curry(curryV(plusV_gf())).min_arity() == max_size_t);
|
||||
REQUIRE(curry(curryN<3>(plusV_gf())).min_arity() == 3);
|
||||
}
|
||||
{
|
||||
REQUIRE(curryV(curry(minus3_gl)).min_arity() == max_size_t);
|
||||
REQUIRE(curryV(curryV(plusV_gf())).min_arity() == max_size_t);
|
||||
REQUIRE(curryV(curryN<3>(plusV_gf())).min_arity() == max_size_t);
|
||||
}
|
||||
{
|
||||
REQUIRE(curryN<2>(curry(minus3_gl)).min_arity() == 2);
|
||||
REQUIRE(curryN<2>(curryV(plusV_gf())).min_arity() == 2);
|
||||
REQUIRE(curryN<2>(curryN<3>(plusV_gf())).min_arity() == 2);
|
||||
}
|
||||
}
|
||||
SECTION("is_curried") {
|
||||
static_assert(!is_curried_v<void(int)>, "static unit test error");
|
||||
static_assert(!is_curried_v<decltype(minus2_gl)>, "static unit test error");
|
||||
static_assert(is_curried_v<decltype(curry(minus2_gl))>, "static unit test error");
|
||||
|
||||
auto c = curry(minus3_gl);
|
||||
static_assert(is_curried_v<decltype(c)>, "static unit test error");
|
||||
|
||||
auto c10 = c(box(10));
|
||||
static_assert(is_curried_v<decltype(c10)>, "static unit test error");
|
||||
|
||||
const auto c10_2 = c10(box(2));
|
||||
static_assert(is_curried_v<decltype(c10_2)>, "static unit test error");
|
||||
|
||||
auto c10_2_3 = c10_2(box(3));
|
||||
static_assert(!is_curried_v<decltype(c10_2_3)>, "static unit test error");
|
||||
|
||||
REQUIRE(c10_2_3.v() == 5);
|
||||
}
|
||||
SECTION("typed_lambdas/simple") {
|
||||
REQUIRE(curry(_42_tl) == 42);
|
||||
REQUIRE(curry(id_tl)(42) == 42);
|
||||
REQUIRE(curry(minus2_tl)(8,4) == 4);
|
||||
REQUIRE(curry(minus3_tl)(8,5,2) == 1);
|
||||
}
|
||||
SECTION("typed_lambdas/one_by_one_calling") {
|
||||
REQUIRE(curry(id_tl)(42) == 42);
|
||||
REQUIRE(curry(minus2_tl)(8)(4) == 4);
|
||||
REQUIRE(curry(minus3_tl)(8)(5)(2) == 1);
|
||||
}
|
||||
SECTION("typed_lambdas/combined_calling") {
|
||||
REQUIRE(curry(minus3_tl)(8,5)(2) == 1);
|
||||
REQUIRE(curry(minus3_tl)(8)(5,2) == 1);
|
||||
|
||||
REQUIRE(curry(minus4_tl)(14,2)(3)(4) == 5);
|
||||
REQUIRE(curry(minus4_tl)(14)(2,3)(4) == 5);
|
||||
REQUIRE(curry(minus4_tl)(14)(2)(3,4) == 5);
|
||||
REQUIRE(curry(minus4_tl)(14,2)(3,4) == 5);
|
||||
REQUIRE(curry(minus4_tl)(14,2,3)(4) == 5);
|
||||
REQUIRE(curry(minus4_tl)(14)(2,3,4) == 5);
|
||||
}
|
||||
SECTION("generic_lambdas/simple") {
|
||||
REQUIRE(curry(id_gl)(42) == 42);
|
||||
REQUIRE(curry(minus2_gl)(8,4) == 4);
|
||||
REQUIRE(curry(minus3_gl)(8,5,2) == 1);
|
||||
}
|
||||
SECTION("generic_lambdas/one_by_one_calling") {
|
||||
REQUIRE(curry(id_gl)(42) == 42);
|
||||
REQUIRE(curry(minus2_gl)(8)(4) == 4);
|
||||
REQUIRE(curry(minus3_gl)(8)(5)(2) == 1);
|
||||
}
|
||||
SECTION("generic_lambdas/combined_calling") {
|
||||
REQUIRE(curry(minus3_gl)(8,5)(2) == 1);
|
||||
REQUIRE(curry(minus3_gl)(8)(5,2) == 1);
|
||||
|
||||
REQUIRE(curry(minus4_gl)(14,2)(3)(4) == 5);
|
||||
REQUIRE(curry(minus4_gl)(14)(2,3)(4) == 5);
|
||||
REQUIRE(curry(minus4_gl)(14)(2)(3,4) == 5);
|
||||
REQUIRE(curry(minus4_gl)(14,2)(3,4) == 5);
|
||||
REQUIRE(curry(minus4_gl)(14,2,3)(4) == 5);
|
||||
REQUIRE(curry(minus4_gl)(14)(2,3,4) == 5);
|
||||
}
|
||||
SECTION("nested_lambdas/full_apply") {
|
||||
{
|
||||
REQUIRE(curry([](){
|
||||
return _42_tl;
|
||||
})() == 42);
|
||||
//
|
||||
REQUIRE(curry([](){
|
||||
return curry(_42_tl);
|
||||
}) == 42);
|
||||
}
|
||||
{
|
||||
REQUIRE(curry([](){
|
||||
return id_gl;
|
||||
})(9) == 9);
|
||||
//
|
||||
REQUIRE(curry([](){
|
||||
return curry(id_gl);
|
||||
})(9) == 9);
|
||||
}
|
||||
{
|
||||
REQUIRE(curry([](){
|
||||
return minus2_gl;
|
||||
})(9,5) == 4);
|
||||
//
|
||||
REQUIRE(curry([](){
|
||||
return curry(minus2_gl);
|
||||
})(9,5) == 4);
|
||||
REQUIRE(curry([](){
|
||||
return curry(minus2_gl);
|
||||
})(9)(5) == 4);
|
||||
//
|
||||
REQUIRE(curry([](){
|
||||
return curry(minus3_gl);
|
||||
})(9,4,3) == 2);
|
||||
REQUIRE(curry([](){
|
||||
return curry(minus3_gl);
|
||||
})(9)(4)(3) == 2);
|
||||
REQUIRE(curry([](){
|
||||
return curry(minus3_gl);
|
||||
})(9,4)(3) == 2);
|
||||
REQUIRE(curry([](){
|
||||
return curry(minus3_gl);
|
||||
})(9)(4,3) == 2);
|
||||
}
|
||||
}
|
||||
SECTION("variadic_functions") {
|
||||
{
|
||||
const auto c = curry(plusV_gf());
|
||||
REQUIRE(c(15) == 15);
|
||||
REQUIRE(curry(plusV_gf(), 6) == 6);
|
||||
}
|
||||
{
|
||||
const auto c = curryV(plusV_gf());
|
||||
REQUIRE(c(1,2,3,4,5)() == 15);
|
||||
REQUIRE(curryV(plusV_gf(), 1, 2, 3)() == 6);
|
||||
}
|
||||
{
|
||||
const auto c = curryN<3>(plusV_gf());
|
||||
REQUIRE(c(1,2,3) == 6);
|
||||
REQUIRE(curryN<0>(plusV_gf(), 1, 2, 3) == 6);
|
||||
}
|
||||
{
|
||||
char buffer[256] = {'\0'};
|
||||
auto c = kari::curryV(std::snprintf, buffer, 256, "%d + %d = %d");
|
||||
c(37, 5, 42)();
|
||||
REQUIRE(std::strcmp("37 + 5 = 42", buffer) == 0);
|
||||
}
|
||||
{
|
||||
char buffer[256] = {'\0'};
|
||||
auto c = kari::curryN<3>(std::snprintf, buffer, 256, "%d + %d = %d");
|
||||
c(37, 5, 42);
|
||||
REQUIRE(std::strcmp("37 + 5 = 42", buffer) == 0);
|
||||
}
|
||||
}
|
||||
SECTION("variadic_functions/recurring") {
|
||||
{
|
||||
auto c0 = curry(curry(plusV_gf()));
|
||||
auto c1 = curry(curryV(plusV_gf()));
|
||||
auto c2 = curry(curryN<3>(plusV_gf()));
|
||||
REQUIRE(c0(42) == 42);
|
||||
REQUIRE(c1(40,2)() == 42);
|
||||
REQUIRE(c2(37,2,3) == 42);
|
||||
}
|
||||
{
|
||||
auto c0 = curryV(curry(plusV_gf()));
|
||||
auto c1 = curryV(curryV(plusV_gf()));
|
||||
auto c2 = curryV(curryN<3>(plusV_gf()));
|
||||
REQUIRE(c0(40,2)() == 42);
|
||||
REQUIRE(c1(40,2)() == 42);
|
||||
REQUIRE(c2(40,2)() == 42);
|
||||
}
|
||||
{
|
||||
auto c0 = curryN<2>(curry(plusV_gf()));
|
||||
auto c1 = curryN<2>(curryV(plusV_gf()));
|
||||
auto c2 = curryN<2>(curryN<3>(plusV_gf()));
|
||||
auto c3 = curryN<4>(curryN<3>(plusV_gf()));
|
||||
REQUIRE(c0(40,2) == 42);
|
||||
REQUIRE(c1(40,2) == 42);
|
||||
REQUIRE(c2(40,2) == 42);
|
||||
REQUIRE(c3(20,15,5,2) == 42);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("kari_helpers") {
|
||||
SECTION("fid") {
|
||||
REQUIRE(fid(box(10)).v() == 10);
|
||||
}
|
||||
SECTION("fconst") {
|
||||
REQUIRE(fconst(box(10), 20).v() == 10);
|
||||
{
|
||||
auto b10 = fconst(box(10));
|
||||
REQUIRE(b10(20).v() == 10);
|
||||
REQUIRE(std::move(b10)(30).v() == 10);
|
||||
REQUIRE(b10(20).v() == 100500);
|
||||
}
|
||||
}
|
||||
SECTION("fflip") {
|
||||
REQUIRE(fflip(curry(std::minus<>()))(10, 20) == 10);
|
||||
REQUIRE(fflip(minus3_gl)(10,20,50) == -40);
|
||||
}
|
||||
SECTION("fcompose") {
|
||||
using namespace kari::underscore;
|
||||
REQUIRE(fcompose(_+2, _*2, 4) == 10);
|
||||
REQUIRE((_+2) * (_*2) * 4 == 10);
|
||||
REQUIRE(4 * (_+2) * (_*2) == 12);
|
||||
{
|
||||
const auto s3 = [](int v1, int v2, int v3){
|
||||
return v1 + v2 + v3;
|
||||
};
|
||||
const auto c = curry(s3) * (_*2) * 10 * 20 * 30;
|
||||
REQUIRE(c == 70);
|
||||
}
|
||||
{
|
||||
// (. (+2)) (*2) $ 10 == 24
|
||||
int i = fflip(fcompose)(_+2, _*2, 10);
|
||||
int j = (_*(_+2))(_*2)(10);
|
||||
REQUIRE(i == 24);
|
||||
REQUIRE(j == 24);
|
||||
}
|
||||
{
|
||||
// ((+2) .) (*2) $ 10 == 24
|
||||
int i = fcompose(_+2)(_*2, 10);
|
||||
int j = ((_+2) * _)(_*2)(10);
|
||||
REQUIRE(i == 22);
|
||||
REQUIRE(j == 22);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace kari_regression {
|
||||
namespace change_type_after_applying {
|
||||
template < typename C >
|
||||
struct first_type_impl;
|
||||
|
||||
template < std::size_t N, typename F, typename A, typename... Args >
|
||||
struct first_type_impl<curry_t<N, F, A, Args...>> {
|
||||
using type = A;
|
||||
};
|
||||
|
||||
template < typename C >
|
||||
struct first_type
|
||||
: first_type_impl<std::remove_cv_t<std::remove_reference_t<C>>> {};
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("kari_regression") {
|
||||
SECTION("change_type_after_applying") {
|
||||
using namespace kari_regression::change_type_after_applying;
|
||||
const auto f3 = [](int& v1, int v2, int v3){
|
||||
return v1 + v2 + v3;
|
||||
};
|
||||
int i = 0;
|
||||
auto c0 = curry(f3, 0);
|
||||
auto c1 = c0(std::ref(i));
|
||||
auto c2 = std::move(c0)(std::ref(i));
|
||||
static_assert(std::is_same<
|
||||
typename first_type<decltype(c1)>::type,
|
||||
typename first_type<decltype(c2)>::type
|
||||
>::value,"static unit test error");
|
||||
}
|
||||
SECTION("curryN_already_curried_function") {
|
||||
auto c = curryN<3>(plusV_gf());
|
||||
auto c2 = curryN<3>(c);
|
||||
REQUIRE(c2(1,2,3) == 6);
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
Reference in New Issue
Block a user