Skip to content

Instantly share code, notes, and snippets.

@benloong
Last active December 20, 2016 06:36
Show Gist options
  • Save benloong/75968572261b2e4b99c3bccfa2014e94 to your computer and use it in GitHub Desktop.
Save benloong/75968572261b2e4b99c3bccfa2014e94 to your computer and use it in GitHub Desktop.
c++ delegate implementation
#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