-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ add first function_ref implementation
* the current implementation only supports up to one argument * void return type is currently not fully supported
- Loading branch information
Showing
6 changed files
with
346 additions
and
0 deletions.
There are no files selected for viewing
8 changes: 8 additions & 0 deletions
8
docs/sherds/2023/2023-10/2023-10-13T17_05_55Z_post_HJOtakocHZZVtTha.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
Shortcuts for `function_ref` | ||
|
||
We made some shortcuts in the `function_ref` implementation: | ||
|
||
* direct call to the callables (no `invoke`), this could mess up the calls for binding | ||
* no specialisation to `invocables` this could end up in ugly compiler errors | ||
* only support for one argument (to much boilerplate) | ||
* void is not proper supported (would need a specialisation) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#ifndef ZLL_FUNCTIONAL_DETAIL_BOUNDENTITYTPE_HPP | ||
#define ZLL_FUNCTIONAL_DETAIL_BOUNDENTITYTPE_HPP | ||
|
||
#include "zll/meta/traits/enable_if.hpp" | ||
#include "zll/meta/traits/is_const.hpp" | ||
#include "zll/meta/traits/is_function.hpp" | ||
#include "zll/meta/traits/is_object.hpp" | ||
|
||
namespace zll { | ||
namespace detail { | ||
|
||
struct bound_entity_object {}; | ||
struct bound_entity_function {}; | ||
|
||
union bound_entity_type { | ||
void* object_ptr; | ||
const void* const_object_ptr; | ||
void (*fn_ptr)(); | ||
|
||
bound_entity_type() : object_ptr(NULL) {} | ||
|
||
template <typename T> | ||
explicit bound_entity_type(T* ptr, bound_entity_object) : object_ptr(ptr) {} | ||
|
||
template <typename T> | ||
explicit bound_entity_type(const T* ptr, bound_entity_object) : const_object_ptr(ptr) {} | ||
|
||
template <typename T> | ||
explicit bound_entity_type(T* ptr, bound_entity_function) : fn_ptr(reinterpret_cast<void (*)()>(ptr)) {} | ||
}; | ||
|
||
template <typename T> | ||
static typename zll::meta::enable_if<zll::meta::is_object<T>::value && zll::meta::is_const<T>::value, T*>::type get( | ||
bound_entity_type entity) { | ||
return static_cast<T*>(entity.const_object_ptr); | ||
} | ||
|
||
template <typename T> | ||
static typename zll::meta::enable_if<zll::meta::is_object<T>::value && !(zll::meta::is_const<T>::value), T*>::type get( | ||
bound_entity_type entity) { | ||
return static_cast<T*>(entity.object_ptr); | ||
} | ||
|
||
template <typename T> | ||
static typename zll::meta::enable_if<!zll::meta::is_object<T>::value && (zll::meta::is_function<T>::value), T*>::type | ||
get(bound_entity_type entity) { | ||
return reinterpret_cast<T*>(entity.fn_ptr); | ||
} | ||
|
||
} // namespace detail | ||
} // namespace zll | ||
|
||
#endif // ZLL_FUNCTIONAL_DETAIL_BOUNDENTITYTPE_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#ifndef ZLL_FUNCTIONAL_DETAIL_FNTYPES_HPP | ||
#define ZLL_FUNCTIONAL_DETAIL_FNTYPES_HPP | ||
|
||
namespace zll { | ||
namespace detail { | ||
// clang-format off | ||
template <typename> struct fn_types; | ||
|
||
template <typename R> struct fn_types<R()> { typedef R type(); }; | ||
template <typename R> struct fn_types<R() const> { typedef R type(); }; | ||
|
||
template <typename R, typename T> struct fn_types<R(T)> { typedef R type(T); }; | ||
template <typename R, typename T> struct fn_types<R(T) const> { typedef R type(T); }; | ||
// clang-format on | ||
} // namespace detail | ||
} // namespace zll | ||
|
||
#endif // ZLL_FUNCTIONAL_DETAIL_FNTYPES_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
#ifndef ZLL_FUNCTIONAL_FUNCTIONREF_HPP | ||
#define ZLL_FUNCTIONAL_FUNCTIONREF_HPP | ||
|
||
#include "zll/functional/detail/bound_entity_type.hpp" | ||
#include "zll/functional/detail/fn_types.hpp" | ||
|
||
#include "zll/memory/address_of.hpp" | ||
|
||
#include "zll/meta/traits/enable_if.hpp" | ||
#include "zll/meta/traits/is_object.hpp" | ||
#include "zll/meta/traits/is_function.hpp" | ||
#include "zll/meta/traits/remove_reference.hpp" | ||
|
||
#include "zll/utils/nontype.hpp" | ||
|
||
namespace zll { | ||
namespace detail { | ||
|
||
template <typename T, typename U> | ||
struct fn_enable_if_object { | ||
typedef typename zll::meta::enable_if<zll::meta::is_object<T>::value, U>::type type; | ||
}; | ||
|
||
template <typename T, typename U> | ||
struct fn_enable_if_function { | ||
typedef typename zll::meta::enable_if<zll::meta::is_function<T>::value, U>::type type; | ||
}; | ||
|
||
} // namespace detail | ||
|
||
template <typename SIG_T, typename = typename detail::fn_types<SIG_T>::type> | ||
class function_ref; | ||
|
||
template <typename SIG_T, typename R> | ||
class function_ref<SIG_T, R()> { | ||
typedef detail::bound_entity_type entity_type; | ||
typedef R (*thunk_ptr_type)(entity_type); | ||
|
||
public: | ||
typedef R (*signature_type)(); | ||
|
||
template <typename F> | ||
explicit function_ref( | ||
const F& f, typename zll::meta::enable_if<!(zll::meta::is_member_pointer<F>::value || | ||
zll::is_nontype<typename zll::meta::remove_cvref<F>::type>::value), | ||
void*>::type = NULL) | ||
: m_bound_entity(zll::addressof(f), detail::bound_entity_object()), | ||
m_thunk_ptr(function_ref::thunk_call<typename zll::meta::remove_reference<F>::type>) {} | ||
|
||
template <typename F> | ||
explicit function_ref(F* f, typename detail::fn_enable_if_function<F, void*>::type = NULL) | ||
: m_bound_entity(f, detail::bound_entity_function()), m_thunk_ptr(function_ref::thunk_fn_call<F>) {} | ||
|
||
template <signature_type VALUE> | ||
function_ref(zll::nontype_t<signature_type, VALUE>) | ||
: m_bound_entity(), m_thunk_ptr(function_ref::thunk_nontype_call<VALUE>) {} | ||
|
||
template <typename T, T VALUE, typename U> | ||
function_ref(zll::nontype_t<T, VALUE>, U& obj) | ||
: m_bound_entity(zll::addressof(obj), detail::bound_entity_object()), | ||
m_thunk_ptr(function_ref::thunk_member_call<T, VALUE, U>) {} | ||
|
||
R operator()() const { return m_thunk_ptr(m_bound_entity); } | ||
|
||
private: | ||
template <typename T> | ||
static typename zll::meta::enable_if<!(zll::is_nontype<T>::value), R>::type thunk_call(entity_type entity) { | ||
T& obj = *detail::get<T>(entity); | ||
return obj(); | ||
} | ||
|
||
template <typename F> | ||
static R thunk_fn_call(entity_type entity) { | ||
return detail::get<F>(entity)(); | ||
} | ||
|
||
template <signature_type VALUE> | ||
static R thunk_nontype_call(entity_type) { | ||
return VALUE(); | ||
} | ||
|
||
template <typename T, T VALUE, typename U> | ||
static R thunk_member_call(entity_type entity) { | ||
U& obj = *detail::get<U>(entity); | ||
return (obj.*VALUE)(); | ||
} | ||
|
||
entity_type m_bound_entity; | ||
thunk_ptr_type m_thunk_ptr; | ||
}; | ||
|
||
template <typename SIG_T, typename R, typename ARG1_T> | ||
class function_ref<SIG_T, R(ARG1_T)> { | ||
typedef detail::bound_entity_type entity_type; | ||
typedef R (*thunk_ptr_type)(entity_type, ARG1_T); | ||
|
||
public: | ||
typedef R (*signature_type)(ARG1_T); | ||
|
||
template <typename F> | ||
explicit function_ref( | ||
const F& f, typename zll::meta::enable_if<!(zll::meta::is_member_pointer<F>::value || | ||
zll::is_nontype<typename zll::meta::remove_cvref<F>::type>::value), | ||
void*>::type = NULL) | ||
: m_bound_entity(zll::addressof(f), detail::bound_entity_object()), | ||
m_thunk_ptr(function_ref::thunk_call<typename zll::meta::remove_reference<F>::type>) {} | ||
|
||
template <typename F> | ||
explicit function_ref(F* f, typename detail::fn_enable_if_function<F, void*>::type = NULL) | ||
: m_bound_entity(f, detail::bound_entity_function()), m_thunk_ptr(function_ref::thunk_fn_call<F>) {} | ||
|
||
template <signature_type VALUE> | ||
function_ref(zll::nontype_t<signature_type, VALUE>) | ||
: m_bound_entity(), m_thunk_ptr(function_ref::thunk_nontype_call<VALUE>) {} | ||
|
||
template <typename T, T VALUE, typename U> | ||
function_ref(zll::nontype_t<T, VALUE>, U& obj) | ||
: m_bound_entity(zll::addressof(obj), detail::bound_entity_object()), | ||
m_thunk_ptr(function_ref::thunk_member_call<T, VALUE, U>) {} | ||
|
||
R operator()(ARG1_T arg) const { return m_thunk_ptr(m_bound_entity, arg); } | ||
|
||
private: | ||
template <typename T> | ||
static typename zll::meta::enable_if<!(zll::is_nontype<T>::value), R>::type thunk_call(entity_type entity, | ||
ARG1_T arg) { | ||
T& obj = *detail::get<T>(entity); | ||
return obj(arg); | ||
} | ||
|
||
template <typename F> | ||
static R thunk_fn_call(entity_type entity, ARG1_T arg) { | ||
return detail::get<F>(entity)(arg); | ||
} | ||
|
||
template <signature_type VALUE> | ||
static R thunk_nontype_call(entity_type, ARG1_T arg) { | ||
return VALUE(arg); | ||
} | ||
|
||
template <typename T, T VALUE, typename U> | ||
static R thunk_member_call(entity_type entity, ARG1_T arg) { | ||
U& obj = *detail::get<U>(entity); | ||
return (obj.*VALUE)(arg); | ||
} | ||
|
||
entity_type m_bound_entity; | ||
thunk_ptr_type m_thunk_ptr; | ||
}; | ||
|
||
} // namespace zll | ||
|
||
#endif // ZLL_FUNCTIONAL_FUNCTIONREF_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
#include <zll/functional/function_ref.hpp> | ||
#include <zll/utils/typeof_macro.hpp> | ||
|
||
#include <utest.h> | ||
|
||
struct functor1 { | ||
int operator()() const { return 17; } | ||
}; | ||
|
||
int free_fun1() { return 42; } | ||
|
||
struct static_fun { | ||
static int fun() { return 15; } | ||
}; | ||
|
||
struct member_fun { | ||
int fun() const { return 3; } | ||
}; | ||
|
||
UTEST(functional_function_ref, no_parameter) { | ||
{ | ||
functor1 fun; | ||
zll::function_ref<int() const> fn_ref(fun); | ||
|
||
ASSERT_EQ(fn_ref(), 17); | ||
} | ||
{ | ||
const functor1 fun; | ||
zll::function_ref<int() const> fn_ref(fun); | ||
|
||
ASSERT_EQ(fn_ref(), 17); | ||
} | ||
{ | ||
zll::function_ref<int()> fn_ref(free_fun1); | ||
ASSERT_EQ(fn_ref(), 42); | ||
} | ||
{ | ||
zll::function_ref<int()> fn_ref(&free_fun1); | ||
ASSERT_EQ(fn_ref(), 42); | ||
} | ||
{ | ||
zll::nontype_t<int (*)(), free_fun1> nontype; | ||
zll::function_ref<int()> fn_ref(nontype); | ||
ASSERT_EQ(fn_ref(), 42); | ||
} | ||
{ | ||
zll::nontype_t<int (*)(), static_fun::fun> nontype; | ||
zll::function_ref<int()> fn_ref(nontype); | ||
ASSERT_EQ(fn_ref(), 15); | ||
} | ||
{ | ||
zll::nontype_t<ZLL_TYPE_OF(&member_fun::fun), &member_fun::fun> nontype; | ||
|
||
member_fun obj; | ||
zll::function_ref<int()> fn_ref(nontype, obj); | ||
ASSERT_EQ(fn_ref(), 3); | ||
} | ||
} | ||
|
||
struct functor2 { | ||
int operator()(int a) const { return a; } | ||
}; | ||
|
||
int free_fun2(char) { return 42; } | ||
|
||
struct static_fun2 { | ||
static int fun(int a) { return a; } | ||
}; | ||
|
||
struct member_fun2 { | ||
int fun(int a) const { return a; } | ||
}; | ||
|
||
UTEST(functional_function_ref, one_parameter) { | ||
{ | ||
functor2 fun; | ||
zll::function_ref<int(int) const> fn_ref(fun); | ||
|
||
ASSERT_EQ(fn_ref(5), 5); | ||
} | ||
{ | ||
const functor2 fun; | ||
zll::function_ref<int(int) const> fn_ref(fun); | ||
|
||
ASSERT_EQ(fn_ref(8), 8); | ||
} | ||
{ | ||
zll::function_ref<int(char)> fn_ref(free_fun2); | ||
ASSERT_EQ(fn_ref('a'), 42); | ||
} | ||
{ | ||
zll::function_ref<int(char)> fn_ref(&free_fun2); | ||
ASSERT_EQ(fn_ref('f'), 42); | ||
} | ||
{ | ||
zll::nontype_t<int (*)(char), free_fun2> nontype; | ||
zll::function_ref<int(char)> fn_ref(nontype); | ||
ASSERT_EQ(fn_ref('g'), 42); | ||
} | ||
{ | ||
zll::nontype_t<int (*)(int), static_fun2::fun> nontype; | ||
zll::function_ref<int(int)> fn_ref(nontype); | ||
ASSERT_EQ(fn_ref(11), 11); | ||
} | ||
{ | ||
zll::nontype_t<ZLL_TYPE_OF(&member_fun2::fun), &member_fun2::fun> nontype; | ||
|
||
member_fun2 obj; | ||
zll::function_ref<int(int)> fn_ref(nontype, obj); | ||
ASSERT_EQ(fn_ref(-12), -12); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters