Changed non-capturing lambda API to runtime function pointer API

This commit is contained in:
John Wellbelove 2026-03-31 11:23:49 +01:00 committed by Benedek Kupper
parent bfbb7259e1
commit ea397ec2dd
2 changed files with 186 additions and 123 deletions

View File

@ -118,6 +118,11 @@ namespace etl
template <typename TReturn, typename... TArgs> template <typename TReturn, typename... TArgs>
class delegate<TReturn(TArgs...)> final : public delegate_tag class delegate<TReturn(TArgs...)> final : public delegate_tag
{ {
private:
using object_ptr = void*;
using function_ptr = TReturn(*)(TArgs...);
public: public:
using return_type = TReturn; using return_type = TReturn;
@ -141,7 +146,7 @@ namespace etl
template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !is_delegate<TLambda>::value, void>> template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !is_delegate<TLambda>::value, void>>
ETL_CONSTEXPR14 delegate(TLambda& instance) ETL_NOEXCEPT ETL_CONSTEXPR14 delegate(TLambda& instance) ETL_NOEXCEPT
{ {
assign((void*)(&instance), lambda_stub<TLambda>); assign(object_ptr(&instance), lambda_stub<TLambda>);
} }
//************************************************************************* //*************************************************************************
@ -150,26 +155,24 @@ namespace etl
template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !is_delegate<TLambda>::value, void>> template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !is_delegate<TLambda>::value, void>>
ETL_CONSTEXPR14 delegate(const TLambda& instance) ETL_NOEXCEPT ETL_CONSTEXPR14 delegate(const TLambda& instance) ETL_NOEXCEPT
{ {
assign((void*)(&instance), const_lambda_stub<TLambda>); assign(object_ptr(&instance), const_lambda_stub<TLambda>);
} }
//************************************************************************* //*************************************************************************
// Delete construction from rvalue reference lambda or functor. // Delete construction from rvalue reference lambda or functor.
// Excludes non-capturing lambdas convertible to a function pointer. // Excludes non-capturing lambdas convertible to a function pointer.
//************************************************************************* //*************************************************************************
template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_same<etl::delegate<TReturn(TArgs...)>, TLambda>::value && !etl::is_convertible<TLambda, TReturn(*)(TArgs...)>::value, void>> template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value &&
!etl::is_same<etl::delegate<TReturn(TArgs...)>, TLambda>::value &&
!etl::is_convertible<TLambda, function_ptr>::value, void>>
ETL_CONSTEXPR14 delegate(TLambda&& instance) = delete; ETL_CONSTEXPR14 delegate(TLambda&& instance) = delete;
//************************************************************************* //*************************************************************************
// Construct from non-capturing rvalue lambda convertible to function pointer. // Construct from a function pointer.
// Converts to a function pointer to avoid storing a dangling pointer
// to a destroyed temporary.
//************************************************************************* //*************************************************************************
template <typename TLambda, etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_reference<TLambda>::value && etl::is_convertible<TLambda, TReturn(*)(TArgs...)>::value, int> = 0> delegate(function_ptr fp) ETL_NOEXCEPT
delegate(TLambda&& instance) ETL_NOEXCEPT
{ {
TReturn(*fp)(TArgs...) = static_cast<TReturn(*)(TArgs...)>(instance); assign(fp, function_ptr_stub);
assign(reinterpret_cast<void*>(fp), function_ptr_stub);
} }
//************************************************************************* //*************************************************************************
@ -179,7 +182,7 @@ namespace etl
ETL_NODISCARD ETL_NODISCARD
static ETL_CONSTEXPR14 delegate create() ETL_NOEXCEPT static ETL_CONSTEXPR14 delegate create() ETL_NOEXCEPT
{ {
return delegate(ETL_NULLPTR, function_stub<Method>); return delegate(function_stub<Method>);
} }
//************************************************************************* //*************************************************************************
@ -189,7 +192,7 @@ namespace etl
ETL_NODISCARD ETL_NODISCARD
static ETL_CONSTEXPR14 delegate create(TLambda& instance) ETL_NOEXCEPT static ETL_CONSTEXPR14 delegate create(TLambda& instance) ETL_NOEXCEPT
{ {
return delegate((void*)(&instance), lambda_stub<TLambda>); return delegate(object_ptr(&instance), lambda_stub<TLambda>);
} }
//************************************************************************* //*************************************************************************
@ -199,20 +202,16 @@ namespace etl
ETL_NODISCARD ETL_NODISCARD
static ETL_CONSTEXPR14 delegate create(const TLambda& instance) ETL_NOEXCEPT static ETL_CONSTEXPR14 delegate create(const TLambda& instance) ETL_NOEXCEPT
{ {
return delegate((void*)(&instance), const_lambda_stub<TLambda>); return delegate(object_ptr(&instance), const_lambda_stub<TLambda>);
} }
//************************************************************************* //*************************************************************************
// Create from non-capturing rvalue lambda convertible to function pointer. // Create from a function pointer.
// Converts to a function pointer to avoid storing a dangling pointer
// to a destroyed temporary.
//************************************************************************* //*************************************************************************
template <typename TLambda, etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_reference<TLambda>::value && etl::is_convertible<TLambda, TReturn(*)(TArgs...)>::value, int> = 0>
ETL_NODISCARD ETL_NODISCARD
static delegate create(TLambda&& instance) ETL_NOEXCEPT static delegate create(function_ptr fp) ETL_NOEXCEPT
{ {
TReturn(*fp)(TArgs...) = static_cast<TReturn(*)(TArgs...)>(instance); return delegate(fp, function_ptr_stub);
return delegate(reinterpret_cast<void*>(fp), function_ptr_stub);
} }
//************************************************************************* //*************************************************************************
@ -222,7 +221,7 @@ namespace etl
ETL_NODISCARD ETL_NODISCARD
static ETL_CONSTEXPR14 delegate create(T& instance) ETL_NOEXCEPT static ETL_CONSTEXPR14 delegate create(T& instance) ETL_NOEXCEPT
{ {
return delegate((void*)(&instance), method_stub<T, Method>); return delegate(object_ptr(&instance), method_stub<T, Method>);
} }
//************************************************************************* //*************************************************************************
@ -240,7 +239,7 @@ namespace etl
ETL_NODISCARD ETL_NODISCARD
static ETL_CONSTEXPR14 delegate create(const T& instance) ETL_NOEXCEPT static ETL_CONSTEXPR14 delegate create(const T& instance) ETL_NOEXCEPT
{ {
return delegate((void*)(&instance), const_method_stub<T, Method>); return delegate(object_ptr(&instance), const_method_stub<T, Method>);
} }
//************************************************************************* //*************************************************************************
@ -310,7 +309,7 @@ namespace etl
template <TReturn(*Method)(TArgs...)> template <TReturn(*Method)(TArgs...)>
ETL_CONSTEXPR14 void set() ETL_NOEXCEPT ETL_CONSTEXPR14 void set() ETL_NOEXCEPT
{ {
assign(ETL_NULLPTR, function_stub<Method>); assign(function_stub<Method>);
} }
//************************************************************************* //*************************************************************************
@ -319,7 +318,7 @@ namespace etl
template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !is_delegate<TLambda>::value, void>> template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !is_delegate<TLambda>::value, void>>
ETL_CONSTEXPR14 void set(TLambda& instance) ETL_NOEXCEPT ETL_CONSTEXPR14 void set(TLambda& instance) ETL_NOEXCEPT
{ {
assign((void*)(&instance), lambda_stub<TLambda>); assign(object_ptr(&instance), lambda_stub<TLambda>);
} }
//************************************************************************* //*************************************************************************
@ -328,19 +327,15 @@ namespace etl
template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !is_delegate<TLambda>::value, void>> template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !is_delegate<TLambda>::value, void>>
ETL_CONSTEXPR14 void set(const TLambda& instance) ETL_NOEXCEPT ETL_CONSTEXPR14 void set(const TLambda& instance) ETL_NOEXCEPT
{ {
assign((void*)(&instance), const_lambda_stub<TLambda>); assign(object_ptr(&instance), const_lambda_stub<TLambda>);
} }
//************************************************************************* //*************************************************************************
// Set from non-capturing rvalue lambda convertible to function pointer. // Set from a function pointer.
// Converts to a function pointer to avoid storing a dangling pointer
// to a destroyed temporary.
//************************************************************************* //*************************************************************************
template <typename TLambda, etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_reference<TLambda>::value && etl::is_convertible<TLambda, TReturn(*)(TArgs...)>::value, int> = 0> void set(function_ptr fp) ETL_NOEXCEPT
void set(TLambda&& instance) ETL_NOEXCEPT
{ {
TReturn(*fp)(TArgs...) = static_cast<TReturn(*)(TArgs...)>(instance); assign(fp, function_ptr_stub);
assign(reinterpret_cast<void*>(fp), function_ptr_stub);
} }
//************************************************************************* //*************************************************************************
@ -349,7 +344,7 @@ namespace etl
template <typename T, TReturn(T::* Method)(TArgs...)> template <typename T, TReturn(T::* Method)(TArgs...)>
ETL_CONSTEXPR14 void set(T& instance) ETL_NOEXCEPT ETL_CONSTEXPR14 void set(T& instance) ETL_NOEXCEPT
{ {
assign((void*)(&instance), method_stub<T, Method>); assign(object_ptr(&instance), method_stub<T, Method>);
} }
//************************************************************************* //*************************************************************************
@ -358,7 +353,7 @@ namespace etl
template <typename T, TReturn(T::* Method)(TArgs...) const> template <typename T, TReturn(T::* Method)(TArgs...) const>
ETL_CONSTEXPR14 void set(T& instance) ETL_NOEXCEPT ETL_CONSTEXPR14 void set(T& instance) ETL_NOEXCEPT
{ {
assign((void*)(&instance), const_method_stub<T, Method>); assign(object_ptr(&instance), const_method_stub<T, Method>);
} }
//************************************************************************* //*************************************************************************
@ -367,7 +362,7 @@ namespace etl
template <typename T, T& Instance, TReturn(T::* Method)(TArgs...)> template <typename T, T& Instance, TReturn(T::* Method)(TArgs...)>
ETL_CONSTEXPR14 void set() ETL_NOEXCEPT ETL_CONSTEXPR14 void set() ETL_NOEXCEPT
{ {
assign(ETL_NULLPTR, method_instance_stub<T, Method, Instance>); assign(method_instance_stub<T, Method, Instance>);
} }
//************************************************************************* //*************************************************************************
@ -377,7 +372,7 @@ namespace etl
template <typename T, TReturn(T::* Method)(TArgs...), T& Instance> template <typename T, TReturn(T::* Method)(TArgs...), T& Instance>
ETL_CONSTEXPR14 void set() ETL_NOEXCEPT ETL_CONSTEXPR14 void set() ETL_NOEXCEPT
{ {
assign(ETL_NULLPTR, method_instance_stub<T, Method, Instance>); assign(method_instance_stub<T, Method, Instance>);
} }
//************************************************************************* //*************************************************************************
@ -386,7 +381,7 @@ namespace etl
template <typename T, T const& Instance, TReturn(T::* Method)(TArgs...) const> template <typename T, T const& Instance, TReturn(T::* Method)(TArgs...) const>
ETL_CONSTEXPR14 void set() ETL_NOEXCEPT ETL_CONSTEXPR14 void set() ETL_NOEXCEPT
{ {
assign(ETL_NULLPTR, const_method_instance_stub<T, Method, Instance>); assign(const_method_instance_stub<T, Method, Instance>);
} }
//************************************************************************* //*************************************************************************
@ -396,7 +391,7 @@ namespace etl
template <typename T, TReturn(T::* Method)(TArgs...) const, T const& Instance> template <typename T, TReturn(T::* Method)(TArgs...) const, T const& Instance>
ETL_CONSTEXPR14 void set() ETL_NOEXCEPT ETL_CONSTEXPR14 void set() ETL_NOEXCEPT
{ {
assign(ETL_NULLPTR, const_method_instance_stub<T, Method, Instance>); assign(const_method_instance_stub<T, Method, Instance>);
} }
//************************************************************************* //*************************************************************************
@ -419,7 +414,7 @@ namespace etl
ETL_ASSERT(is_valid(), ETL_ERROR(delegate_uninitialised)); ETL_ASSERT(is_valid(), ETL_ERROR(delegate_uninitialised));
return (*invocation.stub)(invocation.object, etl::forward<TCallArgs>(args)...); return (*invocation.stub)(invocation, etl::forward<TCallArgs>(args)...);
} }
//************************************************************************* //*************************************************************************
@ -436,7 +431,7 @@ namespace etl
if (is_valid()) if (is_valid())
{ {
(*invocation.stub)(invocation.object, etl::forward<TCallArgs>(args)...); (*invocation.stub)(invocation, etl::forward<TCallArgs>(args)...);
return true; return true;
} }
else else
@ -461,7 +456,7 @@ namespace etl
if (is_valid()) if (is_valid())
{ {
result = (*invocation.stub)(invocation.object, etl::forward<TCallArgs>(args)...); result = (*invocation.stub)(invocation, etl::forward<TCallArgs>(args)...);
} }
return result; return result;
@ -479,7 +474,7 @@ namespace etl
if (is_valid()) if (is_valid())
{ {
return (*invocation.stub)(invocation.object, etl::forward<TCallArgs>(args)...); return (*invocation.stub)(invocation, etl::forward<TCallArgs>(args)...);
} }
else else
{ {
@ -499,7 +494,7 @@ namespace etl
if (is_valid()) if (is_valid())
{ {
return (*invocation.stub)(invocation.object, etl::forward<TCallArgs>(args)...); return (*invocation.stub)(invocation, etl::forward<TCallArgs>(args)...);
} }
else else
{ {
@ -518,7 +513,7 @@ namespace etl
template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !is_delegate<TLambda>::value, void>> template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !is_delegate<TLambda>::value, void>>
ETL_CONSTEXPR14 delegate& operator =(TLambda& instance) ETL_NOEXCEPT ETL_CONSTEXPR14 delegate& operator =(TLambda& instance) ETL_NOEXCEPT
{ {
assign((void*)(&instance), lambda_stub<TLambda>); assign(object_ptr(&instance), lambda_stub<TLambda>);
return *this; return *this;
} }
@ -528,20 +523,16 @@ namespace etl
template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !is_delegate<TLambda>::value, void>> template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !is_delegate<TLambda>::value, void>>
ETL_CONSTEXPR14 delegate& operator =(const TLambda& instance) ETL_NOEXCEPT ETL_CONSTEXPR14 delegate& operator =(const TLambda& instance) ETL_NOEXCEPT
{ {
assign((void*)(&instance), const_lambda_stub<TLambda>); assign(object_ptr(&instance), const_lambda_stub<TLambda>);
return *this; return *this;
} }
//************************************************************************* //*************************************************************************
// Create from non-capturing rvalue lambda convertible to function pointer. // Create from a function pointer.
// Converts to a function pointer to avoid storing a dangling pointer
// to a destroyed temporary.
//************************************************************************* //*************************************************************************
template <typename TLambda, etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_reference<TLambda>::value && etl::is_convertible<TLambda, TReturn(*)(TArgs...)>::value, int> = 0> delegate& operator =(function_ptr fp) ETL_NOEXCEPT
delegate& operator =(TLambda&& instance) ETL_NOEXCEPT
{ {
TReturn(*fp)(TArgs...) = static_cast<TReturn(*)(TArgs...)>(instance); assign(fp, function_ptr_stub);
assign(reinterpret_cast<void*>(fp), function_ptr_stub);
return *this; return *this;
} }
@ -582,13 +573,11 @@ namespace etl
private: private:
using stub_type = TReturn(*)(void* object, TArgs...);
//************************************************************************* //*************************************************************************
// Callable compatibility: detects if C (or const C) is invocable with (TArgs...) and returns a type // Callable compatibility: detects if C (or const C) is invocable with (TArgs...) and returns a type
// convertible to TReturn. Works with generic lambdas and functors. // convertible to TReturn. Works with generic lambdas and functors.
template <typename TCallableType, typename = void> template <typename TCallableType, typename = void>
struct is_invocable_with struct is_invocable_with
: etl::false_type {}; : etl::false_type {};
template <typename TCallableType> template <typename TCallableType>
@ -614,11 +603,32 @@ namespace etl
//************************************************************************* //*************************************************************************
struct invocation_element struct invocation_element
{ {
invocation_element() = default; using stub_type = TReturn(*)(const invocation_element&, TArgs...);
//*********************************************************************** //***********************************************************************
ETL_CONSTEXPR14 invocation_element(void* object_, stub_type stub_) ETL_NOEXCEPT ETL_CONSTEXPR14 invocation_element() ETL_NOEXCEPT
: object(object_) : ptr(object_ptr(ETL_NULLPTR))
, stub(ETL_NULLPTR)
{
}
//***********************************************************************
ETL_CONSTEXPR14 invocation_element(stub_type stub_) ETL_NOEXCEPT
: ptr()
, stub(stub_)
{
}
//***********************************************************************
ETL_CONSTEXPR14 invocation_element(object_ptr object_, stub_type stub_) ETL_NOEXCEPT
: ptr(object_)
, stub(stub_)
{
}
//***********************************************************************
ETL_CONSTEXPR14 invocation_element(function_ptr fp_, stub_type stub_) ETL_NOEXCEPT
: ptr(fp_)
, stub(stub_) , stub(stub_)
{ {
} }
@ -626,59 +636,109 @@ namespace etl
//*********************************************************************** //***********************************************************************
ETL_CONSTEXPR14 bool operator ==(const invocation_element& rhs) const ETL_NOEXCEPT ETL_CONSTEXPR14 bool operator ==(const invocation_element& rhs) const ETL_NOEXCEPT
{ {
return (rhs.stub == stub) && (rhs.object == object); return (rhs.stub == stub) &&
((stub == function_ptr_stub) ? (rhs.ptr.fp == ptr.fp)
: (rhs.ptr.object == ptr.object));
} }
//*********************************************************************** //***********************************************************************
ETL_CONSTEXPR14 bool operator !=(const invocation_element& rhs) const ETL_NOEXCEPT ETL_CONSTEXPR14 bool operator !=(const invocation_element& rhs) const ETL_NOEXCEPT
{ {
return (rhs.stub != stub) || (rhs.object != object); return !operator==(rhs);
} }
//*********************************************************************** //***********************************************************************
ETL_CONSTEXPR14 void clear() ETL_NOEXCEPT ETL_CONSTEXPR14 void clear() ETL_NOEXCEPT
{ {
object = ETL_NULLPTR; stub = ETL_NULLPTR;
stub = ETL_NULLPTR;
} }
//*********************************************************************** //***********************************************************************
void* object = ETL_NULLPTR; union ptr_type
stub_type stub = ETL_NULLPTR; {
ETL_CONSTEXPR14 ptr_type() ETL_NOEXCEPT
: object(ETL_NULLPTR)
{
}
ETL_CONSTEXPR14 ptr_type(object_ptr object_) ETL_NOEXCEPT
: object(object_)
{
}
ETL_CONSTEXPR14 ptr_type(function_ptr fp_) ETL_NOEXCEPT
: fp(fp_)
{
}
object_ptr object;
function_ptr fp;
};
ptr_type ptr;
stub_type stub;
}; };
using stub_type = typename invocation_element::stub_type;
//************************************************************************* //*************************************************************************
/// Constructs a delegate from an object and stub. /// Constructs a delegate from an object and stub.
//************************************************************************* //*************************************************************************
ETL_CONSTEXPR14 delegate(void* object, stub_type stub) ETL_NOEXCEPT ETL_CONSTEXPR14 delegate(object_ptr object, stub_type stub) ETL_NOEXCEPT
: invocation(object, stub) : invocation(object, stub)
{ {
} }
//*************************************************************************
/// Constructs a delegate from an function and stub.
//*************************************************************************
ETL_CONSTEXPR14 delegate(function_ptr fp, stub_type stub) ETL_NOEXCEPT
: invocation(fp, stub)
{
}
//************************************************************************* //*************************************************************************
/// Constructs a delegate from a stub. /// Constructs a delegate from a stub.
//************************************************************************* //*************************************************************************
ETL_CONSTEXPR14 delegate(stub_type stub) ETL_NOEXCEPT ETL_CONSTEXPR14 delegate(stub_type stub) ETL_NOEXCEPT
: invocation(ETL_NULLPTR, stub) : invocation(stub)
{ {
} }
//************************************************************************* //*************************************************************************
/// Assign from an object and stub. /// Assign from an object and stub.
//************************************************************************* //*************************************************************************
ETL_CONSTEXPR14 void assign(void* object, stub_type stub) ETL_NOEXCEPT ETL_CONSTEXPR14 void assign(object_ptr object, stub_type stub) ETL_NOEXCEPT
{ {
invocation.object = object; invocation.ptr.object = object;
invocation.stub = stub;
}
//*************************************************************************
/// Assign from a function and stub.
//*************************************************************************
ETL_CONSTEXPR14 void assign(function_ptr fp, stub_type stub) ETL_NOEXCEPT
{
invocation.ptr.fp = fp;
invocation.stub = stub; invocation.stub = stub;
} }
//*************************************************************************
/// Assign from a stub.
//*************************************************************************
ETL_CONSTEXPR14 void assign(stub_type stub) ETL_NOEXCEPT
{
invocation.ptr.object = ETL_NULLPTR;
invocation.stub = stub;
}
//************************************************************************* //*************************************************************************
/// Stub call for a member function. Run time instance. /// Stub call for a member function. Run time instance.
//************************************************************************* //*************************************************************************
template <typename T, TReturn(T::*Method)(TArgs...)> template <typename T, TReturn(T::*Method)(TArgs...)>
static ETL_CONSTEXPR14 TReturn method_stub(void* object, TArgs... args) static ETL_CONSTEXPR14 TReturn method_stub(const invocation_element& invocation, TArgs... args)
{ {
T* p = static_cast<T*>(object); T* p = static_cast<T*>(invocation.ptr.object);
return (p->*Method)(etl::forward<TArgs>(args)...); return (p->*Method)(etl::forward<TArgs>(args)...);
} }
@ -686,9 +746,9 @@ namespace etl
/// Stub call for a const member function. Run time instance. /// Stub call for a const member function. Run time instance.
//************************************************************************* //*************************************************************************
template <typename T, TReturn(T::*Method)(TArgs...) const> template <typename T, TReturn(T::*Method)(TArgs...) const>
static ETL_CONSTEXPR14 TReturn const_method_stub(void* object, TArgs... args) static ETL_CONSTEXPR14 TReturn const_method_stub(const invocation_element& invocation, TArgs... args)
{ {
T* const p = static_cast<T*>(object); T* const p = static_cast<T*>(invocation.ptr.object);
return (p->*Method)(etl::forward<TArgs>(args)...); return (p->*Method)(etl::forward<TArgs>(args)...);
} }
@ -696,7 +756,7 @@ namespace etl
/// Stub call for a member function. Compile time instance. /// Stub call for a member function. Compile time instance.
//************************************************************************* //*************************************************************************
template <typename T, TReturn(T::*Method)(TArgs...), T& Instance> template <typename T, TReturn(T::*Method)(TArgs...), T& Instance>
static ETL_CONSTEXPR14 TReturn method_instance_stub(void*, TArgs... args) static ETL_CONSTEXPR14 TReturn method_instance_stub(const invocation_element&, TArgs... args)
{ {
return (Instance.*Method)(etl::forward<TArgs>(args)...); return (Instance.*Method)(etl::forward<TArgs>(args)...);
} }
@ -705,7 +765,7 @@ namespace etl
/// Stub call for a const member function. Compile time instance. /// Stub call for a const member function. Compile time instance.
//************************************************************************* //*************************************************************************
template <typename T, TReturn(T::*Method)(TArgs...) const, const T& Instance> template <typename T, TReturn(T::*Method)(TArgs...) const, const T& Instance>
static ETL_CONSTEXPR14 TReturn const_method_instance_stub(void*, TArgs... args) static ETL_CONSTEXPR14 TReturn const_method_instance_stub(const invocation_element&, TArgs... args)
{ {
return (Instance.*Method)(etl::forward<TArgs>(args)...); return (Instance.*Method)(etl::forward<TArgs>(args)...);
} }
@ -715,7 +775,7 @@ namespace etl
/// Stub call for a function operator. Compile time instance. /// Stub call for a function operator. Compile time instance.
//************************************************************************* //*************************************************************************
template <typename T, T& Instance> template <typename T, T& Instance>
static ETL_CONSTEXPR14 TReturn operator_instance_stub(void*, TArgs... args) static ETL_CONSTEXPR14 TReturn operator_instance_stub(const invocation_element&, TArgs... args)
{ {
return Instance.operator()(etl::forward<TArgs>(args)...); return Instance.operator()(etl::forward<TArgs>(args)...);
} }
@ -725,30 +785,28 @@ namespace etl
/// Stub call for a free function. /// Stub call for a free function.
//************************************************************************* //*************************************************************************
template <TReturn(*Method)(TArgs...)> template <TReturn(*Method)(TArgs...)>
static ETL_CONSTEXPR14 TReturn function_stub(void*, TArgs... args) static ETL_CONSTEXPR14 TReturn function_stub(const invocation_element&, TArgs... args)
{ {
return (Method)(etl::forward<TArgs>(args)...); return (Method)(etl::forward<TArgs>(args)...);
} }
//************************************************************************* //*************************************************************************
/// Stub call for a runtime function pointer stored in the object field. /// Stub call for a runtime function pointer stored in the invocation_element.
//************************************************************************* //*************************************************************************
static TReturn function_ptr_stub(void* object, TArgs... args) static TReturn function_ptr_stub(const invocation_element& invocation, TArgs... args)
{ {
ETL_STATIC_ASSERT(sizeof(void*) >= sizeof(TReturn(*)(TArgs...)), "etl::delegate: function pointer too large to store in object field"); return invocation.ptr.fp(etl::forward<TArgs>(args)...);
TReturn(*fp)(TArgs...) = reinterpret_cast<TReturn(*)(TArgs...)>(object);
return fp(etl::forward<TArgs>(args)...);
} }
//************************************************************************* //*************************************************************************
/// Stub call for a lambda or functor function. /// Stub call for a lambda or functor function.
//************************************************************************* //*************************************************************************
template <typename TLambda> template <typename TLambda>
static ETL_CONSTEXPR14 TReturn lambda_stub(void* object, TArgs... arg) static ETL_CONSTEXPR14 TReturn lambda_stub(const invocation_element& invocation, TArgs... arg)
{ {
ETL_STATIC_ASSERT(is_compatible_callable<TLambda>::value, "etl::delegate: bound lambda/functor is not compatible with the delegate signature"); ETL_STATIC_ASSERT(is_compatible_callable<TLambda>::value, "etl::delegate: bound lambda/functor is not compatible with the delegate signature");
TLambda* p = static_cast<TLambda*>(object); TLambda* p = static_cast<TLambda*>(invocation.ptr.object);
return (p->operator())(etl::forward<TArgs>(arg)...); return (p->operator())(etl::forward<TArgs>(arg)...);
} }
@ -756,11 +814,11 @@ namespace etl
/// Stub call for a const lambda or functor function. /// Stub call for a const lambda or functor function.
//************************************************************************* //*************************************************************************
template <typename TLambda> template <typename TLambda>
static ETL_CONSTEXPR14 TReturn const_lambda_stub(void* object, TArgs... arg) static ETL_CONSTEXPR14 TReturn const_lambda_stub(const invocation_element& invocation, TArgs... arg)
{ {
ETL_STATIC_ASSERT(is_compatible_callable<TLambda>::value, "etl::delegate: bound lambda/functor is not compatible with the delegate signature"); ETL_STATIC_ASSERT(is_compatible_callable<TLambda>::value, "etl::delegate: bound lambda/functor is not compatible with the delegate signature");
const TLambda* p = static_cast<const TLambda*>(object); const TLambda* p = static_cast<const TLambda*>(invocation.ptr.object);
return (p->operator())(etl::forward<TArgs>(arg)...); return (p->operator())(etl::forward<TArgs>(arg)...);
} }

View File

@ -274,7 +274,7 @@ namespace
}; };
//******************************************* //*******************************************
int times_2(int a) int times_2(int a)
{ {
return a * 2; return a * 2;
} }
@ -315,7 +315,7 @@ namespace
// Check the return type. // Check the return type.
CHECK_TRUE((std::is_same<Delegate::return_type, int>::value)); CHECK_TRUE((std::is_same<Delegate::return_type, int>::value));
// Check the argument types. // Check the argument types.
CHECK_TRUE((std::is_same<Delegate::argument_types, etl::type_list<float, long>>::value)); CHECK_TRUE((std::is_same<Delegate::argument_types, etl::type_list<float, long>>::value));
} }
@ -636,7 +636,7 @@ namespace
//************************************************************************* //*************************************************************************
TEST_FIXTURE(SetupFixture, test_construct_from_rvalue_non_capturing_lambda) TEST_FIXTURE(SetupFixture, test_construct_from_rvalue_non_capturing_lambda)
{ {
etl::delegate<int(int, int)> d([](int i, int j) { function_called = FunctionCalled::Lambda_Called; parameter_correct = (i == VALUE1) && (j == VALUE2); return i + j; }); etl::delegate<int(int, int)> d(+[](int i, int j) { function_called = FunctionCalled::Lambda_Called; parameter_correct = (i == VALUE1) && (j == VALUE2); return i + j; });
int result = d(VALUE1, VALUE2); int result = d(VALUE1, VALUE2);
@ -650,7 +650,7 @@ namespace
{ {
etl::delegate<int(int, int)> d; etl::delegate<int(int, int)> d;
d = [](int i, int j) { function_called = FunctionCalled::Lambda_Called; parameter_correct = (i == VALUE1) && (j == VALUE2); return i + j + 2; }; d = +[](int i, int j) { function_called = FunctionCalled::Lambda_Called; parameter_correct = (i == VALUE1) && (j == VALUE2); return i + j + 2; };
int result = d(VALUE1, VALUE2); int result = d(VALUE1, VALUE2);
@ -662,7 +662,7 @@ namespace
//************************************************************************* //*************************************************************************
TEST_FIXTURE(SetupFixture, test_create_from_rvalue_non_capturing_lambda) TEST_FIXTURE(SetupFixture, test_create_from_rvalue_non_capturing_lambda)
{ {
auto d = etl::delegate<int(int, int)>::create([](int i, int j) { function_called = FunctionCalled::Lambda_Called; parameter_correct = (i == VALUE1) && (j == VALUE2); return i + j + 5; }); auto d = etl::delegate<int(int, int)>::create(+[](int i, int j) { function_called = FunctionCalled::Lambda_Called; parameter_correct = (i == VALUE1) && (j == VALUE2); return i + j + 5; });
int result = d(VALUE1, VALUE2); int result = d(VALUE1, VALUE2);
@ -1221,20 +1221,20 @@ namespace
} }
//************************************************************************* //*************************************************************************
//#if ETL_USING_CPP17 #if ETL_USING_CPP17
// TEST_FIXTURE(SetupFixture, test_make_delegate_member_static) TEST_FIXTURE(SetupFixture, test_make_delegate_member_static)
// { {
// auto d = etl::make_delegate<Object::member_static>(); auto d = etl::make_delegate<Object::member_static>();
//
// Data data; Data data;
// data.d = VALUE1; data.d = VALUE1;
//
// d(data, VALUE2); d(data, VALUE2);
//
// CHECK(function_called == FunctionCalled::Member_Static_Called); CHECK(function_called == FunctionCalled::Member_Static_Called);
// CHECK(parameter_correct); CHECK(parameter_correct);
// } }
//#endif #endif
//************************************************************************* //*************************************************************************
#if ETL_USING_CPP14 #if ETL_USING_CPP14
@ -1253,20 +1253,20 @@ namespace
#endif #endif
//************************************************************************* //*************************************************************************
//#if ETL_USING_CPP17 #if ETL_USING_CPP17
// TEST_FIXTURE(SetupFixture, test_make_delegate_member_static_constexpr) TEST_FIXTURE(SetupFixture, test_make_delegate_member_static_constexpr)
// { {
// constexpr auto d = etl::make_delegate<Object::member_static>(); constexpr auto d = etl::make_delegate<Object::member_static>();
//
// Data data; Data data;
// data.d = VALUE1; data.d = VALUE1;
//
// d(data, VALUE2); d(data, VALUE2);
//
// CHECK(function_called == FunctionCalled::Member_Static_Called); CHECK(function_called == FunctionCalled::Member_Static_Called);
// CHECK(parameter_correct); CHECK(parameter_correct);
// } }
//#endif #endif
#if !(defined(ETL_COMPILER_GCC) && (__GNUC__ <= 5)) #if !(defined(ETL_COMPILER_GCC) && (__GNUC__ <= 5))
//************************************************************************* //*************************************************************************
@ -1677,7 +1677,7 @@ namespace
TEST_FIXTURE(SetupFixture, test_set_free_int) TEST_FIXTURE(SetupFixture, test_set_free_int)
{ {
etl::delegate<void(int, int)> d; etl::delegate<void(int, int)> d;
d.set<free_int>(); d.set<free_int>();
d(VALUE1, VALUE2); d(VALUE1, VALUE2);
@ -1690,7 +1690,7 @@ namespace
TEST_FIXTURE(SetupFixture, test_set_lambda_int) TEST_FIXTURE(SetupFixture, test_set_lambda_int)
{ {
etl::delegate<void(int, int)> d; etl::delegate<void(int, int)> d;
d.set([](int i, int j) { function_called = FunctionCalled::Lambda_Called; parameter_correct = (i == VALUE1) && (j == VALUE2); }); d.set([](int i, int j) { function_called = FunctionCalled::Lambda_Called; parameter_correct = (i == VALUE1) && (j == VALUE2); });
d(VALUE1, VALUE2); d(VALUE1, VALUE2);
@ -1704,7 +1704,7 @@ namespace
{ {
Object object; Object object;
etl::delegate<void(const Data&, int)> d; etl::delegate<void(const Data&, int)> d;
d.set<Object, &Object::member_reference>(object); d.set<Object, &Object::member_reference>(object);
Data data; Data data;
@ -1851,8 +1851,11 @@ namespace
auto d1 = etl::delegate<void(int, int)>::create<Object, &Object::member_int>(object); auto d1 = etl::delegate<void(int, int)>::create<Object, &Object::member_int>(object);
auto d2 = d1; auto d2 = d1;
auto d3 = etl::delegate<void(int, int)>::create([](int, int) { });
auto d4 = d3;
CHECK(d1 == d2); CHECK(d1 == d2);
CHECK(d3 == d4);
} }
//************************************************************************* //*************************************************************************
@ -1862,8 +1865,10 @@ namespace
auto d1 = etl::delegate<void(int, int)>::create<Object, &Object::member_int>(object); auto d1 = etl::delegate<void(int, int)>::create<Object, &Object::member_int>(object);
auto d2 = etl::delegate<void(int, int)>::create<Object, &Object::member_int_const>(object); auto d2 = etl::delegate<void(int, int)>::create<Object, &Object::member_int_const>(object);
auto d3 = etl::delegate<void(int, int)>::create([](int, int) { });
CHECK(d1 != d2); CHECK(d1 != d2);
CHECK(d1 != d3);
} }
//************************************************************************* //*************************************************************************