Last active
December 20, 2016 06:36
-
-
Save benloong/75968572261b2e4b99c3bccfa2014e94 to your computer and use it in GitHub Desktop.
c++ delegate implementation
This file contains hidden or 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
#pragma once | |
#include<type_traits> | |
template <typename T> class Delegate; | |
template<class R, class ...Args> | |
class Delegate <R(Args...)> final | |
{ | |
private: | |
using stub_type = R(* )(const Delegate&, Args&&...); | |
using deleter_type = void(*)(void*); | |
typedef R(*F)(Args...); | |
template<typename Callable> | |
const Callable& Callee() const { | |
return *static_cast<Callable*>(object_ptr); | |
} | |
static R function_stub(const Delegate& delegate, Args&&... args) | |
{ | |
return delegate.function_ptr(std::forward<Args>(args)...); | |
} | |
template<typename F> | |
static R function_stub(const Delegate& delegate, Args&&... args) { | |
return delegate.Callee<F>()(std::forward<Args>(args)...); | |
} | |
template<typename T> | |
static void free(void *p) { | |
T* pf = static_cast<T*>(p); | |
pf->~T(); | |
} | |
static void free(void *p) { | |
p = nullptr; | |
} | |
private: | |
enum | |
{ | |
SPACE_SIZE = 6 * sizeof(void *) | |
}; | |
private: | |
stub_type stub_ptr = nullptr; | |
deleter_type deleter_ptr = nullptr; | |
union { | |
F function_ptr; | |
void* object_ptr; | |
}; | |
uint8_t space[SPACE_SIZE]; | |
public: | |
Delegate(F f) { | |
stub_ptr = function_stub; | |
function_ptr = f; | |
} | |
template<typename Fn> | |
Delegate(Fn fn) { | |
using Decay = std::decay_t<Fn>; | |
stub_ptr = function_stub<Decay>; | |
Decay *p = static_cast<Decay*>((void *)space); | |
object_ptr = new(p)Decay(std::move(fn)); | |
deleter_ptr = free<Decay>; | |
} | |
~Delegate() noexcept | |
{ | |
if (deleter_ptr != nullptr) | |
{ | |
deleter_ptr(object_ptr); | |
} | |
} | |
Delegate(Delegate const&) = default; | |
Delegate& operator=(Delegate const&) = default; | |
Delegate() noexcept = default; | |
Delegate(Delegate&&) noexcept = default; | |
Delegate& operator=(Delegate&&) noexcept = default; | |
Delegate(std::nullptr_t const) noexcept : Delegate() { } | |
operator bool() const noexcept | |
{ | |
return stub_ptr == nullptr; | |
} | |
bool operator ==(Delegate const& rhs) const noexcept | |
{ | |
return (stub_ptr == rhs.stub_ptr) && (object_ptr == rhs.object_ptr); | |
} | |
bool operator !=(Delegate const& rhs) const noexcept | |
{ | |
return !(operator==(rhs)); | |
} | |
bool operator ==(std::nullptr_t const) const noexcept | |
{ | |
return stub_ptr == nullptr; | |
} | |
bool operator !=(std::nullptr_t const) const noexcept | |
{ | |
return stub_ptr != nullptr; | |
} | |
R operator ()(Args... args) const { | |
return (*stub_ptr)(*this, std::forward<Args>(args)...); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment