mirror of
https://github.com/BlackMATov/kari.hpp.git
synced 2025-12-17 00:16:52 +07:00
Merge branch 'dev'
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
build-tests-*
|
||||||
tests/build/*
|
tests/build/*
|
||||||
tests/.vscode/*
|
tests/.vscode/*
|
||||||
tests/CMakeLists.txt.user
|
tests/CMakeLists.txt.user
|
||||||
23
README.md
23
README.md
@@ -18,7 +18,7 @@
|
|||||||
[appveyor]: https://ci.appveyor.com/project/BlackMATov/kari-hpp
|
[appveyor]: https://ci.appveyor.com/project/BlackMATov/kari-hpp
|
||||||
[license]: https://github.com/BlackMATov/kari.hpp/blob/master/LICENSE.md
|
[license]: https://github.com/BlackMATov/kari.hpp/blob/master/LICENSE.md
|
||||||
[godbolt]: https://godbolt.org/g/XPBgjY
|
[godbolt]: https://godbolt.org/g/XPBgjY
|
||||||
[wandbox]: https://wandbox.org/permlink/eKfLeyjXvOLfzQvG
|
[wandbox]: https://wandbox.org/permlink/IVcSfxEAG9xkJQpl
|
||||||
|
|
||||||
[kari]: https://github.com/BlackMATov/kari.hpp
|
[kari]: https://github.com/BlackMATov/kari.hpp
|
||||||
|
|
||||||
@@ -82,6 +82,27 @@ auto c2 = kari::curry(foo)(38)(3,1);
|
|||||||
std::cout << c0 << "," << c1 << "," << c2 << std::endl;
|
std::cout << c0 << "," << c1 << "," << c2 << std::endl;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Binding member functions and member objects
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Foo {
|
||||||
|
int v = 40;
|
||||||
|
int addV(int add) {
|
||||||
|
v += add;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
} foo;
|
||||||
|
|
||||||
|
auto c0 = kari::curry(&Foo::addV);
|
||||||
|
auto c1 = kari::curry(&Foo::v);
|
||||||
|
|
||||||
|
auto r0 = c0(std::ref(foo))(2);
|
||||||
|
auto r1 = c1(foo);
|
||||||
|
|
||||||
|
// output: 42,42
|
||||||
|
std::cout << r0 << "," << r1 << std::endl;
|
||||||
|
```
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
|||||||
326
kari.hpp
326
kari.hpp
@@ -24,13 +24,203 @@ namespace kari
|
|||||||
template < typename... Ts >
|
template < typename... Ts >
|
||||||
using void_t = typename make_void<Ts...>::type;
|
using void_t = typename make_void<Ts...>::type;
|
||||||
|
|
||||||
|
//
|
||||||
|
// is_reference_wrapper, is_reference_wrapper_v
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
template < typename T >
|
||||||
|
struct is_reference_wrapper_impl
|
||||||
|
: public std::false_type {};
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
struct is_reference_wrapper_impl<std::reference_wrapper<T>>
|
||||||
|
: public std::true_type {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
struct is_reference_wrapper
|
||||||
|
: public detail::is_reference_wrapper_impl<std::remove_cv_t<T>> {};
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
constexpr bool is_reference_wrapper_v = is_reference_wrapper<T>::value;
|
||||||
|
|
||||||
|
//
|
||||||
|
// invoke
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// invoke_member_object_impl
|
||||||
|
//
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename Base, typename F, typename Derived,
|
||||||
|
typename std::enable_if_t<std::is_base_of<Base, std::decay_t<Derived>>::value, int> = 0
|
||||||
|
>
|
||||||
|
constexpr auto invoke_member_object_impl(F Base::* f, Derived&& ref)
|
||||||
|
-> decltype (std::forward<Derived>(ref).*f)
|
||||||
|
{
|
||||||
|
return std::forward<Derived>(ref).*f;
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename Base, typename F, typename RefWrap,
|
||||||
|
typename std::enable_if_t<is_reference_wrapper<std::decay_t<RefWrap>>::value, int> = 0
|
||||||
|
>
|
||||||
|
constexpr auto invoke_member_object_impl(F Base::* f, RefWrap&& ref)
|
||||||
|
-> decltype (ref.get().*f)
|
||||||
|
{
|
||||||
|
return ref.get().*f;
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename Base, typename F, typename Pointer,
|
||||||
|
typename std::enable_if_t<
|
||||||
|
!std::is_base_of<Base, std::decay_t<Pointer>>::value &&
|
||||||
|
!is_reference_wrapper_v<std::decay_t<Pointer>>
|
||||||
|
, int> = 0
|
||||||
|
>
|
||||||
|
constexpr auto invoke_member_object_impl(F Base::* f, Pointer&& ptr)
|
||||||
|
-> decltype ((*std::forward<Pointer>(ptr)).*f)
|
||||||
|
{
|
||||||
|
return (*std::forward<Pointer>(ptr)).*f;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// invoke_member_function_impl
|
||||||
|
//
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename Base, typename F, typename Derived, typename... Args,
|
||||||
|
typename std::enable_if_t<std::is_base_of<Base, std::decay_t<Derived>>::value, int> = 0
|
||||||
|
>
|
||||||
|
constexpr auto invoke_member_function_impl(F Base::* f, Derived&& ref, Args&&... args)
|
||||||
|
-> decltype ((std::forward<Derived>(ref).*f)(std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
return (std::forward<Derived>(ref).*f)(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename Base, typename F, typename RefWrap, typename... Args,
|
||||||
|
typename std::enable_if_t<is_reference_wrapper<std::decay_t<RefWrap>>::value, int> = 0
|
||||||
|
>
|
||||||
|
constexpr auto invoke_member_function_impl(F Base::* f, RefWrap&& ref, Args&&... args)
|
||||||
|
-> decltype ((ref.get().*f)(std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
return (ref.get().*f)(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename Base, typename F, typename Pointer, typename... Args,
|
||||||
|
typename std::enable_if_t<
|
||||||
|
!std::is_base_of<Base, std::decay_t<Pointer>>::value &&
|
||||||
|
!is_reference_wrapper_v<std::decay_t<Pointer>>
|
||||||
|
, int> = 0
|
||||||
|
>
|
||||||
|
constexpr auto invoke_member_function_impl(F Base::* f, Pointer&& ptr, Args&&... args)
|
||||||
|
-> decltype (((*std::forward<Pointer>(ptr)).*f)(std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
return ((*std::forward<Pointer>(ptr)).*f)(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename F, typename... Args,
|
||||||
|
typename std::enable_if_t<!std::is_member_pointer<std::decay_t<F>>::value, int> = 0
|
||||||
|
>
|
||||||
|
constexpr auto invoke(F&& f, Args&&... args)
|
||||||
|
-> decltype (std::forward<F>(f)(std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
return std::forward<F>(f)(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename F, typename T,
|
||||||
|
typename std::enable_if_t<std::is_member_object_pointer<std::decay_t<F>>::value, int> = 0
|
||||||
|
>
|
||||||
|
constexpr auto invoke(F&& f, T&& t)
|
||||||
|
-> decltype (detail::invoke_member_object_impl(std::forward<F>(f), std::forward<T>(t)))
|
||||||
|
{
|
||||||
|
return detail::invoke_member_object_impl(std::forward<F>(f), std::forward<T>(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename F, typename... Args,
|
||||||
|
typename std::enable_if_t<std::is_member_function_pointer<std::decay_t<F>>::value, int> = 0
|
||||||
|
>
|
||||||
|
constexpr auto invoke(F&& f, Args&&... args)
|
||||||
|
-> decltype (detail::invoke_member_function_impl(std::forward<F>(f), std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
return detail::invoke_member_function_impl(std::forward<F>(f), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// invoke_result, invoke_result_t
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
struct invoke_result_impl_tag {};
|
||||||
|
|
||||||
|
template < typename Void, typename F, typename... Args >
|
||||||
|
struct invoke_result_impl {};
|
||||||
|
|
||||||
|
template < typename F, typename... Args >
|
||||||
|
struct invoke_result_impl<void_t<invoke_result_impl_tag, decltype(std_ext::invoke(std::declval<F>(), std::declval<Args>()...))>, F, Args...> {
|
||||||
|
using type = decltype(std_ext::invoke(std::declval<F>(), std::declval<Args>()...));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename F, typename... Args >
|
||||||
|
struct invoke_result
|
||||||
|
: detail::invoke_result_impl<void, F, Args...> {};
|
||||||
|
|
||||||
|
template < typename F, typename... Args >
|
||||||
|
using invoke_result_t = typename invoke_result<F, Args...>::type;
|
||||||
|
|
||||||
|
//
|
||||||
|
// is_invocable, is_invocable_v
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
struct is_invocable_impl_tag {};
|
||||||
|
|
||||||
|
template < typename Void, typename F, typename... Args >
|
||||||
|
struct is_invocable_impl
|
||||||
|
: std::false_type {};
|
||||||
|
|
||||||
|
template < typename F, typename... Args >
|
||||||
|
struct is_invocable_impl<void_t<is_invocable_impl_tag, invoke_result_t<F, Args...>>, F, Args...>
|
||||||
|
: std::true_type {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename F, typename... Args >
|
||||||
|
struct is_invocable
|
||||||
|
: detail::is_invocable_impl<void, F, Args...> {};
|
||||||
|
|
||||||
|
template < typename F, typename... Args >
|
||||||
|
constexpr bool is_invocable_v = is_invocable<F, Args...>::value;
|
||||||
|
|
||||||
//
|
//
|
||||||
// apply
|
// apply
|
||||||
//
|
//
|
||||||
|
|
||||||
template < typename F, typename Tuple, std::size_t... I >
|
template < typename F, typename Tuple, std::size_t... I >
|
||||||
constexpr decltype(auto) apply_impl(F&& f, Tuple&& args, std::index_sequence<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))...);
|
return std_ext::invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(args))...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename F, typename Tuple >
|
template < typename F, typename Tuple >
|
||||||
@@ -40,86 +230,6 @@ namespace kari
|
|||||||
std::forward<Tuple>(args),
|
std::forward<Tuple>(args),
|
||||||
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>());
|
std::make_index_sequence<std::tuple_size<std::decay_t<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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,10 +244,10 @@ namespace kari
|
|||||||
template
|
template
|
||||||
<
|
<
|
||||||
std::size_t N, typename F, typename... Args,
|
std::size_t N, typename F, typename... Args,
|
||||||
typename std::enable_if<std_ext::conjunction_v<
|
typename std::enable_if_t<
|
||||||
std_ext::bool_constant<(N == 0)>,
|
(N == 0) &&
|
||||||
std_ext::is_invocable<F, Args...>
|
std_ext::is_invocable_v<std::decay_t<F>, Args...>
|
||||||
>, int>::type = 0
|
, int> = 0
|
||||||
>
|
>
|
||||||
constexpr auto make_curry(F&& f, std::tuple<Args...>&& args) {
|
constexpr auto make_curry(F&& f, std::tuple<Args...>&& args) {
|
||||||
return std_ext::apply(std::forward<F>(f), std::move(args));
|
return std_ext::apply(std::forward<F>(f), std::move(args));
|
||||||
@@ -146,10 +256,10 @@ namespace kari
|
|||||||
template
|
template
|
||||||
<
|
<
|
||||||
std::size_t N, typename F, typename... Args,
|
std::size_t N, typename F, typename... Args,
|
||||||
typename std::enable_if<std_ext::disjunction_v<
|
typename std::enable_if_t<
|
||||||
std_ext::bool_constant<(N > 0)>,
|
(N > 0) ||
|
||||||
std_ext::negation<std_ext::is_invocable<F, Args...>>
|
!std_ext::is_invocable_v<std::decay_t<F>, Args...>
|
||||||
>, int>::type = 0
|
, int> = 0
|
||||||
>
|
>
|
||||||
constexpr decltype(auto) make_curry(F&& f, std::tuple<Args...>&& args) {
|
constexpr decltype(auto) make_curry(F&& f, std::tuple<Args...>&& args) {
|
||||||
return curry_t<
|
return curry_t<
|
||||||
@@ -240,7 +350,7 @@ namespace kari
|
|||||||
|
|
||||||
template < typename F >
|
template < typename F >
|
||||||
struct is_curried
|
struct is_curried
|
||||||
: detail::is_curried_impl<std::remove_cv_t<std::remove_reference_t<F>>> {};
|
: detail::is_curried_impl<std::remove_cv_t<F>> {};
|
||||||
|
|
||||||
template < typename F >
|
template < typename F >
|
||||||
constexpr bool is_curried_v = is_curried<F>::value;
|
constexpr bool is_curried_v = is_curried<F>::value;
|
||||||
@@ -252,7 +362,7 @@ namespace kari
|
|||||||
template
|
template
|
||||||
<
|
<
|
||||||
typename F,
|
typename F,
|
||||||
typename std::enable_if<is_curried_v<F>, int>::type = 0
|
typename std::enable_if_t<is_curried_v<std::decay_t<F>>, int> = 0
|
||||||
>
|
>
|
||||||
constexpr decltype(auto) curry(F&& f) {
|
constexpr decltype(auto) curry(F&& f) {
|
||||||
return std::forward<F>(f);
|
return std::forward<F>(f);
|
||||||
@@ -261,7 +371,7 @@ namespace kari
|
|||||||
template
|
template
|
||||||
<
|
<
|
||||||
typename F,
|
typename F,
|
||||||
typename std::enable_if<!is_curried_v<F>, int>::type = 0
|
typename std::enable_if_t<!is_curried_v<std::decay_t<F>>, int> = 0
|
||||||
>
|
>
|
||||||
constexpr decltype(auto) curry(F&& f) {
|
constexpr decltype(auto) curry(F&& f) {
|
||||||
return detail::make_curry<0>(std::forward<F>(f));
|
return detail::make_curry<0>(std::forward<F>(f));
|
||||||
@@ -279,7 +389,7 @@ namespace kari
|
|||||||
template
|
template
|
||||||
<
|
<
|
||||||
typename F,
|
typename F,
|
||||||
typename std::enable_if<is_curried_v<F>, int>::type = 0
|
typename std::enable_if_t<is_curried_v<std::decay_t<F>>, int> = 0
|
||||||
>
|
>
|
||||||
constexpr decltype(auto) curryV(F&& f) {
|
constexpr decltype(auto) curryV(F&& f) {
|
||||||
constexpr auto n = std::numeric_limits<std::size_t>::max();
|
constexpr auto n = std::numeric_limits<std::size_t>::max();
|
||||||
@@ -289,7 +399,7 @@ namespace kari
|
|||||||
template
|
template
|
||||||
<
|
<
|
||||||
typename F,
|
typename F,
|
||||||
typename std::enable_if<!is_curried_v<F>, int>::type = 0
|
typename std::enable_if_t<!is_curried_v<std::decay_t<F>>, int> = 0
|
||||||
>
|
>
|
||||||
constexpr decltype(auto) curryV(F&& f) {
|
constexpr decltype(auto) curryV(F&& f) {
|
||||||
constexpr auto n = std::numeric_limits<std::size_t>::max();
|
constexpr auto n = std::numeric_limits<std::size_t>::max();
|
||||||
@@ -308,7 +418,7 @@ namespace kari
|
|||||||
template
|
template
|
||||||
<
|
<
|
||||||
std::size_t N, typename F,
|
std::size_t N, typename F,
|
||||||
typename std::enable_if<is_curried_v<F>, int>::type = 0
|
typename std::enable_if_t<is_curried_v<std::decay_t<F>>, int> = 0
|
||||||
>
|
>
|
||||||
constexpr decltype(auto) curryN(F&& f) {
|
constexpr decltype(auto) curryN(F&& f) {
|
||||||
return std::forward<F>(f).template recurry<N>();
|
return std::forward<F>(f).template recurry<N>();
|
||||||
@@ -317,7 +427,7 @@ namespace kari
|
|||||||
template
|
template
|
||||||
<
|
<
|
||||||
std::size_t N, typename F,
|
std::size_t N, typename F,
|
||||||
typename std::enable_if<!is_curried_v<F>, int>::type = 0
|
typename std::enable_if_t<!is_curried_v<std::decay_t<F>>, int> = 0
|
||||||
>
|
>
|
||||||
constexpr decltype(auto) curryN(F&& f) {
|
constexpr decltype(auto) curryN(F&& f) {
|
||||||
return detail::make_curry<N>(std::forward<F>(f));
|
return detail::make_curry<N>(std::forward<F>(f));
|
||||||
@@ -413,8 +523,8 @@ namespace kari
|
|||||||
template
|
template
|
||||||
<
|
<
|
||||||
typename G, typename F,
|
typename G, typename F,
|
||||||
typename std::enable_if<is_curried_v<G>, int>::type = 0,
|
typename std::enable_if_t<is_curried_v<std::decay_t<G>>, int> = 0,
|
||||||
typename std::enable_if<is_curried_v<F>, int>::type = 0
|
typename std::enable_if_t<is_curried_v<std::decay_t<F>>, int> = 0
|
||||||
>
|
>
|
||||||
constexpr decltype(auto) operator|(G&& g, F&& f) {
|
constexpr decltype(auto) operator|(G&& g, F&& f) {
|
||||||
return fpipe(
|
return fpipe(
|
||||||
@@ -425,8 +535,8 @@ namespace kari
|
|||||||
template
|
template
|
||||||
<
|
<
|
||||||
typename F, typename A,
|
typename F, typename A,
|
||||||
typename std::enable_if< is_curried_v<F>, int>::type = 0,
|
typename std::enable_if_t< is_curried_v<std::decay_t<F>>, int> = 0,
|
||||||
typename std::enable_if<!is_curried_v<A>, int>::type = 0
|
typename std::enable_if_t<!is_curried_v<std::decay_t<A>>, int> = 0
|
||||||
>
|
>
|
||||||
constexpr decltype(auto) operator|(F&& f, A&& a) {
|
constexpr decltype(auto) operator|(F&& f, A&& a) {
|
||||||
return std::forward<F>(f)(std::forward<A>(a));
|
return std::forward<F>(f)(std::forward<A>(a));
|
||||||
@@ -435,8 +545,8 @@ namespace kari
|
|||||||
template
|
template
|
||||||
<
|
<
|
||||||
typename A, typename F,
|
typename A, typename F,
|
||||||
typename std::enable_if<!is_curried_v<A>, int>::type = 0,
|
typename std::enable_if_t<!is_curried_v<std::decay_t<A>>, int> = 0,
|
||||||
typename std::enable_if< is_curried_v<F>, int>::type = 0
|
typename std::enable_if_t< is_curried_v<std::decay_t<F>>, int> = 0
|
||||||
>
|
>
|
||||||
constexpr decltype(auto) operator|(A&& a, F&& f) {
|
constexpr decltype(auto) operator|(A&& a, F&& f) {
|
||||||
return std::forward<F>(f)(std::forward<A>(a));
|
return std::forward<F>(f)(std::forward<A>(a));
|
||||||
@@ -449,8 +559,8 @@ namespace kari
|
|||||||
template
|
template
|
||||||
<
|
<
|
||||||
typename G, typename F,
|
typename G, typename F,
|
||||||
typename std::enable_if<is_curried_v<G>, int>::type = 0,
|
typename std::enable_if_t<is_curried_v<std::decay_t<G>>, int> = 0,
|
||||||
typename std::enable_if<is_curried_v<F>, int>::type = 0
|
typename std::enable_if_t<is_curried_v<std::decay_t<F>>, int> = 0
|
||||||
>
|
>
|
||||||
constexpr decltype(auto) operator*(G&& g, F&& f) {
|
constexpr decltype(auto) operator*(G&& g, F&& f) {
|
||||||
return fcompose(
|
return fcompose(
|
||||||
@@ -461,8 +571,8 @@ namespace kari
|
|||||||
template
|
template
|
||||||
<
|
<
|
||||||
typename F, typename A,
|
typename F, typename A,
|
||||||
typename std::enable_if< is_curried_v<F>, int>::type = 0,
|
typename std::enable_if_t< is_curried_v<std::decay_t<F>>, int> = 0,
|
||||||
typename std::enable_if<!is_curried_v<A>, int>::type = 0
|
typename std::enable_if_t<!is_curried_v<std::decay_t<A>>, int> = 0
|
||||||
>
|
>
|
||||||
constexpr decltype(auto) operator*(F&& f, A&& a) {
|
constexpr decltype(auto) operator*(F&& f, A&& a) {
|
||||||
return std::forward<F>(f)(std::forward<A>(a));
|
return std::forward<F>(f)(std::forward<A>(a));
|
||||||
@@ -471,8 +581,8 @@ namespace kari
|
|||||||
template
|
template
|
||||||
<
|
<
|
||||||
typename A, typename F,
|
typename A, typename F,
|
||||||
typename std::enable_if<!is_curried_v<A>, int>::type = 0,
|
typename std::enable_if_t<!is_curried_v<std::decay_t<A>>, int> = 0,
|
||||||
typename std::enable_if< is_curried_v<F>, int>::type = 0
|
typename std::enable_if_t< is_curried_v<std::decay_t<F>>, int> = 0
|
||||||
>
|
>
|
||||||
constexpr decltype(auto) operator*(A&& a, F&& f) {
|
constexpr decltype(auto) operator*(A&& a, F&& f) {
|
||||||
return std::forward<F>(f)(std::forward<A>(a));
|
return std::forward<F>(f)(std::forward<A>(a));
|
||||||
|
|||||||
126
tests/tests.cpp
126
tests/tests.cpp
@@ -580,6 +580,132 @@ TEST_CASE("kari") {
|
|||||||
REQUIRE(c2(40,2) == 42);
|
REQUIRE(c2(40,2) == 42);
|
||||||
REQUIRE(c3(20,15,5,2) == 42);
|
REQUIRE(c3(20,15,5,2) == 42);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
auto c0 = curry(plusV_gf());
|
||||||
|
auto c1 = curryN<2>(c0);
|
||||||
|
REQUIRE(c1(40,2) == 42);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("member_functions") {
|
||||||
|
{
|
||||||
|
auto c0 = curry(&box::addV);
|
||||||
|
auto c1 = curry(&box::v);
|
||||||
|
REQUIRE(c0(box(10), 2) == 12);
|
||||||
|
REQUIRE(c1(box(12)) == 12);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto c0 = curry(&box::addV);
|
||||||
|
auto c1 = curry(&box::v);
|
||||||
|
|
||||||
|
auto b1 = box(10);
|
||||||
|
const auto b2 = box(10);
|
||||||
|
|
||||||
|
REQUIRE(c0(std::ref(b1), 2) == 12);
|
||||||
|
REQUIRE(c1(std::ref(b2)) == 10);
|
||||||
|
|
||||||
|
REQUIRE(c0(b1, 2) == 14);
|
||||||
|
REQUIRE(c1(b2) == 10);
|
||||||
|
|
||||||
|
REQUIRE(c0(&b1, 2) == 14);
|
||||||
|
REQUIRE(c1(&b2) == 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("member_objects") {
|
||||||
|
struct box2 : box {
|
||||||
|
box2(int v) : box(v), ov(v) {}
|
||||||
|
int ov;
|
||||||
|
};
|
||||||
|
auto c = curry(&box2::ov);
|
||||||
|
auto b1 = box2(10);
|
||||||
|
const auto b2 = box2(10);
|
||||||
|
REQUIRE(c(box2(10)) == 10);
|
||||||
|
REQUIRE(c(b1) == 10);
|
||||||
|
REQUIRE(c(b2) == 10);
|
||||||
|
REQUIRE(c(std::ref(b1)) == 10);
|
||||||
|
REQUIRE(c(std::ref(b2)) == 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("kari_details") {
|
||||||
|
SECTION("invoke") {
|
||||||
|
using namespace kari::detail;
|
||||||
|
REQUIRE(std_ext::invoke(std::minus<>(), 44, 2) == 42);
|
||||||
|
REQUIRE(std_ext::invoke(&box::addV, box(10), 2) == 12);
|
||||||
|
{
|
||||||
|
auto b1 = box(10);
|
||||||
|
const auto b2 = box(10);
|
||||||
|
REQUIRE(std_ext::invoke(&box::addV, b1, 2) == 12);
|
||||||
|
REQUIRE(std_ext::invoke(&box::v, b2) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box::addV, &b1, 2) == 14);
|
||||||
|
REQUIRE(std_ext::invoke(&box::v, &b2) == 10);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto b1 = box(10);
|
||||||
|
const auto b2 = box(10);
|
||||||
|
REQUIRE(std_ext::invoke(&box::addV, std::ref(b1), 2) == 12);
|
||||||
|
REQUIRE(std_ext::invoke(&box::v, std::ref(b2)) == 10);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct box2 : box {
|
||||||
|
box2(int v) : box(v) {}
|
||||||
|
};
|
||||||
|
auto b1 = box2(10);
|
||||||
|
const auto b2 = box2(10);
|
||||||
|
REQUIRE(std_ext::invoke(&box::addV, b1, 2) == 12);
|
||||||
|
REQUIRE(std_ext::invoke(&box::v, b2) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box::addV, &b1, 2) == 14);
|
||||||
|
REQUIRE(std_ext::invoke(&box::v, &b2) == 10);
|
||||||
|
|
||||||
|
REQUIRE(std_ext::invoke(&box2::addV, b1, 2) == 16);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::v, b2) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::addV, &b1, 2) == 18);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::v, &b2) == 10);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct box2 : box {
|
||||||
|
box2(int v) : box(v) {}
|
||||||
|
};
|
||||||
|
auto b1 = box2(10);
|
||||||
|
const auto b2 = box2(10);
|
||||||
|
REQUIRE(std_ext::invoke(&box::addV, std::ref(b1), 2) == 12);
|
||||||
|
REQUIRE(std_ext::invoke(&box::v, std::ref(b2)) == 10);
|
||||||
|
|
||||||
|
REQUIRE(std_ext::invoke(&box2::addV, std::ref(b1), 2) == 14);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::v, std::ref(b2)) == 10);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct box2 : box {
|
||||||
|
box2(int v) : box(v), ov(v) {}
|
||||||
|
int ov;
|
||||||
|
};
|
||||||
|
auto b1 = box2(10);
|
||||||
|
const auto b2 = box2(10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::ov, box2(10)) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::ov, b1) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::ov, b2) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::ov, &b1) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::ov, &b2) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::ov, std::ref(b1)) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::ov, std::ref(b2)) == 10);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct box2 : box {
|
||||||
|
box2(int v) : box(v), ov(v) {}
|
||||||
|
int ov;
|
||||||
|
};
|
||||||
|
struct box3 : box2 {
|
||||||
|
box3(int v) : box2(v) {}
|
||||||
|
};
|
||||||
|
auto b1 = box3(10);
|
||||||
|
const auto b2 = box3(10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::ov, box3(10)) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::ov, b1) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::ov, b2) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::ov, &b1) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::ov, &b2) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::ov, std::ref(b1)) == 10);
|
||||||
|
REQUIRE(std_ext::invoke(&box2::ov, std::ref(b2)) == 10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user