Skip to content

Commit

Permalink
use trivial tuple to store the arguments (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
coyorkdow authored Feb 18, 2023
1 parent bb475a0 commit 29c646a
Show file tree
Hide file tree
Showing 9 changed files with 213 additions and 96 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ list(APPEND closure_src
closure/placeholders.hpp
closure/util.hpp
closure/bind.hpp
closure/trivial_tuple.hpp
)

add_executable(closure_test
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![macOS Status](https://github.com/coyorkdow/closure/actions/workflows/macos.yml/badge.svg)](https://github.com/coyorkdow/closure/actions/workflows/macos.yml)
[![C++ Standard](https://img.shields.io/badge/cpp14-minimum%20required-success?logo=cplusplus)](https://en.cppreference.com/w/cpp/14)

Closure is header-only. To use Closure, simply copy `closure.hpp` and dicectory `closure` into your project.
Closure is header-only. To use Closure, simply copy `closure.hpp` and dicectory `closure` into your project, and don't forget `#include "closure.hpp"`.

## Features

Expand Down Expand Up @@ -214,6 +214,6 @@ Since `closure::Any` means any type, you can assign `c` to any other closure wit
```C++
// it's ok that the 4th parameter is float type, because float can implicitly convert to int
Closure<int(int, int, std::string, float)> c2(lambda, PlaceHolder<1>(), PlaceHolder<3>());
c2 = closure;
c2 = c;
c2(1, 2, "3", 4.2); // result is 6
```
78 changes: 50 additions & 28 deletions closure.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "closure/bind.hpp"
#include "closure/placeholders.hpp"
#include "closure/traits.hpp"
#include "closure/trivial_tuple.hpp"

namespace closure {

Expand Down Expand Up @@ -96,7 +97,7 @@ template <class... Args>
struct MaybeStores {
public:
static constexpr bool value = placeholders::HasNonGetter<ArgList<Args...>>::value;
using type = std::conditional_t<value, decltype(std::make_tuple(std::declval<Args>()...)), std::tuple<>>;
using type = std::conditional_t<value, tuple::TrivialTuple<std::decay_t<Args>...>, tuple::TrivialTuple<>>;
};

// Overload for function pointer and functor
Expand All @@ -117,7 +118,7 @@ class ClosureImpl<R(Args...), Callable, ArgList<StoredArgs...>> : public Closure

public:
using callee_type = Callable;
using stored_types = decltype(std::make_tuple(std::declval<StoredArgs>()...)); /*std::tuple<StoredArgs...>*/
using stored_types = tuple::TrivialTuple<std::decay_t<StoredArgs>...>;
using maybe_stores = MaybeStores<StoredArgs...>;
static_assert(!maybe_stores::value || std::is_same<stored_types, typename maybe_stores::type>::value,
"maybe stored type is not same as the stored_types");
Expand Down Expand Up @@ -176,7 +177,7 @@ class ClosureImpl<R(Args...), Callable, ArgList<StoredArgs...>> : public Closure

template <class MaybeHasPlaceHolder, std::enable_if_t<!MaybeHasPlaceHolder::value, int> = 0, std::size_t... I>
typename base::result_type InvokeHelper(std::index_sequence<I...>, Args&&... args) {
return invoke::INVOKE(callable_, std::get<I>(static_cast<stored_types&>(*this))..., std::forward<Args>(args)...);
return invoke::INVOKE(callable_, tuple::get<I>(static_cast<stored_types&>(*this))..., std::forward<Args>(args)...);
}

callee_type callable_;
Expand Down Expand Up @@ -464,25 +465,33 @@ class Closure<R(Args...)> {
};

// MakeClosure for function pointer, remove cv-qualifier and noexcept

template <class R, class... Args, class... Bounds,
std::enable_if_t<!placeholders::HasPlaceHolder<ArgList<Bounds...>>::value, int> = 0>
auto MakeClosure(R (*fptr)(Args...), Bounds&&... bound_args) {
auto MakeClosure_ClosureImplType(R (*fptr)(Args...), Bounds&&... bound_args) {
using closure_args = closureimpl::RemovePrefixWeakT<ArgList<Bounds...>, ArgList<Args...>>;
using closure_res_t = typename std::remove_pointer_t<decltype(closureimpl::MakeClosureImpl<R>(
nullptr, closure_args{}, fptr, std::forward<Bounds>(bound_args)...))>::closure_type;
return Closure<closure_res_t>(fptr, std::forward<Bounds>(bound_args)...);
using type =
decltype(closureimpl::MakeClosureImpl<R>(nullptr, closure_args{}, fptr, std::forward<Bounds>(bound_args)...));
return (type)(nullptr);
}

template <class R, class... Args, class... Bounds,
std::enable_if_t<placeholders::HasPlaceHolder<ArgList<Bounds...>>::value, int> = 0>
auto MakeClosure(R (*fptr)(Args...), Bounds&&... bound_args) {
auto MakeClosure_ClosureImplType(R (*fptr)(Args...), Bounds&&... bound_args) {
using bounds_l = ArgList<Bounds...>;
using args_l = ArgList<Args...>;
using replaced_types = closureimpl::ReplacePlaceHoldersWithGettersT<bounds_l, args_l>;
using closure_args = ConcatT<typename closureimpl::ReplacePlaceHoldersWithGetters<bounds_l, args_l>::agents_prototype,
closureimpl::RemovePrefixWeakT<bounds_l, args_l>>;
using closure_res_t = typename std::remove_pointer_t<decltype(closureimpl::MakeClosureImpl<R>(
nullptr, closure_args{}, replaced_types{}, fptr, std::forward<Bounds>(bound_args)...))>::closure_type;
using type = decltype(closureimpl::MakeClosureImpl<R>(nullptr, closure_args{}, replaced_types{}, fptr,
std::forward<Bounds>(bound_args)...));
return (type)(nullptr);
}

template <class R, class... Args, class... Bounds>
auto MakeClosure(R (*fptr)(Args...), Bounds&&... bound_args) {
using impl_type = decltype(MakeClosure_ClosureImplType(fptr, std::forward<Bounds>(bound_args)...));
using closure_res_t = typename std::remove_pointer_t<impl_type>::closure_type;
return Closure<closure_res_t>(fptr, std::forward<Bounds>(bound_args)...);
}

Expand All @@ -494,30 +503,36 @@ template <class Functor, class... Bounds,
std::enable_if_t<traits::IsSimpleFunctor<std::remove_reference_t<Functor>>::value &&
!placeholders::HasPlaceHolder<ArgList<Bounds...>>::value,
int> = 0>
auto MakeClosure(Functor&& functor, Bounds&&... bound_args) {
auto MakeClosure_ClosureImplType(Functor&& functor, Bounds&&... bound_args) {
using functor_traits = traits::SimpleFunctorTraits<std::remove_reference_t<Functor>>;
using closure_res_t =
typename std::remove_pointer_t<decltype(closureimpl::MakeClosureImpl<typename functor_traits::return_type>(
nullptr, typename functor_traits::args_type{}, std::forward<Functor>(functor),
std::forward<Bounds>(bound_args)...))>::closure_type;
return Closure<closure_res_t>(std::forward<Functor>(functor), std::forward<Bounds>(bound_args)...);
using type = decltype(closureimpl::MakeClosureImpl<typename functor_traits::return_type>(
nullptr, typename functor_traits::args_type{}, std::forward<Functor>(functor),
std::forward<Bounds>(bound_args)...));
return (type)(nullptr);
}

template <class Functor, class... Bounds,
std::enable_if_t<traits::IsSimpleFunctor<std::remove_reference_t<Functor>>::value &&
placeholders::HasPlaceHolder<ArgList<Bounds...>>::value,
int> = 0>
auto MakeClosure(Functor&& functor, Bounds&&... bound_args) {
auto MakeClosure_ClosureImplType(Functor&& functor, Bounds&&... bound_args) {
using functor_traits = traits::SimpleFunctorTraits<std::remove_reference_t<Functor>>;
using bounds_l = ArgList<Bounds...>;
using args_l = typename functor_traits::args_type;
using replaced_types = closureimpl::ReplacePlaceHoldersWithGettersT<bounds_l, args_l>;
using closure_args = ConcatT<typename closureimpl::ReplacePlaceHoldersWithGetters<bounds_l, args_l>::agents_prototype,
closureimpl::RemovePrefixWeakT<bounds_l, args_l>>;
using closure_res_t =
typename std::remove_pointer_t<decltype(closureimpl::MakeClosureImpl<typename functor_traits::return_type>(
nullptr, closure_args{}, replaced_types{}, std::forward<Functor>(functor),
std::forward<Bounds>(bound_args)...))>::closure_type;
using type = decltype(closureimpl::MakeClosureImpl<typename functor_traits::return_type>(
nullptr, closure_args{}, replaced_types{}, std::forward<Functor>(functor), std::forward<Bounds>(bound_args)...));
return (type)(nullptr);
}

template <class Functor, class... Bounds,
std::enable_if_t<traits::IsSimpleFunctor<std::remove_reference_t<Functor>>::value, int> = 0>
auto MakeClosure(Functor&& functor, Bounds&&... bound_args) {
using impl_type =
decltype(MakeClosure_ClosureImplType(std::forward<Functor>(functor), std::forward<Bounds>(bound_args)...));
using closure_res_t = typename std::remove_pointer_t<impl_type>::closure_type;
return Closure<closure_res_t>(std::forward<Functor>(functor), std::forward<Bounds>(bound_args)...);
}

Expand All @@ -526,22 +541,22 @@ template <class Method, class... Bounds,
std::enable_if_t<std::is_member_function_pointer<Method>::value &&
!placeholders::HasPlaceHolder<ArgList<Bounds...>>::value,
int> = 0>
auto MakeClosure(Method method, Bounds&&... bound_args) {
auto MakeClosure_ClosureImplType(Method method, Bounds&&... bound_args) {
using mfp_traits = traits::MemberFunctionPointerTraits<Method>;
using class_type = typename mfp_traits::class_type;
using args_type = typename mfp_traits::args_type;
using return_type = typename mfp_traits::return_type;
using closure_args = closureimpl::RemovePrefixWeakT<ArgList<Bounds...>, ConcatT<ArgList<class_type*>, args_type>>;
using closure_res_t = typename std::remove_pointer_t<decltype(closureimpl::MakeClosureImpl<return_type>(
nullptr, closure_args{}, method, std::forward<Bounds>(bound_args)...))>::closure_type;
return Closure<closure_res_t>(method, std::forward<Bounds>(bound_args)...);
using type = decltype(closureimpl::MakeClosureImpl<return_type>(nullptr, closure_args{}, method,
std::forward<Bounds>(bound_args)...));
return (type)(nullptr);
}

template <class Method, class... Bounds,
std::enable_if_t<std::is_member_function_pointer<Method>::value &&
placeholders::HasPlaceHolder<ArgList<Bounds...>>::value,
int> = 0>
auto MakeClosure(Method method, Bounds&&... bound_args) {
auto MakeClosure_ClosureImplType(Method method, Bounds&&... bound_args) {
using mfp_traits = traits::MemberFunctionPointerTraits<Method>;
using bounds_l = ArgList<Bounds...>;
using class_type = typename mfp_traits::class_type;
Expand All @@ -550,8 +565,15 @@ auto MakeClosure(Method method, Bounds&&... bound_args) {
using replaced_types = closureimpl::ReplacePlaceHoldersWithGettersT<bounds_l, args_l>;
using closure_args = ConcatT<typename closureimpl::ReplacePlaceHoldersWithGetters<bounds_l, args_l>::agents_prototype,
closureimpl::RemovePrefixWeakT<bounds_l, args_l>>;
using closure_res_t = typename std::remove_pointer_t<decltype(closureimpl::MakeClosureImpl<return_type>(
nullptr, closure_args{}, replaced_types{}, method, std::forward<Bounds>(bound_args)...))>::closure_type;
using type = decltype(closureimpl::MakeClosureImpl<return_type>(nullptr, closure_args{}, replaced_types{}, method,
std::forward<Bounds>(bound_args)...));
return type(nullptr);
}

template <class Method, class... Bounds, std::enable_if_t<std::is_member_function_pointer<Method>::value, int> = 0>
auto MakeClosure(Method method, Bounds&&... bound_args) {
using impl_type = decltype(MakeClosure_ClosureImplType(method, std::forward<Bounds>(bound_args)...));
using closure_res_t = typename std::remove_pointer_t<impl_type>::closure_type;
return Closure<closure_res_t>(method, std::forward<Bounds>(bound_args)...);
}

Expand Down
9 changes: 5 additions & 4 deletions closure/placeholders.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#pragma once

#include "closure/traits.hpp"
#include "closure/trivial_tuple.hpp"
#include "closure/util.hpp"

namespace closure {
Expand Down Expand Up @@ -151,15 +152,15 @@ template <size_t I, class AgentsTuple, class... Os>
struct HasNonGetter<ArgList<Getter<AgentsTuple, I>, Os...>> : HasNonGetter<ArgList<Os...>> {};

template <size_t I, class Tuple, class Agents,
std::enable_if_t<IsGetter<std::decay_t<decltype(std::get<I>(std::declval<Tuple>()))>>::value, int> = 0>
std::enable_if_t<IsGetter<std::decay_t<decltype(tuple::get<I>(std::declval<Tuple>()))>>::value, int> = 0>
decltype(auto) TryMapAndGet(Tuple&& tuple, Agents&& agents) noexcept {
return std::get<I>(std::forward<Tuple>(tuple)).Get(agents);
return tuple::get<I>(std::forward<Tuple>(tuple)).Get(agents);
}

template <size_t I, class Tuple, class Agents,
std::enable_if_t<!IsGetter<std::decay_t<decltype(std::get<I>(std::declval<Tuple>()))>>::value, int> = 0>
std::enable_if_t<!IsGetter<std::decay_t<decltype(tuple::get<I>(std::declval<Tuple>()))>>::value, int> = 0>
decltype(auto) TryMapAndGet(Tuple&& tuple, Agents&&) noexcept {
return std::get<I>(std::forward<Tuple>(tuple));
return tuple::get<I>(std::forward<Tuple>(tuple));
}

}; // namespace placeholders
Expand Down
77 changes: 28 additions & 49 deletions closure/traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,55 +100,6 @@ using std::void_t;

namespace traits {

template <class Tp>
struct IsFunctionOrPointerToFunction
: std::integral_constant<bool, std::is_function<Tp>::value || std::is_function<std::remove_pointer_t<Tp>>::value> {
};

template <class Tp, void_t<decltype(&Tp::operator->), decltype(&Tp::operator*)>* = nullptr>
auto IsDereferencableImpl(int) -> std::integral_constant<
bool, std::is_pointer<decltype(std::declval<Tp>().operator->())>::value &&
std::is_reference<decltype(std::declval<Tp>().operator*())>::value &&
std::is_same<std::remove_pointer_t<decltype(std::declval<Tp>().operator->())>,
std::remove_reference_t<decltype(std::declval<Tp>().operator*())>>::value>;

template <class Tp>
auto IsDereferencableImpl(...) -> std::is_pointer<Tp>;

template <class Ptr>
struct IsDereferencable : decltype(IsDereferencableImpl<Ptr>(0)) {};

template <class Dereferencable, class Method, class... Args>
auto TryCallMethod(int, Dereferencable&&, Method&&, Args&&...)
-> decltype(((*std::declval<Dereferencable>()).*std::declval<Method>())(std::declval<Args>()...), std::true_type{});

auto TryCallMethod(float, ...) -> std::false_type;

template <class Dereferencable, class Method>
struct CanUsePointerToMemberFunction : std::false_type {};

template <class Dereferencable, class R, class Class, class... Args>
struct CanUsePointerToMemberFunction<Dereferencable, R (Class::*)(Args...)>
: decltype(TryCallMethod(0, std::declval<Dereferencable>(), std::declval<R (Class::*)(Args...)>(),
std::declval<Args>()...)) {};

template <class Dereferencable, class R, class Class, class... Args>
struct CanUsePointerToMemberFunction<Dereferencable, R (Class::*)(Args...) const>
: decltype(TryCallMethod(0, std::declval<Dereferencable>(), std::declval<R (Class::*)(Args...) const>(),
std::declval<Args>()...)) {};

#if !(__cplusplus < 201703L)
template <class Dereferencable, class R, class Class, class... Args>
struct CanUsePointerToMemberFunction<Dereferencable, R (Class::*)(Args...) noexcept>
: decltype(TryCallMethod(0, std::declval<Dereferencable>(), std::declval<R (Class::*)(Args...) noexcept>(),
std::declval<Args>()...)) {};

template <class Dereferencable, class R, class Class, class... Args>
struct CanUsePointerToMemberFunction<Dereferencable, R (Class::*)(Args...) const noexcept>
: decltype(TryCallMethod(0, std::declval<Dereferencable>(), std::declval<R (Class::*)(Args...) const noexcept>(),
std::declval<Args>()...)) {};
#endif

template <class Op>
struct MemberFunctionPointerTraits {};

Expand All @@ -166,6 +117,20 @@ struct MemberFunctionPointerTraits<R (Class::*)(Args...) const> {
using args_type = ArgList<Args...>;
};

template <class R, class Class, class... Args>
struct MemberFunctionPointerTraits<R (Class::*)(Args...) volatile> {
using class_type = Class;
using return_type = R;
using args_type = ArgList<Args...>;
};

template <class R, class Class, class... Args>
struct MemberFunctionPointerTraits<R (Class::*)(Args...) const volatile> {
using class_type = Class;
using return_type = R;
using args_type = ArgList<Args...>;
};

#if !(__cplusplus < 201703L)
template <class R, class Class, class... Args>
struct MemberFunctionPointerTraits<R (Class::*)(Args...) noexcept> {
Expand All @@ -180,6 +145,20 @@ struct MemberFunctionPointerTraits<R (Class::*)(Args...) const noexcept> {
using return_type = R;
using args_type = ArgList<Args...>;
};

template <class R, class Class, class... Args>
struct MemberFunctionPointerTraits<R (Class::*)(Args...) volatile noexcept> {
using class_type = Class;
using return_type = R;
using args_type = ArgList<Args...>;
};

template <class R, class Class, class... Args>
struct MemberFunctionPointerTraits<R (Class::*)(Args...) const volatile noexcept> {
using class_type = Class;
using return_type = R;
using args_type = ArgList<Args...>;
};
#endif

// Traits for simple functor.
Expand Down
Loading

0 comments on commit 29c646a

Please sign in to comment.