review: delegate

This commit is contained in:
Michele Caini
2018-11-30 10:34:49 +01:00
parent 9e5a2db4c5
commit 58ceb454dd
+26 -28
View File
@@ -2,7 +2,6 @@
#define ENTT_SIGNAL_DELEGATE_HPP
#include <utility>
#include <functional>
#include <type_traits>
#include "../config/config.h"
@@ -81,21 +80,6 @@ class delegate;
template<typename Ret, typename... Args>
class delegate<Ret(Args...)> final {
using proto_fn_type = Ret(const void *, Args...);
using stub_type = std::pair<const void *, proto_fn_type *>;
template<auto Function>
static Ret proto(const void *, Args... args) {
return std::invoke(Function, args...);
}
template<bool Const, typename Class, auto Member>
static Ret proto(const void *instance, Args... args) {
if constexpr(Const) {
return std::invoke(Member, static_cast<const Class *>(instance), args...);
} else {
return std::invoke(Member, const_cast<Class *>(static_cast<const Class *>(instance)), args...);
}
}
public:
/*! @brief Function type of the delegate. */
@@ -103,7 +87,7 @@ public:
/*! @brief Default constructor. */
delegate() ENTT_NOEXCEPT
: stub{}
: fn{nullptr}, ref{nullptr}
{}
/**
@@ -112,7 +96,7 @@ public:
*/
template<auto Function>
delegate(connect_arg_t<Function>) ENTT_NOEXCEPT
: stub{}
: delegate{}
{
connect<Function>();
}
@@ -125,7 +109,7 @@ public:
*/
template<auto Member, typename Class>
delegate(connect_arg_t<Member>, Class *instance) ENTT_NOEXCEPT
: stub{}
: delegate{}
{
connect<Member>(instance);
}
@@ -137,7 +121,11 @@ public:
template<auto Function>
void connect() ENTT_NOEXCEPT {
static_assert(std::is_invocable_r_v<Ret, decltype(Function), Args...>);
stub = std::make_pair(nullptr, &proto<Function>);
ref = nullptr;
fn = [](const void *, Args... args) -> Ret {
return std::invoke(Function, args...);
};
}
/**
@@ -154,7 +142,15 @@ public:
template<auto Member, typename Class>
void connect(Class *instance) ENTT_NOEXCEPT {
static_assert(std::is_invocable_r_v<Ret, decltype(Member), Class, Args...>);
stub = std::make_pair(instance, &proto<std::is_const_v<Class>, std::remove_const_t<Class>, Member>);
ref = instance;
fn = [](const void *instance, Args... args) -> Ret {
if constexpr(std::is_const_v<Class>) {
return std::invoke(Member, static_cast<Class *>(instance), args...);
} else {
return std::invoke(Member, static_cast<Class *>(const_cast<void *>(instance)), args...);
}
};
}
/**
@@ -163,7 +159,8 @@ public:
* After a reset, a delegate can be safely invoked with no effect.
*/
void reset() ENTT_NOEXCEPT {
stub = std::make_pair(nullptr, nullptr);
ref = nullptr;
fn = nullptr;
}
/**
@@ -171,7 +168,7 @@ public:
* @return An opaque pointer to the instance bound to the delegate, if any.
*/
const void * instance() const ENTT_NOEXCEPT {
return stub.first;
return ref;
}
/**
@@ -189,7 +186,7 @@ public:
* @return The value returned by the underlying function.
*/
Ret operator()(Args... args) const {
return stub.second(stub.first, args...);
return fn(ref, args...);
}
/**
@@ -197,8 +194,8 @@ public:
* @return False if the delegate is empty, true otherwise.
*/
explicit operator bool() const ENTT_NOEXCEPT {
// no need to test also stub.first
return stub.second;
// no need to test also data
return fn;
}
/**
@@ -210,11 +207,12 @@ public:
* @return True if the two delegates are identical, false otherwise.
*/
bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
return stub.first == other.stub.first && stub.second == other.stub.second;
return ref == other.ref && fn == other.fn;
}
private:
stub_type stub{};
proto_fn_type *fn;
const void *ref;
};