summaryrefslogtreecommitdiff
path: root/src/util/callback.h
diff options
context:
space:
mode:
authoraura <nw@moneybot.cc>2026-03-16 10:15:01 +0100
committeraura <nw@moneybot.cc>2026-03-16 10:15:01 +0100
commitfdc5e8760fb7ac0af8e7ebb98a2076db15e31082 (patch)
treec94991e1e594c7703295aa413caf40786f343c1f /src/util/callback.h
parente2829336cfedb39d23263f75b61ed969c8193534 (diff)
giga refactor, fix ALL the leaks
Diffstat (limited to 'src/util/callback.h')
-rw-r--r--src/util/callback.h88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/util/callback.h b/src/util/callback.h
new file mode 100644
index 0000000..df93b59
--- /dev/null
+++ b/src/util/callback.h
@@ -0,0 +1,88 @@
+#pragma once
+#include "typedef.h"
+
+template <typename T>
+struct FN;
+
+template <typename RET, typename... ARGS>
+struct FN<RET(ARGS...)> {
+ // voodoo
+ template <typename T> struct __strip_ref { using type = T; };
+ template <typename T> struct __strip_ref<T&> { using type = T; };
+ template <typename T> struct __strip_ref<T&&> { using type = T; };
+ template <typename R, typename... A> struct __strip_ref<R(A...)> { using type = R(*)(A...); };
+ template <typename R, typename... A> struct __strip_ref<R(&)(A...)> { using type = R(*)(A...); };
+
+ void* data;
+ U32 size;
+ RET( *invoke )( void*, ARGS... );
+ void( *destroy )( void* );
+ void*( *clone )( void* );
+
+ template <typename F>
+ FN( F&& f ) {
+ using __stripped = typename __strip_ref<F>::type;
+ data = new __stripped( static_cast<F&&>(f) );
+ size = sizeof( __stripped );
+ invoke = pfn( void* d, ARGS... args ) -> RET {
+ return ( *(__stripped*)d )( args... );
+ };
+ destroy = pfn( void* d ) {
+ delete (__stripped*)d;
+ };
+ clone = pfn( void* data ) {
+ return (void*)new __stripped( *(__stripped*)data );
+ };
+ }
+
+ template <>
+ FN( int&& ) : data( 0 ), invoke( 0 ), destroy( 0 ) {}
+ FN() : data( 0 ), invoke( 0 ), destroy( 0 ) {}
+
+ FN( FN&& other ) : data( other.data ), invoke( other.invoke ), destroy( other.destroy ) {
+ other.data = 0;
+ other.invoke = 0;
+ other.destroy = 0;
+ }
+
+ FN& operator=( FN&& other ) {
+ if( this == &other ) return *this;
+ if( destroy ) destroy( data );
+ data = other.data;
+ invoke = other.invoke;
+ destroy = other.destroy;
+ other.data = 0;
+ other.invoke = 0;
+ other.destroy = 0;
+ return *this;
+ }
+
+ FN( const FN& other ) {
+ *this = other;
+ };
+
+ FN& operator=( const FN& other ) {
+ if( !other.data ) {
+ data = 0;
+ invoke = 0;
+ destroy = 0;
+ size = 0;
+ return *this;
+ }
+
+ size = other.size;
+ data = other.clone( other.data );
+ invoke = other.invoke;
+ destroy = other.destroy;
+ clone = other.clone;
+ return *this;
+ }
+
+ ~FN() { if( destroy ) destroy( data ); }
+ operator bool() const { return !!invoke; }
+
+ RET operator()( ARGS... args ) const {
+ return invoke( data, args... );
+ }
+
+};