diff options
| author | day <day@national.shitposting.agency> | 2026-03-16 16:25:49 +0100 |
|---|---|---|
| committer | day <day@national.shitposting.agency> | 2026-03-16 16:25:49 +0100 |
| commit | 7f85c9fc75bd62ac09ea4457d3b17f85988fca66 (patch) | |
| tree | 15248e42bfafc6bd19e50c9010b701057958ff3a /src/util/callback.h | |
| parent | 872c39b24ecf4063f785ff3e8b2f940acd8c2d59 (diff) | |
| parent | 991352b0d2767e6bd1a46f554db4ac9d208c13ad (diff) | |
Merge remote-tracking branch 'origin/master' into obj
Diffstat (limited to 'src/util/callback.h')
| -rw-r--r-- | src/util/callback.h | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/src/util/callback.h b/src/util/callback.h new file mode 100644 index 0000000..a2c9477 --- /dev/null +++ b/src/util/callback.h @@ -0,0 +1,84 @@ +#pragma once +#include "typedef.h" + +template <typename T> +struct FN; +// voodoo +template <typename RET, typename... ARGS> +struct FN<RET(ARGS...)> { + 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...); }; + + static const unsigned int BUF_SIZE = 32; + + alignas(8) char buf[BUF_SIZE]; + void* data; + RET( *invoke )( void*, ARGS... ); + void( *destroy )( void* ); + void*( *clone )( void*, char* ); + + template <typename F> + FN(F&& f) { + using __stripped = typename __strip_ref<F>::type; + + if constexpr( sizeof(__stripped) <= BUF_SIZE ) { + new (buf) __stripped( f ); + data = buf; + destroy = pfn( void* d ) { + ( (__stripped*)d )->~__stripped(); + }; + clone = pfn( void* d, char* dst ) -> void* { + new (dst) __stripped( *(__stripped*)d ); + return dst; + }; + } else { + data = new __stripped( f ); + destroy = pfn( void* d ) { + delete (__stripped*)d; + }; + clone = pfn( void* d, char* dst ) -> void* { + return new __stripped( *(__stripped*)d ); + }; + } + + invoke = pfn( void* d, ARGS... args ) -> RET { + return ( *(__stripped*)d )( args... ); + }; + } + + FN( I32&& ) : data( 0 ), invoke( 0 ), destroy( 0 ), clone( 0 ) {} + FN( U32&& ) : data( 0 ), invoke( 0 ), destroy( 0 ), clone( 0 ) {} + FN() : data( 0 ), invoke( 0 ), destroy( 0 ), clone( 0 ) {} + + FN( const FN& other ) : invoke( other.invoke ), destroy( other.destroy ), clone( other.clone ) { + if( !other.data ) { + data = 0; + return; + } + + data = other.clone( other.data, buf ); + } + + FN& operator=( const FN& other ) { + if( this == &other ) return *this; + if( destroy && data ) destroy( data ); + invoke = other.invoke; + destroy = other.destroy; + clone = other.clone; + data = other.data ? other.clone( other.data, buf ) : 0; + return *this; + } + + ~FN() { + if( destroy && data ) destroy( data ); + } + + RET operator()( ARGS... args ) const { + return invoke( data, args... ); + } + + operator bool() const { return !!invoke; } +}; |
