Skip to content

Instantly share code, notes, and snippets.

@xenobrain
Last active June 16, 2026 22:35
Show Gist options
  • Select an option

  • Save xenobrain/ed90e8a54ad948cebf480fbbc3d0772b to your computer and use it in GitHub Desktop.

Select an option

Save xenobrain/ed90e8a54ad948cebf480fbbc3d0772b to your computer and use it in GitHub Desktop.
delegate
module;
#include <xc.foundation/defines.h>
export module xc.foundation.delegate.api;
import xc.foundation.types;
export namespace xc {
template <typename F>
class Delegate;
template <typename R, typename... Args>
class Delegate<R(Args...)> {
using proxy_fn = R (*)(void*, Args...);
public:
// bind free function
template <R (*Fn)(Args...)>
auto bind() noexcept -> Delegate& {
instance_ = nullptr;
proxy_ = &fn_proxy<Fn>;
return *this;
}
// bind non-const member function
template <class C, R (C::*Fn)(Args...)>
auto bind(C* inst) noexcept -> Delegate& {
instance_ = inst;
proxy_ = &method_proxy<C, Fn>;
return *this;
}
// bind const member function
template <class C, R (C::*Fn)(Args...) const>
auto bind(C const* inst) noexcept -> Delegate& {
instance_ = const_cast<C*>(inst);
proxy_ = &const_method_proxy<C, Fn>;
return *this;
}
XC_FORCE_INLINE auto invoke(Args... args) const -> R {
XC_ASSERT(proxy_ != nullptr);
if constexpr (is_void_v<R>) {
proxy_(instance_, static_cast<Args&&>(args)...);
}
else {
return proxy_(instance_, static_cast<Args&&>(args)...);
}
}
XC_FORCE_INLINE auto operator()(Args... args) const -> R { return invoke(static_cast<Args&&>(args)...); }
explicit operator bool() const noexcept { return proxy_ != nullptr; }
auto reset() noexcept -> void {
instance_ = nullptr;
proxy_ = nullptr;
}
private:
template <R (*Fn)(Args...)>
static auto fn_proxy(void*, Args... args) noexcept -> R {
return Fn(static_cast<Args&&>(args)...);
}
template <class C, R (C::*Fn)(Args...)>
static auto method_proxy(void* inst, Args... args) noexcept -> R {
return (static_cast<C*>(inst)->*Fn)(static_cast<Args&&>(args)...);
}
template <class C, R (C::*Fn)(Args...) const>
static auto const_method_proxy(void* inst, Args... args) noexcept -> R {
return (static_cast<C const*>(inst)->*Fn)(static_cast<Args&&>(args)...);
}
void* instance_{};
proxy_fn proxy_{};
};
static_assert(is_trivially_copyable_v<Delegate<i32()>>);
static_assert(sizeof(Delegate<i32()>) == 2 * sizeof(void*));
}
#include <xc.foundation/defines.h>
import xc.foundation.types;
import xc.foundation.delegate.api;
// Compile-time guarantees
namespace compile_time {
using D = xc::Delegate<xc::i32()>;
static_assert(xc::is_trivially_copyable_v<D>, "Delegate must be trivially copyable");
static_assert(sizeof(D) == 2 * sizeof(void*), "Delegate must be exactly two pointers (16 B on 64-bit)");
static_assert(xc::is_void_v<void>);
inline auto run() -> void { /* static_asserts fire at compile time */ }
}
// Free-function bind test
namespace free_fn {
inline xc::i32 counter{};
extern "C" xc::i32 add(xc::i32 a, xc::i32 b) {
return a + b;
}
auto run() -> void {
xc::Delegate<xc::i32(xc::i32, xc::i32)> d;
XC_ASSERT(!d);
d.bind<add>();
XC_ASSERT(d);
XC_ASSERT(d(3, 4) == 7);
XC_ASSERT(d.invoke(-1, 10) == 9);
// Copy: trivial memcpy semantics
auto d2 = d;
XC_ASSERT(d2(100, 200) == 300);
d.reset();
XC_ASSERT(!d);
}
}
// Member-function bind test
namespace member_fn {
struct Calculator {
xc::i32 base{};
auto multiply(xc::i32 x) -> xc::i32 { return base * x; }
};
auto run() -> void {
Calculator calc{42};
xc::Delegate<xc::i32(xc::i32)> d;
d.bind<Calculator, &Calculator::multiply>(&calc);
XC_ASSERT(d(3) == 126);
calc.base = 10;
XC_ASSERT(d(7) == 70); // live pointer to instance
// Copy preserves the same instance pointer
auto d2 = d;
XC_ASSERT(d2(5) == 50);
}
}
// Const member-function bind test
namespace const_fn {
struct Sensor {
xc::f32 value{};
auto read() const -> xc::f32 { return value; }
};
auto run() -> void {
Sensor s{3.14f};
xc::Delegate<xc::f32()> d;
d.bind<Sensor, &Sensor::read>(&s);
XC_ASSERT(d() == 3.14f);
s.value = 2.71f;
XC_ASSERT(d() == 2.71f);
}
}
// Void-return delegate test
namespace void_ret {
inline bool called{};
extern "C" void set_flag() {
called = true;
}
auto run() -> void {
called = false;
xc::Delegate<void()> d;
d.bind<set_flag>();
d();
XC_ASSERT(called);
}
}
//Entry point
extern "C" auto entry() -> void {
compile_time::run(); // NOLINT — body is empty; static_asserts fire at compile time
free_fn::run();
member_fn::run();
const_fn::run();
void_ret::run();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment