Skip to content

Instantly share code, notes, and snippets.

@pplux
Created July 13, 2020 13:05
Show Gist options
  • Select an option

  • Save pplux/4ef53360dba1d362538de9f4dedafd09 to your computer and use it in GitHub Desktop.

Select an option

Save pplux/4ef53360dba1d362538de9f4dedafd09 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <assert.h>
#include <vector>
template<class T>
struct Func{};
// std::func replacement without dynamic memory allocation (captures are limited to 48 bytes)
// this could be extended to support captures >48 bytes... of course, with a bit more of logic
// and some state.
template<class R, class... Args>
struct Func<R(Args...)> {
template<class U>
Func(U &&callable) { set(std::move(callable)); }
template<class U>
Func& operator=(U &&callable) { set(std::move(callable)); return *this; }
Func(Func&& other) noexcept {
swap(std::move(other));
}
Func& operator=(Func &&other) noexcept {
swap(std::move(other));
}
~Func() {
if (_destroy) _destroy(_space);
}
R operator()(Args... args) {
return _func(_space, std::forward<Args>(args)...);
}
template<class U>
void set(U &&callable) {
assert(sizeof(U) <= sizeof(_space));
new (_space)U(std::move(callable));
_func = [](void *ptr, Args... args) -> R { return (*reinterpret_cast<U*>(ptr))(std::forward<Args>(args)...); };
_destroy = [](void *ptr) { reinterpret_cast<U*>(ptr)->~U();};
};
void swap(Func &&other) {
std::swap(_space, other._space);
std::swap(_func, other._func);
std::swap(_destroy, other._destroy);
}
R (*_func)(void *, Args...) = nullptr;
void (*_destroy)(void *) = nullptr;
uint8_t _space[64-sizeof(_func)-sizeof(_destroy)];
};
int main ()
{
int f = 5.0f;
std::vector<Func<float(int,int)>> callbacks;
callbacks.push_back([](int a, int b) -> float { return a+b;});
callbacks.push_back([f](int a, int b) -> float { return f+a+b;});
for(auto &&f: callbacks) {
printf("%f\n", f(1,2));
}
}
@meshula

meshula commented Jan 30, 2021

Copy link
Copy Markdown

This is a really nice reference, thanks for posting.

@pplux

pplux commented Oct 3, 2023

Copy link
Copy Markdown
Author

Based on some conversations, this is an example of the same concept but for Callbacks that doesn't need to be stored

#include <stdio.h>
#include <utility>

template<class T> struct Callback;

template<class R, class... Args>
struct Callback<R(Args...)> {
    Callback() {}
    
    template<class F>
    Callback(F *f) {
        _func = [](void *data, Args... args) -> R {
            F *f = (F*)data;
            return (*f)(args...);
        };
        data = (void*)f;
    }

    template<class F>
    Callback(F &&func) : Callback(&func) {}

    R operator()(Args... args) {
        return _func(data, std::forward<Args>(args)...);
    }

    R (*_func)(void *, Args...) = nullptr;
    void *data = nullptr;
};

__attribute__((noinline))
void test(Callback<void(int)> callback, int times) {
    for (int i = 0; i < times; i++) {
        callback(i);
    }
}

int main(int argc, char **argv) {
    float f = 2.5f;
    auto lambda = [&](int i) { printf("%s %f\n", argv[i], f); };
    test(&lambda, argc);

    // TEST 2
    test([&](int i) { printf("%s %f\n", argv[i], f);} , argc);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment